1
0
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2026-03-03 14:24:06 +00:00

Compare commits

96 الالتزامات
2.1.5 ... 2.3.2

المؤلف SHA1 الرسالة التاريخ
Adam Cooke
66d26c8d4f Merge pull request #2834 from postalserver/release-please--branches--main
chore(main): release 2.3.2
2024-03-01 14:44:42 +00:00
github-actions[bot]
343292bbde chore(main): release 2.3.2 2024-03-01 13:15:31 +00:00
Adam Cooke
694240ddcd fix: truncate output and details in deliveries to 250 characters
closes #2831
2024-03-01 13:14:48 +00:00
github-actions[bot]
18ba7140b4 chore(main): release 2.3.1 (#2812)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-23 22:25:22 +00:00
Adam Cooke
2834e2c379 fix: update raw headers after changing messages to during parsing
Previously, headers were not updated but the mail gem parsing may decide
to change the transfer encoding. If it does this, the body is updated to
the new format but the header is not, this results in a mismatch when the
message it sent onwards and the client being unable render the message.

The specific situation identified was changing an HTML-only e-mail from
quoted-printable to 7bit.

closes #2816
2024-02-23 22:16:36 +00:00
Adam Cooke
559b08ddd3 chore(github-actions): allow stale action to be run on demand 2024-02-22 00:30:49 +00:00
Adam Cooke
57b72fb4b7 chore(github-actions): add 'docs' label to exclude from staleness checks 2024-02-22 00:28:03 +00:00
Adam Cooke
d90a456dfa chore(github-actions): add action to close stale issues and PRs 2024-02-22 00:27:15 +00:00
Adam Cooke
d7dce16c50 Merge pull request #2790 from postalserver/release-please--branches--main
chore(main): release 2.3.0
2024-02-14 15:04:09 +00:00
github-actions[bot]
b8bab1bd0e chore(main): release 2.3.0 2024-02-13 15:59:15 +00:00
Adam Cooke
7c23994d24 fix: use correct method for disconnecting smtp connections 2024-02-13 15:57:59 +00:00
Adam Cooke
42ab5b3a6b fix: explicitly disable TLS & starttls for unknown SSL modes
closes #2564
2024-02-13 15:57:48 +00:00
Adam Cooke
f9f7fb30fe fix: retry mysql connections on message DB pool 2024-02-13 15:56:40 +00:00
Adam Cooke
b8cb563553 Merge pull request #2801 from postalserver/smtp-tests
Tests for the SMTP Server
2024-02-13 15:55:57 +00:00
Adam Cooke
e83e2a5e33 Merge pull request #2799 from postalserver/remove-server-fd
Remove SMTP server reloading
2024-02-13 15:55:30 +00:00
Adam Cooke
c3c304e98b refactor: remove reloading on the smtp server 2024-02-13 15:51:44 +00:00
Adam Cooke
241f37e78d Merge pull request #2797 from postalserver/rubocop
Code Quality Improvements
2024-02-13 14:24:41 +00:00
Adam Cooke
c83601af69 chore: silence message DB migrations during provisioning 2024-02-13 11:56:48 +00:00
Adam Cooke
6214892710 chore: annotate models 2024-02-13 11:46:35 +00:00
Adam Cooke
1fceef7cea fix: add ruby platform to gemfile 2024-02-12 18:14:29 +00:00
Adam Cooke
dece1d487a test: add initial tests for Postal::SMTPServer::Client 2024-02-12 18:07:44 +00:00
Adam Cooke
ec636661d5 style(rubocop): remaining offences 2024-02-12 09:55:20 +00:00
Adam Cooke
c6326a6524 style(rubocop): Style/MultilineBlockChain 2024-02-12 09:55:19 +00:00
Adam Cooke
013b3ea931 style(rubocop): Style/PreferredHashMethods 2024-02-12 09:55:19 +00:00
Adam Cooke
ffcb707247 style(rubocop): Style/MissingRespondToMissing 2024-02-12 09:55:19 +00:00
Adam Cooke
83ac764510 style(rubocop): Style/HashExcept 2024-02-12 09:55:19 +00:00
Adam Cooke
c995027ff5 style(rubocop): Style/HashEachMethods 2024-02-12 09:55:19 +00:00
Adam Cooke
ec7dcf4f9a style(rubocop): Lint/UnderscorePrefixedVariableName 2024-02-12 09:55:19 +00:00
Adam Cooke
278ef0886a style(rubocop): Lint/SuppressedException 2024-02-12 09:55:18 +00:00
Adam Cooke
bab6346239 style(rubocop): Lint/DuplicateMethods 2024-02-12 09:55:18 +00:00
Adam Cooke
a1dc0f77ac style(rubocop): Lint/DuplicateBranch 2024-02-12 09:55:18 +00:00
Adam Cooke
0e0aca06c9 style(rubocop): Layout/* 2024-02-12 09:55:18 +00:00
Adam Cooke
9ce28a427f style(rubocop): Style/SelectByRegexp 2024-02-12 09:55:18 +00:00
Adam Cooke
157d11457c style(rubocop): Style/GlobalVars 2024-02-12 09:55:18 +00:00
Adam Cooke
e896f4689a style(rubocop): Style/ClassAndModuleChildren 2024-02-12 09:55:18 +00:00
Adam Cooke
b9f3f313f8 style(rubocop): Style/AndOr 2024-02-12 09:55:17 +00:00
Adam Cooke
4674e63b5f style(rubocop): Lint/MissingSuper 2024-02-12 09:55:15 +00:00
Adam Cooke
be97f43308 style(rubocop): disable Style/SpecialGlobalVars 2024-02-12 09:40:35 +00:00
Adam Cooke
75be690748 style(rubocop): Style/GlobalStdStream 2024-02-12 09:40:35 +00:00
Adam Cooke
9563f30c96 style(rubocop): Naming/MemoizedInstanceVariableName 2024-02-12 09:40:34 +00:00
Adam Cooke
00a02f2655 style(rubocop): Style/SafeNavigation 2024-02-12 09:40:34 +00:00
Adam Cooke
04a34831c7 style(rubocop): Style/For 2024-02-12 09:40:34 +00:00
Adam Cooke
6a58ecf605 style(rubocop): Style/IdenticalConditionalBranches 2024-02-12 09:40:31 +00:00
Adam Cooke
6ad56ee9c9 style(rubocop): Lint/IneffectiveAccessModifier 2024-02-10 23:03:28 +00:00
Adam Cooke
c558f1c69c style(rubocop): Style/NumericPredicate 2024-02-10 22:59:30 +00:00
Adam Cooke
7119e8642d style(rubocop): Lint/ShadowingOuterLocalVariable 2024-02-10 22:51:09 +00:00
Adam Cooke
bd85920565 style(rubocop): Style/WordArray 2024-02-10 22:39:43 +00:00
Adam Cooke
129dffab9e style(rubocop): Style/MutableConstant 2024-02-10 17:34:29 +00:00
Adam Cooke
d508772a40 style(rubocop): disable Style/StringConcatenation cop 2024-02-10 17:30:32 +00:00
Adam Cooke
b0ac9ef0b9 style(rubocop): relax method length and block nexting for now 2024-02-10 17:26:45 +00:00
Adam Cooke
a5d5ba5326 style(rubocop): Layout/MultilineMethodCallBraceLayout 2024-02-10 17:25:45 +00:00
Adam Cooke
919a60116c style(rubocop): Naming/FileName 2024-02-10 17:24:37 +00:00
Adam Cooke
0cf35a8392 style(rubocop): Layout/EmptyLines 2024-02-10 17:23:24 +00:00
Adam Cooke
12a5ef3279 style(rubocop): Lint/RedundantStringCoercion 2024-02-10 17:22:59 +00:00
Adam Cooke
0966b44018 style(rubocop): Lint/ShadowedException 2024-02-10 17:21:54 +00:00
Adam Cooke
389ea77050 style(rubocop): Security/YAMLLoad 2024-02-10 17:21:08 +00:00
Adam Cooke
ee94e4e1a0 style(rubocop): Lint/UnusedBlockArgument 2024-02-10 17:20:13 +00:00
Adam Cooke
7590a46234 style(rubocop): Lint/UselessAssignment 2024-02-10 17:18:24 +00:00
Adam Cooke
25d7d66b47 test: FactoryBot.lint will lint all registered factories 2024-02-10 17:18:24 +00:00
Adam Cooke
cfd8d63321 style(rubocop): Layout/EmptyLinesAroundBlockBody 2024-02-10 17:18:24 +00:00
Adam Cooke
1cf665a0cf test: remove FACTORIES_EXCLUDED_FROM_LINT 2024-02-10 17:18:24 +00:00
Adam Cooke
930cf39dba style(rubocop): disable complexity cops for now 2024-02-10 17:18:23 +00:00
Adam Cooke
6d4dea7f7f style(rubocop): update rubocop rules 2024-02-10 17:18:23 +00:00
Adam Cooke
e142d0da5f style(rubocop): Layout/LineLength 2024-02-10 17:18:23 +00:00
Adam Cooke
59f299b704 style(rubocop): Layout/LeadingCommentSpace 2024-02-10 17:18:23 +00:00
Adam Cooke
b4cc81264c style(rubocop): Style/StringLiterals 2024-02-10 17:18:23 +00:00
Adam Cooke
0e4ed5ca03 style(rubocop): Layout/EmptyLineAfterMagicComment 2024-02-10 17:18:23 +00:00
Adam Cooke
6ab36c09c9 style(rubocop): Style/FrozenStringLiteralComment 2024-02-10 17:18:22 +00:00
Adam Cooke
ba5bfbd6a0 fix: fix bug with received header in SMTP server 2024-02-10 17:17:06 +00:00
Adam Cooke
97a328419b Merge pull request #2786 from postalserver/privacy-mode 2024-02-07 10:12:37 +00:00
Adam Cooke
ed2e62b94f feat: remove strip_received_headers config option
This previously removed all Received headers which were sent to the smtp
server when enabled. This is not something that should be happening.
2024-02-07 09:45:12 +00:00
Adam Cooke
15f9671b66 feat: privacy mode
Adds support for hiding IP addresses & hostnames associated with clients sending
authenticated mail in to Postal over SMTP and HTTP
2024-02-07 09:45:09 +00:00
github-actions[bot]
19e3bc20c6 chore(main): release 2.2.2 (#2783)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-06 13:28:29 +00:00
Adam Cooke
f05c2e4503 fix: upgrade nokogiri 2024-02-06 13:15:27 +00:00
Adam Cooke
7bc5230cba fix: re-add reconnect: true to database
This is deprecated and, in my tests, isn't needed but to avoid any
potential issues I am re-adding it here. When we upgrade to Rails 7.1,
we can remove this and that'll handle reconnections as appropriate.
2024-02-06 13:14:21 +00:00
Adam Cooke
b9edcf5b7d test: rename database spec file 2024-02-06 12:43:28 +00:00
Adam Cooke
54306a9748 fix: adds new connection pool which will discard failed clients
closes #2780
2024-02-06 12:43:28 +00:00
github-actions[bot]
304828a672 chore(main): release 2.2.1 (#2773)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-03 22:24:28 +00:00
Adam Cooke
4528a14d27 fix: fixes issue starting application in production mode
I haven't observed these all that recently and these fixes are temporary until
I have time to look properly.
2024-02-03 22:17:51 +00:00
Adam Cooke
96ba4b8f30 refactor: remove Postal.database_url 2024-02-01 18:09:39 +00:00
github-actions[bot]
ff901e99f7 chore(main): release 2.2.0 (#2766)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-01 16:54:50 +00:00
Adam Cooke
ce19bf7988 fix: use utc timestamps when determining raw table names 2024-02-01 16:41:41 +00:00
Adam Cooke
8794a2f447 chore: add script to send html emails to a local SMTP server 2024-02-01 13:54:05 +00:00
Adam Cooke
6b2bf9062d fix: extract x-postal-tag before holding
closes #2684
2024-02-01 13:53:45 +00:00
Adam Cooke
49cceaa6ca fix: move tracking middleware before host authorization
closes #2415
2024-01-31 17:55:39 +00:00
Adam Cooke
71f51db3c2 fix: fixes error messages in web ui 2024-01-30 17:34:11 +00:00
Adam Cooke
4a46f690de feat: load signing key path from POSTAL_SIGNING_KEY_PATH 2024-01-30 14:13:19 +00:00
Adam Cooke
854aa5ebc8 feat: support for configuring postal with environment variables 2024-01-30 13:11:56 +00:00
Adam Cooke
990b575902 refactor: remove Postal::Job.perform method
this wasn't used
2024-01-30 11:06:39 +00:00
Adam Cooke
2bad645d98 fix: don't use indifferent access for job params
All jobs refer to parameters using string keys.

closes #2477
closes #2714
closes #2476
closes #2500
2024-01-30 11:06:22 +00:00
Adam Cooke
41f6cf4d90 chore: add binstubs for bundle and rspec 2024-01-30 10:19:40 +00:00
Adam Cooke
3fb40e4e24 fix: ignore message DB migrations in autoloader 2024-01-30 10:19:37 +00:00
Adam Cooke
0f9882f132 refactor: remove explicit autoload 2024-01-30 09:15:25 +00:00
github-actions[bot]
26aae298a4 chore(main): release 2.1.6 (#2765)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-01-30 09:07:12 +00:00
Adam Cooke
88108566f8 chore(build): fixes docker login action credentials 2024-01-30 09:04:13 +00:00
Adam Cooke
e156c21dee chore: update release please to include more categories in changelog 2024-01-30 09:03:08 +00:00
245 ملفات معدلة مع 2849 إضافات و842 حذوفات

عرض الملف

@@ -2,7 +2,7 @@
name: 🐛 Bug report
about: Create a report to help us improve Postal and fix issues.
title: ''
labels: bug
labels: ''
assignees: ''
---

عرض الملف

@@ -97,17 +97,17 @@ jobs:
- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
with:
registry: ${{ vars.KRYSTAL_REGISTRY_HOST }}
username: ${{ vars.KRYSTAL_REGISTRY_USERNAME }}
password: ${{ secrets.KRYSTAL_REGISTRY_PASSWORD }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v4
with:
push: true
tags: |
ghcr.io/postalserver/postal:stable
ghcr.io/postalserver/postal:${{ needs.release-please.outputs.version }}
cache-from: type=local,src=/cache/krystal-identity
cache-to: type=local,dest=/cache/krystal-identity,mode=max
cache-from: type=gha
cache-to: type=gha,mode=max
target: full
build-args: |
VERSION=${{ needs.release-please.outputs.version }}

30
.github/workflows/close.yml مباع Normal file
عرض الملف

@@ -0,0 +1,30 @@
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.'
close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.'
stale-issue-label: stale
stale-pr-label: stale
days-before-issue-stale: 30
days-before-pr-stale: 45
days-before-issue-close: 5
days-before-pr-close: 10
exempt-all-assignees: true
exempt-all-milestones: true
exempt-issue-labels: bug,enhancement,docs,install,feature

عرض الملف

@@ -1,3 +1,3 @@
{
".": "2.1.5"
".": "2.3.2"
}

عرض الملف

@@ -1,35 +1,175 @@
inherit_from:
- https://dev.k.io/rubocop/rubocop.rails.yml
AllCops:
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:
EnforcedStyle: double_quotes
AutoCorrect: true
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
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
# 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:
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:
Enabled: false
Metrics/ClassLength:
Enabled: false
Metrics/CyclomaticComplexity:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/ModuleLength:
Enabled: false
Metrics/PerceivedComplexity:
Lint/UnusedMethodArgument:
Enabled: false
Lint/MissingSuper:
Style/SpecialGlobalVars:
Enabled: false

عرض الملف

@@ -2,6 +2,175 @@
This file contains all the latest changes and updates to Postal.
## [2.3.2](https://github.com/postalserver/postal/compare/2.3.1...2.3.2) (2024-03-01)
### Bug Fixes
* truncate output and details in deliveries to 250 characters ([694240d](https://github.com/postalserver/postal/commit/694240ddcdef1df9b32888de8fb743d2dee86462)), closes [#2831](https://github.com/postalserver/postal/issues/2831)
## [2.3.1](https://github.com/postalserver/postal/compare/2.3.0...2.3.1) (2024-02-23)
### Bug Fixes
* update raw headers after changing messages to during parsing ([2834e2c](https://github.com/postalserver/postal/commit/2834e2c37971db9b0b0498e38b382cf1f8ee26eb)), closes [#2816](https://github.com/postalserver/postal/issues/2816)
### Miscellaneous Chores
* **github-actions:** add 'docs' label to exclude from staleness checks ([57b72fb](https://github.com/postalserver/postal/commit/57b72fb4b7f7fc934cfa23906de65b8f6d6d1978))
* **github-actions:** add action to close stale issues and PRs ([d90a456](https://github.com/postalserver/postal/commit/d90a456dfa661d87e820160d2045c73c765564d2))
* **github-actions:** allow stale action to be run on demand ([559b08d](https://github.com/postalserver/postal/commit/559b08ddd31ecd904fd09c1e2822161b853166b9))
## [2.3.0](https://github.com/postalserver/postal/compare/2.2.2...2.3.0) (2024-02-13)
### Features
* privacy mode ([15f9671](https://github.com/postalserver/postal/commit/15f9671b667cf369255aaa27ee4257267990095c))
* remove strip_received_headers config option ([ed2e62b](https://github.com/postalserver/postal/commit/ed2e62b94fe76d7aeca0ede98f11a1c4f94c5996))
### Bug Fixes
* add ruby platform to gemfile ([1fceef7](https://github.com/postalserver/postal/commit/1fceef7cea76352fd6166fb3f1e8d0ff8591078e))
* explicitly disable TLS & starttls for unknown SSL modes ([42ab5b3](https://github.com/postalserver/postal/commit/42ab5b3a6b21992c89f8479137699dc9090f0ccc)), closes [#2564](https://github.com/postalserver/postal/issues/2564)
* fix bug with received header in SMTP server ([ba5bfbd](https://github.com/postalserver/postal/commit/ba5bfbd6a0af9ea33bedb2948822417bd1a3fbc5))
* retry mysql connections on message DB pool ([f9f7fb3](https://github.com/postalserver/postal/commit/f9f7fb30fee46b661b6dccde4362383ea591532b))
* use correct method for disconnecting smtp connections ([7c23994](https://github.com/postalserver/postal/commit/7c23994d243ec7d9a17ee053f8c3fa8de0a33097))
### Styles
* **rubocop:** disable complexity cops for now ([930cf39](https://github.com/postalserver/postal/commit/930cf39dba37401f90e293c938dee07daf3d9a31))
* **rubocop:** disable Style/SpecialGlobalVars ([be97f43](https://github.com/postalserver/postal/commit/be97f4330897f96085eb29ed7019b1a3e50af88e))
* **rubocop:** disable Style/StringConcatenation cop ([d508772](https://github.com/postalserver/postal/commit/d508772a40ef26e5c3a8304aa1f2b8c7985081bd))
* **rubocop:** Layout/* ([0e0aca0](https://github.com/postalserver/postal/commit/0e0aca06c90f6d2f4db1c4090a35c4537c76e13a))
* **rubocop:** Layout/EmptyLineAfterMagicComment ([0e4ed5c](https://github.com/postalserver/postal/commit/0e4ed5ca0393f9a56e1efa7ae377d2e4b876bfe1))
* **rubocop:** Layout/EmptyLines ([0cf35a8](https://github.com/postalserver/postal/commit/0cf35a83926d499a279775bcc32dd4ea79b7a8c9))
* **rubocop:** Layout/EmptyLinesAroundBlockBody ([cfd8d63](https://github.com/postalserver/postal/commit/cfd8d63321d1821aad7fa9d6b8462c3d551aca61))
* **rubocop:** Layout/LeadingCommentSpace ([59f299b](https://github.com/postalserver/postal/commit/59f299b704533488b74075beb8692397eb434aab))
* **rubocop:** Layout/LineLength ([e142d0d](https://github.com/postalserver/postal/commit/e142d0da5fbee19e6f9f1741ff9dee0a2d7dd169))
* **rubocop:** Layout/MultilineMethodCallBraceLayout ([a5d5ba5](https://github.com/postalserver/postal/commit/a5d5ba5326728413bb95456e92c854977d225a7f))
* **rubocop:** Lint/DuplicateBranch ([a1dc0f7](https://github.com/postalserver/postal/commit/a1dc0f77ac69937d7f30c9401608dfbe66987d45))
* **rubocop:** Lint/DuplicateMethods ([bab6346](https://github.com/postalserver/postal/commit/bab6346239e4f50bdd51101c45f3a0cd66f47096))
* **rubocop:** Lint/IneffectiveAccessModifier ([6ad56ee](https://github.com/postalserver/postal/commit/6ad56ee9c9e5bad19b065fcec3ada3280adbb1f4))
* **rubocop:** Lint/MissingSuper ([4674e63](https://github.com/postalserver/postal/commit/4674e63b5ff84307f5b772e870e88109af2daf52))
* **rubocop:** Lint/RedundantStringCoercion ([12a5ef3](https://github.com/postalserver/postal/commit/12a5ef3279bf6c1e5c38bf7e846de1d17bf98c09))
* **rubocop:** Lint/ShadowedException ([0966b44](https://github.com/postalserver/postal/commit/0966b44018bc1e2f131358635776fcc3b75ee8eb))
* **rubocop:** Lint/ShadowingOuterLocalVariable ([7119e86](https://github.com/postalserver/postal/commit/7119e8642dffeee7a27f90145073e45664ea58d3))
* **rubocop:** Lint/SuppressedException ([278ef08](https://github.com/postalserver/postal/commit/278ef0886ac53e6bed15793301dc69c95a37dbde))
* **rubocop:** Lint/UnderscorePrefixedVariableName ([ec7dcf4](https://github.com/postalserver/postal/commit/ec7dcf4f9a0bdb367a90f1a3b35336909ebc60d7))
* **rubocop:** Lint/UnusedBlockArgument ([ee94e4e](https://github.com/postalserver/postal/commit/ee94e4e1a013bbe8fbdd8ef94f15ed0fa20709ac))
* **rubocop:** Lint/UselessAssignment ([7590a46](https://github.com/postalserver/postal/commit/7590a462341bddd412e660db9546ba1909aea9d7))
* **rubocop:** Naming/FileName ([919a601](https://github.com/postalserver/postal/commit/919a60116c5d81ed787061ff4614da4f1e067d4e))
* **rubocop:** Naming/MemoizedInstanceVariableName ([9563f30](https://github.com/postalserver/postal/commit/9563f30c96fba12073e845319b8d79a542d88109))
* **rubocop:** relax method length and block nexting for now ([b0ac9ef](https://github.com/postalserver/postal/commit/b0ac9ef0b96ab78c2961f45b6e9f20f87a6f1d07))
* **rubocop:** remaining offences ([ec63666](https://github.com/postalserver/postal/commit/ec636661d5c4b9e8f48e6f263ffef834acb68b39))
* **rubocop:** Security/YAMLLoad ([389ea77](https://github.com/postalserver/postal/commit/389ea7705047bf8700836137514b2497af3c6c01))
* **rubocop:** Style/AndOr ([b9f3f31](https://github.com/postalserver/postal/commit/b9f3f313f8ec992917bad3a51f0481f89675e935))
* **rubocop:** Style/ClassAndModuleChildren ([e896f46](https://github.com/postalserver/postal/commit/e896f4689a8fc54979f0a6c2b7ce14746856bad6))
* **rubocop:** Style/For ([04a3483](https://github.com/postalserver/postal/commit/04a34831c74a3a44547f93100c35db650bc4eef6))
* **rubocop:** Style/FrozenStringLiteralComment ([6ab36c0](https://github.com/postalserver/postal/commit/6ab36c09c966eb9a8b8ada52155f74d2537977f2))
* **rubocop:** Style/GlobalStdStream ([75be690](https://github.com/postalserver/postal/commit/75be6907483ea25f828461eb790d3f6f46ca683b))
* **rubocop:** Style/GlobalVars ([157d114](https://github.com/postalserver/postal/commit/157d11457c520147807901b75b3ba22d29172f24))
* **rubocop:** Style/HashEachMethods ([c995027](https://github.com/postalserver/postal/commit/c995027ff53962ae49341372f75e2bf43ecde0d2))
* **rubocop:** Style/HashExcept ([83ac764](https://github.com/postalserver/postal/commit/83ac76451071f097e7197f77fc5ad16e9cf58593))
* **rubocop:** Style/IdenticalConditionalBranches ([6a58ecf](https://github.com/postalserver/postal/commit/6a58ecf605250b8fa891cb14fca0c0e0ce0d7eb9))
* **rubocop:** Style/MissingRespondToMissing ([ffcb707](https://github.com/postalserver/postal/commit/ffcb707247fe2a69905aa6e4dc668abeb9924611))
* **rubocop:** Style/MultilineBlockChain ([c6326a6](https://github.com/postalserver/postal/commit/c6326a6524e6d71d23bc2c256f3f9416c38b0846))
* **rubocop:** Style/MutableConstant ([129dffa](https://github.com/postalserver/postal/commit/129dffab9ed8726ca4066e7052adc699129de2d2))
* **rubocop:** Style/NumericPredicate ([c558f1c](https://github.com/postalserver/postal/commit/c558f1c69ce9498564161d8cef3fcb8213103498))
* **rubocop:** Style/PreferredHashMethods ([013b3ea](https://github.com/postalserver/postal/commit/013b3ea9315c14f24b08574d68e1688f33d78b8d))
* **rubocop:** Style/SafeNavigation ([00a02f2](https://github.com/postalserver/postal/commit/00a02f2655b6e3296ad0e7ea9b9872da936b56ed))
* **rubocop:** Style/SelectByRegexp ([9ce28a4](https://github.com/postalserver/postal/commit/9ce28a427fadf6fafd942e009792be4b5539d40d))
* **rubocop:** Style/StringLiterals ([b4cc812](https://github.com/postalserver/postal/commit/b4cc81264c85d5f0061e5b5121a30d7bdcabc189))
* **rubocop:** Style/WordArray ([bd85920](https://github.com/postalserver/postal/commit/bd8592056573d1c6933d753ed50bdf9a7466e761))
* **rubocop:** update rubocop rules ([6d4dea7](https://github.com/postalserver/postal/commit/6d4dea7f7f0145ff2b99cf2505bc70a3e5925256))
### Miscellaneous Chores
* annotate models ([6214892](https://github.com/postalserver/postal/commit/6214892710e21c2aa29a319d5809f7bdf0d50529))
* silence message DB migrations during provisioning ([c83601a](https://github.com/postalserver/postal/commit/c83601af69f35e338b1f7c10ef7994f74b96f8bf))
### Code Refactoring
* remove reloading on the smtp server ([c3c304e](https://github.com/postalserver/postal/commit/c3c304e98b3274433248792b6403acf63d7a513b))
### Tests
* add initial tests for Postal::SMTPServer::Client ([dece1d4](https://github.com/postalserver/postal/commit/dece1d487ac2fdce104700939a79a5579b60a0cb))
* FactoryBot.lint will lint all registered factories ([25d7d66](https://github.com/postalserver/postal/commit/25d7d66b4709fe5442d554097a6ef074aeb15f72))
* remove FACTORIES_EXCLUDED_FROM_LINT ([1cf665a](https://github.com/postalserver/postal/commit/1cf665a0cf61d1eae3d08bdadf6fccaab6413023))
## [2.2.2](https://github.com/postalserver/postal/compare/2.2.1...2.2.2) (2024-02-06)
### Bug Fixes
* adds new connection pool which will discard failed clients ([54306a9](https://github.com/postalserver/postal/commit/54306a974802c2e4d17e0980531e2d0dba08150a)), closes [#2780](https://github.com/postalserver/postal/issues/2780)
* re-add reconnect: true to database ([7bc5230](https://github.com/postalserver/postal/commit/7bc5230cbaae58fb6f8512d1d1b0e6a2eb989b56))
* upgrade nokogiri ([f05c2e4](https://github.com/postalserver/postal/commit/f05c2e4503688e59a5ef513a5a1064d0ebbb5813))
### Tests
* rename database spec file ([b9edcf5](https://github.com/postalserver/postal/commit/b9edcf5b7dda7f4976a9d3f90668bbdacea57350))
## [2.2.1](https://github.com/postalserver/postal/compare/2.2.0...2.2.1) (2024-02-03)
### Bug Fixes
* fixes issue starting application in production mode ([4528a14](https://github.com/postalserver/postal/commit/4528a14d273c141e5719f19c3b08c00364b47638))
### Code Refactoring
* remove Postal.database_url ([96ba4b8](https://github.com/postalserver/postal/commit/96ba4b8f309cfcd1d605e5c7fc05507b21c78c6f))
## [2.2.0](https://github.com/postalserver/postal/compare/2.1.6...2.2.0) (2024-02-01)
### Features
* load signing key path from POSTAL_SIGNING_KEY_PATH ([4a46f69](https://github.com/postalserver/postal/commit/4a46f690de3010f1ae4d6c17739530a4eae35c09))
* support for configuring postal with environment variables ([854aa5e](https://github.com/postalserver/postal/commit/854aa5ebc87de692b4691d48759aefd6fae9d133))
### Bug Fixes
* don't use indifferent access for job params ([2bad645](https://github.com/postalserver/postal/commit/2bad645d980ad4b712a3c863b5350e4ee2895071)), closes [#2477](https://github.com/postalserver/postal/issues/2477) [#2714](https://github.com/postalserver/postal/issues/2714) [#2476](https://github.com/postalserver/postal/issues/2476) [#2500](https://github.com/postalserver/postal/issues/2500)
* extract x-postal-tag before holding ([6b2bf90](https://github.com/postalserver/postal/commit/6b2bf9062d662ede14617c4995ffaacca023a3b1)), closes [#2684](https://github.com/postalserver/postal/issues/2684)
* fixes error messages in web ui ([71f51db](https://github.com/postalserver/postal/commit/71f51db3c2515addaf8b280667555427d64796be))
* ignore message DB migrations in autoloader ([3fb40e4](https://github.com/postalserver/postal/commit/3fb40e4e247893b314e42affa4604a7a71a52c59))
* move tracking middleware before host authorization ([49cceaa](https://github.com/postalserver/postal/commit/49cceaa6ca862965448041279fc439ecba163ff8)), closes [#2415](https://github.com/postalserver/postal/issues/2415)
* use utc timestamps when determining raw table names ([ce19bf7](https://github.com/postalserver/postal/commit/ce19bf7988d522bf46aabf68090751427e286ffc))
### Miscellaneous Chores
* add binstubs for bundle and rspec ([41f6cf4](https://github.com/postalserver/postal/commit/41f6cf4d909518526af55ecb3fcccfa8fb8e1da2))
* add script to send html emails to a local SMTP server ([8794a2f](https://github.com/postalserver/postal/commit/8794a2f44783658a075a6f3985079ae4743412b1))
### Code Refactoring
* remove explicit autoload ([0f9882f](https://github.com/postalserver/postal/commit/0f9882f13204124df630606b1b9e36787c9c4011))
* remove Postal::Job.perform method ([990b575](https://github.com/postalserver/postal/commit/990b575902c45bb1678cc95f53ef3166c4b7092e))
## [2.1.6](https://github.com/postalserver/postal/compare/2.1.5...2.1.6) (2024-01-30)
### Miscellaneous Chores
* **build:** fixes docker login action credentials ([8810856](https://github.com/postalserver/postal/commit/88108566f8ab33f1a4263a36a5c1ffc071645ac3))
* update release please to include more categories in changelog ([e156c21](https://github.com/postalserver/postal/commit/e156c21dee304de7d10c2958c493cce73c2d8fea))
## [2.1.5](https://github.com/postalserver/postal/compare/2.1.4...2.1.5) (2024-01-30)

11
Gemfile
عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
gem "authie"
gem "autoprefixer-rails"
@@ -10,12 +12,12 @@ gem "clockwork"
gem "dotenv-rails"
gem "dynamic_form"
gem "encrypto_signo"
gem "execjs", "~> 2.7", "< 2.8"
gem "foreman"
gem "gelf"
gem "haml"
gem "hashie"
gem "highline", require: false
gem "execjs", '~> 2.7', "< 2.8"
gem "jwt"
gem "kaminari"
gem "mail"
@@ -28,8 +30,8 @@ gem "puma"
gem "rails", "= 6.1.7.6"
gem "resolv", "~> 0.2.1"
gem "secure_headers"
gem 'sentry-rails'
gem 'sentry-ruby'
gem "sentry-rails"
gem "sentry-ruby"
gem "turbolinks", "~> 5"
group :development, :assets do
@@ -46,9 +48,10 @@ end
group :development do
gem "annotate"
gem "database_cleaner", require: false
gem "factory_bot_rails", "~> 4.0", require: false
gem "factory_bot_rails", require: false
gem "rspec", require: false
gem "rspec-rails", require: false
gem "rubocop"
gem "rubocop-rails"
gem "timecop"
end

عرض الملف

@@ -89,7 +89,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.2.2)
concurrent-ruby (1.2.3)
crass (1.0.6)
database_cleaner (2.0.2)
database_cleaner-active_record (>= 2, < 3)
@@ -104,15 +104,17 @@ GEM
dotenv-rails (2.8.1)
dotenv (= 2.8.1)
railties (>= 3.2)
dynamic_form (1.1.4)
dynamic_form (1.3.1)
actionview (> 5.2.0)
activemodel (> 5.2.0)
encrypto_signo (1.0.0)
erubi (1.12.0)
execjs (2.7.0)
factory_bot (4.11.1)
activesupport (>= 3.0.0)
factory_bot_rails (4.11.1)
factory_bot (~> 4.11.1)
railties (>= 3.0.0)
factory_bot (6.4.6)
activesupport (>= 5.0.0)
factory_bot_rails (6.4.3)
factory_bot (~> 6.4)
railties (>= 5.0.0)
ffi (1.15.5)
foreman (0.87.2)
gelf (3.1.0)
@@ -125,7 +127,7 @@ GEM
tilt
hashie (5.0.0)
highline (2.1.0)
i18n (1.12.0)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
jquery-rails (4.5.1)
rails-dom-testing (>= 1, < 3)
@@ -145,9 +147,9 @@ GEM
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
loofah (2.19.1)
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
nokogiri (>= 1.12.0)
mail (2.8.1)
mini_mime (>= 0.1.1)
net-imap
@@ -156,8 +158,8 @@ GEM
marcel (1.0.2)
method_source (1.0.0)
mini_mime (1.1.2)
mini_portile2 (2.8.1)
minitest (5.18.0)
mini_portile2 (2.8.5)
minitest (5.22.2)
moonrope (2.0.2)
deep_merge (~> 1.0)
json
@@ -177,20 +179,20 @@ GEM
activerecord (>= 4.0.0)
activesupport (>= 4.0.0)
nio4r (2.7.0)
nokogiri (1.14.3)
mini_portile2 (~> 2.8.0)
nokogiri (1.16.2)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.14.3-arm64-darwin)
nokogiri (1.16.2-arm64-darwin)
racc (~> 1.4)
nokogiri (1.14.3-x86_64-linux)
nokogiri (1.16.2-x86_64-linux)
racc (~> 1.4)
parallel (1.22.1)
parser (3.2.1.1)
ast (~> 2.4.1)
puma (6.4.2)
nio4r (~> 2.0)
racc (1.6.2)
rack (2.2.6.4)
racc (1.7.3)
rack (2.2.8)
rack-test (2.1.0)
rack (>= 1.3)
rails (6.1.7.6)
@@ -208,11 +210,13 @@ GEM
bundler (>= 1.15.0)
railties (= 6.1.7.6)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.5.0)
loofah (~> 2.19, >= 2.19.1)
rails-html-sanitizer (1.6.0)
loofah (~> 2.21)
nokogiri (~> 1.14)
railties (6.1.7.6)
actionpack (= 6.1.7.6)
activesupport (= 6.1.7.6)
@@ -220,7 +224,7 @@ GEM
rake (>= 12.2)
thor (~> 1.0)
rainbow (3.1.1)
rake (13.0.6)
rake (13.1.0)
rbtree (0.4.6)
regexp_parser (2.7.0)
resolv (0.2.2)
@@ -292,8 +296,9 @@ GEM
activesupport (>= 5.2)
sprockets (>= 3.0.0)
temple (0.10.0)
thor (1.2.1)
thor (1.3.0)
tilt (2.1.0)
timecop (0.9.8)
timeout (0.3.2)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
@@ -306,10 +311,11 @@ GEM
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
zeitwerk (2.6.7)
zeitwerk (2.6.13)
PLATFORMS
arm64-darwin-22
arm64-darwin-23
ruby
x86_64-linux
@@ -330,7 +336,7 @@ DEPENDENCIES
dynamic_form
encrypto_signo
execjs (~> 2.7, < 2.8)
factory_bot_rails (~> 4.0)
factory_bot_rails
foreman
gelf
haml
@@ -356,6 +362,7 @@ DEPENDENCIES
secure_headers
sentry-rails
sentry-ruby
timecop
turbolinks (~> 5)
uglifier (>= 1.3.0)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# 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.

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
authenticator :server do
friendly_name "Server Authenticator"
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
friendly_name "Messages API"
description "This API allows you to access message details"
@@ -12,7 +14,7 @@ controller :messages do
action do
begin
message = identity.server.message(params.id)
rescue Postal::MessageDB::Message::NotFound => e
rescue Postal::MessageDB::Message::NotFound
error "MessageNotFound", id: params.id
end
structure :message, message, return: true
@@ -28,7 +30,7 @@ controller :messages do
action do
begin
message = identity.server.message(params.id)
rescue Postal::MessageDB::Message::NotFound => e
rescue Postal::MessageDB::Message::NotFound
error "MessageNotFound", id: params.id
end
message.deliveries.map do |d|

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
controller :send do
friendly_name "Send API"
description "This API allows you to send messages"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
structure :delivery do
basic :id
basic :status

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
structure :message do
basic :id
basic :token
@@ -5,9 +7,9 @@ structure :message do
expansion(:status) do
{
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,
hold_expiry: o.hold_expiry ? o.hold_expiry.to_f : nil
hold_expiry: o.hold_expiry&.to_f
}
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class AddressEndpointsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "authie/session"
class ApplicationController < ActionController::Base
@@ -46,11 +48,7 @@ class ApplicationController < ActionController::Base
helper_method :page_title
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
else
redirect_to url_with_return_to(url), *args
end
redirect_to url_with_return_to(url), *args
end
def set_timezone
@@ -90,7 +88,7 @@ class ApplicationController < ActionController::Base
def render_form_errors(action_name, object)
respond_to do |wants|
wants.html { render action_name }
wants.json { render json: { form_errors: object.errors.full_messages }, status: :unprocessable_entity }
wants.json { render json: { form_errors: object.errors.map(&:full_message) }, status: :unprocessable_entity }
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module WithinOrganization
extend ActiveSupport::Concern

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class CredentialsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class DomainsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class HelpController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class HTTPEndpointsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IPAddressesController < ApplicationController
before_action :admin_required

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IPPoolRulesController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IPPoolsController < ApplicationController
before_action :admin_required
@@ -31,7 +33,7 @@ class IPPoolsController < ApplicationController
def destroy
@ip_pool.destroy
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."
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class MessagesController < ApplicationController
include WithinOrganization
@@ -186,7 +188,7 @@ class MessagesController < ApplicationController
if qs[:before]
begin
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]}'"
end
end
@@ -194,7 +196,7 @@ class MessagesController < ApplicationController
if qs[:after]
begin
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]}'"
end
end
@@ -220,6 +222,7 @@ class MessagesController < ApplicationController
time = Chronic.parse(string, context: :past)
end
rescue StandardError
time = nil
end
raise TimeUndetermined, "Couldn't determine a suitable time from '#{string}'" if time.nil?

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class OrganizationIPPoolsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class OrganizationsController < ApplicationController
before_action :admin_required, only: [:new, :create, :delete, :destroy]

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class RoutesController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ServersController < ApplicationController
include WithinOrganization
@@ -41,7 +43,12 @@ class ServersController < ApplicationController
def update
extra_params = [:spam_threshold, :spam_failure_threshold, :postmaster_address]
extra_params += [:send_limit, :allow_sender, :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))
redirect_to_with_json organization_server_path(organization, @server), notice: "Server settings have been updated"
else

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SessionsController < ApplicationController
layout "sub"
@@ -8,7 +10,7 @@ class SessionsController < ApplicationController
login(User.authenticate(params[:email_address], params[:password]))
flash[:remember_login] = true
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."
render "new"
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SMTPEndpointsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class TrackDomainsController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class UserController < ApplicationController
skip_before_action :login_required, only: [:new, :create, :join]
@@ -69,7 +71,9 @@ class UserController < ApplicationController
if @user.save
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
redirect_to_with_json settings_path, notice: "Your settings have been updated successfully."
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class UsersController < ApplicationController
before_action :admin_required

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class WebhooksController < ApplicationController
include WithinOrganization

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module ApplicationHelper
def format_delivery_details(server, text)
@@ -28,7 +30,7 @@ module ApplicationHelper
server_domains = server.domains.verified.order(:name)
unless server_domains.empty?
s << "<optgroup label='Server Domains'>"
for domain in server_domains
server_domains.each do |domain|
selected = domain == selected_domain ? "selected='selected'" : ""
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
end
@@ -38,7 +40,7 @@ module ApplicationHelper
organization_domains = server.organization.domains.verified.order(:name)
unless organization_domains.empty?
s << "<optgroup label='Organization Domains'>"
for domain in organization_domains
organization_domains.each do |domain|
selected = domain == selected_domain ? "selected='selected'" : ""
s << "<option value='#{domain.id}' #{selected}>#{domain.name}</option>"
end
@@ -54,7 +56,7 @@ module ApplicationHelper
http_endpoints = server.http_endpoints.order(:name).to_a
if http_endpoints.present?
s << "<optgroup label='HTTP Endpoints'>"
for endpoint in http_endpoints
http_endpoints.each do |endpoint|
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
@@ -65,7 +67,7 @@ module ApplicationHelper
smtp_endpoints = server.smtp_endpoints.order(:name).to_a
if smtp_endpoints.present?
s << "<optgroup label='SMTP Endpoints'>"
for endpoint in smtp_endpoints
smtp_endpoints.each do |endpoint|
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.description}</option>"
@@ -76,7 +78,7 @@ module ApplicationHelper
address_endpoints = server.address_endpoints.order(:address).to_a
if address_endpoints.present?
s << "<optgroup label='Address Endpoints'>"
for endpoint in address_endpoints
address_endpoints.each do |endpoint|
value = "#{endpoint.class}##{endpoint.uuid}"
selected = value == selected_value ? "selected='selected'" : ""
s << "<option value='#{value}' #{selected}>#{endpoint.address}</option>"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ActionDeletionJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ActionDeletionsJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class CheckAllDNSJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "authie/session"
class CleanupAuthieSessionsJob < Postal::Job

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ExpireHeldMessagesJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ProcessMessageRetentionJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class PruneSuppressionListsJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class PruneWebhookRequestsJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class RequeueWebhooksJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SendNotificationsJob < Postal::Job
def perform

عرض الملف

@@ -1,16 +1,17 @@
# frozen_string_literal: true
class SendWebhookJob < Postal::Job
def perform
if server = Server.find(params["server_id"])
new_items = {}
if params["payload"]
for key, value in params["payload"]
next unless key.to_s =~ /\A_(\w+)/
params["payload"]&.each do |key, value|
next unless key.to_s =~ /\A_(\w+)/
begin
new_items[::Regexp.last_match(1)] = server.message_db.message(value.to_i).webhook_hash
rescue Postal::MessageDB::Message::NotFound
end
begin
new_items[::Regexp.last_match(1)] = server.message_db.message(value.to_i).webhook_hash
rescue Postal::MessageDB::Message::NotFound
# No message found, don't do any replacement
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class SleepJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class TidyRawMessagesJob < Postal::Job
def perform

عرض الملف

@@ -1,5 +1,8 @@
# frozen_string_literal: true
class UnqueueMessageJob < Postal::Job
# rubocop:disable Layout/LineLength
def perform
if original_message = QueuedMessage.find_by_id(params["id"])
if original_message.acquire_lock
@@ -91,11 +94,11 @@ class UnqueueMessageJob < Postal::Job
log "#{log_prefix} Message is a bounce"
original_messages = queued_message.message.original_messages
unless original_messages.empty?
for original_message in queued_message.message.original_messages
queued_message.message.update(bounce_for_id: original_message.id, domain_id: original_message.domain_id)
queued_message.message.create_delivery("Processed", details: "This has been detected as a bounce message for <msg:#{original_message.id}>.")
original_message.bounce!(queued_message.message)
log "#{log_prefix} Bounce linked with message #{original_message.id}"
queued_message.message.original_messages.each do |orig_msg|
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:#{orig_msg.id}>.")
orig_msg.bounce!(queued_message.message)
log "#{log_prefix} Bounce linked with message #{orig_msg.id}"
end
queued_message.destroy
next
@@ -292,6 +295,12 @@ class UnqueueMessageJob < Postal::Job
next
end
# Extract a tag and add it to the message if one doesn't exist
if queued_message.message.tag.nil? && tag = queued_message.message.headers["x-postal-tag"]
log "#{log_prefix} Added tag #{tag.last}"
queued_message.message.update(tag: tag.last)
end
#
# If the credentials for this message is marked as holding and this isn't manual, hold it
#
@@ -312,12 +321,6 @@ class UnqueueMessageJob < Postal::Job
next
end
# Extract a tag and add it to the message if one doesn't exist
if queued_message.message.tag.nil? && tag = queued_message.message.headers["x-postal-tag"]
log "#{log_prefix} Added tag #{tag.last}"
queued_message.message.update(tag: tag.last)
end
# Parse the content of the message as appropriate
if queued_message.message.should_parse?
log "#{log_prefix} Parsing message content as it hasn't been parsed before"
@@ -421,15 +424,17 @@ class UnqueueMessageJob < Postal::Job
end
rescue StandardError => e
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
log "#{log_prefix} Queued message was unlocked"
if defined?(Sentry)
Sentry.capture_exception(e, extra: { job_id: self.id, server_id: queued_message.server_id, message_id: queued_message.message_id })
end
if queued_message.message
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}")
end
queued_message.message&.create_delivery("Error",
details: "An internal error occurred while sending " \
"this message. This message will be retried " \
"automatically.",
output: "#{e.class}: #{e.message}", log_id: "J-#{self.id}")
end
end
@@ -446,9 +451,11 @@ class UnqueueMessageJob < Postal::Job
nil
end
end
# rubocop:enable Layout/LineLength
private
# rubocop:disable Naming/MemoizedInstanceVariableName
def cached_sender(klass, *args)
@sender ||= begin
sender = klass.new(*args)
@@ -456,5 +463,6 @@ class UnqueueMessageJob < Postal::Job
sender
end
end
# rubocop:enable Naming/MemoizedInstanceVariableName
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class WebhookDeliveryJob < Postal::Job
def perform

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class AppMailer < ApplicationMailer
def verify_email_address(user)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ApplicationMailer < ActionMailer::Base
default from: "#{Postal.smtp_from_name} <#{Postal.smtp_from_address}>"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: additional_route_endpoints
@@ -35,9 +37,7 @@ class AdditionalRouteEndpoint < ApplicationRecord
end
def _endpoint=(value)
if value.blank?
self.endpoint = nil
elsif value =~ /\#/
if value && value =~ /\#/
class_name, id = value.split("#", 2)
unless Route::ENDPOINT_TYPES.include?(class_name)
raise Postal::Error, "Invalid endpoint class name '#{class_name}'"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: address_endpoints

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module HasAuthentication
extend ActiveSupport::Concern
@@ -42,18 +44,4 @@ module HasAuthentication
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

عرض الملف

@@ -1,9 +1,11 @@
# frozen_string_literal: true
require "resolv"
module HasDNSChecks
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
def dns_checked?
@@ -42,12 +44,12 @@ module HasDNSChecks
def check_spf_record
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?
self.spf_status = "Missing"
self.spf_error = "No SPF record exists for this domain"
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?
self.spf_status = "Invalid"
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
def self.included(base)
@@ -18,7 +20,7 @@ module HasMessage
def include_message
queued_messages = all.to_a
server_ids = queued_messages.map(&:server_id).uniq
if server_ids.size == 0
if server_ids.empty?
return []
elsif server_ids.size > 1
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
def self.included(base)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module HasUUID
def self.included(base)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: credentials
@@ -21,7 +23,7 @@ class Credential < ApplicationRecord
belongs_to :server
TYPES = ["SMTP", "API", "SMTP-IP"]
TYPES = %w[SMTP API SMTP-IP].freeze
validates :key, presence: true, uniqueness: { case_sensitive: false }
validates :type, inclusion: { in: TYPES }

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: domains
@@ -42,15 +44,14 @@ class Domain < ApplicationRecord
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 :owner, optional: true, polymorphic: true
has_many :routes, 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 :verification_method, inclusion: { in: VERIFICATION_METHODS }
@@ -83,8 +84,8 @@ class Domain < ApplicationRecord
def parent_domains
parts = name.split(".")
parts[0, parts.size - 1].each_with_index.map do |p, i|
parts[i..-1].join(".")
parts[0, parts.size - 1].each_with_index.map do |_, i|
parts[i..].join(".")
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: http_endpoints
@@ -29,8 +31,8 @@ class HTTPEndpoint < ApplicationRecord
has_many :routes, as: :endpoint
has_many :additional_route_endpoints, dependent: :destroy, as: :endpoint
ENCODINGS = ["BodyAsJSON", "FormData"]
FORMATS = ["Hash", "RawMessage"]
ENCODINGS = %w[BodyAsJSON FormData].freeze
FORMATS = %w[Hash RawMessage].freeze
before_destroy :update_routes

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
class IncomingMessagePrototype
attr_accessor :to
@@ -22,13 +24,14 @@ class IncomingMessagePrototype
end
def route
@routes ||= if @to.present?
uname, domain = @to.split("@", 2)
uname, tag = uname.split("+", 2)
@server.routes.includes(:domain).where(domains: { name: domain }, name: uname).first
end
@route ||= if @to.present?
uname, domain = @to.split("@", 2)
uname, _tag = uname.split("+", 2)
@server.routes.includes(:domain).where(domains: { name: domain }, name: uname).first
end
end
# rubocop:disable Lint/DuplicateMethods
def attachments
(@attachments || []).map do |attachment|
{
@@ -38,6 +41,7 @@ class IncomingMessagePrototype
}
end
end
# rubocop:enable Lint/DuplicateMethods
def create_messages
if valid?
@@ -91,7 +95,7 @@ class IncomingMessagePrototype
content: attachment[:data]
}
end
mail.header["Received"] = "from #{@source_type} (#{@ip} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822}"
mail.header["Received"] = Postal::ReceivedHeader.generate(@server, @source_type, @ip, :http)
mail.to_s
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: ip_addresses

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: ip_pools

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: ip_pool_rules
@@ -66,18 +68,22 @@ class IPPoolRule < ApplicationRecord
errors.add :ip_pool_id, "must belong to the organization"
end
def self.address_matches?(condition, address)
address = Postal::Helpers.strip_name_from_address(address)
if condition =~ /@/
parts = address.split("@")
domain = parts.pop
uname = parts.join("@")
uname, = uname.split("+", 2)
condition == "#{uname}@#{domain}"
else
# Match as a domain
condition == address.split("@").last
class << self
def address_matches?(condition, address)
address = Postal::Helpers.strip_name_from_address(address)
if condition =~ /@/
parts = address.split("@")
domain = parts.pop
uname = parts.join("@")
uname, = uname.split("+", 2)
condition == "#{uname}@#{domain}"
else
# Match as a domain
condition == address.split("@").last
end
end
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: organizations
@@ -23,7 +25,7 @@
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_SUPER_QUOTA = 10_000
@@ -48,7 +50,7 @@ class Organization < ApplicationRecord
has_many :ip_pool_rules, dependent: :destroy, as: :owner
after_create do
if pool = IPPool.default
if IPPool.default
ip_pools << IPPool.default
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: organization_ip_pools

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: organization_users

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "resolv"
class OutgoingMessagePrototype
@@ -47,13 +49,11 @@ class OutgoingMessagePrototype
end
def find_domain
@domain ||= begin
domain = @server.authenticated_domain_for_address(@from)
if @server.allow_sender? && domain.nil?
domain = @server.authenticated_domain_for_address(@sender)
end
domain || :none
domain = @server.authenticated_domain_for_address(@from)
if @server.allow_sender? && domain.nil?
domain = @server.authenticated_domain_for_address(@sender)
end
domain || :none
end
def to_addresses
@@ -93,6 +93,7 @@ class OutgoingMessagePrototype
@errors || {}
end
# rubocop:disable Lint/DuplicateMethods
def attachments
(@attachments || []).map do |attachment|
{
@@ -102,6 +103,7 @@ class OutgoingMessagePrototype
}
end
end
# rubocop:enable Lint/DuplicateMethods
def validate
@errors = []
@@ -135,7 +137,7 @@ class OutgoingMessagePrototype
end
if attachments.present?
attachments.each_with_index do |attachment, index|
attachments.each do |attachment|
if attachment[:name].blank?
@errors << "AttachmentMissingName" unless @errors.include?("AttachmentMissingName")
elsif attachment[:data].blank?
@@ -175,7 +177,7 @@ class OutgoingMessagePrototype
content: attachment[:data]
}
end
mail.header["Received"] = "from #{@source_type} (#{resolved_hostname} [#{@ip}]) by Postal with HTTP; #{Time.now.utc.rfc2822}"
mail.header["Received"] = Postal::ReceivedHeader.generate(@server, @source_type, @ip, :http)
mail.message_id = "<#{@message_id}>"
mail.to_s
end
@@ -196,12 +198,4 @@ class OutgoingMessagePrototype
{ id: message.id, token: message.token }
end
def resolved_hostname
@resolved_hostname ||= begin
Resolv.new.getname(@ip)
rescue StandardError
@ip
end
end
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: queued_messages

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: routes
@@ -22,7 +24,9 @@
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
@@ -31,9 +35,6 @@ class Route < ApplicationRecord
belongs_to :endpoint, polymorphic: true, optional: true
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 :spam_mode, inclusion: { in: SPAM_MODES }
validates :endpoint, presence: { if: proc { mode == "Endpoint" } }
@@ -115,7 +116,7 @@ class Route < ApplicationRecord
if route.save
seen << route.id
else
route.errors.each do |field, message|
route.errors.each do |_, message|
errors.add :base, message
end
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
errors.add :name, "is configured on the #{route.server.full_permalink} mail server"
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"
end
end
@@ -218,12 +219,16 @@ class Route < ApplicationRecord
errors.add :base, "Additional routes are not permitted unless the primary route is an actual endpoint"
end
def self.find_by_name_and_domain(name, domain)
route = Route.includes(:domain).where(name: name, domains: { name: domain }).first
if route.nil?
route = Route.includes(:domain).where(name: "*", domains: { name: domain }).first
class << self
def find_by_name_and_domain(name, domain)
route = Route.includes(:domain).where(name: name, domains: { name: domain }).first
if route.nil?
route = Route.includes(:domain).where(name: "*", domains: { name: domain }).first
end
route
end
route
end
end

عرض الملف

@@ -1,35 +1,38 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: servers
#
# id :integer not null, primary key
# organization_id :integer
# uuid :string(255)
# name :string(255)
# mode :string(255)
# ip_pool_id :integer
# created_at :datetime
# updated_at :datetime
# permalink :string(255)
# send_limit :integer
# allow_sender :boolean default(FALSE)
# deleted_at :datetime
# domains_not_to_click_track :text(65535)
# log_smtp_data :boolean default(FALSE)
# message_retention_days :integer
# mode :string(255)
# name :string(255)
# outbound_spam_threshold :decimal(8, 2)
# permalink :string(255)
# postmaster_address :string(255)
# privacy_mode :boolean default(FALSE)
# raw_message_retention_days :integer
# raw_message_retention_size :integer
# allow_sender :boolean default(FALSE)
# token :string(255)
# send_limit :integer
# send_limit_approaching_at :datetime
# send_limit_approaching_notified_at :datetime
# send_limit_exceeded_at :datetime
# send_limit_exceeded_notified_at :datetime
# spam_threshold :decimal(8, 2)
# spam_failure_threshold :decimal(8, 2)
# postmaster_address :string(255)
# spam_threshold :decimal(8, 2)
# suspended_at :datetime
# outbound_spam_threshold :decimal(8, 2)
# domains_not_to_click_track :text(65535)
# suspension_reason :string(255)
# log_smtp_data :boolean default(FALSE)
# token :string(255)
# uuid :string(255)
# created_at :datetime
# updated_at :datetime
# ip_pool_id :integer
# organization_id :integer
#
# Indexes
#
@@ -41,7 +44,8 @@
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 HasSoftDestroy
@@ -62,8 +66,6 @@ class Server < ApplicationRecord
has_many :track_domains, dependent: :destroy
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
default_value :permalink, -> { name ? name.parameterize : nil }
default_value :raw_message_retention_days, -> { 30 }
@@ -155,11 +157,11 @@ class Server < ApplicationRecord
time = Time.now.utc
total_outgoing = 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_bounces += stat[:bounces]
end
total_outgoing == 0 ? 0 : (total_bounces / total_outgoing) * 100
total_outgoing.zero? ? 0 : (total_bounces / total_outgoing) * 100
end
end
@@ -218,6 +220,10 @@ class Server < ApplicationRecord
}
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)
return nil if address.blank?
@@ -226,16 +232,24 @@ class Server < ApplicationRecord
return nil unless uname
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 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
end
# If there is a matching domain, return it
return domain if domain
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
def find_authenticated_domain_from_headers(headers)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: smtp_endpoints
@@ -24,7 +26,7 @@ class SMTPEndpoint < ApplicationRecord
has_many :routes, 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

عرض الملف

@@ -1,11 +1,13 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: statistics
#
# id :integer not null, primary key
# total_messages :bigint(8) default(0)
# total_outgoing :bigint(8) default(0)
# total_incoming :bigint(8) default(0)
# total_incoming :bigint default(0)
# total_messages :bigint default(0)
# total_outgoing :bigint default(0)
#
class Statistic < ApplicationRecord

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: track_domains

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: users

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: user_invites

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: webhooks

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: webhook_events
@@ -14,16 +16,16 @@
class WebhookEvent < ApplicationRecord
EVENTS = [
"MessageSent",
"MessageDelayed",
"MessageDeliveryFailed",
"MessageHeld",
"MessageBounced",
"MessageLinkClicked",
"MessageLoaded",
"DomainDNSError"
]
EVENTS = %w[
MessageSent
MessageDelayed
MessageDeliveryFailed
MessageHeld
MessageBounced
MessageLinkClicked
MessageLoaded
DomainDNSError
].freeze
belongs_to :webhook

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: webhook_requests
@@ -19,7 +21,7 @@ class WebhookRequest < ApplicationRecord
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 :webhook, optional: true

عرض الملف

@@ -19,7 +19,11 @@
.fieldSet__input
= f.select :allow_sender, [["No", false], ["Yes - can use Sender header", true]], {}, :class => 'input input--select'
%p.fieldSet__text If enabled, outgoing messages can use any address in the From header as long as a Sender header is included with an authorized address.
.fieldSet__field
= f.label :privacy_mode, "Privacy mode", :class => 'fieldSet__label'
.fieldSet__input
= f.select :privacy_mode, [["Disabled", false], ["Enabled", true]], {}, :class => 'input input--select'
%p.fieldSet__text If enabled, when Postal adds Received headers to e-mails it will not include IP or hostname information of the client submitting the message.
.fieldSet__field
= f.label :log_smtp_data, "Log SMTP data?", :class => 'fieldSet__label'
.fieldSet__input

عرض الملف

@@ -1,3 +1,109 @@
#!/usr/bin/env ruby
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
load Gem.bin_path("bundler", "bundle")
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'bundle' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require "rubygems"
m = Module.new do
module_function
def invoked_as_script?
File.expand_path($0) == File.expand_path(__FILE__)
end
def env_var_version
ENV["BUNDLER_VERSION"]
end
def cli_arg_version
return unless invoked_as_script? # don't want to hijack other binstubs
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
bundler_version = a
end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
bundler_version = $1
update_index = i
end
bundler_version
end
def gemfile
gemfile = ENV["BUNDLE_GEMFILE"]
return gemfile if gemfile && !gemfile.empty?
File.expand_path("../Gemfile", __dir__)
end
def lockfile
lockfile =
case File.basename(gemfile)
when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
else "#{gemfile}.lock"
end
File.expand_path(lockfile)
end
def lockfile_version
return unless File.file?(lockfile)
lockfile_contents = File.read(lockfile)
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
Regexp.last_match(1)
end
def bundler_requirement
@bundler_requirement ||=
env_var_version ||
cli_arg_version ||
bundler_requirement_for(lockfile_version)
end
def bundler_requirement_for(version)
return "#{Gem::Requirement.default}.a" unless version
bundler_gem_version = Gem::Version.new(version)
bundler_gem_version.approximate_recommendation
end
def load_bundler!
ENV["BUNDLE_GEMFILE"] ||= gemfile
activate_bundler
end
def activate_bundler
gem_error = activation_error_handling do
gem "bundler", bundler_requirement
end
return if gem_error.nil?
require_error = activation_error_handling do
require "bundler/version"
end
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
exit 42
end
def activation_error_handling
yield
nil
rescue StandardError, LoadError => e
e
end
end
m.load_bundler!
if m.invoked_as_script?
load Gem.bin_path("bundler", "bundle")
end

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require_relative "../config/boot"
require "rake"
Rake.application.run

27
bin/rspec Executable file
عرض الملف

@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'rspec' is installed as part of a gem, and
# this file is here to facilitate running it.
#
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
bundle_binstub = File.expand_path("bundle", __dir__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
require "rubygems"
require "bundler/setup"
load Gem.bin_path("rspec-core", "rspec")

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "pathname"
require "fileutils"
include FileUtils

عرض الملف

@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "pathname"
require "fileutils"
include FileUtils

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require_relative "boot"
require "rails"
@@ -27,14 +29,14 @@ module Postal
end
# Include from lib
config.eager_load_namespaces << Postal
config.eager_load_paths << Rails.root.join("lib")
# 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
require "postal/tracking_middleware"
config.middleware.use Postal::TrackingMiddleware
config.middleware.insert_before ActionDispatch::HostAuthorization, Postal::TrackingMiddleware
config.logger = Postal.logger_for(:rails)

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
$stdout.sync = true

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Clockwork
configure do |config|

عرض الملف

@@ -1,8 +1,19 @@
default: &default
adapter: mysql2
reconnect: true
encoding: <%= Postal.config.main_db.encoding %>
pool: <%= Postal.config.main_db.pool_size %>
username: <%= Postal.config.main_db.username %>
password: <%= Postal.config.main_db.password %>
host: <%= Postal.config.main_db.host %>
port: <%= Postal.config.main_db.port %>
database: <%= Postal.config.main_db.database %>
development:
url: <%= Postal.database_url %>
<<: *default
production:
url: <%= Postal.database_url %>
<<: *default
test:
url: <%= Postal.database_url %>
<<: *default

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Load the Rails application.
require_relative "application"

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do
# 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')
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger = ActiveSupport::Logger.new($stdout)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end

عرض الملف

@@ -1,3 +1,5 @@
# frozen_string_literal: true
Rails.application.configure do
# 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.
# ApplicationController.renderer.defaults.merge!(

لم تُعرض بعض الملفات لأن الكثير من الملفات تغيرت في هذا الاختلاف إظهار المزيد