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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +290 -0
- data/Rakefile +12 -0
- data/lib/generators/propel_auth/install_generator.rb +486 -0
- data/lib/generators/propel_auth/pack_generator.rb +277 -0
- data/lib/generators/propel_auth/templates/agency.rb +7 -0
- data/lib/generators/propel_auth/templates/agent.rb +7 -0
- data/lib/generators/propel_auth/templates/auth/base_passwords_controller.rb.tt +99 -0
- data/lib/generators/propel_auth/templates/auth/base_tokens_controller.rb.tt +90 -0
- data/lib/generators/propel_auth/templates/auth/passwords_controller.rb.tt +126 -0
- data/lib/generators/propel_auth/templates/auth_mailer.rb +180 -0
- data/lib/generators/propel_auth/templates/authenticatable.rb +38 -0
- data/lib/generators/propel_auth/templates/concerns/confirmable.rb +145 -0
- data/lib/generators/propel_auth/templates/concerns/lockable.rb +123 -0
- data/lib/generators/propel_auth/templates/concerns/propel_authentication.rb +44 -0
- data/lib/generators/propel_auth/templates/concerns/rack_session_disable.rb +19 -0
- data/lib/generators/propel_auth/templates/concerns/recoverable.rb +124 -0
- data/lib/generators/propel_auth/templates/config/environments/development_email.rb +43 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_agencies.rb +20 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_agents.rb +11 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_invitations.rb +28 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_organizations.rb +18 -0
- data/lib/generators/propel_auth/templates/db/migrate/create_users.rb +43 -0
- data/lib/generators/propel_auth/templates/db/seeds.rb +29 -0
- data/lib/generators/propel_auth/templates/invitation.rb +133 -0
- data/lib/generators/propel_auth/templates/lib/propel_auth.rb +84 -0
- data/lib/generators/propel_auth/templates/organization.rb +7 -0
- data/lib/generators/propel_auth/templates/propel_auth.rb +132 -0
- data/lib/generators/propel_auth/templates/services/auth_notification_service.rb +89 -0
- data/lib/generators/propel_auth/templates/test/concerns/confirmable_test.rb.tt +247 -0
- data/lib/generators/propel_auth/templates/test/concerns/lockable_test.rb.tt +282 -0
- data/lib/generators/propel_auth/templates/test/concerns/propel_authentication_test.rb.tt +75 -0
- data/lib/generators/propel_auth/templates/test/concerns/recoverable_test.rb.tt +327 -0
- data/lib/generators/propel_auth/templates/test/controllers/auth/lockable_integration_test.rb.tt +196 -0
- data/lib/generators/propel_auth/templates/test/controllers/auth/password_reset_integration_test.rb.tt +471 -0
- data/lib/generators/propel_auth/templates/test/controllers/auth/tokens_controller_test.rb.tt +265 -0
- data/lib/generators/propel_auth/templates/test/mailers/auth_mailer_test.rb.tt +216 -0
- data/lib/generators/propel_auth/templates/test/mailers/previews/auth_mailer_preview.rb +161 -0
- data/lib/generators/propel_auth/templates/tokens_controller.rb.tt +96 -0
- data/lib/generators/propel_auth/templates/user.rb +21 -0
- data/lib/generators/propel_auth/templates/user_test.rb.tt +81 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/account_unlock.html.erb +213 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/account_unlock.text.erb +56 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/email_confirmation.html.erb +213 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/email_confirmation.text.erb +32 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/password_reset.html.erb +166 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/password_reset.text.erb +32 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/user_invitation.html.erb +194 -0
- data/lib/generators/propel_auth/templates/views/auth_mailer/user_invitation.text.erb +51 -0
- data/lib/generators/propel_auth/test/dummy/Dockerfile +72 -0
- data/lib/generators/propel_auth/test/dummy/Gemfile +63 -0
- data/lib/generators/propel_auth/test/dummy/Gemfile.lock +394 -0
- data/lib/generators/propel_auth/test/dummy/README.md +24 -0
- data/lib/generators/propel_auth/test/dummy/Rakefile +6 -0
- data/lib/generators/propel_auth/test/dummy/app/assets/stylesheets/application.css +10 -0
- data/lib/generators/propel_auth/test/dummy/app/controllers/application_controller.rb +4 -0
- data/lib/generators/propel_auth/test/dummy/app/helpers/application_helper.rb +2 -0
- data/lib/generators/propel_auth/test/dummy/app/jobs/application_job.rb +7 -0
- data/lib/generators/propel_auth/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/lib/generators/propel_auth/test/dummy/app/models/application_record.rb +3 -0
- data/lib/generators/propel_auth/test/dummy/app/views/layouts/application.html.erb +27 -0
- data/lib/generators/propel_auth/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/lib/generators/propel_auth/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/lib/generators/propel_auth/test/dummy/app/views/pwa/manifest.json.erb +22 -0
- data/lib/generators/propel_auth/test/dummy/app/views/pwa/service-worker.js +26 -0
- data/lib/generators/propel_auth/test/dummy/bin/brakeman +7 -0
- data/lib/generators/propel_auth/test/dummy/bin/dev +2 -0
- data/lib/generators/propel_auth/test/dummy/bin/docker-entrypoint +14 -0
- data/lib/generators/propel_auth/test/dummy/bin/rails +4 -0
- data/lib/generators/propel_auth/test/dummy/bin/rake +4 -0
- data/lib/generators/propel_auth/test/dummy/bin/rubocop +8 -0
- data/lib/generators/propel_auth/test/dummy/bin/setup +34 -0
- data/lib/generators/propel_auth/test/dummy/bin/thrust +5 -0
- data/lib/generators/propel_auth/test/dummy/config/application.rb +42 -0
- data/lib/generators/propel_auth/test/dummy/config/boot.rb +4 -0
- data/lib/generators/propel_auth/test/dummy/config/cable.yml +10 -0
- data/lib/generators/propel_auth/test/dummy/config/credentials.yml.enc +1 -0
- data/lib/generators/propel_auth/test/dummy/config/database.yml +41 -0
- data/lib/generators/propel_auth/test/dummy/config/environment.rb +5 -0
- data/lib/generators/propel_auth/test/dummy/config/environments/development.rb +72 -0
- data/lib/generators/propel_auth/test/dummy/config/environments/production.rb +89 -0
- data/lib/generators/propel_auth/test/dummy/config/environments/test.rb +53 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/assets.rb +10 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/content_security_policy.rb +25 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/filter_parameter_logging.rb +8 -0
- data/lib/generators/propel_auth/test/dummy/config/initializers/inflections.rb +16 -0
- data/lib/generators/propel_auth/test/dummy/config/locales/en.yml +31 -0
- data/lib/generators/propel_auth/test/dummy/config/master.key +1 -0
- data/lib/generators/propel_auth/test/dummy/config/puma.rb +41 -0
- data/lib/generators/propel_auth/test/dummy/config/routes.rb +2 -0
- data/lib/generators/propel_auth/test/dummy/config/storage.yml +34 -0
- data/lib/generators/propel_auth/test/dummy/config.ru +6 -0
- data/lib/generators/propel_auth/test/dummy/db/schema.rb +14 -0
- data/lib/generators/propel_auth/test/generators/authentication/controllers/tokens_controller_test.rb +230 -0
- data/lib/generators/propel_auth/test/generators/authentication/install_generator_test.rb +490 -0
- data/lib/generators/propel_auth/test/generators/authentication/uninstall_generator_test.rb +408 -0
- data/lib/generators/propel_auth/test/integration/generator_integration_test.rb +158 -0
- data/lib/generators/propel_auth/test/integration/multi_version_generator_test.rb +125 -0
- data/lib/generators/propel_auth/unpack_generator.rb +345 -0
- data/lib/propel_auth.rb +3 -0
- 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
|