propel_authentication 0.1.1

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/LICENSE +21 -0
  3. data/README.md +290 -0
  4. data/Rakefile +12 -0
  5. data/lib/generators/propel_auth/install_generator.rb +486 -0
  6. data/lib/generators/propel_auth/pack_generator.rb +277 -0
  7. data/lib/generators/propel_auth/templates/agency.rb +7 -0
  8. data/lib/generators/propel_auth/templates/agent.rb +7 -0
  9. data/lib/generators/propel_auth/templates/auth/base_passwords_controller.rb.tt +99 -0
  10. data/lib/generators/propel_auth/templates/auth/base_tokens_controller.rb.tt +90 -0
  11. data/lib/generators/propel_auth/templates/auth/passwords_controller.rb.tt +126 -0
  12. data/lib/generators/propel_auth/templates/auth_mailer.rb +180 -0
  13. data/lib/generators/propel_auth/templates/authenticatable.rb +38 -0
  14. data/lib/generators/propel_auth/templates/concerns/confirmable.rb +145 -0
  15. data/lib/generators/propel_auth/templates/concerns/lockable.rb +123 -0
  16. data/lib/generators/propel_auth/templates/concerns/propel_authentication.rb +44 -0
  17. data/lib/generators/propel_auth/templates/concerns/rack_session_disable.rb +19 -0
  18. data/lib/generators/propel_auth/templates/concerns/recoverable.rb +124 -0
  19. data/lib/generators/propel_auth/templates/config/environments/development_email.rb +43 -0
  20. data/lib/generators/propel_auth/templates/db/migrate/create_agencies.rb +20 -0
  21. data/lib/generators/propel_auth/templates/db/migrate/create_agents.rb +11 -0
  22. data/lib/generators/propel_auth/templates/db/migrate/create_invitations.rb +28 -0
  23. data/lib/generators/propel_auth/templates/db/migrate/create_organizations.rb +18 -0
  24. data/lib/generators/propel_auth/templates/db/migrate/create_users.rb +43 -0
  25. data/lib/generators/propel_auth/templates/db/seeds.rb +29 -0
  26. data/lib/generators/propel_auth/templates/invitation.rb +133 -0
  27. data/lib/generators/propel_auth/templates/lib/propel_auth.rb +84 -0
  28. data/lib/generators/propel_auth/templates/organization.rb +7 -0
  29. data/lib/generators/propel_auth/templates/propel_auth.rb +132 -0
  30. data/lib/generators/propel_auth/templates/services/auth_notification_service.rb +89 -0
  31. data/lib/generators/propel_auth/templates/test/concerns/confirmable_test.rb.tt +247 -0
  32. data/lib/generators/propel_auth/templates/test/concerns/lockable_test.rb.tt +282 -0
  33. data/lib/generators/propel_auth/templates/test/concerns/propel_authentication_test.rb.tt +75 -0
  34. data/lib/generators/propel_auth/templates/test/concerns/recoverable_test.rb.tt +327 -0
  35. data/lib/generators/propel_auth/templates/test/controllers/auth/lockable_integration_test.rb.tt +196 -0
  36. data/lib/generators/propel_auth/templates/test/controllers/auth/password_reset_integration_test.rb.tt +471 -0
  37. data/lib/generators/propel_auth/templates/test/controllers/auth/tokens_controller_test.rb.tt +265 -0
  38. data/lib/generators/propel_auth/templates/test/mailers/auth_mailer_test.rb.tt +216 -0
  39. data/lib/generators/propel_auth/templates/test/mailers/previews/auth_mailer_preview.rb +161 -0
  40. data/lib/generators/propel_auth/templates/tokens_controller.rb.tt +96 -0
  41. data/lib/generators/propel_auth/templates/user.rb +21 -0
  42. data/lib/generators/propel_auth/templates/user_test.rb.tt +81 -0
  43. data/lib/generators/propel_auth/templates/views/auth_mailer/account_unlock.html.erb +213 -0
  44. data/lib/generators/propel_auth/templates/views/auth_mailer/account_unlock.text.erb +56 -0
  45. data/lib/generators/propel_auth/templates/views/auth_mailer/email_confirmation.html.erb +213 -0
  46. data/lib/generators/propel_auth/templates/views/auth_mailer/email_confirmation.text.erb +32 -0
  47. data/lib/generators/propel_auth/templates/views/auth_mailer/password_reset.html.erb +166 -0
  48. data/lib/generators/propel_auth/templates/views/auth_mailer/password_reset.text.erb +32 -0
  49. data/lib/generators/propel_auth/templates/views/auth_mailer/user_invitation.html.erb +194 -0
  50. data/lib/generators/propel_auth/templates/views/auth_mailer/user_invitation.text.erb +51 -0
  51. data/lib/generators/propel_auth/test/dummy/Dockerfile +72 -0
  52. data/lib/generators/propel_auth/test/dummy/Gemfile +63 -0
  53. data/lib/generators/propel_auth/test/dummy/Gemfile.lock +394 -0
  54. data/lib/generators/propel_auth/test/dummy/README.md +24 -0
  55. data/lib/generators/propel_auth/test/dummy/Rakefile +6 -0
  56. data/lib/generators/propel_auth/test/dummy/app/assets/stylesheets/application.css +10 -0
  57. data/lib/generators/propel_auth/test/dummy/app/controllers/application_controller.rb +4 -0
  58. data/lib/generators/propel_auth/test/dummy/app/helpers/application_helper.rb +2 -0
  59. data/lib/generators/propel_auth/test/dummy/app/jobs/application_job.rb +7 -0
  60. data/lib/generators/propel_auth/test/dummy/app/mailers/application_mailer.rb +4 -0
  61. data/lib/generators/propel_auth/test/dummy/app/models/application_record.rb +3 -0
  62. data/lib/generators/propel_auth/test/dummy/app/views/layouts/application.html.erb +27 -0
  63. data/lib/generators/propel_auth/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  64. data/lib/generators/propel_auth/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  65. data/lib/generators/propel_auth/test/dummy/app/views/pwa/manifest.json.erb +22 -0
  66. data/lib/generators/propel_auth/test/dummy/app/views/pwa/service-worker.js +26 -0
  67. data/lib/generators/propel_auth/test/dummy/bin/brakeman +7 -0
  68. data/lib/generators/propel_auth/test/dummy/bin/dev +2 -0
  69. data/lib/generators/propel_auth/test/dummy/bin/docker-entrypoint +14 -0
  70. data/lib/generators/propel_auth/test/dummy/bin/rails +4 -0
  71. data/lib/generators/propel_auth/test/dummy/bin/rake +4 -0
  72. data/lib/generators/propel_auth/test/dummy/bin/rubocop +8 -0
  73. data/lib/generators/propel_auth/test/dummy/bin/setup +34 -0
  74. data/lib/generators/propel_auth/test/dummy/bin/thrust +5 -0
  75. data/lib/generators/propel_auth/test/dummy/config/application.rb +42 -0
  76. data/lib/generators/propel_auth/test/dummy/config/boot.rb +4 -0
  77. data/lib/generators/propel_auth/test/dummy/config/cable.yml +10 -0
  78. data/lib/generators/propel_auth/test/dummy/config/credentials.yml.enc +1 -0
  79. data/lib/generators/propel_auth/test/dummy/config/database.yml +41 -0
  80. data/lib/generators/propel_auth/test/dummy/config/environment.rb +5 -0
  81. data/lib/generators/propel_auth/test/dummy/config/environments/development.rb +72 -0
  82. data/lib/generators/propel_auth/test/dummy/config/environments/production.rb +89 -0
  83. data/lib/generators/propel_auth/test/dummy/config/environments/test.rb +53 -0
  84. data/lib/generators/propel_auth/test/dummy/config/initializers/assets.rb +10 -0
  85. data/lib/generators/propel_auth/test/dummy/config/initializers/content_security_policy.rb +25 -0
  86. data/lib/generators/propel_auth/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
  87. data/lib/generators/propel_auth/test/dummy/config/initializers/inflections.rb +16 -0
  88. data/lib/generators/propel_auth/test/dummy/config/locales/en.yml +31 -0
  89. data/lib/generators/propel_auth/test/dummy/config/master.key +1 -0
  90. data/lib/generators/propel_auth/test/dummy/config/puma.rb +41 -0
  91. data/lib/generators/propel_auth/test/dummy/config/routes.rb +2 -0
  92. data/lib/generators/propel_auth/test/dummy/config/storage.yml +34 -0
  93. data/lib/generators/propel_auth/test/dummy/config.ru +6 -0
  94. data/lib/generators/propel_auth/test/dummy/db/schema.rb +14 -0
  95. data/lib/generators/propel_auth/test/generators/authentication/controllers/tokens_controller_test.rb +230 -0
  96. data/lib/generators/propel_auth/test/generators/authentication/install_generator_test.rb +490 -0
  97. data/lib/generators/propel_auth/test/generators/authentication/uninstall_generator_test.rb +408 -0
  98. data/lib/generators/propel_auth/test/integration/generator_integration_test.rb +158 -0
  99. data/lib/generators/propel_auth/test/integration/multi_version_generator_test.rb +125 -0
  100. data/lib/generators/propel_auth/unpack_generator.rb +345 -0
  101. data/lib/propel_auth.rb +3 -0
  102. metadata +195 -0
