auction_fun_core 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +12 -0
  3. data/.env.development.template +7 -0
  4. data/.env.test.template +7 -0
  5. data/.rspec +3 -0
  6. data/.standard.yml +3 -0
  7. data/.tool-versions +5 -0
  8. data/CHANGELOG.md +145 -0
  9. data/CODE_OF_CONDUCT.md +84 -0
  10. data/LICENSE.txt +21 -0
  11. data/Procfile +4 -0
  12. data/README.md +141 -0
  13. data/Rakefile +13 -0
  14. data/auction_fun_core.gemspec +57 -0
  15. data/config/app.rb +5 -0
  16. data/config/application.rb +37 -0
  17. data/config/boot.rb +15 -0
  18. data/db/migrate/20240216200926_enable_postgres_extensions.rb +13 -0
  19. data/db/migrate/20240217115734_create_users.rb +28 -0
  20. data/db/migrate/20240220140151_create_custom_types.rb +11 -0
  21. data/db/migrate/20240220140254_create_staffs.rb +20 -0
  22. data/db/migrate/20240229142933_create_custom_types.rb +13 -0
  23. data/db/migrate/20240229143000_create_auctions.rb +29 -0
  24. data/db/migrate/20240304144422_create_bids.rb +19 -0
  25. data/db/seeds.rb +116 -0
  26. data/i18n/en-US/contracts/contracts.en-US.yml +72 -0
  27. data/i18n/en-US/mail/user_context/registration.en-US.yml +11 -0
  28. data/i18n/pt-BR/contracts/contracts.pt-BR.yml +72 -0
  29. data/i18n/pt-BR/mail/user_context/registration.pt-BR.yml +12 -0
  30. data/lib/auction_fun_core/business/configuration.rb +18 -0
  31. data/lib/auction_fun_core/business/token_generator.rb +17 -0
  32. data/lib/auction_fun_core/commands/auction_context/create_auction.rb +19 -0
  33. data/lib/auction_fun_core/commands/auction_context/delete_auction.rb +15 -0
  34. data/lib/auction_fun_core/commands/auction_context/update_auction.rb +18 -0
  35. data/lib/auction_fun_core/commands/bid_context/create_bid.rb +19 -0
  36. data/lib/auction_fun_core/commands/bid_context/delete_bid.rb +15 -0
  37. data/lib/auction_fun_core/commands/bid_context/update_bid.rb +18 -0
  38. data/lib/auction_fun_core/commands/staff_context/create_staff.rb +19 -0
  39. data/lib/auction_fun_core/commands/user_context/create_user.rb +19 -0
  40. data/lib/auction_fun_core/contracts/application_contract.rb +55 -0
  41. data/lib/auction_fun_core/contracts/auction_context/create_contract.rb +101 -0
  42. data/lib/auction_fun_core/contracts/auction_context/processor/finish_contract.rb +27 -0
  43. data/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +34 -0
  44. data/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +46 -0
  45. data/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +34 -0
  46. data/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +79 -0
  47. data/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +69 -0
  48. data/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +68 -0
  49. data/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +47 -0
  50. data/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +52 -0
  51. data/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +47 -0
  52. data/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +40 -0
  53. data/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +40 -0
  54. data/lib/auction_fun_core/contracts/user_context/registration_contract.rb +63 -0
  55. data/lib/auction_fun_core/entities/auction.rb +17 -0
  56. data/lib/auction_fun_core/entities/bid.rb +10 -0
  57. data/lib/auction_fun_core/entities/staff.rb +21 -0
  58. data/lib/auction_fun_core/entities/user.rb +37 -0
  59. data/lib/auction_fun_core/events/app.rb +27 -0
  60. data/lib/auction_fun_core/events/listener.rb +89 -0
  61. data/lib/auction_fun_core/operations/auction_context/create_operation.rb +77 -0
  62. data/lib/auction_fun_core/operations/auction_context/processor/finish_operation.rb +61 -0
  63. data/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +57 -0
  64. data/lib/auction_fun_core/operations/auction_context/processor/start_operation.rb +84 -0
  65. data/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +57 -0
  66. data/lib/auction_fun_core/operations/base.rb +11 -0
  67. data/lib/auction_fun_core/operations/bid_context/create_bid_closed_operation.rb +64 -0
  68. data/lib/auction_fun_core/operations/bid_context/create_bid_penny_operation.rb +64 -0
  69. data/lib/auction_fun_core/operations/bid_context/create_bid_standard_operation.rb +74 -0
  70. data/lib/auction_fun_core/operations/staff_context/authentication_operation.rb +52 -0
  71. data/lib/auction_fun_core/operations/staff_context/registration_operation.rb +76 -0
  72. data/lib/auction_fun_core/operations/user_context/authentication_operation.rb +52 -0
  73. data/lib/auction_fun_core/operations/user_context/email_confirmation_operation.rb +67 -0
  74. data/lib/auction_fun_core/operations/user_context/phone_confirmation_operation.rb +67 -0
  75. data/lib/auction_fun_core/operations/user_context/registration_operation.rb +105 -0
  76. data/lib/auction_fun_core/relations/auctions.rb +119 -0
  77. data/lib/auction_fun_core/relations/bids.rb +28 -0
  78. data/lib/auction_fun_core/relations/staffs.rb +27 -0
  79. data/lib/auction_fun_core/relations/users.rb +26 -0
  80. data/lib/auction_fun_core/repos/auction_context/auction_repository.rb +42 -0
  81. data/lib/auction_fun_core/repos/bid_context/bid_repository.rb +27 -0
  82. data/lib/auction_fun_core/repos/staff_context/staff_repository.rb +64 -0
  83. data/lib/auction_fun_core/repos/user_context/user_repository.rb +78 -0
  84. data/lib/auction_fun_core/services/mail/templates/layout.html.erb +72 -0
  85. data/lib/auction_fun_core/services/mail/templates/user_context/registration.html.erb +170 -0
  86. data/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +25 -0
  87. data/lib/auction_fun_core/version.rb +8 -0
  88. data/lib/auction_fun_core/workers/application_job.rb +22 -0
  89. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish_operation_job.rb +32 -0
  90. data/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +32 -0
  91. data/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +40 -0
  92. data/lib/auction_fun_core.rb +21 -0
  93. data/lib/tasks/database.rake +87 -0
  94. data/system/providers/background_job.rb +15 -0
  95. data/system/providers/core.rb +35 -0
  96. data/system/providers/db.rb +26 -0
  97. data/system/providers/events.rb +13 -0
  98. data/system/providers/logger.rb +11 -0
  99. data/system/providers/mail.rb +25 -0
  100. data/system/providers/persistence.rb +18 -0
  101. data/system/providers/settings.rb +26 -0
  102. metadata +400 -0
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Relations
5
+ # SQL relation for auctions.
6
+ # @see https://rom-rb.org/5.0/learn/sql/relations/
7
+ class Auctions < ROM::Relation[:sql]
8
+ use :pagination, per_page: 10
9
+
10
+ KINDS = Types::Coercible::String.default("standard").enum("standard", "penny", "closed")
11
+ STATUSES = Types::Coercible::String.default("scheduled")
12
+ .enum("scheduled", "running", "paused", "canceled", "finished")
13
+
14
+ schema(:auctions, infer: true) do
15
+ attribute :id, Types::Integer
16
+ attribute :staff_id, Types::ForeignKey(:staffs)
17
+ attribute :title, Types::String
18
+ attribute :description, Types::String
19
+ attribute :kind, KINDS
20
+ attribute :status, STATUSES
21
+ attribute :started_at, Types::DateTime
22
+ attribute :finished_at, Types::DateTime
23
+ attribute :stopwatch, Types::Integer
24
+ attribute :initial_bid_cents, Types::Integer
25
+ attribute :initial_bid_currency, Types::String
26
+ attribute :minimal_bid_cents, Types::Integer
27
+ attribute :minimal_bid_currency, Types::String
28
+
29
+ attribute :metadata, Types::PG::JSONB
30
+ attribute :statistics, Types::PG::JSONB
31
+ primary_key :id
32
+
33
+ associations do
34
+ belongs_to :staff, as: :staff, relation: :staffs
35
+ has_many :bids, as: :bids, relation: :bids
36
+ end
37
+ end
38
+
39
+ struct_namespace Entities
40
+ auto_struct(true)
41
+
42
+ def all(page = 1, per_page = 10, options = {bidders_count: 3})
43
+ offset = ((page - 1) * per_page)
44
+
45
+ read(all_auctions_with_bid_info(per_page, offset, options))
46
+ end
47
+
48
+ def info(auction_id, options = {bidders_count: 3})
49
+ raise "Invalid argument" unless auction_id.is_a?(Integer)
50
+
51
+ read(auction_with_bid_info(auction_id, options))
52
+ end
53
+
54
+ private
55
+
56
+ def auction_with_bid_info(auction_id, options = {bidders_count: 3})
57
+ "SELECT a.id, a.title, a.description, a.kind, a.status, a.started_at, a.finished_at, a.stopwatch, a.initial_bid_cents,
58
+ (SELECT COUNT(*) FROM (SELECT * FROM bids WHERE bids.auction_id = #{auction_id}) dt) AS total_bids,
59
+ CASE
60
+ WHEN a.kind = 'standard' THEN
61
+ json_build_object(
62
+ 'current', a.minimal_bid_cents,
63
+ 'minimal', a.minimal_bid_cents,
64
+ 'bidders', COALESCE(
65
+ json_agg(json_build_object('id', bi.id, 'user_id', users.id, 'name', users.name, 'value', bi.value_cents, 'date', bi.created_at) ORDER BY value_cents DESC)
66
+ FILTER (where bi.id IS NOT NULL AND users.id IS NOT NULL), '[]'::json
67
+ )
68
+ )
69
+ WHEN a.kind = 'penny' THEN
70
+ json_build_object(
71
+ 'value', a.initial_bid_cents,
72
+ 'bidders', COALESCE(
73
+ json_agg(json_build_object('id', bi.id, 'user_id', users.id, 'name', users.name, 'value', bi.value_cents, 'date', bi.created_at) ORDER BY value_cents DESC)
74
+ FILTER (where bi.id IS NOT NULL AND users.id IS NOT NULL), '[]'::json
75
+ )
76
+ )
77
+ WHEN a.kind = 'closed' THEN
78
+ json_build_object('minimal', (a.initial_bid_cents + (a.initial_bid_cents * 0.10))::int)
79
+ END as bids
80
+ FROM auctions as a
81
+ LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id AND a.id = #{auction_id}
82
+ LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id
83
+ WHERE a.id = #{auction_id}
84
+ GROUP BY a.id"
85
+ end
86
+
87
+ def all_auctions_with_bid_info(per_page, offset, options = {bidders_count: 3})
88
+ "SELECT a.id, a.title, a.description, a.kind, a.status, a.started_at, a.finished_at, a.stopwatch, a.initial_bid_cents,
89
+ (SELECT COUNT(*) FROM (SELECT * FROM bids WHERE bids.auction_id = a.id) dt) AS total_bids,
90
+ CASE
91
+ WHEN a.kind = 'standard' THEN
92
+ json_build_object(
93
+ 'current', a.minimal_bid_cents,
94
+ 'minimal', a.minimal_bid_cents,
95
+ 'bidders', COALESCE(
96
+ json_agg(json_build_object('id', bi.id, 'user_id', users.id, 'name', users.name, 'value', bi.value_cents, 'date', bi.created_at) ORDER BY value_cents DESC)
97
+ FILTER (where bi.id IS NOT NULL AND users.id IS NOT NULL), '[]'::json
98
+ )
99
+ )
100
+ WHEN a.kind = 'penny' THEN
101
+ json_build_object(
102
+ 'value', a.initial_bid_cents,
103
+ 'bidders', COALESCE(
104
+ json_agg(json_build_object('id', bi.id, 'user_id', users.id, 'name', users.name, 'value', bi.value_cents, 'date', bi.created_at) ORDER BY value_cents DESC)
105
+ FILTER (where bi.id IS NOT NULL AND users.id IS NOT NULL), '[]'::json
106
+ )
107
+ )
108
+ WHEN a.kind = 'closed' THEN
109
+ json_build_object('minimal', (a.initial_bid_cents + (a.initial_bid_cents * 0.10))::int)
110
+ END as bids
111
+ FROM auctions as a
112
+ LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id
113
+ LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id
114
+ GROUP BY a.id
115
+ LIMIT #{per_page} OFFSET #{offset}"
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Relations
5
+ # SQL relation for bids
6
+ # @see https://rom-rb.org/5.0/learn/sql/relations/
7
+ class Bids < ROM::Relation[:sql]
8
+ use :pagination, per_page: 3
9
+
10
+ schema(:bids, infer: true) do
11
+ attribute :id, Types::Integer
12
+
13
+ attribute :auction_id, Types::ForeignKey(:auctions)
14
+ attribute :user_id, Types::ForeignKey(:users)
15
+
16
+ associations do
17
+ belongs_to :auction
18
+ belongs_to :user
19
+ end
20
+
21
+ primary_key :id
22
+ end
23
+
24
+ struct_namespace Entities
25
+ auto_struct(true)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Relations
5
+ # SQL relation for staffs.
6
+ # @see https://rom-rb.org/5.0/learn/sql/relations/
7
+ class Staffs < ROM::Relation[:sql]
8
+ use :pagination, per_page: 10
9
+
10
+ STAFF_KINDS = Types::Coercible::String.default("common").enum("root", "common")
11
+
12
+ schema(:staffs, infer: true) do
13
+ attribute :id, Types::Integer
14
+ attribute :name, Types::String
15
+ attribute :email, Types::String
16
+ attribute :phone, Types::String
17
+ attribute :kind, STAFF_KINDS
18
+ attribute :active, Types::Bool
19
+
20
+ primary_key :id
21
+ end
22
+
23
+ struct_namespace Entities
24
+ auto_struct(true)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Relations
5
+ # SQL relation for users.
6
+ # @see https://rom-rb.org/5.0/learn/sql/relations/
7
+ class Users < ROM::Relation[:sql]
8
+ use :pagination, per_page: 10
9
+
10
+ schema(:users, infer: true) do
11
+ attribute :id, Types::Integer
12
+ attribute :name, Types::String
13
+ attribute :email, Types::String
14
+ attribute :phone, Types::String
15
+ attribute :active, Types::Bool
16
+ attribute :balance_cents, Types::Integer
17
+ attribute :balance_currency, Types::String
18
+
19
+ primary_key :id
20
+ end
21
+
22
+ struct_namespace Entities
23
+ auto_struct(true)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Repos
5
+ module AuctionContext
6
+ # SQL repository for auctions.
7
+ class AuctionRepository < ROM::Repository[:auctions]
8
+ include Import["container"]
9
+
10
+ struct_namespace Entities
11
+ commands :create, update: :by_pk, delete: :by_pk
12
+
13
+ # Returns all auctions in the database.
14
+ # @return [Array<ROM::Struct::Auction>, []]
15
+ def all
16
+ auctions.to_a
17
+ end
18
+
19
+ # Returns the total number of auctions in database.
20
+ # @return [Integer]
21
+ def count
22
+ auctions.count
23
+ end
24
+
25
+ # Search auction in database by primary key.
26
+ # @param id [Integer] Auction ID
27
+ # @return [ROM::Struct::Auction, nil]
28
+ def by_id(id)
29
+ auctions.by_pk(id).one
30
+ end
31
+
32
+ # Search auction in database by primary key.
33
+ # @param id [Integer] Auction ID
34
+ # @raise [ROM::TupleCountMismatchError] if not found on database
35
+ # @return [ROM::Struct::Auction]
36
+ def by_id!(id)
37
+ auctions.by_pk(id).one!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Repos
5
+ module BidContext
6
+ # SQL repository for bids.
7
+ class BidRepository < ROM::Repository[:bids]
8
+ include Import["container"]
9
+
10
+ struct_namespace Entities
11
+ commands :create, update: :by_pk, delete: :by_pk
12
+
13
+ # Returns the total number of bids in database.
14
+ # @return [Integer]
15
+ def count
16
+ bids.count
17
+ end
18
+
19
+ # @param conditions [Hash] DSL Dataset
20
+ # @return [Boolean]
21
+ def exists?(conditions)
22
+ bids.exist?(conditions)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Repos
5
+ module StaffContext
6
+ # SQL repository for staffs.
7
+ class StaffRepository < ROM::Repository[:staffs]
8
+ include Import["container"]
9
+
10
+ struct_namespace Entities
11
+ commands :create, update: :by_pk, delete: :by_pk
12
+
13
+ # Returns all staffs in database.
14
+ # @return [Array<ROM::Struct::Staff>, []]
15
+ def all
16
+ staffs.to_a
17
+ end
18
+
19
+ # Returns the total number of staffs in database.
20
+ # @return [Integer]
21
+ def count
22
+ staffs.count
23
+ end
24
+
25
+ # Mount SQL conditions in query for search in database.
26
+ # @param conditions [Hash] DSL Dataset
27
+ # @return [AuctionFunCore::Relations::Staffs]
28
+ def query(conditions)
29
+ staffs.where(conditions)
30
+ end
31
+
32
+ # Search staff in database by primary key.
33
+ # @param id [Integer] Staff ID
34
+ # @return [ROM::Struct::Staff, nil]
35
+ def by_id(id)
36
+ staffs.by_pk(id).one
37
+ end
38
+
39
+ # Search staffs in database by primary key.
40
+ # @param id [Integer] Staff ID
41
+ # @raise [ROM::TupleCountMismatchError] if not found on database
42
+ # @return [ROM::Struct::Auction]
43
+ def by_id!(id)
44
+ staffs.by_pk(id).one!
45
+ end
46
+
47
+ # Search staff in database by email of phone keys.
48
+ # @param login [String] Staff email or phone
49
+ # @return [ROM::Struct::Staff, nil]
50
+ def by_login(login)
51
+ staffs.where(Sequel[email: login] | Sequel[phone: login]).one
52
+ end
53
+
54
+ # Checks if it returns any staff given one or more conditions.
55
+ # @param conditions [Hash] DSL Dataset
56
+ # @return [true] when some staff is returned from the given condition.
57
+ # @return [false] when no staff is returned from the given condition.
58
+ def exists?(conditions)
59
+ staffs.exist?(conditions)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AuctionFunCore
4
+ module Repos
5
+ module UserContext
6
+ # SQL repository for users.
7
+ class UserRepository < ROM::Repository[:users]
8
+ include Import["container"]
9
+
10
+ struct_namespace Entities
11
+ commands :create, update: :by_pk, delete: :by_pk
12
+
13
+ # Returns all users in database.
14
+ # @return [Array<ROM::Struct::User>, []]
15
+ def all
16
+ users.to_a
17
+ end
18
+
19
+ # Returns the total number of users in database.
20
+ # @return [Integer]
21
+ def count
22
+ users.count
23
+ end
24
+
25
+ # Mount SQL conditions in query for search in database.
26
+ # @param conditions [Hash] DSL Dataset
27
+ # @return [AuctionFunCore::Relations::Users]
28
+ def query(conditions)
29
+ users.where(conditions)
30
+ end
31
+
32
+ # Search user in database by primary key.
33
+ # @param id [Integer] User ID
34
+ # @return [ROM::Struct::User, nil]
35
+ def by_id(id)
36
+ users.by_pk(id).one
37
+ end
38
+
39
+ # Search user in database by primary key.
40
+ # @param id [Integer] User ID
41
+ # @raise [ROM::TupleCountMismatchError] if not found on database
42
+ # @return [ROM::Struct::Auction]
43
+ def by_id!(id)
44
+ users.by_pk(id).one!
45
+ end
46
+
47
+ # Search user in database by email of phone keys.
48
+ # @param login [String] User email or phone
49
+ # @return [ROM::Struct::User, nil]
50
+ def by_login(login)
51
+ users.where(Sequel[email: login] | Sequel[phone: login]).one
52
+ end
53
+
54
+ # Search user in database by email_confirmation_token key.
55
+ # @param email_confirmation_token [String] User email confirmation token
56
+ # @return [ROM::Struct::User, nil]
57
+ def by_email_confirmation_token(email_confirmation_token)
58
+ users.where(Sequel[email_confirmation_token: email_confirmation_token]).one
59
+ end
60
+
61
+ # Search user in database by phone_confirmation_token of phone keys.
62
+ # @param phone [String] User phone confirmation token
63
+ # @return [ROM::Struct::User, nil]
64
+ def by_phone_confirmation_token(phone_confirmation_token)
65
+ users.where(Sequel[phone_confirmation_token: phone_confirmation_token]).one
66
+ end
67
+
68
+ # Checks if it returns any user given one or more conditions.
69
+ # @param conditions [Hash] DSL Dataset
70
+ # @return [true] when some user is returned from the given condition.
71
+ # @return [false] when no user is returned from the given condition.
72
+ def exists?(conditions)
73
+ users.exist?(conditions)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,72 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
3
+ <head>
4
+ <title>AuctionFun</title>
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <style type="text/css">
9
+ #outlook a {
10
+ padding: 0;
11
+ }
12
+ body {
13
+ margin: 0;
14
+ padding: 0;
15
+ -webkit-text-size-adjust: 100%;
16
+ -ms-text-size-adjust: 100%;
17
+ }
18
+ table,
19
+ td {
20
+ border-collapse: collapse;
21
+ mso-table-lspace: 0pt;
22
+ mso-table-rspace: 0pt;
23
+ }
24
+ img {
25
+ border: 0;
26
+ height: auto;
27
+ line-height: 100%;
28
+ outline: none;
29
+ text-decoration: none;
30
+ -ms-interpolation-mode: bicubic;
31
+ }
32
+ p {
33
+ display: block;
34
+ margin: 13px 0;
35
+ }
36
+ </style>
37
+ <style type="text/css">
38
+ .mj-outlook-group-fix { width:100% !important; }
39
+ </style>
40
+ <style type="text/css">
41
+ @media only screen and (min-width:480px) {
42
+ .mj-column-per-100 {
43
+ width: 100% !important;
44
+ max-width: 100%;
45
+ }
46
+ }
47
+ </style>
48
+ <style type="text/css">
49
+ @media only screen and (max-width:480px) {
50
+ table.mj-full-width-mobile {
51
+ width: 100% !important;
52
+ }
53
+ td.mj-full-width-mobile {
54
+ width: auto !important;
55
+ }
56
+ }
57
+ </style>
58
+ <style type="text/css">
59
+ a,
60
+ span,
61
+ td,
62
+ th {
63
+ -webkit-font-smoothing: antialiased !important;
64
+ -moz-osx-font-smoothing: grayscale !important;
65
+ }
66
+ </style>
67
+ </head>
68
+ <body style="background-color:#ffffff;">
69
+ <%= yield %>
70
+ </div>
71
+ </body>
72
+ </html>
@@ -0,0 +1,170 @@
1
+ <table align="center" border="0" cellpadding="0" cellspacing="0" style="width:600px;" width="600">
2
+ <tr>
3
+ <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
4
+ <div style="margin:0px auto;max-width:600px;">
5
+ <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
6
+ <tbody>
7
+ <tr>
8
+ <td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:0px;text-align:center;">
9
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
10
+ <tr>
11
+ <td style="vertical-align:top;width:600px;">
12
+ <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
13
+ <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
14
+ <tbody>
15
+ <tr>
16
+ <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
17
+ <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
18
+ <tbody>
19
+ <tr>
20
+ <td style="width:50px;">
21
+ <img alt="image description" height="auto" src="https://codedmails.com/images/logo-circle.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:14px;" width="50" />
22
+ </td>
23
+ </tr>
24
+ </tbody>
25
+ </table>
26
+ </td>
27
+ </tr>
28
+ <tr>
29
+ <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
30
+ <div style="font-family:Helvetica, Arial, sans-serif;font-size:18px;font-weight:400;line-height:24px;text-align:left;color:#434245;">
31
+ <h1 style="margin: 0; font-size: 24px; line-height: normal; font-weight: bold;">
32
+ <%= I18n.t("mail.general.hello", name: @user.name) %>,
33
+ </h1>
34
+ </div>
35
+ </td>
36
+ </tr>
37
+ </tbody>
38
+ </table>
39
+ </div>
40
+ </td>
41
+ </tr>
42
+ </table>
43
+ </td>
44
+ </tr>
45
+ </tbody>
46
+ </table>
47
+ </div>
48
+ </td>
49
+ </tr>
50
+ </table>
51
+ <table align="center" border="0" cellpadding="0" cellspacing="0" style="width:600px;" width="600">
52
+ <tr>
53
+ <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
54
+ <div style="margin:0px auto;max-width:600px;">
55
+ <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
56
+ <tbody>
57
+ <tr>
58
+ <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
59
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
60
+ <tr>
61
+ <td style="vertical-align:top;width:600px;">
62
+ <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
63
+ <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
64
+ <tbody>
65
+ <tr>
66
+ <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
67
+ <div style="font-family:Helvetica, Arial, sans-serif;font-size:18px;font-weight:400;line-height:24px;text-align:left;color:#434245;">
68
+ <%= I18n.t("mail.user_context.registration.body.description") %>
69
+ </div>
70
+ </td>
71
+ </tr>
72
+ <tr>
73
+ <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
74
+ <div style="font-family:Helvetica, Arial, sans-serif;font-size:18px;font-weight:400;line-height:24px;text-align:left;color:#434245;">
75
+ <%= raw I18n.t("mail.user_context.registration.body.email_confirmation_token", token: @user.email_confirmation_token) %>
76
+ </div>
77
+ </td>
78
+ </tr>
79
+ <tr>
80
+ <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
81
+ <div style="font-family:Helvetica, Arial, sans-serif;font-size:18px;font-weight:bold;line-height:24px;text-align:left;color:#434245;">
82
+ <%= I18n.t("mail.general.team") %>
83
+ </div>
84
+ </td>
85
+ </tr>
86
+ <tr>
87
+ <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
88
+ <table align="left" border="0" cellpadding="0" cellspacing="0" role="presentation">
89
+ <tr>
90
+ <td>
91
+ <table align="left" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
92
+ <tbody>
93
+ <tr>
94
+ <td style="padding:4px;">
95
+ <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:18px;">
96
+ <tbody>
97
+ <tr>
98
+ <td style="font-size:0;height:18px;vertical-align:middle;width:18px;">
99
+ <a href="https://twitter.com/auctionfun" target="_blank" style="color: #2e58ff; text-decoration: none;">
100
+ <img alt="twitter-logo" height="18" src="https://codedmails.com/images/social/black/twitter-logo-transparent-black.png" style="border-radius:3px;display:block;" width="18" />
101
+ </a>
102
+ </td>
103
+ </tr>
104
+ </tbody>
105
+ </table>
106
+ </td>
107
+ </tr>
108
+ </tbody>
109
+ </table>
110
+ </td>
111
+ <td>
112
+ <table align="left" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
113
+ <tbody>
114
+ <tr>
115
+ <td style="padding:4px;">
116
+ <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:18px;">
117
+ <tbody>
118
+ <tr>
119
+ <td style="font-size:0;height:18px;vertical-align:middle;width:18px;">
120
+ <a href="https://facebook.com/auctionfun" target="_blank" style="color: #2e58ff; text-decoration: none;">
121
+ <img alt="facebook-logo" height="18" src="https://codedmails.com/images/social/black/facebook-logo-transparent-black.png" style="border-radius:3px;display:block;" width="18" />
122
+ </a>
123
+ </td>
124
+ </tr>
125
+ </tbody>
126
+ </table>
127
+ </td>
128
+ </tr>
129
+ </tbody>
130
+ </table>
131
+ </td>
132
+ <td>
133
+ <table align="left" border="0" cellpadding="0" cellspacing="0" role="presentation" style="float:none;display:inline-table;">
134
+ <tbody>
135
+ <tr>
136
+ <td style="padding:4px;">
137
+ <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-radius:3px;width:18px;">
138
+ <tbody>
139
+ <tr>
140
+ <td style="font-size:0;height:18px;vertical-align:middle;width:18px;">
141
+ <a href="https://instagram.com/auctionfun" target="_blank" style="color: #2e58ff; text-decoration: none;">
142
+ <img alt="instagram-logo" height="18" src="https://codedmails.com/images/social/black/instagram-logo-transparent-black.png" style="border-radius:3px;display:block;" width="18" />
143
+ </a>
144
+ </td>
145
+ </tr>
146
+ </tbody>
147
+ </table>
148
+ </td>
149
+ </tr>
150
+ </tbody>
151
+ </table>
152
+ </td>
153
+ </tr>
154
+ </table>
155
+ </td>
156
+ </tr>
157
+ </tbody>
158
+ </table>
159
+ </div>
160
+ </td>
161
+ </tr>
162
+ </table>
163
+ </td>
164
+ </tr>
165
+ </tbody>
166
+ </table>
167
+ </div>
168
+ </td>
169
+ </tr>
170
+ </table>