diff --git a/Gemfile b/Gemfile
index 4ccba12..b4a6805 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,6 +15,7 @@ gem 'rails', '~> 6.0'
gem 'redis-rails', '~> 5.0'
gem 'responders', '~> 3.0'
gem 'sidekiq', '~> 6.0'
+gem 'simple_form', '~> 5.0'
gem 'validates_email_format_of', '~> 1.6'
gem 'webpacker', '~> 4.2'
@@ -25,7 +26,7 @@ gem 'devise', '~> 4.7'
# styles
gem 'bulma-rails', '~> 0.8.0'
-gem 'foundation_emails', '~> 2.2'
+gem 'premailer-rails', '~> 1.11'
group :development, :test do
gem 'factory_bot_rails', '~> 5.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index fbe0002..5026ec4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -303,6 +303,9 @@ GEM
rack (~> 2.0)
rack-protection (>= 2.0.0)
redis (>= 4.1.0)
+ simple_form (5.0.2)
+ actionpack (>= 5.0)
+ activemodel (>= 5.0)
simplecov (0.18.5)
docile (~> 1.1)
simplecov-html (~> 0.11)
@@ -370,6 +373,7 @@ DEPENDENCIES
shoulda-callback-matchers (~> 1.1)
shoulda-matchers (~> 3.1)
sidekiq (~> 6.0)
+ simple_form (~> 5.0)
simplecov (~> 0.16)
spring
spring-watcher-listen (~> 2.0)
diff --git a/Procfile b/Procfile
new file mode 100644
index 0000000..037059d
--- /dev/null
+++ b/Procfile
@@ -0,0 +1,4 @@
+web: bundle exec puma -C config/puma.rb
+webpack: bin/webpack
+worker: bundle exec sidekiq -C config/sidekiq.yml
+release: bin/rake db:migrate
diff --git a/README.md b/README.md
index 044348d..eae4d0e 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ This repo is a designed to be a Dockerized Rails 6 template:
- `bundle`
- `yarn install --check-files`
- `Find/replace all TODO`
+ - `docker-compose up --build`
### Dependencies
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 99e194d..661bf1d 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -13,3 +13,22 @@
*/
@import "bulma"; // https://bulma.io/documentation/
+@import "./devise";
+
+html {
+ background-image: radial-gradient(circle at 13% 47%, rgba(140, 140, 140,0.03) 0%, rgba(140, 140, 140,0.03) 25%,transparent 25%, transparent 100%),radial-gradient(circle at 28% 63%, rgba(143, 143, 143,0.03) 0%, rgba(143, 143, 143,0.03) 16%,transparent 16%, transparent 100%),radial-gradient(circle at 81% 56%, rgba(65, 65, 65,0.03) 0%, rgba(65, 65, 65,0.03) 12%,transparent 12%, transparent 100%),radial-gradient(circle at 26% 48%, rgba(60, 60, 60,0.03) 0%, rgba(60, 60, 60,0.03) 6%,transparent 6%, transparent 100%),radial-gradient(circle at 97% 17%, rgba(150, 150, 150,0.03) 0%, rgba(150, 150, 150,0.03) 56%,transparent 56%, transparent 100%),radial-gradient(circle at 50% 100%, rgba(25, 25, 25,0.03) 0%, rgba(25, 25, 25,0.03) 36%,transparent 36%, transparent 100%),radial-gradient(circle at 55% 52%, rgba(69, 69, 69,0.03) 0%, rgba(69, 69, 69,0.03) 6%,transparent 6%, transparent 100%),linear-gradient(90deg, rgb(255,255,255),rgb(255,255,255));
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.toggleable {
+ display: none;
+
+ &.is-active {
+ display: inherit;
+ }
+}
+
+.notifications-container {
+ padding: $size-7;
+}
diff --git a/app/assets/stylesheets/devise.scss b/app/assets/stylesheets/devise.scss
new file mode 100644
index 0000000..81eaaa9
--- /dev/null
+++ b/app/assets/stylesheets/devise.scss
@@ -0,0 +1,15 @@
+#registrations, #passwords {
+ padding-top: $size-1;
+}
+
+#registrations-column {
+ background-color: $white;
+ padding: $size-6;
+}
+
+#registrations-column-form, #registrations-column-form-submit-button,
+#registration-edit-account-deletion-container, #registrations-edit-passwords,
+#registrations-edit-update-password, #passwords-column-form, #unlocks-column-form,
+#confirmations-column-form {
+ padding: $size-3;
+}
diff --git a/app/assets/stylesheets/mailer.scss b/app/assets/stylesheets/mailer.scss
new file mode 100644
index 0000000..384554f
--- /dev/null
+++ b/app/assets/stylesheets/mailer.scss
@@ -0,0 +1,18 @@
+@import "bulma";
+
+body {
+ background-color: $grey-light;
+}
+
+.email-main-container {
+ padding: $size-3;
+ background-color: $white;
+}
+
+.email-details {
+ padding: $size-1 $size-5 ;
+}
+
+.email-action-button-container {
+ padding: $size-1;
+}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 93e99b4..2eb6f8e 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -8,7 +8,7 @@ class ApplicationController < ActionController::Base
authenticate_user!
return if current_user.admin?
- redirect_to root_path, flash: { alert: 'You are not allowed to do that.' }
+ redirect_to root_path, flash: { alert: "Whoops! We don't know where that path goes ¯\\_(ツ)_/¯" }
end
protected
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 15b06f0..e416307 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,4 +1,27 @@
# frozen_string_literal: true
module ApplicationHelper
+ # Javascript Pack helper for controller-based JS
+ def javascript_controller_pack_tag_helper
+ javascript_pack_tag params[:controller]
+ rescue Webpacker::Manifest::MissingEntryError
+ begin
+ # Fallback retry for nested controllers
+ namespace = params[:controller].split('/').first
+ javascript_pack_tag namespace
+ rescue StandardError
+ nil
+ end
+ end
+
+ def notification_type(name)
+ case name.to_sym
+ when :notice
+ 'info'
+ when :alert
+ 'danger'
+ else
+ name
+ end
+ end
end
diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js
deleted file mode 100644
index e69de29..0000000
diff --git a/app/javascript/controllers/home.js b/app/javascript/controllers/home.js
deleted file mode 100644
index e69de29..0000000
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index c7264c9..75fb5c6 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -4,8 +4,10 @@
// that code so it'll be compiled.
require("@rails/ujs").start()
-require("turbolinks").start()
+// require("turbolinks").start()
require("channels")
+require("./bulma/base")
+require("jquery")
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
diff --git a/app/javascript/packs/bulma/base.js b/app/javascript/packs/bulma/base.js
new file mode 100644
index 0000000..b03acca
--- /dev/null
+++ b/app/javascript/packs/bulma/base.js
@@ -0,0 +1 @@
+require("./notification")
diff --git a/app/javascript/packs/bulma/notification.js b/app/javascript/packs/bulma/notification.js
new file mode 100644
index 0000000..9804c1e
--- /dev/null
+++ b/app/javascript/packs/bulma/notification.js
@@ -0,0 +1,16 @@
+// https://bulma.io/documentation/elements/notification/#javascript-example
+// document.addEventListener('DOMContentLoaded', () => {
+// (document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
+// $notification = $delete.parentNode;
+//
+// $delete.addEventListener('click', () => {
+// $notification.parentNode.removeChild($notification);
+// });
+// });
+// });
+
+$(function(){
+ $('.notification .delete').on('click', function(){
+ $(this).parent().hide();
+ });
+});
diff --git a/app/javascript/packs/devise.js b/app/javascript/packs/devise.js
new file mode 100644
index 0000000..34f91a2
--- /dev/null
+++ b/app/javascript/packs/devise.js
@@ -0,0 +1,11 @@
+$(function() {
+ $('#registration-edit-password-button').on('click', function(){
+ $('#registrations-edit-update-password').toggleClass('is-active');
+ return false;
+ });
+
+ $('#registration-edit-account-delete-button').on('click', function(){
+ $('#registration-edit-account-delete').toggleClass('is-active');
+ return false;
+ });
+});
diff --git a/app/mailers/bulma_devise_mailer.rb b/app/mailers/bulma_devise_mailer.rb
new file mode 100644
index 0000000..3d72fe6
--- /dev/null
+++ b/app/mailers/bulma_devise_mailer.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class BulmaDeviseMailer < Devise::Mailer
+ default from: App::Config::DEFAULT_EMAIL
+ layout 'mailer'
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index b5048f2..fde03d8 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -3,10 +3,23 @@
class User < ApplicationRecord
acts_as_paranoid
+ before
+
# Include default devise modules. Others available are:
# :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable,
:confirmable, :lockable, :timeoutable, :trackable
+ validates :username, uniqueness: true
validates :email, presence: true, email_format: { message: 'format is not valid' }
+
+ before_validation :set_username, on: :create
+
+ private
+
+ def set_username
+ return if username.present?
+
+ self.username = Digest::MD5.hexdigest(Time.now.to_f.to_s + email)
+ end
end
diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb
new file mode 100644
index 0000000..6990656
--- /dev/null
+++ b/app/views/devise/confirmations/new.html.erb
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+ Resend Confirmation Email
+
+
+
+
+
+
+
+
+
diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb
new file mode 100644
index 0000000..431eaa7
--- /dev/null
+++ b/app/views/devise/mailer/confirmation_instructions.html.erb
@@ -0,0 +1,25 @@
+
+
+
+
+ Account Confirmation
+
+
+
+
+
+
+
+
+
+
+ Welcome <%= @email %>! Please confirm your email address to verify your account.
+
+
+
+ <%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token), class: "button is-primary is-fullwidth is-rounded" %>
+
+
+
+
+
diff --git a/app/views/devise/mailer/email_changed.html.erb b/app/views/devise/mailer/email_changed.html.erb
new file mode 100644
index 0000000..0a25f0c
--- /dev/null
+++ b/app/views/devise/mailer/email_changed.html.erb
@@ -0,0 +1,28 @@
+
+
+
+
+ Account Email Updated
+
+
+
+
+
+
+
+
+
+
+ Your email has been chnaged to <%= @resource.try(:unconfirmed_email?) ? @resource.unconfirmed_email : @resource.email %>.
+
+
+
+
+
+ Please contact support if you did not make these changes.
+
+
+
+
+
+
diff --git a/app/views/devise/mailer/password_change.html.erb b/app/views/devise/mailer/password_change.html.erb
new file mode 100644
index 0000000..c3f78e3
--- /dev/null
+++ b/app/views/devise/mailer/password_change.html.erb
@@ -0,0 +1,26 @@
+
+
+
+
+ Account Password Updated
+
+
+
+
+
+
+
+
+
+
We're contacting you to notify you that your password has been changed.
+
+
+
+
+ Please contact support if you did not make these changes.
+
+
+
+
+
+
diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb
new file mode 100644
index 0000000..9b06926
--- /dev/null
+++ b/app/views/devise/mailer/reset_password_instructions.html.erb
@@ -0,0 +1,26 @@
+
+
+
+
+ Reset Password
+
+
+
+
+
+
+
+
+
+
Someone has requested a link to change your password. You can do this through the link below.
+
+
If you didn't request this, please ignore this email.
+
Your password won't change until you access the link above and create a new one.
+
+
+ <%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token), class: "button is-primary is-fullwidth is-rounded" %>
+
+
+
+
+
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb
new file mode 100644
index 0000000..a27cda6
--- /dev/null
+++ b/app/views/devise/mailer/unlock_instructions.html.erb
@@ -0,0 +1,25 @@
+
+
+
+
+ Account Unlock
+
+
+
+
+
+
+
+
+
+
Your account has been locked due to an excessive number of unsuccessful sign in attempts.
+
+
Click the link below to unlock your account:
+
+
+ <%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token), class: "button is-primary is-fullwidth is-rounded" %>
+
+
+
+
+
diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb
new file mode 100644
index 0000000..b8346ca
--- /dev/null
+++ b/app/views/devise/passwords/edit.html.erb
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+ Update Password
+
+
+
+
+
+
+
+
+
diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb
new file mode 100644
index 0000000..c91fbc2
--- /dev/null
+++ b/app/views/devise/passwords/new.html.erb
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+ Reset My Password
+
+
+
+
+
+
+
+
+
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb
new file mode 100644
index 0000000..c953711
--- /dev/null
+++ b/app/views/devise/registrations/edit.html.erb
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+ <%= link_to "Back", :back, class: "button is-primary is-fullwidth is-rounded is-light" %>
+
+
+
+ <%= link_to "Close my account", "#registration-edit-account-delete", id: "registration-edit-account-delete-button", class: "button is-danger is-fullwidth is-rounded is-light" %>
+
+
+
+
+
+
+
Warning! Account deletion is permanant and can not be recovered.
+
+
+ <%= link_to "Delete My Account", registration_path(resource_name),
+ data: { confirm: "Are you sure?" }, method: :delete,
+ class: "button is-danger is-two-thirds is-rounded" %>
+
+
+
+
+
+
+
diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb
new file mode 100644
index 0000000..5a35240
--- /dev/null
+++ b/app/views/devise/registrations/new.html.erb
@@ -0,0 +1,71 @@
+
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb
new file mode 100644
index 0000000..bede0bb
--- /dev/null
+++ b/app/views/devise/sessions/new.html.erb
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+ Log in <%= resource_name %>
+
+
+
+
+
+
+
+
+
diff --git a/app/views/devise/shared/_error_messages.html.erb b/app/views/devise/shared/_error_messages.html.erb
new file mode 100644
index 0000000..4df4080
--- /dev/null
+++ b/app/views/devise/shared/_error_messages.html.erb
@@ -0,0 +1,12 @@
+<% if resource.errors.any? %>
+
+
+ <%= I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase) %>
+
+
+ <% resource.errors.full_messages.each do |message| %>
+ - <%= message %>
+ <% end %>
+
+
+<% end %>
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb
new file mode 100644
index 0000000..51ee7c4
--- /dev/null
+++ b/app/views/devise/shared/_links.html.erb
@@ -0,0 +1,39 @@
+
+ <% if controller_name != 'sessions' %>
+
+ <%= link_to "Log in", new_session_path(resource_name) %>
+
+ <% end %>
+
+ <% if devise_mapping.registerable? && controller_name != 'registrations' %>
+
+ <%= link_to "Sign up", new_registration_path(resource_name) %>
+
+ <% end %>
+
+ <% if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
+
+ <%= link_to "Password Recovery", new_password_path(resource_name) %>
+
+ <% end %>
+
+ <% if devise_mapping.confirmable? && controller_name != 'confirmations' %>
+
+ <%= link_to "Confirm Account", new_confirmation_path(resource_name) %>
+
+ <% end %>
+
+ <% if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
+
+ <%= link_to "Unlock Account", new_unlock_path(resource_name) %>
+
+ <% end %>
+
+ <% if devise_mapping.omniauthable? %>
+ <% resource_class.omniauth_providers.each do |provider| %>
+
+ <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %>
+
+ <% end %>
+ <% end %>
+
diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb
new file mode 100644
index 0000000..d1dcb9e
--- /dev/null
+++ b/app/views/devise/unlocks/new.html.erb
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+ Account Unlock
+
+
+
+
+
+
+
+
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 9786a7c..4539283 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -12,12 +12,14 @@
- <%= notice %>
- <%= alert %>
+ <%= render "shared/notifications" %>
<%= yield %>
+
+ <%= render "shared/developer_view" %>
<%= javascript_pack_tag 'application' %>
+ <%= javascript_controller_pack_tag_helper %>