@@ -0,0 +1,32 @@
1
+ ================================================================================
2
+ <%= @organization_name %>
3
+ ================================================================================
4
+
5
+ Welcome <%= @display_name %>!
6
+
7
+ Thank you for signing up! To get started, please confirm your email address.
8
+
9
+ CONFIRM YOUR EMAIL ADDRESS:
10
+ <%= confirmation_url(@user) %>
11
+
12
+ This confirmation link will expire in 24 hours for security reasons.
13
+
14
+ 🔒 SECURITY NOTICE
15
+ If you didn't create an account with us, please ignore this email.
16
+ Your email address will not be added to our system.
17
+
18
+ Once confirmed, you'll be able to:
19
+ • Access your account dashboard
20
+ • Update your profile settings
21
+ • Receive important notifications
22
+ • Take advantage of all platform features
23
+
24
+ Need help? Contact our support team at <%= @support_email %>
25
+
26
+ ================================================================================
27
+ <%= @organization_name %>
28
+ Support: <%= @support_email %>
29
+
30
+ This email was sent to <%= @email_address || @user.email_address %>.
31
+ If you have questions, contact us at <%= @support_email %>.
32
+ ================================================================================
@@ -0,0 +1,166 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Reset Your Password</title>
7
+ <style>
8
+ body {
9
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
10
+ line-height: 1.6;
11
+ color: #333;
12
+ max-width: 600px;
13
+ margin: 0 auto;
14
+ padding: 20px;
15
+ background-color: #f8f9fa;
16
+ }
17
+ .container {
18
+ background-color: #ffffff;
19
+ padding: 40px;
20
+ border-radius: 8px;
21
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
22
+ }
23
+ .header {
24
+ text-align: center;
25
+ margin-bottom: 30px;
26
+ }
27
+ .logo {
28
+ font-size: 24px;
29
+ font-weight: bold;
30
+ color: #007bff;
31
+ margin-bottom: 10px;
32
+ }
33
+ h1 {
34
+ color: #333;
35
+ font-size: 28px;
36
+ margin-bottom: 20px;
37
+ text-align: center;
38
+ }
39
+ .greeting {
40
+ font-size: 18px;
41
+ margin-bottom: 20px;
42
+ }
43
+ .message {
44
+ margin-bottom: 30px;
45
+ line-height: 1.8;
46
+ }
47
+ .cta-button {
48
+ display: inline-block;
49
+ background-color: #007bff;
50
+ color: white;
51
+ padding: 15px 30px;
52
+ text-decoration: none;
53
+ border-radius: 5px;
54
+ font-weight: bold;
55
+ text-align: center;
56
+ margin: 20px 0;
57
+ }
58
+ .cta-button:hover {
59
+ background-color: #0056b3;
60
+ }
61
+ .security-notice {
62
+ background-color: #fff3cd;
63
+ border: 1px solid #ffeaa7;
64
+ border-radius: 5px;
65
+ padding: 20px;
66
+ margin: 20px 0;
67
+ }
68
+ .security-notice h3 {
69
+ color: #856404;
70
+ margin-top: 0;
71
+ }
72
+ .expiry-notice {
73
+ background-color: #f8d7da;
74
+ border: 1px solid #f5c6cb;
75
+ border-radius: 5px;
76
+ padding: 15px;
77
+ margin: 20px 0;
78
+ text-align: center;
79
+ }
80
+ .footer {
81
+ margin-top: 40px;
82
+ padding-top: 20px;
83
+ border-top: 1px solid #eee;
84
+ font-size: 14px;
85
+ color: #666;
86
+ }
87
+ .token-info {
88
+ background-color: #f8f9fa;
89
+ border: 1px solid #dee2e6;
90
+ border-radius: 5px;
91
+ padding: 15px;
92
+ margin: 20px 0;
93
+ font-family: monospace;
94
+ word-break: break-all;
95
+ }
96
+ @media (max-width: 600px) {
97
+ .container {
98
+ padding: 20px;
99
+ }
100
+ .cta-button {
101
+ display: block;
102
+ width: 100%;
103
+ text-align: center;
104
+ }
105
+ }
106
+ </style>
107
+ </head>
108
+ <body>
109
+ <div class="container">
110
+ <div class="header">
111
+ <div class="logo"><%= @organization_name %></div>
112
+ </div>
113
+
114
+ <h1>🔐 Reset Your Password</h1>
115
+
116
+ <div class="greeting">
117
+ Hello <%= @display_name %>,
118
+ </div>
119
+
120
+ <div class="message">
121
+ <p>We received a request to reset the password for your account associated with <strong><%= @user.email_address %></strong>.</p>
122
+
123
+ <p>If you requested this password reset, click the button below to create a new password:</p>
124
+ </div>
125
+
126
+ <div style="text-align: center;">
127
+ <a href="<%= @reset_url %>" class="cta-button">Reset My Password</a>
128
+ </div>
129
+
130
+ <div class="expiry-notice">
131
+ ⏰ <strong>This link will expire in <%= @expiration_minutes %> minutes</strong> for your security.
132
+ </div>
133
+
134
+ <div class="security-notice">
135
+ <h3>🛡️ Security Information</h3>
136
+ <ul>
137
+ <li><strong>Didn't request this?</strong> You can safely ignore this email. Your password will not be changed.</li>
138
+ <li><strong>Keep it secure:</strong> Never share this link with anyone. We will never ask for your password via email.</li>
139
+ <li><strong>Need help?</strong> Contact our support team at <a href="mailto:<%= @support_email %>"><%= @support_email %></a></li>
140
+ </ul>
141
+ </div>
142
+
143
+ <div class="message">
144
+ <p><strong>If the button doesn't work, copy and paste this link into your browser:</strong></p>
145
+ <div class="token-info">
146
+ <%= @reset_url %>
147
+ </div>
148
+ </div>
149
+
150
+ <div class="footer">
151
+ <p>This email was sent to <%= @user.email_address %> because a password reset was requested for your <%= @organization_name %> account.</p>
152
+
153
+ <p>For security reasons, this password reset link can only be used once and will expire in <%= @expiration_minutes %> minutes.</p>
154
+
155
+ <p>If you continue to have problems, please contact us at <a href="mailto:<%= @support_email %>"><%= @support_email %></a></p>
156
+
157
+ <hr style="margin: 20px 0; border: none; border-top: 1px solid #eee;">
158
+
159
+ <p style="font-size: 12px; color: #999;">
160
+ <strong><%= @organization_name %></strong><br>
161
+ This is an automated message. Please do not reply directly to this email.
162
+ </p>
163
+ </div>
164
+ </div>
165
+ </body>
166
+ </html>
@@ -0,0 +1,32 @@
1
+ RESET YOUR PASSWORD - <%= @organization_name %>
2
+ =====================================
3
+
4
+ Hello <%= @display_name %>,
5
+
6
+ We received a request to reset the password for your account associated with <%= @user.email_address %>.
7
+
8
+ If you requested this password reset, visit the link below to create a new password:
9
+
10
+ <%= @reset_url %>
11
+
12
+ ⏰ IMPORTANT: This link will expire in <%= @expiration_minutes %> minutes for your security.
13
+
14
+ 🛡️ SECURITY INFORMATION
15
+ ------------------------
16
+
17
+ • Didn't request this? You can safely ignore this email. Your password will not be changed.
18
+
19
+ • Keep it secure: Never share this link with anyone. We will never ask for your password via email.
20
+
21
+ • Need help? Contact our support team at <%= @support_email %>
22
+
23
+ For security reasons, this password reset link can only be used once and will expire in <%= @expiration_minutes %> minutes.
24
+
25
+ If you continue to have problems, please contact us at <%= @support_email %>
26
+
27
+ ---
28
+
29
+ <%= @organization_name %>
30
+ This is an automated message. Please do not reply directly to this email.
31
+
32
+ This email was sent to <%= @user.email_address %> because a password reset was requested for your <%= @organization_name %> account.
@@ -0,0 +1,194 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>You're Invited to Join <%= @invitation.organization.name %></title>
7
+ <style>
8
+ body {
9
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
10
+ line-height: 1.6;
11
+ color: #333;
12
+ max-width: 600px;
13
+ margin: 0 auto;
14
+ padding: 20px;
15
+ background-color: #f8f9fa;
16
+ }
17
+ .container {
18
+ background-color: #ffffff;
19
+ padding: 40px;
20
+ border-radius: 8px;
21
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
22
+ }
23
+ .header {
24
+ text-align: center;
25
+ margin-bottom: 30px;
26
+ }
27
+ .logo {
28
+ font-size: 24px;
29
+ font-weight: bold;
30
+ color: #007bff;
31
+ margin-bottom: 10px;
32
+ }
33
+ h1 {
34
+ color: #28a745;
35
+ font-size: 28px;
36
+ margin-bottom: 20px;
37
+ text-align: center;
38
+ }
39
+ .greeting {
40
+ font-size: 18px;
41
+ margin-bottom: 20px;
42
+ }
43
+ .message {
44
+ margin-bottom: 30px;
45
+ line-height: 1.8;
46
+ }
47
+ .cta-button {
48
+ display: inline-block;
49
+ background-color: #007bff;
50
+ color: white;
51
+ padding: 15px 30px;
52
+ text-decoration: none;
53
+ border-radius: 5px;
54
+ font-weight: bold;
55
+ text-align: center;
56
+ margin: 20px 0;
57
+ }
58
+ .cta-button:hover {
59
+ background-color: #0056b3;
60
+ }
61
+ .invitation-details {
62
+ background-color: #e7f3ff;
63
+ border: 1px solid #b8daff;
64
+ border-radius: 5px;
65
+ padding: 20px;
66
+ margin: 20px 0;
67
+ }
68
+ .invitation-details h3 {
69
+ color: #004085;
70
+ margin-top: 0;
71
+ }
72
+ .getting-started {
73
+ background-color: #d4edda;
74
+ border: 1px solid #c3e6cb;
75
+ border-radius: 5px;
76
+ padding: 20px;
77
+ margin: 20px 0;
78
+ }
79
+ .getting-started h3 {
80
+ color: #155724;
81
+ margin-top: 0;
82
+ }
83
+ .expiry-notice {
84
+ background-color: #fff3cd;
85
+ border: 1px solid #ffeaa7;
86
+ border-radius: 5px;
87
+ padding: 15px;
88
+ margin: 20px 0;
89
+ text-align: center;
90
+ }
91
+ .footer {
92
+ margin-top: 40px;
93
+ padding-top: 20px;
94
+ border-top: 1px solid #eee;
95
+ font-size: 14px;
96
+ color: #666;
97
+ }
98
+ .token-info {
99
+ background-color: #f8f9fa;
100
+ border: 1px solid #dee2e6;
101
+ border-radius: 5px;
102
+ padding: 15px;
103
+ margin: 20px 0;
104
+ font-family: monospace;
105
+ word-break: break-all;
106
+ }
107
+ @media (max-width: 600px) {
108
+ .container {
109
+ padding: 20px;
110
+ }
111
+ .cta-button {
112
+ display: block;
113
+ width: 100%;
114
+ text-align: center;
115
+ }
116
+ }
117
+ </style>
118
+ </head>
119
+ <body>
120
+ <div class="container">
121
+ <div class="header">
122
+ <div class="logo"><%= @invitation.organization.name %></div>
123
+ </div>
124
+
125
+ <h1>🎉 You're Invited!</h1>
126
+
127
+ <div class="greeting">
128
+ Hello <%= @invitation.first_name %>,
129
+ </div>
130
+
131
+ <div class="message">
132
+ <p><strong><%= @inviter_display_name %>
133
+
134
+ <p>We're excited to have you as part of our team. Click the button below to accept your invitation and get started:</p>
135
+ </div>
136
+
137
+ <div style="text-align: center;">
138
+ <a href="<%= @invitation_url %>" class="cta-button">Accept Invitation</a>
139
+ </div>
140
+
141
+ <div class="invitation-details">
142
+ <h3>📋 Invitation Details</h3>
143
+ <ul>
144
+ <li><strong>Organization:</strong> <%= @invitation.organization.name %></li>
145
+ <li><strong>Invited by:</strong> <%= @inviter_display_name %>
146
+ <li><strong>Your email:</strong> <%= @invitation.email_address %></li>
147
+ <li><strong>Invitation sent:</strong> <%= @invitation.created_at.strftime("%B %d, %Y at %I:%M %p %Z") %></li>
148
+ </ul>
149
+ </div>
150
+
151
+ <div class="expiry-notice">
152
+ ⏰ <strong>This invitation will expire in <%= @expiration_days %> days</strong> for security reasons.
153
+ </div>
154
+
155
+ <div class="getting-started">
156
+ <h3>🚀 Getting Started</h3>
157
+ <p>Once you accept this invitation, you'll be able to:</p>
158
+ <ul>
159
+ <li><strong>Create your account</strong> with a secure password</li>
160
+ <li><strong>Access your organization's resources</strong> and collaborate with your team</li>
161
+ <li><strong>Set up your profile</strong> and preferences</li>
162
+ <li><strong>Explore the platform</strong> and discover all available features</li>
163
+ </ul>
164
+ <p><strong>Need help getting started?</strong> Our support team is here to help at <a href="mailto:<%= @support_email %>"><%= @support_email %></a></p>
165
+ </div>
166
+
167
+ <div class="message">
168
+ <p><strong>Questions about this invitation?</strong></p>
169
+ <p>If you have any questions about this invitation or <%= @invitation.organization.name %>, you can reach out to <%= @inviter_display_name %>
170
+ </div>
171
+
172
+ <div class="message">
173
+ <p><strong>If the button doesn't work, copy and paste this link into your browser:</strong></p>
174
+ <div class="token-info">
175
+ <%= @invitation_url %>
176
+ </div>
177
+ </div>
178
+
179
+ <div class="footer">
180
+ <p><strong>Didn't expect this invitation?</strong></p>
181
+ <p>If you didn't expect to receive this invitation, you can safely ignore this email. No account will be created until you accept the invitation.</p>
182
+
183
+ <p>This invitation was sent to <%= @invitation.email_address %> by <%= @inviter_display_name %>
184
+
185
+ <hr style="margin: 20px 0; border: none; border-top: 1px solid #eee;">
186
+
187
+ <p style="font-size: 12px; color: #999;">
188
+ <strong><%= @organization_name %></strong><br>
189
+ This is an automated invitation email. Please do not reply directly to this email.
190
+ </p>
191
+ </div>
192
+ </div>
193
+ </body>
194
+ </html>
@@ -0,0 +1,51 @@
1
+ YOU'RE INVITED TO JOIN <%= @invitation.organization.name.upcase %>
2
+ ================================================================
3
+
4
+ Hello <%= @invitation.first_name %>,
5
+
6
+ 🎉 EXCITING NEWS!
7
+ ------------------
8
+ <%= @inviter_display_name %>
9
+
10
+ We're excited to have you as part of our team. Click the link below to accept your invitation and get started.
11
+
12
+ ACCEPT YOUR INVITATION
13
+ -----------------------
14
+ <%= @invitation_url %>
15
+
16
+ ⏰ IMPORTANT: This invitation will expire in <%= @expiration_days %> days for security reasons.
17
+
18
+ 📋 INVITATION DETAILS
19
+ ----------------------
20
+ • Organization: <%= @invitation.organization.name %>
21
+ • Invited by: <%= @inviter_display_name %>
22
+ • Your email: <%= @invitation.email_address %>
23
+ • Invitation sent: <%= @invitation.created_at.strftime("%B %d, %Y at %I:%M %p %Z") %>
24
+
25
+ 🚀 GETTING STARTED
26
+ -------------------
27
+ Once you accept this invitation, you'll be able to:
28
+
29
+ • Create your account with a secure password
30
+ • Access your organization's resources and collaborate with your team
31
+ • Set up your profile and preferences
32
+ • Explore the platform and discover all available features
33
+
34
+ Need help getting started? Our support team is here to help at <%= @support_email %>
35
+
36
+ QUESTIONS ABOUT THIS INVITATION?
37
+ ---------------------------------
38
+ If you have any questions about this invitation or <%= @invitation.organization.name %>, you can reach out to <%= @inviter_display_name %>
39
+
40
+ DIDN'T EXPECT THIS INVITATION?
41
+ -------------------------------
42
+ If you didn't expect to receive this invitation, you can safely ignore this email. No account will be created until you accept the invitation.
43
+
44
+ For security reasons, this invitation link can only be used once and will expire in <%= @expiration_days %> days.
45
+
46
+ ---
47
+
48
+ <%= @organization_name %>
49
+ This is an automated invitation email. Please do not reply directly to this email.
50
+
51
+ This invitation was sent to <%= @invitation.email_address %> by <%= @inviter_display_name %>
@@ -0,0 +1,72 @@
1
+ # syntax=docker/dockerfile:1
2
+ # check=error=true
3
+
4
+ # This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
5
+ # docker build -t dummy .
6
+ # docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name dummy dummy
7
+
8
+ # For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html
9
+
10
+ # Make sure RUBY_VERSION matches the Ruby version in .ruby-version
11
+ ARG RUBY_VERSION=3.2.7
12
+ FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
13
+
14
+ # Rails app lives here
15
+ WORKDIR /rails
16
+
17
+ # Install base packages
18
+ RUN apt-get update -qq && \
19
+ apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \
20
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
21
+
22
+ # Set production environment
23
+ ENV RAILS_ENV="production" \
24
+ BUNDLE_DEPLOYMENT="1" \
25
+ BUNDLE_PATH="/usr/local/bundle" \
26
+ BUNDLE_WITHOUT="development"
27
+
28
+ # Throw-away build stage to reduce size of final image
29
+ FROM base AS build
30
+
31
+ # Install packages needed to build gems
32
+ RUN apt-get update -qq && \
33
+ apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
34
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
35
+
36
+ # Install application gems
37
+ COPY Gemfile Gemfile.lock ./
38
+ RUN bundle install && \
39
+ rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
40
+ bundle exec bootsnap precompile --gemfile
41
+
42
+ # Copy application code
43
+ COPY . .
44
+
45
+ # Precompile bootsnap code for faster boot times
46
+ RUN bundle exec bootsnap precompile app/ lib/
47
+
48
+ # Precompiling assets for production without requiring secret RAILS_MASTER_KEY
49
+ RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
50
+
51
+
52
+
53
+
54
+ # Final stage for app image
55
+ FROM base
56
+
57
+ # Copy built artifacts: gems, application
58
+ COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
59
+ COPY --from=build /rails /rails
60
+
61
+ # Run and own only the runtime files as a non-root user for security
62
+ RUN groupadd --system --gid 1000 rails && \
63
+ useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
64
+ chown -R rails:rails db log storage tmp
65
+ USER 1000:1000
66
+
67
+ # Entrypoint prepares the database.
68
+ ENTRYPOINT ["/rails/bin/docker-entrypoint"]
69
+
70
+ # Start server via Thruster by default, this can be overwritten at runtime
71
+ EXPOSE 80
72
+ CMD ["./bin/thrust", "./bin/rails", "server"]
@@ -0,0 +1,63 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "propel_access", path: "../../"
4
+
5
+ # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
6
+ gem "rails", "~> 8.0.2"
7
+ # The modern asset pipeline for Rails [https://github.com/rails/propshaft]
8
+ gem "propshaft"
9
+ # Use sqlite3 as the database for Active Record
10
+ gem "sqlite3", ">= 2.1"
11
+ # Use the Puma web server [https://github.com/puma/puma]
12
+ gem "puma", ">= 5.0"
13
+ # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
14
+ gem "importmap-rails"
15
+ # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
16
+ gem "turbo-rails"
17
+ # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
18
+ gem "stimulus-rails"
19
+ # Build JSON APIs with ease [https://github.com/rails/jbuilder]
20
+ gem "jbuilder"
21
+
22
+ # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
23
+ # gem "bcrypt", "~> 3.1.7"
24
+
25
+ # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
26
+ gem "tzinfo-data", platforms: %i[ windows jruby ]
27
+
28
+ # Use the database-backed adapters for Rails.cache, Active Job, and Action Cable
29
+ gem "solid_cache"
30
+ gem "solid_queue"
31
+ gem "solid_cable"
32
+
33
+ # Reduces boot times through caching; required in config/boot.rb
34
+ gem "bootsnap", require: false
35
+
36
+ # Deploy this application anywhere as a Docker container [https://kamal-deploy.org]
37
+ gem "kamal", require: false
38
+
39
+ # Add HTTP asset caching/compression and X-Sendfile acceleration to Puma [https://github.com/basecamp/thruster/]
40
+ gem "thruster", require: false
41
+
42
+ # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
43
+ # gem "image_processing", "~> 1.2"
44
+
45
+ group :development, :test do
46
+ # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
47
+ gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
48
+
49
+ # Static analysis for security vulnerabilities [https://brakemanscanner.org/]
50
+ gem "brakeman", require: false
51
+
52
+ # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
53
+ gem "rubocop-rails-omakase", require: false
54
+ end
55
+
56
+ group :development do
57
+ # Use console on exceptions pages [https://github.com/rails/web-console]
58
+ gem "web-console"
59
+ end
60
+ gem "bcrypt", "~> 3.1.20"
61
+ gem "jwt", "~> 2.7"
62
+ gem "rdoc", "6.13.0"
63
+ gem "letter_opener", "~> 1.8", group: :development