مراية لـ
https://github.com/postalserver/postal.git
تم المزامنة 2026-03-03 14:24:06 +00:00
Compare commits
96 الالتزامات
| المؤلف | SHA1 | التاريخ | |
|---|---|---|---|
|
|
66d26c8d4f | ||
|
|
343292bbde | ||
|
|
694240ddcd | ||
|
|
18ba7140b4 | ||
|
|
2834e2c379 | ||
|
|
559b08ddd3 | ||
|
|
57b72fb4b7 | ||
|
|
d90a456dfa | ||
|
|
d7dce16c50 | ||
|
|
b8bab1bd0e | ||
|
|
7c23994d24 | ||
|
|
42ab5b3a6b | ||
|
|
f9f7fb30fe | ||
|
|
b8cb563553 | ||
|
|
e83e2a5e33 | ||
|
|
c3c304e98b | ||
|
|
241f37e78d | ||
|
|
c83601af69 | ||
|
|
6214892710 | ||
|
|
1fceef7cea | ||
|
|
dece1d487a | ||
|
|
ec636661d5 | ||
|
|
c6326a6524 | ||
|
|
013b3ea931 | ||
|
|
ffcb707247 | ||
|
|
83ac764510 | ||
|
|
c995027ff5 | ||
|
|
ec7dcf4f9a | ||
|
|
278ef0886a | ||
|
|
bab6346239 | ||
|
|
a1dc0f77ac | ||
|
|
0e0aca06c9 | ||
|
|
9ce28a427f | ||
|
|
157d11457c | ||
|
|
e896f4689a | ||
|
|
b9f3f313f8 | ||
|
|
4674e63b5f | ||
|
|
be97f43308 | ||
|
|
75be690748 | ||
|
|
9563f30c96 | ||
|
|
00a02f2655 | ||
|
|
04a34831c7 | ||
|
|
6a58ecf605 | ||
|
|
6ad56ee9c9 | ||
|
|
c558f1c69c | ||
|
|
7119e8642d | ||
|
|
bd85920565 | ||
|
|
129dffab9e | ||
|
|
d508772a40 | ||
|
|
b0ac9ef0b9 | ||
|
|
a5d5ba5326 | ||
|
|
919a60116c | ||
|
|
0cf35a8392 | ||
|
|
12a5ef3279 | ||
|
|
0966b44018 | ||
|
|
389ea77050 | ||
|
|
ee94e4e1a0 | ||
|
|
7590a46234 | ||
|
|
25d7d66b47 | ||
|
|
cfd8d63321 | ||
|
|
1cf665a0cf | ||
|
|
930cf39dba | ||
|
|
6d4dea7f7f | ||
|
|
e142d0da5f | ||
|
|
59f299b704 | ||
|
|
b4cc81264c | ||
|
|
0e4ed5ca03 | ||
|
|
6ab36c09c9 | ||
|
|
ba5bfbd6a0 | ||
|
|
97a328419b | ||
|
|
ed2e62b94f | ||
|
|
15f9671b66 | ||
|
|
19e3bc20c6 | ||
|
|
f05c2e4503 | ||
|
|
7bc5230cba | ||
|
|
b9edcf5b7d | ||
|
|
54306a9748 | ||
|
|
304828a672 | ||
|
|
4528a14d27 | ||
|
|
96ba4b8f30 | ||
|
|
ff901e99f7 | ||
|
|
ce19bf7988 | ||
|
|
8794a2f447 | ||
|
|
6b2bf9062d | ||
|
|
49cceaa6ca | ||
|
|
71f51db3c2 | ||
|
|
4a46f690de | ||
|
|
854aa5ebc8 | ||
|
|
990b575902 | ||
|
|
2bad645d98 | ||
|
|
41f6cf4d90 | ||
|
|
3fb40e4e24 | ||
|
|
0f9882f132 | ||
|
|
26aae298a4 | ||
|
|
88108566f8 | ||
|
|
e156c21dee |
@@ -2,7 +2,7 @@
|
||||
name: 🐛 Bug report
|
||||
about: Create a report to help us improve Postal and fix issues.
|
||||
title: ''
|
||||
labels: bug
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
10
.github/workflows/ci.yml
مباع
10
.github/workflows/ci.yml
مباع
@@ -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
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"
|
||||
}
|
||||
|
||||
164
.rubocop.yml
164
.rubocop.yml
@@ -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
|
||||
|
||||
169
CHANGELOG.md
169
CHANGELOG.md
@@ -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
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
|
||||
|
||||
59
Gemfile.lock
59
Gemfile.lock
@@ -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)
|
||||
|
||||
|
||||
2
Rakefile
2
Rakefile
@@ -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
|
||||
|
||||
110
bin/bundle
110
bin/bundle
@@ -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"
|
||||
|
||||
2
bin/rake
2
bin/rake
@@ -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
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!(
|
||||
|
||||
لم تُعرض بعض الملفات لأن الكثير من الملفات تغيرت في هذا الاختلاف إظهار المزيد
المرجع في مشكلة جديدة
حظر مستخدم