mirror of
https://github.com/postalserver/postal.git
synced 2026-10-19 18:56:05 +00:00
Merge pull request #2797 from postalserver/rubocop
Code Quality Improvements
This commit is contained in:
+151
-12
@@ -1,35 +1,174 @@
|
|||||||
inherit_from:
|
AllCops:
|
||||||
- https://dev.k.io/rubocop/rubocop.rails.yml
|
TargetRubyVersion: 3.0
|
||||||
|
NewCops: enable
|
||||||
|
Exclude:
|
||||||
|
- "bin/*"
|
||||||
|
- "db/schema.rb"
|
||||||
|
# Fixes missing gem exception when running Rubocop on GitHub Actions.
|
||||||
|
- "vendor/bundle/**/*"
|
||||||
|
|
||||||
|
# Always use double quotes
|
||||||
Style/StringLiterals:
|
Style/StringLiterals:
|
||||||
EnforcedStyle: double_quotes
|
EnforcedStyle: double_quotes
|
||||||
|
|
||||||
Style/WordArray:
|
# We prefer arrays of symbols to look like an array of symbols.
|
||||||
|
# For example: [:one, :two, :three] as opposed to %i[one two three]
|
||||||
|
Style/SymbolArray:
|
||||||
EnforcedStyle: brackets
|
EnforcedStyle: brackets
|
||||||
|
|
||||||
Layout/LineLength:
|
# There should always be empty lines inside a class. For example
|
||||||
|
#
|
||||||
|
# class MyExample
|
||||||
|
#
|
||||||
|
# def some_method
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# end
|
||||||
|
Layout/EmptyLinesAroundClassBody:
|
||||||
|
EnforcedStyle: empty_lines
|
||||||
|
|
||||||
|
# We want to keep attr_* definitions separated on their own lines, rather than
|
||||||
|
# all of them collapsed into a single attr_* call. The collapsed/grouped variant
|
||||||
|
# is harder to read, and harder to see what's been changed in diffs.
|
||||||
|
Style/AccessorGrouping:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
# Blocks are slightly different to classes, in these cases there should
|
||||||
|
# not be new lines around the contents of the block.
|
||||||
|
#
|
||||||
|
# proc do
|
||||||
|
# # Do something
|
||||||
|
# end
|
||||||
|
Layout/EmptyLinesAroundBlockBody:
|
||||||
|
EnforcedStyle: no_empty_lines
|
||||||
|
|
||||||
|
# Modules are the same as classes unless they're being used for namespacing
|
||||||
|
# purposes in which case there should not be new lines.
|
||||||
|
Layout/EmptyLinesAroundModuleBody:
|
||||||
|
EnforcedStyle: empty_lines_except_namespace
|
||||||
|
|
||||||
|
# Space is required following -> when writing a lambda:
|
||||||
|
#
|
||||||
|
# somethign = -> (var) { block }
|
||||||
|
Layout/SpaceInLambdaLiteral:
|
||||||
|
EnforcedStyle: require_space
|
||||||
|
|
||||||
|
Layout/FirstHashElementIndentation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# We don't mind setting assignments in conditions so this has been disabled to
|
||||||
|
# allow `if something = something_else` without worrying about brackets.
|
||||||
|
Lint/AssignmentInCondition:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# Top level documentation is quite rare...
|
||||||
|
Style/Documentation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# We want to allow inner slashes in a regexp to be used when using /xxx/ form.
|
||||||
|
Style/RegexpLiteral:
|
||||||
|
AllowInnerSlashes: true
|
||||||
|
|
||||||
|
# Blocks of if statements are perfectly fine and usually more readable than
|
||||||
|
# putting everything onto a single line just because we can.
|
||||||
|
Style/IfUnlessModifier:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# We prefer assignments to happen within the condition rather than setting a
|
||||||
|
# variable to the result of a condition.
|
||||||
|
Style/ConditionalAssignment:
|
||||||
|
EnforcedStyle: assign_inside_condition
|
||||||
|
IncludeTernaryExpressions: false
|
||||||
|
|
||||||
|
# Empty methods should not be compacted onto a single line
|
||||||
|
Style/EmptyMethod:
|
||||||
|
EnforcedStyle: expanded
|
||||||
|
|
||||||
|
# As above, just flag them.
|
||||||
|
Lint/UnusedBlockArgument:
|
||||||
|
AutoCorrect: false
|
||||||
|
|
||||||
|
# While we don't want to make heavy use of get_ or set_ methods we do often need
|
||||||
|
# to use these when we want to refer to actually getting or setting something
|
||||||
|
# (usually from another API).
|
||||||
|
Naming/AccessorMethodName:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# If we want a boolean called :true, we should be allowed that. These are likely
|
||||||
|
# not mistakes.
|
||||||
|
Lint/BooleanSymbol:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# Using block.map(&:upcase) is not always the neatest way to show something. For
|
||||||
|
# example if you have a block that just calls one thing, you don't want it
|
||||||
|
# collapsed.
|
||||||
|
#
|
||||||
|
# action do |user|
|
||||||
|
# user.delete
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# This should be action(&:delete) because it is not clear what is actually
|
||||||
|
# happening without the context of knowing what the inner variable should be
|
||||||
|
# called.
|
||||||
|
Style/SymbolProc:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
# Allow a maxmium of 5 arguments and don't include keyword arguments
|
||||||
|
Metrics/ParameterLists:
|
||||||
|
Max: 5
|
||||||
|
CountKeywordArgs: false
|
||||||
|
|
||||||
|
# This cop checks for chaining of a block after another block that spans multiple lines.
|
||||||
|
Style/MultilineBlockChain:
|
||||||
|
Exclude:
|
||||||
|
- "spec/**/*.rb"
|
||||||
|
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Style/FrozenStringLiteralComment:
|
||||||
|
Enabled: true
|
||||||
|
SafeAutoCorrect: true
|
||||||
|
|
||||||
|
Naming/PredicateName:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/LineLength:
|
||||||
|
# We want to reduce this back down to 120 but there are a fair number of offences
|
||||||
|
# of this which need addressing individually and carefully.
|
||||||
|
Max: 200
|
||||||
|
|
||||||
|
Metrics/PerceivedComplexity:
|
||||||
|
# As above, we want to enable this again in the future, but for now we'll just
|
||||||
|
# disable it entirely.
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/CyclomaticComplexity:
|
||||||
|
# As above.
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/MethodLength:
|
||||||
|
# As above.
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/BlockNesting:
|
||||||
|
# As above.
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/StringConcatenation:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Metrics/BlockLength:
|
Metrics/BlockLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Metrics/ClassLength:
|
Metrics/ClassLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Metrics/CyclomaticComplexity:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Metrics/MethodLength:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Metrics/ModuleLength:
|
Metrics/ModuleLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Metrics/PerceivedComplexity:
|
Lint/UnusedMethodArgument:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Lint/MissingSuper:
|
Style/SpecialGlobalVars:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source "https://rubygems.org"
|
source "https://rubygems.org"
|
||||||
gem "authie"
|
gem "authie"
|
||||||
gem "autoprefixer-rails"
|
gem "autoprefixer-rails"
|
||||||
@@ -10,12 +12,12 @@ gem "clockwork"
|
|||||||
gem "dotenv-rails"
|
gem "dotenv-rails"
|
||||||
gem "dynamic_form"
|
gem "dynamic_form"
|
||||||
gem "encrypto_signo"
|
gem "encrypto_signo"
|
||||||
|
gem "execjs", "~> 2.7", "< 2.8"
|
||||||
gem "foreman"
|
gem "foreman"
|
||||||
gem "gelf"
|
gem "gelf"
|
||||||
gem "haml"
|
gem "haml"
|
||||||
gem "hashie"
|
gem "hashie"
|
||||||
gem "highline", require: false
|
gem "highline", require: false
|
||||||
gem "execjs", '~> 2.7', "< 2.8"
|
|
||||||
gem "jwt"
|
gem "jwt"
|
||||||
gem "kaminari"
|
gem "kaminari"
|
||||||
gem "mail"
|
gem "mail"
|
||||||
@@ -28,8 +30,8 @@ gem "puma"
|
|||||||
gem "rails", "= 6.1.7.6"
|
gem "rails", "= 6.1.7.6"
|
||||||
gem "resolv", "~> 0.2.1"
|
gem "resolv", "~> 0.2.1"
|
||||||
gem "secure_headers"
|
gem "secure_headers"
|
||||||
gem 'sentry-rails'
|
gem "sentry-rails"
|
||||||
gem 'sentry-ruby'
|
gem "sentry-ruby"
|
||||||
gem "turbolinks", "~> 5"
|
gem "turbolinks", "~> 5"
|
||||||
|
|
||||||
group :development, :assets do
|
group :development, :assets do
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
authenticator :server do
|
authenticator :server do
|
||||||
friendly_name "Server Authenticator"
|
friendly_name "Server Authenticator"
|
||||||
header "X-Server-API-Key", "The API token for a server that you wish to authenticate with.", example: "f29a45f0d4e1744ebaee"
|
header "X-Server-API-Key", "The API token for a server that you wish to authenticate with.", example: "f29a45f0d4e1744ebaee"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
controller :messages do
|
controller :messages do
|
||||||
friendly_name "Messages API"
|
friendly_name "Messages API"
|
||||||
description "This API allows you to access message details"
|
description "This API allows you to access message details"
|
||||||
@@ -12,7 +14,7 @@ controller :messages do
|
|||||||
action do
|
action do
|
||||||
begin
|
begin
|
||||||
message = identity.server.message(params.id)
|
message = identity.server.message(params.id)
|
||||||
rescue Postal::MessageDB::Message::NotFound => e
|
rescue Postal::MessageDB::Message::NotFound
|
||||||
error "MessageNotFound", id: params.id
|
error "MessageNotFound", id: params.id
|
||||||
end
|
end
|
||||||
structure :message, message, return: true
|
structure :message, message, return: true
|
||||||
@@ -28,7 +30,7 @@ controller :messages do
|
|||||||
action do
|
action do
|
||||||
begin
|
begin
|
||||||
message = identity.server.message(params.id)
|
message = identity.server.message(params.id)
|
||||||
rescue Postal::MessageDB::Message::NotFound => e
|
rescue Postal::MessageDB::Message::NotFound
|
||||||
error "MessageNotFound", id: params.id
|
error "MessageNotFound", id: params.id
|
||||||
end
|
end
|
||||||
message.deliveries.map do |d|
|
message.deliveries.map do |d|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
controller :send do
|
controller :send do
|
||||||
friendly_name "Send API"
|
friendly_name "Send API"
|
||||||
description "This API allows you to send messages"
|
description "This API allows you to send messages"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
structure :delivery do
|
structure :delivery do
|
||||||
basic :id
|
basic :id
|
||||||
basic :status
|
basic :status
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
structure :message do
|
structure :message do
|
||||||
basic :id
|
basic :id
|
||||||
basic :token
|
basic :token
|
||||||
@@ -5,9 +7,9 @@ structure :message do
|
|||||||
expansion(:status) do
|
expansion(:status) do
|
||||||
{
|
{
|
||||||
status: o.status,
|
status: o.status,
|
||||||
last_delivery_attempt: o.last_delivery_attempt ? o.last_delivery_attempt.to_f : nil,
|
last_delivery_attempt: o.last_delivery_attempt&.to_f,
|
||||||
held: o.held,
|
held: o.held,
|
||||||
hold_expiry: o.hold_expiry ? o.hold_expiry.to_f : nil
|
hold_expiry: o.hold_expiry&.to_f
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AddressEndpointsController < ApplicationController
|
class AddressEndpointsController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "authie/session"
|
require "authie/session"
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
@@ -46,11 +48,7 @@ class ApplicationController < ActionController::Base
|
|||||||
helper_method :page_title
|
helper_method :page_title
|
||||||
|
|
||||||
def redirect_to_with_return_to(url, *args)
|
def redirect_to_with_return_to(url, *args)
|
||||||
if params[:return_to].blank? || !params[:return_to].starts_with?("/")
|
|
||||||
redirect_to url_with_return_to(url), *args
|
redirect_to url_with_return_to(url), *args
|
||||||
else
|
|
||||||
redirect_to url_with_return_to(url), *args
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_timezone
|
def set_timezone
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module WithinOrganization
|
module WithinOrganization
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CredentialsController < ApplicationController
|
class CredentialsController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class DomainsController < ApplicationController
|
class DomainsController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class HelpController < ApplicationController
|
class HelpController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class HTTPEndpointsController < ApplicationController
|
class HTTPEndpointsController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class IPAddressesController < ApplicationController
|
class IPAddressesController < ApplicationController
|
||||||
|
|
||||||
before_action :admin_required
|
before_action :admin_required
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class IPPoolRulesController < ApplicationController
|
class IPPoolRulesController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class IPPoolsController < ApplicationController
|
class IPPoolsController < ApplicationController
|
||||||
|
|
||||||
before_action :admin_required
|
before_action :admin_required
|
||||||
@@ -31,7 +33,7 @@ class IPPoolsController < ApplicationController
|
|||||||
def destroy
|
def destroy
|
||||||
@ip_pool.destroy
|
@ip_pool.destroy
|
||||||
redirect_to_with_json :ip_pools, notice: "IP pool has been removed successfully."
|
redirect_to_with_json :ip_pools, notice: "IP pool has been removed successfully."
|
||||||
rescue ActiveRecord::DeleteRestrictionError => e
|
rescue ActiveRecord::DeleteRestrictionError
|
||||||
redirect_to_with_json [:edit, @ip_pool], alert: "IP pool cannot be removed because it still has associated addresses or servers."
|
redirect_to_with_json [:edit, @ip_pool], alert: "IP pool cannot be removed because it still has associated addresses or servers."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MessagesController < ApplicationController
|
class MessagesController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
@@ -186,7 +188,7 @@ class MessagesController < ApplicationController
|
|||||||
if qs[:before]
|
if qs[:before]
|
||||||
begin
|
begin
|
||||||
options[:where][:timestamp][:less_than] = get_time_from_string(qs[:before]).to_f
|
options[:where][:timestamp][:less_than] = get_time_from_string(qs[:before]).to_f
|
||||||
rescue TimeUndetermined => e
|
rescue TimeUndetermined
|
||||||
flash.now[:alert] = "Couldn't determine time for before from '#{qs[:before]}'"
|
flash.now[:alert] = "Couldn't determine time for before from '#{qs[:before]}'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -194,7 +196,7 @@ class MessagesController < ApplicationController
|
|||||||
if qs[:after]
|
if qs[:after]
|
||||||
begin
|
begin
|
||||||
options[:where][:timestamp][:greater_than] = get_time_from_string(qs[:after]).to_f
|
options[:where][:timestamp][:greater_than] = get_time_from_string(qs[:after]).to_f
|
||||||
rescue TimeUndetermined => e
|
rescue TimeUndetermined
|
||||||
flash.now[:alert] = "Couldn't determine time for after from '#{qs[:after]}'"
|
flash.now[:alert] = "Couldn't determine time for after from '#{qs[:after]}'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -220,6 +222,7 @@ class MessagesController < ApplicationController
|
|||||||
time = Chronic.parse(string, context: :past)
|
time = Chronic.parse(string, context: :past)
|
||||||
end
|
end
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
|
time = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
raise TimeUndetermined, "Couldn't determine a suitable time from '#{string}'" if time.nil?
|
raise TimeUndetermined, "Couldn't determine a suitable time from '#{string}'" if time.nil?
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class OrganizationIPPoolsController < ApplicationController
|
class OrganizationIPPoolsController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class OrganizationsController < ApplicationController
|
class OrganizationsController < ApplicationController
|
||||||
|
|
||||||
before_action :admin_required, only: [:new, :create, :delete, :destroy]
|
before_action :admin_required, only: [:new, :create, :delete, :destroy]
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class RoutesController < ApplicationController
|
class RoutesController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ServersController < ApplicationController
|
class ServersController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
@@ -41,7 +43,12 @@ class ServersController < ApplicationController
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
extra_params = [:spam_threshold, :spam_failure_threshold, :postmaster_address]
|
extra_params = [:spam_threshold, :spam_failure_threshold, :postmaster_address]
|
||||||
extra_params += [:send_limit, :allow_sender, :privacy_mode, :log_smtp_data, :outbound_spam_threshold, :message_retention_days, :raw_message_retention_days, :raw_message_retention_size] if current_user.admin?
|
|
||||||
|
if current_user.admin?
|
||||||
|
extra_params += [:send_limit, :allow_sender, :privacy_mode, :log_smtp_data, :outbound_spam_threshold,
|
||||||
|
:message_retention_days, :raw_message_retention_days, :raw_message_retention_size]
|
||||||
|
end
|
||||||
|
|
||||||
if @server.update(safe_params(*extra_params))
|
if @server.update(safe_params(*extra_params))
|
||||||
redirect_to_with_json organization_server_path(organization, @server), notice: "Server settings have been updated"
|
redirect_to_with_json organization_server_path(organization, @server), notice: "Server settings have been updated"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SessionsController < ApplicationController
|
class SessionsController < ApplicationController
|
||||||
|
|
||||||
layout "sub"
|
layout "sub"
|
||||||
@@ -8,7 +10,7 @@ class SessionsController < ApplicationController
|
|||||||
login(User.authenticate(params[:email_address], params[:password]))
|
login(User.authenticate(params[:email_address], params[:password]))
|
||||||
flash[:remember_login] = true
|
flash[:remember_login] = true
|
||||||
redirect_to_with_return_to root_path
|
redirect_to_with_return_to root_path
|
||||||
rescue Postal::Errors::AuthenticationError => e
|
rescue Postal::Errors::AuthenticationError
|
||||||
flash.now[:alert] = "The credentials you've provided are incorrect. Please check and try again."
|
flash.now[:alert] = "The credentials you've provided are incorrect. Please check and try again."
|
||||||
render "new"
|
render "new"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SMTPEndpointsController < ApplicationController
|
class SMTPEndpointsController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class TrackDomainsController < ApplicationController
|
class TrackDomainsController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class UserController < ApplicationController
|
class UserController < ApplicationController
|
||||||
|
|
||||||
skip_before_action :login_required, only: [:new, :create, :join]
|
skip_before_action :login_required, only: [:new, :create, :join]
|
||||||
@@ -69,7 +71,9 @@ class UserController < ApplicationController
|
|||||||
|
|
||||||
if @user.save
|
if @user.save
|
||||||
if email_changed
|
if email_changed
|
||||||
redirect_to_with_json verify_path(return_to: settings_path), notice: "Your settings have been updated successfully. As you've changed, your e-mail address you'll need to verify it before you can continue."
|
redirect_to_with_json verify_path(return_to: settings_path),
|
||||||
|
notice: "Your settings have been updated successfully. As you've changed, your e-mail " \
|
||||||
|
"address you'll need to verify it before you can continue."
|
||||||
else
|
else
|
||||||
redirect_to_with_json settings_path, notice: "Your settings have been updated successfully."
|
redirect_to_with_json settings_path, notice: "Your settings have been updated successfully."
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class UsersController < ApplicationController
|
class UsersController < ApplicationController
|
||||||
|
|
||||||
before_action :admin_required
|
before_action :admin_required
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class WebhooksController < ApplicationController
|
class WebhooksController < ApplicationController
|
||||||
|
|
||||||
include WithinOrganization
|
include WithinOrganization
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module ApplicationHelper
|
module ApplicationHelper
|
||||||
|
|
||||||
def format_delivery_details(server, text)
|
def format_delivery_details(server, text)
|
||||||
@@ -28,7 +30,7 @@ module ApplicationHelper
|
|||||||
server_domains = server.domains.verified.order(:name)
|
server_domains = server.domains.verified.order(:name)
|
||||||
unless server_domains.empty?
|
unless server_domains.empty?
|
||||||
s << "<optgroup label='Server Domains'>"
|
s << "<optgroup label='Server Domains'>"
|
||||||
for domain in server_domains
|
server_domains.each do |domain|
|
||||||
selected = domain == selected_domain ? "selected='selected'" : ""
|
selected = domain == selected_domain ? "selected='selected'" : ""
|
||||||
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
|
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
|
||||||
end
|
end
|
||||||
@@ -38,7 +40,7 @@ module ApplicationHelper
|
|||||||
organization_domains = server.organization.domains.verified.order(:name)
|
organization_domains = server.organization.domains.verified.order(:name)
|
||||||
unless organization_domains.empty?
|
unless organization_domains.empty?
|
||||||
s << "<optgroup label='Organization Domains'>"
|
s << "<optgroup label='Organization Domains'>"
|
||||||
for domain in organization_domains
|
organization_domains.each do |domain|
|
||||||
selected = domain == selected_domain ? "selected='selected'" : ""
|
selected = domain == selected_domain ? "selected='selected'" : ""
|
||||||
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
|
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
|
||||||
end
|
end
|
||||||
@@ -54,7 +56,7 @@ module ApplicationHelper
|
|||||||
http_endpoints = server.http_endpoints.order(:name).to_a
|
http_endpoints = server.http_endpoints.order(:name).to_a
|
||||||
if http_endpoints.present?
|
if http_endpoints.present?
|
||||||
s << "<optgroup label='HTTP Endpoints'>"
|
s << "<optgroup label='HTTP Endpoints'>"
|
||||||
for endpoint in http_endpoints
|
http_endpoints.each do |endpoint|
|
||||||
value = "#{endpoint.class}##{endpoint.uuid}"
|
value = "#{endpoint.class}##{endpoint.uuid}"
|
||||||
selected = value == selected_value ? "selected='selected'" : ""
|
selected = value == selected_value ? "selected='selected'" : ""
|
||||||
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
|
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
|
||||||
@@ -65,7 +67,7 @@ module ApplicationHelper
|
|||||||
smtp_endpoints = server.smtp_endpoints.order(:name).to_a
|
smtp_endpoints = server.smtp_endpoints.order(:name).to_a
|
||||||
if smtp_endpoints.present?
|
if smtp_endpoints.present?
|
||||||
s << "<optgroup label='SMTP Endpoints'>"
|
s << "<optgroup label='SMTP Endpoints'>"
|
||||||
for endpoint in smtp_endpoints
|
smtp_endpoints.each do |endpoint|
|
||||||
value = "#{endpoint.class}##{endpoint.uuid}"
|
value = "#{endpoint.class}##{endpoint.uuid}"
|
||||||
selected = value == selected_value ? "selected='selected'" : ""
|
selected = value == selected_value ? "selected='selected'" : ""
|
||||||
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
|
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
|
||||||
@@ -76,7 +78,7 @@ module ApplicationHelper
|
|||||||
address_endpoints = server.address_endpoints.order(:address).to_a
|
address_endpoints = server.address_endpoints.order(:address).to_a
|
||||||
if address_endpoints.present?
|
if address_endpoints.present?
|
||||||
s << "<optgroup label='Address Endpoints'>"
|
s << "<optgroup label='Address Endpoints'>"
|
||||||
for endpoint in address_endpoints
|
address_endpoints.each do |endpoint|
|
||||||
value = "#{endpoint.class}##{endpoint.uuid}"
|
value = "#{endpoint.class}##{endpoint.uuid}"
|
||||||
selected = value == selected_value ? "selected='selected'" : ""
|
selected = value == selected_value ? "selected='selected'" : ""
|
||||||
s << "<option value='#{value}' #{selected}>#{endpoint.address}</option>"
|
s << "<option value='#{value}' #{selected}>#{endpoint.address}</option>"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActionDeletionJob < Postal::Job
|
class ActionDeletionJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActionDeletionsJob < Postal::Job
|
class ActionDeletionsJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CheckAllDNSJob < Postal::Job
|
class CheckAllDNSJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "authie/session"
|
require "authie/session"
|
||||||
|
|
||||||
class CleanupAuthieSessionsJob < Postal::Job
|
class CleanupAuthieSessionsJob < Postal::Job
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ExpireHeldMessagesJob < Postal::Job
|
class ExpireHeldMessagesJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ProcessMessageRetentionJob < Postal::Job
|
class ProcessMessageRetentionJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class PruneSuppressionListsJob < Postal::Job
|
class PruneSuppressionListsJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class PruneWebhookRequestsJob < Postal::Job
|
class PruneWebhookRequestsJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class RequeueWebhooksJob < Postal::Job
|
class RequeueWebhooksJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SendNotificationsJob < Postal::Job
|
class SendNotificationsJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SendWebhookJob < Postal::Job
|
class SendWebhookJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
if server = Server.find(params["server_id"])
|
if server = Server.find(params["server_id"])
|
||||||
new_items = {}
|
new_items = {}
|
||||||
if params["payload"]
|
params["payload"]&.each do |key, value|
|
||||||
for key, value in params["payload"]
|
|
||||||
next unless key.to_s =~ /\A_(\w+)/
|
next unless key.to_s =~ /\A_(\w+)/
|
||||||
|
|
||||||
begin
|
begin
|
||||||
new_items[::Regexp.last_match(1)] = server.message_db.message(value.to_i).webhook_hash
|
new_items[::Regexp.last_match(1)] = server.message_db.message(value.to_i).webhook_hash
|
||||||
rescue Postal::MessageDB::Message::NotFound
|
rescue Postal::MessageDB::Message::NotFound
|
||||||
end
|
# No message found, don't do any replacement
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SleepJob < Postal::Job
|
class SleepJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class TidyRawMessagesJob < Postal::Job
|
class TidyRawMessagesJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class UnqueueMessageJob < Postal::Job
|
class UnqueueMessageJob < Postal::Job
|
||||||
|
|
||||||
|
# rubocop:disable Layout/LineLength
|
||||||
def perform
|
def perform
|
||||||
if original_message = QueuedMessage.find_by_id(params["id"])
|
if original_message = QueuedMessage.find_by_id(params["id"])
|
||||||
if original_message.acquire_lock
|
if original_message.acquire_lock
|
||||||
@@ -91,11 +94,11 @@ class UnqueueMessageJob < Postal::Job
|
|||||||
log "#{log_prefix} Message is a bounce"
|
log "#{log_prefix} Message is a bounce"
|
||||||
original_messages = queued_message.message.original_messages
|
original_messages = queued_message.message.original_messages
|
||||||
unless original_messages.empty?
|
unless original_messages.empty?
|
||||||
for original_message in queued_message.message.original_messages
|
queued_message.message.original_messages.each do |orig_msg|
|
||||||
queued_message.message.update(bounce_for_id: original_message.id, domain_id: original_message.domain_id)
|
queued_message.message.update(bounce_for_id: orig_msg.id, domain_id: orig_msg.domain_id)
|
||||||
queued_message.message.create_delivery("Processed", details: "This has been detected as a bounce message for <msg:#{original_message.id}>.")
|
queued_message.message.create_delivery("Processed", details: "This has been detected as a bounce message for <msg:#{orig_msg.id}>.")
|
||||||
original_message.bounce!(queued_message.message)
|
orig_msg.bounce!(queued_message.message)
|
||||||
log "#{log_prefix} Bounce linked with message #{original_message.id}"
|
log "#{log_prefix} Bounce linked with message #{orig_msg.id}"
|
||||||
end
|
end
|
||||||
queued_message.destroy
|
queued_message.destroy
|
||||||
next
|
next
|
||||||
@@ -421,15 +424,17 @@ class UnqueueMessageJob < Postal::Job
|
|||||||
end
|
end
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
log "#{log_prefix} Internal error: #{e.class}: #{e.message}"
|
log "#{log_prefix} Internal error: #{e.class}: #{e.message}"
|
||||||
e.backtrace.each { |e| log("#{log_prefix} #{e}") }
|
e.backtrace.each { |line| log("#{log_prefix} #{line}") }
|
||||||
queued_message.retry_later
|
queued_message.retry_later
|
||||||
log "#{log_prefix} Queued message was unlocked"
|
log "#{log_prefix} Queued message was unlocked"
|
||||||
if defined?(Sentry)
|
if defined?(Sentry)
|
||||||
Sentry.capture_exception(e, extra: { job_id: self.id, server_id: queued_message.server_id, message_id: queued_message.message_id })
|
Sentry.capture_exception(e, extra: { job_id: self.id, server_id: queued_message.server_id, message_id: queued_message.message_id })
|
||||||
end
|
end
|
||||||
if queued_message.message
|
queued_message.message&.create_delivery("Error",
|
||||||
queued_message.message.create_delivery("Error", details: "An internal error occurred while sending this message. This message will be retried automatically. If this persists, contact support for assistance.", output: "#{e.class}: #{e.message}", log_id: "J-#{self.id}")
|
details: "An internal error occurred while sending " \
|
||||||
end
|
"this message. This message will be retried " \
|
||||||
|
"automatically.",
|
||||||
|
output: "#{e.class}: #{e.message}", log_id: "J-#{self.id}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -446,9 +451,11 @@ class UnqueueMessageJob < Postal::Job
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Layout/LineLength
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# rubocop:disable Naming/MemoizedInstanceVariableName
|
||||||
def cached_sender(klass, *args)
|
def cached_sender(klass, *args)
|
||||||
@sender ||= begin
|
@sender ||= begin
|
||||||
sender = klass.new(*args)
|
sender = klass.new(*args)
|
||||||
@@ -456,5 +463,6 @@ class UnqueueMessageJob < Postal::Job
|
|||||||
sender
|
sender
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Naming/MemoizedInstanceVariableName
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class WebhookDeliveryJob < Postal::Job
|
class WebhookDeliveryJob < Postal::Job
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AppMailer < ApplicationMailer
|
class AppMailer < ApplicationMailer
|
||||||
|
|
||||||
def verify_email_address(user)
|
def verify_email_address(user)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ApplicationMailer < ActionMailer::Base
|
class ApplicationMailer < ActionMailer::Base
|
||||||
|
|
||||||
default from: "#{Postal.smtp_from_name} <#{Postal.smtp_from_address}>"
|
default from: "#{Postal.smtp_from_name} <#{Postal.smtp_from_address}>"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: additional_route_endpoints
|
# Table name: additional_route_endpoints
|
||||||
@@ -35,9 +37,7 @@ class AdditionalRouteEndpoint < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def _endpoint=(value)
|
def _endpoint=(value)
|
||||||
if value.blank?
|
if value && value =~ /\#/
|
||||||
self.endpoint = nil
|
|
||||||
elsif value =~ /\#/
|
|
||||||
class_name, id = value.split("#", 2)
|
class_name, id = value.split("#", 2)
|
||||||
unless Route::ENDPOINT_TYPES.include?(class_name)
|
unless Route::ENDPOINT_TYPES.include?(class_name)
|
||||||
raise Postal::Error, "Invalid endpoint class name '#{class_name}'"
|
raise Postal::Error, "Invalid endpoint class name '#{class_name}'"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: address_endpoints
|
# Table name: address_endpoints
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ApplicationRecord < ActiveRecord::Base
|
class ApplicationRecord < ActiveRecord::Base
|
||||||
|
|
||||||
self.abstract_class = true
|
self.abstract_class = true
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module HasAuthentication
|
module HasAuthentication
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
@@ -42,18 +44,4 @@ module HasAuthentication
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class Postal::Errors::AuthenticationError < Postal::Error
|
|
||||||
|
|
||||||
attr_reader :error
|
|
||||||
|
|
||||||
def initialize(error)
|
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
"Authentication Failed: #{@error}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# -*- SkipSchemaAnnotations
|
# -*- SkipSchemaAnnotations
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "resolv"
|
require "resolv"
|
||||||
|
|
||||||
module HasDNSChecks
|
module HasDNSChecks
|
||||||
|
|
||||||
def dns_ok?
|
def dns_ok?
|
||||||
spf_status == "OK" && dkim_status == "OK" && ["OK", "Missing"].include?(mx_status) && ["OK", "Missing"].include?(return_path_status)
|
spf_status == "OK" && dkim_status == "OK" && %w[OK Missing].include?(mx_status) && %w[OK Missing].include?(return_path_status)
|
||||||
end
|
end
|
||||||
|
|
||||||
def dns_checked?
|
def dns_checked?
|
||||||
@@ -42,12 +44,12 @@ module HasDNSChecks
|
|||||||
|
|
||||||
def check_spf_record
|
def check_spf_record
|
||||||
result = resolver.getresources(name, Resolv::DNS::Resource::IN::TXT)
|
result = resolver.getresources(name, Resolv::DNS::Resource::IN::TXT)
|
||||||
spf_records = result.map(&:data).select { |d| d =~ /\Av=spf1/ }
|
spf_records = result.map(&:data).grep(/\Av=spf1/)
|
||||||
if spf_records.empty?
|
if spf_records.empty?
|
||||||
self.spf_status = "Missing"
|
self.spf_status = "Missing"
|
||||||
self.spf_error = "No SPF record exists for this domain"
|
self.spf_error = "No SPF record exists for this domain"
|
||||||
else
|
else
|
||||||
suitable_spf_records = spf_records.select { |d| d =~ /include:\s*#{Regexp.escape(Postal.config.dns.spf_include)}/ }
|
suitable_spf_records = spf_records.grep(/include:\s*#{Regexp.escape(Postal.config.dns.spf_include)}/)
|
||||||
if suitable_spf_records.empty?
|
if suitable_spf_records.empty?
|
||||||
self.spf_status = "Invalid"
|
self.spf_status = "Invalid"
|
||||||
self.spf_error = "An SPF record exists but it doesn't include #{Postal.config.dns.spf_include}"
|
self.spf_error = "An SPF record exists but it doesn't include #{Postal.config.dns.spf_include}"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module HasMessage
|
module HasMessage
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
@@ -18,7 +20,7 @@ module HasMessage
|
|||||||
def include_message
|
def include_message
|
||||||
queued_messages = all.to_a
|
queued_messages = all.to_a
|
||||||
server_ids = queued_messages.map(&:server_id).uniq
|
server_ids = queued_messages.map(&:server_id).uniq
|
||||||
if server_ids.size == 0
|
if server_ids.empty?
|
||||||
return []
|
return []
|
||||||
elsif server_ids.size > 1
|
elsif server_ids.size > 1
|
||||||
raise Postal::Error, "'include_message' can only be used on collections of messages from the same server"
|
raise Postal::Error, "'include_message' can only be used on collections of messages from the same server"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module HasSoftDestroy
|
module HasSoftDestroy
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module HasUUID
|
module HasUUID
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: credentials
|
# Table name: credentials
|
||||||
@@ -21,7 +23,7 @@ class Credential < ApplicationRecord
|
|||||||
|
|
||||||
belongs_to :server
|
belongs_to :server
|
||||||
|
|
||||||
TYPES = ["SMTP", "API", "SMTP-IP"]
|
TYPES = %w[SMTP API SMTP-IP].freeze
|
||||||
|
|
||||||
validates :key, presence: true, uniqueness: { case_sensitive: false }
|
validates :key, presence: true, uniqueness: { case_sensitive: false }
|
||||||
validates :type, inclusion: { in: TYPES }
|
validates :type, inclusion: { in: TYPES }
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: domains
|
# Table name: domains
|
||||||
@@ -42,15 +44,14 @@ class Domain < ApplicationRecord
|
|||||||
|
|
||||||
include HasDNSChecks
|
include HasDNSChecks
|
||||||
|
|
||||||
VERIFICATION_EMAIL_ALIASES = ["webmaster", "postmaster", "admin", "administrator", "hostmaster"]
|
VERIFICATION_EMAIL_ALIASES = %w[webmaster postmaster admin administrator hostmaster].freeze
|
||||||
|
VERIFICATION_METHODS = %w[DNS Email].freeze
|
||||||
|
|
||||||
belongs_to :server, optional: true
|
belongs_to :server, optional: true
|
||||||
belongs_to :owner, optional: true, polymorphic: true
|
belongs_to :owner, optional: true, polymorphic: true
|
||||||
has_many :routes, dependent: :destroy
|
has_many :routes, dependent: :destroy
|
||||||
has_many :track_domains, dependent: :destroy
|
has_many :track_domains, dependent: :destroy
|
||||||
|
|
||||||
VERIFICATION_METHODS = ["DNS", "Email"]
|
|
||||||
|
|
||||||
validates :name, presence: true, format: { with: /\A[a-z0-9\-.]*\z/ }, uniqueness: { case_sensitive: false, scope: [:owner_type, :owner_id], message: "is already added" }
|
validates :name, presence: true, format: { with: /\A[a-z0-9\-.]*\z/ }, uniqueness: { case_sensitive: false, scope: [:owner_type, :owner_id], message: "is already added" }
|
||||||
validates :verification_method, inclusion: { in: VERIFICATION_METHODS }
|
validates :verification_method, inclusion: { in: VERIFICATION_METHODS }
|
||||||
|
|
||||||
@@ -83,8 +84,8 @@ class Domain < ApplicationRecord
|
|||||||
|
|
||||||
def parent_domains
|
def parent_domains
|
||||||
parts = name.split(".")
|
parts = name.split(".")
|
||||||
parts[0, parts.size - 1].each_with_index.map do |p, i|
|
parts[0, parts.size - 1].each_with_index.map do |_, i|
|
||||||
parts[i..-1].join(".")
|
parts[i..].join(".")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: http_endpoints
|
# Table name: http_endpoints
|
||||||
@@ -29,8 +31,8 @@ class HTTPEndpoint < ApplicationRecord
|
|||||||
has_many :routes, as: :endpoint
|
has_many :routes, as: :endpoint
|
||||||
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
|
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
|
||||||
|
|
||||||
ENCODINGS = ["BodyAsJSON", "FormData"]
|
ENCODINGS = %w[BodyAsJSON FormData].freeze
|
||||||
FORMATS = ["Hash", "RawMessage"]
|
FORMATS = %w[Hash RawMessage].freeze
|
||||||
|
|
||||||
before_destroy :update_routes
|
before_destroy :update_routes
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class IncomingMessagePrototype
|
class IncomingMessagePrototype
|
||||||
|
|
||||||
attr_accessor :to
|
attr_accessor :to
|
||||||
@@ -22,13 +24,14 @@ class IncomingMessagePrototype
|
|||||||
end
|
end
|
||||||
|
|
||||||
def route
|
def route
|
||||||
@routes ||= if @to.present?
|
@route ||= if @to.present?
|
||||||
uname, domain = @to.split("@", 2)
|
uname, domain = @to.split("@", 2)
|
||||||
uname, tag = uname.split("+", 2)
|
uname, _tag = uname.split("+", 2)
|
||||||
@server.routes.includes(:domain).where(domains: { name: domain }, name: uname).first
|
@server.routes.includes(:domain).where(domains: { name: domain }, name: uname).first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Lint/DuplicateMethods
|
||||||
def attachments
|
def attachments
|
||||||
(@attachments || []).map do |attachment|
|
(@attachments || []).map do |attachment|
|
||||||
{
|
{
|
||||||
@@ -38,6 +41,7 @@ class IncomingMessagePrototype
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Lint/DuplicateMethods
|
||||||
|
|
||||||
def create_messages
|
def create_messages
|
||||||
if valid?
|
if valid?
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: ip_addresses
|
# Table name: ip_addresses
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: ip_pools
|
# Table name: ip_pools
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: ip_pool_rules
|
# Table name: ip_pool_rules
|
||||||
@@ -66,7 +68,9 @@ class IPPoolRule < ApplicationRecord
|
|||||||
errors.add :ip_pool_id, "must belong to the organization"
|
errors.add :ip_pool_id, "must belong to the organization"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.address_matches?(condition, address)
|
class << self
|
||||||
|
|
||||||
|
def address_matches?(condition, address)
|
||||||
address = Postal::Helpers.strip_name_from_address(address)
|
address = Postal::Helpers.strip_name_from_address(address)
|
||||||
if condition =~ /@/
|
if condition =~ /@/
|
||||||
parts = address.split("@")
|
parts = address.split("@")
|
||||||
@@ -81,3 +85,5 @@ class IPPoolRule < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: organizations
|
# Table name: organizations
|
||||||
@@ -23,7 +25,7 @@
|
|||||||
|
|
||||||
class Organization < ApplicationRecord
|
class Organization < ApplicationRecord
|
||||||
|
|
||||||
RESERVED_PERMALINKS = ["new", "edit", "remove", "delete", "destroy", "admin", "mail", "org", "server"]
|
RESERVED_PERMALINKS = %w[new edit remove delete destroy admin mail org server].freeze
|
||||||
|
|
||||||
INITIAL_QUOTA = 10
|
INITIAL_QUOTA = 10
|
||||||
INITIAL_SUPER_QUOTA = 10_000
|
INITIAL_SUPER_QUOTA = 10_000
|
||||||
@@ -48,7 +50,7 @@ class Organization < ApplicationRecord
|
|||||||
has_many :ip_pool_rules, dependent: :destroy, as: :owner
|
has_many :ip_pool_rules, dependent: :destroy, as: :owner
|
||||||
|
|
||||||
after_create do
|
after_create do
|
||||||
if pool = IPPool.default
|
if IPPool.default
|
||||||
ip_pools << IPPool.default
|
ip_pools << IPPool.default
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: organization_ip_pools
|
# Table name: organization_ip_pools
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: organization_users
|
# Table name: organization_users
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "resolv"
|
require "resolv"
|
||||||
|
|
||||||
class OutgoingMessagePrototype
|
class OutgoingMessagePrototype
|
||||||
@@ -47,14 +49,12 @@ class OutgoingMessagePrototype
|
|||||||
end
|
end
|
||||||
|
|
||||||
def find_domain
|
def find_domain
|
||||||
@domain ||= begin
|
|
||||||
domain = @server.authenticated_domain_for_address(@from)
|
domain = @server.authenticated_domain_for_address(@from)
|
||||||
if @server.allow_sender? && domain.nil?
|
if @server.allow_sender? && domain.nil?
|
||||||
domain = @server.authenticated_domain_for_address(@sender)
|
domain = @server.authenticated_domain_for_address(@sender)
|
||||||
end
|
end
|
||||||
domain || :none
|
domain || :none
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def to_addresses
|
def to_addresses
|
||||||
@to.is_a?(String) ? @to.to_s.split(/,\s*/) : @to.to_a
|
@to.is_a?(String) ? @to.to_s.split(/,\s*/) : @to.to_a
|
||||||
@@ -93,6 +93,7 @@ class OutgoingMessagePrototype
|
|||||||
@errors || {}
|
@errors || {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Lint/DuplicateMethods
|
||||||
def attachments
|
def attachments
|
||||||
(@attachments || []).map do |attachment|
|
(@attachments || []).map do |attachment|
|
||||||
{
|
{
|
||||||
@@ -102,6 +103,7 @@ class OutgoingMessagePrototype
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Lint/DuplicateMethods
|
||||||
|
|
||||||
def validate
|
def validate
|
||||||
@errors = []
|
@errors = []
|
||||||
@@ -135,7 +137,7 @@ class OutgoingMessagePrototype
|
|||||||
end
|
end
|
||||||
|
|
||||||
if attachments.present?
|
if attachments.present?
|
||||||
attachments.each_with_index do |attachment, index|
|
attachments.each do |attachment|
|
||||||
if attachment[:name].blank?
|
if attachment[:name].blank?
|
||||||
@errors << "AttachmentMissingName" unless @errors.include?("AttachmentMissingName")
|
@errors << "AttachmentMissingName" unless @errors.include?("AttachmentMissingName")
|
||||||
elsif attachment[:data].blank?
|
elsif attachment[:data].blank?
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: queued_messages
|
# Table name: queued_messages
|
||||||
|
|||||||
+12
-7
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: routes
|
# Table name: routes
|
||||||
@@ -22,7 +24,9 @@
|
|||||||
|
|
||||||
class Route < ApplicationRecord
|
class Route < ApplicationRecord
|
||||||
|
|
||||||
MODES = ["Endpoint", "Accept", "Hold", "Bounce", "Reject"]
|
MODES = %w[Endpoint Accept Hold Bounce Reject].freeze
|
||||||
|
SPAM_MODES = %w[Mark Quarantine Fail].freeze
|
||||||
|
ENDPOINT_TYPES = %w[SMTPEndpoint HTTPEndpoint AddressEndpoint].freeze
|
||||||
|
|
||||||
include HasUUID
|
include HasUUID
|
||||||
|
|
||||||
@@ -31,9 +35,6 @@ class Route < ApplicationRecord
|
|||||||
belongs_to :endpoint, polymorphic: true, optional: true
|
belongs_to :endpoint, polymorphic: true, optional: true
|
||||||
has_many :additional_route_endpoints, dependent: :destroy
|
has_many :additional_route_endpoints, dependent: :destroy
|
||||||
|
|
||||||
SPAM_MODES = ["Mark", "Quarantine", "Fail"]
|
|
||||||
ENDPOINT_TYPES = ["SMTPEndpoint", "HTTPEndpoint", "AddressEndpoint"]
|
|
||||||
|
|
||||||
validates :name, presence: true, format: /\A(([a-z0-9\-.]*)|(\*)|(__returnpath__))\z/
|
validates :name, presence: true, format: /\A(([a-z0-9\-.]*)|(\*)|(__returnpath__))\z/
|
||||||
validates :spam_mode, inclusion: { in: SPAM_MODES }
|
validates :spam_mode, inclusion: { in: SPAM_MODES }
|
||||||
validates :endpoint, presence: { if: proc { mode == "Endpoint" } }
|
validates :endpoint, presence: { if: proc { mode == "Endpoint" } }
|
||||||
@@ -115,7 +116,7 @@ class Route < ApplicationRecord
|
|||||||
if route.save
|
if route.save
|
||||||
seen << route.id
|
seen << route.id
|
||||||
else
|
else
|
||||||
route.errors.each do |field, message|
|
route.errors.each do |_, message|
|
||||||
errors.add :base, message
|
errors.add :base, message
|
||||||
end
|
end
|
||||||
raise ActiveRecord::RecordInvalid
|
raise ActiveRecord::RecordInvalid
|
||||||
@@ -200,7 +201,7 @@ class Route < ApplicationRecord
|
|||||||
if route = Route.includes(:domain).where(domains: { name: domain.name }, name: name).where.not(id: id).first
|
if route = Route.includes(:domain).where(domains: { name: domain.name }, name: name).where.not(id: id).first
|
||||||
errors.add :name, "is configured on the #{route.server.full_permalink} mail server"
|
errors.add :name, "is configured on the #{route.server.full_permalink} mail server"
|
||||||
end
|
end
|
||||||
elsif route = Route.where(name: "__returnpath__").where.not(id: id).exists?
|
elsif Route.where(name: "__returnpath__").where.not(id: id).exists?
|
||||||
errors.add :base, "A return path route already exists for this server"
|
errors.add :base, "A return path route already exists for this server"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -218,7 +219,9 @@ class Route < ApplicationRecord
|
|||||||
errors.add :base, "Additional routes are not permitted unless the primary route is an actual endpoint"
|
errors.add :base, "Additional routes are not permitted unless the primary route is an actual endpoint"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.find_by_name_and_domain(name, domain)
|
class << self
|
||||||
|
|
||||||
|
def find_by_name_and_domain(name, domain)
|
||||||
route = Route.includes(:domain).where(name: name, domains: { name: domain }).first
|
route = Route.includes(:domain).where(name: name, domains: { name: domain }).first
|
||||||
if route.nil?
|
if route.nil?
|
||||||
route = Route.includes(:domain).where(name: "*", domains: { name: domain }).first
|
route = Route.includes(:domain).where(name: "*", domains: { name: domain }).first
|
||||||
@@ -227,3 +230,5 @@ class Route < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
+25
-12
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: servers
|
# Table name: servers
|
||||||
@@ -41,7 +43,8 @@
|
|||||||
|
|
||||||
class Server < ApplicationRecord
|
class Server < ApplicationRecord
|
||||||
|
|
||||||
RESERVED_PERMALINKS = ["new", "all", "search", "stats", "edit", "manage", "delete", "destroy", "remove"]
|
RESERVED_PERMALINKS = %w[new all search stats edit manage delete destroy remove].freeze
|
||||||
|
MODES = %w[Live Development].freeze
|
||||||
|
|
||||||
include HasUUID
|
include HasUUID
|
||||||
include HasSoftDestroy
|
include HasSoftDestroy
|
||||||
@@ -62,8 +65,6 @@ class Server < ApplicationRecord
|
|||||||
has_many :track_domains, dependent: :destroy
|
has_many :track_domains, dependent: :destroy
|
||||||
has_many :ip_pool_rules, dependent: :destroy, as: :owner
|
has_many :ip_pool_rules, dependent: :destroy, as: :owner
|
||||||
|
|
||||||
MODES = ["Live", "Development"]
|
|
||||||
|
|
||||||
random_string :token, type: :chars, length: 6, unique: true, upper_letters_only: true
|
random_string :token, type: :chars, length: 6, unique: true, upper_letters_only: true
|
||||||
default_value :permalink, -> { name ? name.parameterize : nil }
|
default_value :permalink, -> { name ? name.parameterize : nil }
|
||||||
default_value :raw_message_retention_days, -> { 30 }
|
default_value :raw_message_retention_days, -> { 30 }
|
||||||
@@ -155,11 +156,11 @@ class Server < ApplicationRecord
|
|||||||
time = Time.now.utc
|
time = Time.now.utc
|
||||||
total_outgoing = 0.0
|
total_outgoing = 0.0
|
||||||
total_bounces = 0.0
|
total_bounces = 0.0
|
||||||
message_db.statistics.get(:daily, [:outgoing, :bounces], time, 30).each do |date, stat|
|
message_db.statistics.get(:daily, [:outgoing, :bounces], time, 30).each do |_, stat|
|
||||||
total_outgoing += stat[:outgoing]
|
total_outgoing += stat[:outgoing]
|
||||||
total_bounces += stat[:bounces]
|
total_bounces += stat[:bounces]
|
||||||
end
|
end
|
||||||
total_outgoing == 0 ? 0 : (total_bounces / total_outgoing) * 100
|
total_outgoing.zero? ? 0 : (total_bounces / total_outgoing) * 100
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -218,6 +219,10 @@ class Server < ApplicationRecord
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Return the domain which can be used to authenticate emails sent from the given e-mail address.
|
||||||
|
#
|
||||||
|
# @param address [String] an e-mail address
|
||||||
|
# @return [Domain, nil] the domain to use for authentication
|
||||||
def authenticated_domain_for_address(address)
|
def authenticated_domain_for_address(address)
|
||||||
return nil if address.blank?
|
return nil if address.blank?
|
||||||
|
|
||||||
@@ -226,16 +231,24 @@ class Server < ApplicationRecord
|
|||||||
return nil unless uname
|
return nil unless uname
|
||||||
return nil unless domain_name
|
return nil unless domain_name
|
||||||
|
|
||||||
uname, = uname.split("+", 2)
|
# Find a verified domain which directly matches the domain name for the given address.
|
||||||
|
domain = Domain.verified
|
||||||
|
.order(owner_type: :desc)
|
||||||
|
.where("(owner_type = 'Organization' AND owner_id = ?) OR " \
|
||||||
|
"(owner_type = 'Server' AND owner_id = ?)", organization_id, id)
|
||||||
|
.where(name: domain_name)
|
||||||
|
.first
|
||||||
|
|
||||||
# Check the server's domain
|
# If there is a matching domain, return it
|
||||||
if domain = Domain.verified.order(owner_type: :desc).where("(owner_type = 'Organization' AND owner_id = ?) OR (owner_type = 'Server' AND owner_id = ?)", organization_id, id).where(name: domain_name).first
|
return domain if domain
|
||||||
return domain
|
|
||||||
end
|
|
||||||
|
|
||||||
return unless any_domain = domains.verified.where(use_for_any: true).order(:name).first
|
# Otherwise, we need to look to see if there is a domain configured which can be used as the authenticated
|
||||||
|
# domain for any domain. This will look for domains directly within the server and return that.
|
||||||
|
any_domain = domains.verified.where(use_for_any: true).order(:name).first
|
||||||
|
return any_domain if any_domain
|
||||||
|
|
||||||
any_domain
|
# Return nil if we can't find anything suitable
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_authenticated_domain_from_headers(headers)
|
def find_authenticated_domain_from_headers(headers)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: smtp_endpoints
|
# Table name: smtp_endpoints
|
||||||
@@ -24,7 +26,7 @@ class SMTPEndpoint < ApplicationRecord
|
|||||||
has_many :routes, as: :endpoint
|
has_many :routes, as: :endpoint
|
||||||
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
|
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
|
||||||
|
|
||||||
SSL_MODES = ["None", "Auto", "STARTTLS", "TLS"]
|
SSL_MODES = %w[None Auto STARTTLS TLS].freeze
|
||||||
|
|
||||||
before_destroy :update_routes
|
before_destroy :update_routes
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: statistics
|
# Table name: statistics
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: track_domains
|
# Table name: track_domains
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: users
|
# Table name: users
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: user_invites
|
# Table name: user_invites
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: webhooks
|
# Table name: webhooks
|
||||||
|
|||||||
+12
-10
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: webhook_events
|
# Table name: webhook_events
|
||||||
@@ -14,16 +16,16 @@
|
|||||||
|
|
||||||
class WebhookEvent < ApplicationRecord
|
class WebhookEvent < ApplicationRecord
|
||||||
|
|
||||||
EVENTS = [
|
EVENTS = %w[
|
||||||
"MessageSent",
|
MessageSent
|
||||||
"MessageDelayed",
|
MessageDelayed
|
||||||
"MessageDeliveryFailed",
|
MessageDeliveryFailed
|
||||||
"MessageHeld",
|
MessageHeld
|
||||||
"MessageBounced",
|
MessageBounced
|
||||||
"MessageLinkClicked",
|
MessageLinkClicked
|
||||||
"MessageLoaded",
|
MessageLoaded
|
||||||
"DomainDNSError"
|
DomainDNSError
|
||||||
]
|
].freeze
|
||||||
|
|
||||||
belongs_to :webhook
|
belongs_to :webhook
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: webhook_requests
|
# Table name: webhook_requests
|
||||||
@@ -19,7 +21,7 @@ class WebhookRequest < ApplicationRecord
|
|||||||
|
|
||||||
include HasUUID
|
include HasUUID
|
||||||
|
|
||||||
RETRIES = { 1 => 2.minutes, 2 => 3.minutes, 3 => 6.minutes, 4 => 10.minutes, 5 => 15.minutes }
|
RETRIES = { 1 => 2.minutes, 2 => 3.minutes, 3 => 6.minutes, 4 => 10.minutes, 5 => 15.minutes }.freeze
|
||||||
|
|
||||||
belongs_to :server
|
belongs_to :server
|
||||||
belongs_to :webhook, optional: true
|
belongs_to :webhook, optional: true
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
APP_PATH = File.expand_path("../config/application", __dir__)
|
APP_PATH = File.expand_path("../config/application", __dir__)
|
||||||
require_relative "../config/boot"
|
require_relative "../config/boot"
|
||||||
require "rails/commands"
|
require "rails/commands"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative "../config/boot"
|
require_relative "../config/boot"
|
||||||
require "rake"
|
require "rake"
|
||||||
Rake.application.run
|
Rake.application.run
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "pathname"
|
require "pathname"
|
||||||
require "fileutils"
|
require "fileutils"
|
||||||
include FileUtils
|
include FileUtils
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "pathname"
|
require "pathname"
|
||||||
require "fileutils"
|
require "fileutils"
|
||||||
include FileUtils
|
include FileUtils
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# This file is used by Rack-based servers to start the application.
|
# This file is used by Rack-based servers to start the application.
|
||||||
|
|
||||||
require_relative "config/environment"
|
require_relative "config/environment"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative "boot"
|
require_relative "boot"
|
||||||
|
|
||||||
require "rails"
|
require "rails"
|
||||||
@@ -30,7 +32,7 @@ module Postal
|
|||||||
config.eager_load_paths << Rails.root.join("lib")
|
config.eager_load_paths << Rails.root.join("lib")
|
||||||
|
|
||||||
# Disable field_with_errors
|
# Disable field_with_errors
|
||||||
config.action_view.field_error_proc = proc { |t, i| t }
|
config.action_view.field_error_proc = proc { |t, _| t }
|
||||||
|
|
||||||
# Load the tracking server middleware
|
# Load the tracking server middleware
|
||||||
require "postal/tracking_middleware"
|
require "postal/tracking_middleware"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||||
|
|
||||||
$stdout.sync = true
|
$stdout.sync = true
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Clockwork
|
module Clockwork
|
||||||
|
|
||||||
configure do |config|
|
configure do |config|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Load the Rails application.
|
# Load the Rails application.
|
||||||
require_relative "application"
|
require_relative "application"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Rails.application.configure do
|
Rails.application.configure do
|
||||||
# Settings specified here will take precedence over those in config/application.rb.
|
# Settings specified here will take precedence over those in config/application.rb.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Rails.application.configure do
|
Rails.application.configure do
|
||||||
# Settings specified here will take precedence over those in config/application.rb.
|
# Settings specified here will take precedence over those in config/application.rb.
|
||||||
|
|
||||||
@@ -71,7 +73,7 @@ Rails.application.configure do
|
|||||||
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
|
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
|
||||||
|
|
||||||
if ENV["RAILS_LOG_TO_STDOUT"].present?
|
if ENV["RAILS_LOG_TO_STDOUT"].present?
|
||||||
logger = ActiveSupport::Logger.new(STDOUT)
|
logger = ActiveSupport::Logger.new($stdout)
|
||||||
logger.formatter = config.log_formatter
|
logger.formatter = config.log_formatter
|
||||||
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Rails.application.configure do
|
Rails.application.configure do
|
||||||
# Settings specified here will take precedence over those in config/application.rb.
|
# Settings specified here will take precedence over those in config/application.rb.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
# ApplicationController.renderer.defaults.merge!(
|
# ApplicationController.renderer.defaults.merge!(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
# Version of your assets, change this if you want to expire all your assets.
|
# Version of your assets, change this if you want to expire all your assets.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
# Specify a serializer for the signed and encrypted cookie jars.
|
# Specify a serializer for the signed and encrypted cookie jars.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
# Configure sensitive parameters which will be filtered from the log file.
|
# Configure sensitive parameters which will be filtered from the log file.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
# Add new inflection rules using the following format. Inflections
|
# Add new inflection rules using the following format. Inflections
|
||||||
@@ -12,7 +14,6 @@
|
|||||||
|
|
||||||
# These inflection rules are supported but not enabled by default:
|
# These inflection rules are supported but not enabled by default:
|
||||||
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
||||||
|
|
||||||
inflect.acronym "DKIM"
|
inflect.acronym "DKIM"
|
||||||
inflect.acronym "HTTP"
|
inflect.acronym "HTTP"
|
||||||
inflect.acronym "SMTP"
|
inflect.acronym "SMTP"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "mail"
|
require "mail"
|
||||||
module Mail
|
module Mail
|
||||||
|
|
||||||
@@ -20,7 +22,7 @@ module Mail
|
|||||||
|
|
||||||
## Extract plain text body of message
|
## Extract plain text body of message
|
||||||
def plain_body
|
def plain_body
|
||||||
if multipart? and text_part
|
if multipart? && text_part
|
||||||
text_part.decoded
|
text_part.decoded
|
||||||
elsif mime_type == "text/plain" || mime_type.nil?
|
elsif mime_type == "text/plain" || mime_type.nil?
|
||||||
decoded
|
decoded
|
||||||
@@ -29,7 +31,7 @@ module Mail
|
|||||||
|
|
||||||
## Extract HTML text body of message
|
## Extract HTML text body of message
|
||||||
def html_body
|
def html_body
|
||||||
if multipart? and html_part
|
if multipart? && html_part
|
||||||
html_part.decoded
|
html_part.decoded
|
||||||
elsif mime_type == "text/html"
|
elsif mime_type == "text/html"
|
||||||
decoded
|
decoded
|
||||||
@@ -109,14 +111,16 @@ module Mail
|
|||||||
# Handle attached emails as attachments
|
# Handle attached emails as attachments
|
||||||
class AttachmentsList < Array
|
class AttachmentsList < Array
|
||||||
|
|
||||||
|
# rubocop:disable Lint/MissingSuper
|
||||||
def initialize(parts_list)
|
def initialize(parts_list)
|
||||||
@parts_list = parts_list
|
@parts_list = parts_list
|
||||||
@content_disposition_type = "attachment"
|
@content_disposition_type = "attachment"
|
||||||
parts_list.map do |p|
|
parts = parts_list.map do |p|
|
||||||
(p.parts.empty? and p.attachment?) ? p : p.attachments
|
p.parts.empty? && p.attachment? ? p : p.attachments
|
||||||
end.flatten.compact.each { |a| self << a }
|
end.flatten.compact
|
||||||
self
|
parts.each { |a| self << a }
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Lint/MissingSuper
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
# Add new mime types for use in respond_to blocks:
|
# Add new mime types for use in respond_to blocks:
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Be sure to restart your server when you modify this file.
|
# Be sure to restart your server when you modify this file.
|
||||||
#
|
#
|
||||||
# This file contains migration options to ease your Rails 5.0 upgrade.
|
# This file contains migration options to ease your Rails 5.0 upgrade.
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "postal"
|
require "postal"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module ActionView
|
module ActionView
|
||||||
module RecordIdentifier
|
module RecordIdentifier
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user