dash_myadventist 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/MIT-LICENSE +20 -0
- data/README.md +17 -0
- data/Rakefile +32 -0
- data/app/assets/config/dash_myadventist_manifest.js +2 -0
- data/app/assets/javascripts/dash_myadventist/application.js +15 -0
- data/app/assets/stylesheets/dash_myadventist/application.css +15 -0
- data/app/controllers/concerns/dash_myadventist/current_user.rb +48 -0
- data/app/controllers/dash_myadventist/passwords_controller.rb +48 -0
- data/app/controllers/dash_myadventist/sessions_controller.rb +46 -0
- data/app/controllers/dash_myadventist/signups_controller.rb +32 -0
- data/app/helpers/dash_myadventist/application_helper.rb +4 -0
- data/app/jobs/dash_myadventist/application_job.rb +4 -0
- data/app/mailers/dash_myadventist/application_mailer.rb +6 -0
- data/app/models/concerns/dash_myadventist/authentication.rb +90 -0
- data/app/models/dash_myadventist/application_record.rb +5 -0
- data/app/models/myadventist_api.rb +102 -0
- data/app/models/myadventist_password.rb +52 -0
- data/app/models/myadventist_response.rb +14 -0
- data/app/models/myadventist_user.rb +49 -0
- data/app/models/signin_response.rb +14 -0
- data/app/views/dash_myadventist/passwords/new.html.erb +20 -0
- data/app/views/dash_myadventist/passwords/reset.html.erb +33 -0
- data/app/views/dash_myadventist/sessions/new.html.erb +22 -0
- data/app/views/dash_myadventist/signups/new.html.erb +29 -0
- data/config/locales/en.yml +40 -0
- data/config/routes.rb +9 -0
- data/lib/dash_myadventist.rb +16 -0
- data/lib/dash_myadventist/engine.rb +4 -0
- data/lib/dash_myadventist/version.rb +3 -0
- data/lib/tasks/dash_myadventist_tasks.rake +4 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b8ee1f4facf467942dcb3fa1b1af29ef072b037d
|
4
|
+
data.tar.gz: 2be04a076538cd27f590208495570878381734b9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 83457218c8d41ff42855053f1031d065d822e87dc618b9d9db505ec3b664f5e329f9e6d73418e5740707904606adb675e6a864fa9712c5d6bc0d474437459d61
|
7
|
+
data.tar.gz: 0f52f66bf103a40cbfa195bd8341eb7be55bea76182c387c8501c99f0a68aa9749e2cbe753a2551a1564d9d603f3d548f1dd1c21d2af3bf265a7e5c781cc44d8
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 danlewis
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Usage
|
2
|
+
|
3
|
+
## 1. Add Initializer
|
4
|
+
|
5
|
+
To override the default settings, create an initializer with the following settings
|
6
|
+
|
7
|
+
DashMyadventist.setup do |config|
|
8
|
+
config.create_user_on_signin = true
|
9
|
+
end
|
10
|
+
|
11
|
+
## 2. Copy Routes
|
12
|
+
|
13
|
+
get 'signin', to: 'sessions#new', as: :signin
|
14
|
+
post 'signin', to: 'sessions#create'
|
15
|
+
delete 'signout', to: 'sessions#destroy', as: :signout
|
16
|
+
get 'signup', to: 'signups#new', as: :signup
|
17
|
+
post 'signup', to: 'signups#create'
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'DashMyadventist'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = 'test/**/*_test.rb'
|
29
|
+
t.verbose = false
|
30
|
+
end
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require rails-ujs
|
14
|
+
//= require activestorage
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module DashMyadventist::CurrentUser
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
helper_method :current_user, :signed_in?
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def current_user
|
11
|
+
@current_user ||= Dash.user_class.constantize.active.find_by_id(session[:user_id])
|
12
|
+
end
|
13
|
+
|
14
|
+
def signed_in?
|
15
|
+
!!current_user
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_user=(user)
|
19
|
+
@current_user = user
|
20
|
+
session[:user_id] = user&.id
|
21
|
+
end
|
22
|
+
|
23
|
+
def authenticate_user!
|
24
|
+
unless signed_in?
|
25
|
+
store_location!
|
26
|
+
redirect_to signin_path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def signout_user
|
31
|
+
session.delete(:user_id)
|
32
|
+
@current_user = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
# store location to redirect user after successful sign in
|
36
|
+
def store_location!
|
37
|
+
if request.url.present? && request.get? && !request.xhr?
|
38
|
+
if uri = URI.parse(request.url) rescue nil
|
39
|
+
path = [uri.path.sub(/\A\/+/, '/'), uri.query].compact.join('?')
|
40
|
+
path = [path, uri.fragment].compact.join('#')
|
41
|
+
session[:after_signin_path] = path
|
42
|
+
return
|
43
|
+
end
|
44
|
+
end
|
45
|
+
session[:after_signin_path] = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class DashMyadventist::PasswordsController < ApplicationController
|
2
|
+
layout "dash/session"
|
3
|
+
|
4
|
+
def new
|
5
|
+
end
|
6
|
+
|
7
|
+
def create
|
8
|
+
response = User.request_password_reset( params[:forgot_password][:email] )
|
9
|
+
if response.success?
|
10
|
+
flash[:notice] = t("dash_myadventist.passwords.reset_sent")
|
11
|
+
redirect_to reset_password_path(
|
12
|
+
reset_token: response.data[:reset_token],
|
13
|
+
email: params[:forgot_password][:email]
|
14
|
+
)
|
15
|
+
else
|
16
|
+
@reset_request_failed = true
|
17
|
+
render :new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# GET
|
22
|
+
def reset
|
23
|
+
@myadventist_password = MyadventistPassword.new(
|
24
|
+
reset_token: params[:reset_token],
|
25
|
+
reset_code: params[:reset_code],
|
26
|
+
email: params[:email]
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
# POST
|
31
|
+
def update_password
|
32
|
+
@myadventist_password = MyadventistPassword.new(myadventist_password_params)
|
33
|
+
if @myadventist_password.save
|
34
|
+
flash[:notice] = t("dash_myadventist.passwords.reset_successfull")
|
35
|
+
redirect_to signin_path
|
36
|
+
else
|
37
|
+
flash[:alert] = t("dash_myadventist.password.reset_failed")
|
38
|
+
render :reset
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def myadventist_password_params
|
45
|
+
params.fetch(:myadventist_password, {}).permit(:email, :reset_token, :reset_code, :password)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class DashMyadventist::SessionsController < ApplicationController
|
2
|
+
layout "dash/session"
|
3
|
+
before_action :already_signed_in, only: [:new, :create]
|
4
|
+
|
5
|
+
# Sign in
|
6
|
+
def new
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
@signin_response = Dash.user_class.constantize.signin_from_myadventist( signin_params.merge(ip: request.remote_ip) )
|
11
|
+
if @signin_response.success?
|
12
|
+
after_signin_success
|
13
|
+
else
|
14
|
+
render :new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Sign out
|
19
|
+
def destroy
|
20
|
+
signout_user
|
21
|
+
flash[:notice] = t("dash_myadventist.sessions.sign_out_success")
|
22
|
+
redirect_to signin_path
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def after_signin_success
|
28
|
+
self.current_user = @signin_response.user
|
29
|
+
redirect_after_signin
|
30
|
+
end
|
31
|
+
|
32
|
+
def redirect_after_signin
|
33
|
+
redirect_to session[:after_signin_path] || dashboard_root_path
|
34
|
+
session.delete(:after_signin_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def already_signed_in
|
38
|
+
if current_user
|
39
|
+
redirect_to dashboard_root_path
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def signin_params
|
44
|
+
params.fetch(:session, {}).permit(:email, :password)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class DashMyadventist::SignupsController < ApplicationController
|
2
|
+
layout "dash/session"
|
3
|
+
before_action :redirect_if_current_sign_in
|
4
|
+
|
5
|
+
def new
|
6
|
+
@myadventist_user = MyadventistUser.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
@myadventist_user = MyadventistUser.new(myadventist_user_params)
|
11
|
+
if @myadventist_user.save
|
12
|
+
flash[:notice] = "Successfully created account. Please sign in"
|
13
|
+
redirect_to signin_path
|
14
|
+
else
|
15
|
+
flash[:alert] = "Unable to create account. Please review error messages."
|
16
|
+
render :new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def myadventist_user_params
|
23
|
+
params.fetch(:myadventist_user, {}).permit(:first_name, :last_name, :email, :password)
|
24
|
+
end
|
25
|
+
|
26
|
+
def redirect_if_current_sign_in
|
27
|
+
if @current_user
|
28
|
+
return redirect_to dashboard_root_path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module DashMyadventist::Authentication
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
# sign in with a myadventist email or username
|
7
|
+
def signin_from_myadventist(options={})
|
8
|
+
options.reverse_merge!(myadventist: {})
|
9
|
+
# get myadventist user id
|
10
|
+
myadventist = MyadventistApi.new(options[:myadventist])
|
11
|
+
response = myadventist.signin(options[:email], options[:password])
|
12
|
+
unless response.success?
|
13
|
+
error_msg =
|
14
|
+
case response.data[:error]
|
15
|
+
when "invalid_grant"
|
16
|
+
"Email and password do not match."
|
17
|
+
else
|
18
|
+
response.data[:error_description]
|
19
|
+
end
|
20
|
+
return SigninResponse.new(false, error: error_msg)
|
21
|
+
end
|
22
|
+
|
23
|
+
# get current user
|
24
|
+
user = self.where(adventist_uid: response.data[:user_id]).first
|
25
|
+
if user
|
26
|
+
if user.can_signin?
|
27
|
+
user.track_sign_in!(options[:ip])
|
28
|
+
return SigninResponse.new(true, user: user)
|
29
|
+
else
|
30
|
+
SigninResponse.new(false, error: "Account has not been activated")
|
31
|
+
end
|
32
|
+
elsif create_on_signin?
|
33
|
+
if user = create_user(response.data)
|
34
|
+
user.track_sign_in!(options[:ip])
|
35
|
+
return SigninResponse.new(true, user: user)
|
36
|
+
else
|
37
|
+
SigninResponse.new(false, error: "Unable to create account on sign in")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
SigninResponse.new(false, error: "Account does not exist")
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_user(data)
|
44
|
+
user = create(
|
45
|
+
status: "active",
|
46
|
+
first_name: data[:first_name],
|
47
|
+
last_name: data[:last_name],
|
48
|
+
email: data[:primary_email],
|
49
|
+
adventist_uid: data[:user_id]
|
50
|
+
)
|
51
|
+
user.persisted? ? user : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
# create the user on signup if they don't already exist
|
55
|
+
def create_on_signin?
|
56
|
+
DashMyadventist.create_user_on_signin
|
57
|
+
end
|
58
|
+
|
59
|
+
# scope when querying for the user to sign in, override to customize
|
60
|
+
# by default we assume the user has an enum status column with option of active
|
61
|
+
def signin_scope
|
62
|
+
self.active
|
63
|
+
end
|
64
|
+
|
65
|
+
def signup_invite_only?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
def request_password_reset(email)
|
70
|
+
MyadventistApi.new.request_reset_email(email)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
# Track the IP address and time the user logged in.
|
76
|
+
def track_sign_in!(ip)
|
77
|
+
self.sign_in_count += 1
|
78
|
+
self.last_sign_in_ip = self.current_sign_in_ip
|
79
|
+
self.last_sign_in_at = self.current_sign_in_at
|
80
|
+
self.current_sign_in_ip = ip
|
81
|
+
self.current_sign_in_at = Time.current
|
82
|
+
self.save(validate: false)
|
83
|
+
end
|
84
|
+
|
85
|
+
# override to check if user has an active account for example
|
86
|
+
def can_signin?
|
87
|
+
active?
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
class MyadventistApi
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@client_id = Rails.application.credentials.env.dig(:myadventist, :client_id)
|
7
|
+
@client_secret = Rails.application.credentials.env.dig(:myadventist, :client_secret)
|
8
|
+
@redirect_host = options[:host] || Rails.application.credentials.env.dig(:myadventist, :redirect_host)
|
9
|
+
@redirect_uri = "#{@redirect_host}/auth/myadventist/callback"
|
10
|
+
@reset_password_redirect_uri = "#{@redirect_host}/passwords/reset"
|
11
|
+
@state = SecureRandom.hex(10)
|
12
|
+
@test = options.key?(:test) ? options[:test] : !Rails.env.production?
|
13
|
+
@api_host = @test ? "https://test.myadventist.org" : "https://myadventist.org"
|
14
|
+
end
|
15
|
+
|
16
|
+
def signin(username, password)
|
17
|
+
signin_response = signin_request(username, password)
|
18
|
+
return signin_response unless signin_response.success?
|
19
|
+
|
20
|
+
# Get user details
|
21
|
+
user_request(signin_response.data[:access_token])
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_account(attributes)
|
25
|
+
create_response = create_account_request(attributes)
|
26
|
+
return create_response unless create_response.success?
|
27
|
+
|
28
|
+
# Get user details
|
29
|
+
user_request(create_response.data[:access_token])
|
30
|
+
end
|
31
|
+
|
32
|
+
def request_reset_email(email)
|
33
|
+
post_request("/OAuth/RequestResetEmail",
|
34
|
+
email: email,
|
35
|
+
scope: "email"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset_password(attributes)
|
40
|
+
post_request("/OAuth/ResetPassword",
|
41
|
+
reset_token: attributes[:reset_token],
|
42
|
+
reset_code: attributes[:reset_code],
|
43
|
+
email: attributes[:email],
|
44
|
+
password: attributes[:password],
|
45
|
+
scope: "email",
|
46
|
+
redirect_uri: @reset_password_redirect_uri
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_account_request(attributes)
|
51
|
+
post_request("/OAuth/CreateUser",
|
52
|
+
firstname: attributes[:first_name],
|
53
|
+
lastname: attributes[:last_name],
|
54
|
+
email: attributes[:email],
|
55
|
+
password: attributes[:password],
|
56
|
+
scope: "email",
|
57
|
+
verified: attributes[:verified]
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def user_request(access_token)
|
62
|
+
post_request("/OAuth/userinfo",
|
63
|
+
grant_type: "authorization_code",
|
64
|
+
access_token: access_token
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def signin_request(username, password)
|
69
|
+
post_request(
|
70
|
+
"/OAuth/Authorize",
|
71
|
+
response_type: "password",
|
72
|
+
scope: "email",
|
73
|
+
username: username,
|
74
|
+
password: password
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def post_request(path, options)
|
81
|
+
conn = Faraday.new(url: @api_host, headers: {"Content-Type" => "application/json"})
|
82
|
+
body = default_request_options.reverse_merge(options)
|
83
|
+
r_start = Time.now
|
84
|
+
response = conn.post path, body.to_json
|
85
|
+
r_end = Time.now
|
86
|
+
Rails.logger.debug "MyAdventist request #{path}: #{(r_end-r_start).in_milliseconds.to_i}ms"
|
87
|
+
unless response.success?
|
88
|
+
Rails.logger.debug "MyAdventist API request failed: #{response.status} code"# - #{response.body}
|
89
|
+
end
|
90
|
+
MyadventistResponse.new(response)
|
91
|
+
end
|
92
|
+
|
93
|
+
def default_request_options
|
94
|
+
{
|
95
|
+
client_id: @client_id,
|
96
|
+
client_secret: @client_secret,
|
97
|
+
state: @state,
|
98
|
+
redirect_uri: @redirect_uri
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class MyadventistPassword
|
2
|
+
include ActiveModel::Model
|
3
|
+
|
4
|
+
validates :reset_code, :reset_token, :email, :password, presence: true
|
5
|
+
validates :email, email: true
|
6
|
+
# Password complexity: at least 1 uppercase and lowercase
|
7
|
+
validates :password, length: {minimum: 12}, format: { with: /(?=.*[A-Z])(?=.*[a-z]).*/, message: I18n.t("dash_myadventist.myadventist_user.validations.password_complexity") }
|
8
|
+
|
9
|
+
attr_accessor :reset_code, :reset_token, :email, :password
|
10
|
+
|
11
|
+
def save
|
12
|
+
return false unless valid?
|
13
|
+
reset_password
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_reset_code?
|
17
|
+
reset_code.blank? || errors[:reset_code].any?
|
18
|
+
end
|
19
|
+
|
20
|
+
def attributes
|
21
|
+
{
|
22
|
+
email: email,
|
23
|
+
password: password,
|
24
|
+
reset_code: reset_code,
|
25
|
+
reset_token: reset_token
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def reset_password
|
30
|
+
myadventist = MyadventistApi.new
|
31
|
+
response = myadventist.reset_password(attributes)
|
32
|
+
|
33
|
+
unless response.success?
|
34
|
+
map_myadventist_errors(response)
|
35
|
+
end
|
36
|
+
response.success?
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# map myadventist errors to attributes
|
42
|
+
def map_myadventist_errors(response)
|
43
|
+
if response.data[:error_description].include?("Invalid or expired reset_token")
|
44
|
+
errors.add :base, "Reset code has expired. Try forgot password again."
|
45
|
+
elsif response.data[:error_description].include?("Code failed validation")
|
46
|
+
errors.add :reset_code, "invalid"
|
47
|
+
else
|
48
|
+
errors.add :base, response.data[:error_description]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class MyadventistResponse
|
2
|
+
|
3
|
+
attr_reader :success, :status, :data
|
4
|
+
|
5
|
+
def initialize(response)
|
6
|
+
@success = response.success?
|
7
|
+
@status = response.status
|
8
|
+
@data = JSON.parse(response.body).transform_keys { |key| key.underscore.to_sym } rescue {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def success?
|
12
|
+
@success
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class MyadventistUser
|
2
|
+
include ActiveModel::Model
|
3
|
+
|
4
|
+
validates :first_name, :last_name, :email, :password, presence: true
|
5
|
+
validates :email, email: true
|
6
|
+
# Password complexity: at least 1 digit, uppercase, lowercase, symbol
|
7
|
+
validates :password, length: {minimum: 12}, format: { with: /(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*\W).*/, message: I18n.t("dash_myadventist.myadventist_user.validations.password_complexity") }
|
8
|
+
|
9
|
+
attr_accessor :first_name, :last_name, :email, :password, :adventist_uid
|
10
|
+
|
11
|
+
def save
|
12
|
+
return false unless valid?
|
13
|
+
create_account
|
14
|
+
end
|
15
|
+
|
16
|
+
def attributes
|
17
|
+
{
|
18
|
+
first_name: first_name,
|
19
|
+
last_name: last_name,
|
20
|
+
email: email,
|
21
|
+
password: password,
|
22
|
+
verified: 1 #hmmm
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_account
|
27
|
+
myadventist = MyadventistApi.new
|
28
|
+
response = myadventist.create_account(attributes)
|
29
|
+
if response.success?
|
30
|
+
self.adventist_uid = response.data[:user_id]
|
31
|
+
return true
|
32
|
+
else
|
33
|
+
map_myadventist_errors(response)
|
34
|
+
end
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# map myadventist errors to attributes
|
41
|
+
def map_myadventist_errors(response)
|
42
|
+
if response.data[:error_description].include?("Email is already in use")
|
43
|
+
errors.add :email, "already taken"
|
44
|
+
else
|
45
|
+
errors.add :base, response.data[:error_description]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="row justify-content-center">
|
3
|
+
<div class="col-12 col-md-6">
|
4
|
+
<h2 class="standout"><%= t("dash_myadventist.passwords.forgot_password") %></h2>
|
5
|
+
|
6
|
+
<div class="card card-session">
|
7
|
+
<div class="card-body">
|
8
|
+
<%= simple_form_for :forgot_password, url: "/passwords" do |f| %>
|
9
|
+
<%= f.input :email, placeholder: t("dash_myadventist.passwords.email_placeholder"), label: false, autofocus: true %>
|
10
|
+
<%= content_tag(:p, t("dash_myadventist.passwords.reset_request_failed"), class: "session-error") if @reset_request_failed %>
|
11
|
+
<div class="actions">
|
12
|
+
<%= f.submit t("dash_myadventist.passwords.send_reset_email"), class: "btn btn-primary" %>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="row justify-content-center">
|
3
|
+
<div class="col-12 col-md-6">
|
4
|
+
<h2 class="standout"><%= t("dash_myadventist.passwords.forgot_password") %></h2>
|
5
|
+
<div class="card card-session">
|
6
|
+
<div class="card-body">
|
7
|
+
<% if @myadventist_password.show_reset_code? %>
|
8
|
+
<p><%= t("dash_myadventist.passwords.reset_request_success") %></p>
|
9
|
+
<% else %>
|
10
|
+
<p><%= t("dash_myadventist.passwords.set_new_password") %></p>
|
11
|
+
<% end %>
|
12
|
+
<% if @myadventist_password.errors[:base].any? %>
|
13
|
+
<p class="session-error"><%= @myadventist_password.errors[:base].join(', ') %></p>
|
14
|
+
<% end %>
|
15
|
+
<%= simple_form_for @myadventist_password, url: "/passwords/update_password" do |f| %>
|
16
|
+
<%= f.input_field :reset_token, as: :hidden %>
|
17
|
+
<%= f.input_field :email, as: :hidden %>
|
18
|
+
<% if @myadventist_password.show_reset_code? %>
|
19
|
+
<%= f.input :reset_code, autofocus: true %>
|
20
|
+
<% else %>
|
21
|
+
<%= f.input_field :reset_code, as: :hidden %>
|
22
|
+
<% end %>
|
23
|
+
<%= f.input :password, label: t("dash_myadventist.passwords.new_password") %>
|
24
|
+
<div class="actions">
|
25
|
+
<%= f.submit t("dash_myadventist.passwords.reset_password"), class: "btn btn-primary" %>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="row justify-content-center">
|
3
|
+
<div class="col-12 col-md-6">
|
4
|
+
<h2 class="standout"><%= t("dash_myadventist.sessions.page_title") %></h2>
|
5
|
+
<p class="text-center"><%= t("dash_myadventist.sessions.no_account")%> <%= link_to t("dash_myadventist.sessions.sign_up"), main_app.signup_path, class: "link-highlight" %></p>
|
6
|
+
<div class="card card-session">
|
7
|
+
<div class="card-body">
|
8
|
+
<%= simple_form_for :session, url: "/signin", html: {novalidate: true} do |f| %>
|
9
|
+
<%= f.input :email, placeholder: t("dash_myadventist.sessions.email_or_username_placeholder"), label: false, autofocus: true %>
|
10
|
+
<%= f.input :password, placeholder: t("dash_myadventist.sessions.password_placeholder"), label: false %>
|
11
|
+
<%= content_tag(:p, @signin_response.error, class: "session-error") if @signin_response %>
|
12
|
+
<%= link_to t("dash_myadventist.sessions.forgot_password"), new_password_path, class: "forgot-password" %>
|
13
|
+
<div class="actions">
|
14
|
+
<%= f.submit t("dash_myadventist.sessions.sign_in"), class: "btn btn-primary", data: {disable_with: t("dash_myadventist.sessions.disable.sign_in")} %>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="row justify-content-center">
|
3
|
+
<div class="col-12">
|
4
|
+
<h2 class="standout"><%= t("dash_myadventist.signups.page_title") %></h2>
|
5
|
+
<p class="text-center"><%= t("dash_myadventist.signups.account_exists") %> <%= link_to t("dash_myadventist.sessions.sign_in"), main_app.signin_path, class: "link-highlight" %></p>
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
<div class="row justify-content-center">
|
9
|
+
<div class="col-md-6">
|
10
|
+
<div class="card card-session">
|
11
|
+
<div class="card-body">
|
12
|
+
<% if @myadventist_user.errors[:base].any? %>
|
13
|
+
<p class="session-error"><%= @myadventist_user.errors[:base].join(', ') %></p>
|
14
|
+
<% end %>
|
15
|
+
<%= simple_form_for @myadventist_user, url: '/signup' do |f| %>
|
16
|
+
<%= f.input :first_name, placeholder: t("dash_myadventist.sessions.first_name_placeholder"), label: false, autofocus: true %>
|
17
|
+
<%= f.input :last_name, placeholder: t("dash_myadventist.sessions.last_name_placeholder"), label: false, autofocus: true %>
|
18
|
+
<%= f.input :email, placeholder: t("dash_myadventist.sessions.email_placeholder"), label: false %>
|
19
|
+
<%= f.input :password, placeholder: t("dash_myadventist.sessions.password_placeholder"), label: false %>
|
20
|
+
<p><%= t("dash_myadventist.signups.terms_agreement_html", link: link_to(t("dash_myadventist.signups.terms_of_use"), "/legal/terms", class: "link-highlight")) %></p>
|
21
|
+
<div class="actions">
|
22
|
+
<%= f.submit t("dash_myadventist.sessions.sign_up"), class: "btn btn-primary" %>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</div>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
en:
|
2
|
+
dash_myadventist:
|
3
|
+
passwords:
|
4
|
+
forgot_password: Forgot Password
|
5
|
+
email_placeholder: Email
|
6
|
+
reset_password: Reset Password
|
7
|
+
new_password: New Password
|
8
|
+
set_new_password: Set a new password for your Adventist Account
|
9
|
+
reset_request_failed: Unable to reset. Please check email is correct
|
10
|
+
reset_request_success: We've sent you an email with instructions to reset your password. Click the link in the email or paste the reset code below.
|
11
|
+
reset_sent: Successfully sent reset password email
|
12
|
+
reset_successfull: Successfully reset password
|
13
|
+
reset_failed: Unable to update password. Please check errors
|
14
|
+
send_reset_email: Send reset email
|
15
|
+
sessions:
|
16
|
+
page_title: Sign in to myAdventist
|
17
|
+
email_or_username_placeholder: Email or username
|
18
|
+
email_placeholder: Email
|
19
|
+
first_name_placeholder: First name
|
20
|
+
forgot_password: Forgot password?
|
21
|
+
last_name_placeholder: Last name
|
22
|
+
password_placeholder: Password
|
23
|
+
no_account: Don't have a myAdventist account?
|
24
|
+
sign_in: Sign in
|
25
|
+
sign_in_title: Sign in with myAdventist
|
26
|
+
sign_in_failed: Email and password do not match.
|
27
|
+
sign_out: Sign out
|
28
|
+
sign_out_success: Successfully signed out
|
29
|
+
sign_up: Sign up
|
30
|
+
sign_up_title: Sign up to myAdventist
|
31
|
+
disable:
|
32
|
+
sign_in: Signing In...
|
33
|
+
signups:
|
34
|
+
page_title: Create your myAdventist account
|
35
|
+
account_exists: Already have a myAdventist account?
|
36
|
+
terms_agreement_html: "By signing up you agree to the %{link}"
|
37
|
+
terms_of_use: terms of use
|
38
|
+
myadventist_user:
|
39
|
+
validations:
|
40
|
+
password_complexity: requires 12 or more characters with at least one uppercase & lowercase character
|
data/config/routes.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
DashMyadventist::Engine.routes.draw do
|
2
|
+
# Sessions
|
3
|
+
# get 'signin', to: 'sessions#new', as: :signin
|
4
|
+
# post 'signin', to: 'sessions#create'
|
5
|
+
# delete 'signout', to: 'sessions#destroy', as: :signout
|
6
|
+
# # Sign up
|
7
|
+
# get 'signup', to: 'signups#new', as: :signup
|
8
|
+
# post 'signup', to: 'signups#create'
|
9
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "dash_myadventist/engine"
|
2
|
+
require "faraday"
|
3
|
+
module DashMyadventist
|
4
|
+
|
5
|
+
# Create user account automatically on successfull sign in
|
6
|
+
mattr_accessor :create_user_on_signin
|
7
|
+
@@create_user_on_signin = true
|
8
|
+
|
9
|
+
# Configuration
|
10
|
+
# DashMyadventist.setup do |config|
|
11
|
+
# config.create_user_on_signin = true
|
12
|
+
# end
|
13
|
+
def self.setup
|
14
|
+
yield self
|
15
|
+
end
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dash_myadventist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- adventistmedia
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-09-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.2.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.3.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 5.2.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.3.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: faraday
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.14.0
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.14.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
description: Dash addon for Myadventist.
|
62
|
+
email:
|
63
|
+
- webmaster@adventistmedia.org.au
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- MIT-LICENSE
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- app/assets/config/dash_myadventist_manifest.js
|
72
|
+
- app/assets/javascripts/dash_myadventist/application.js
|
73
|
+
- app/assets/stylesheets/dash_myadventist/application.css
|
74
|
+
- app/controllers/concerns/dash_myadventist/current_user.rb
|
75
|
+
- app/controllers/dash_myadventist/passwords_controller.rb
|
76
|
+
- app/controllers/dash_myadventist/sessions_controller.rb
|
77
|
+
- app/controllers/dash_myadventist/signups_controller.rb
|
78
|
+
- app/helpers/dash_myadventist/application_helper.rb
|
79
|
+
- app/jobs/dash_myadventist/application_job.rb
|
80
|
+
- app/mailers/dash_myadventist/application_mailer.rb
|
81
|
+
- app/models/concerns/dash_myadventist/authentication.rb
|
82
|
+
- app/models/dash_myadventist/application_record.rb
|
83
|
+
- app/models/myadventist_api.rb
|
84
|
+
- app/models/myadventist_password.rb
|
85
|
+
- app/models/myadventist_response.rb
|
86
|
+
- app/models/myadventist_user.rb
|
87
|
+
- app/models/signin_response.rb
|
88
|
+
- app/views/dash_myadventist/passwords/new.html.erb
|
89
|
+
- app/views/dash_myadventist/passwords/reset.html.erb
|
90
|
+
- app/views/dash_myadventist/sessions/new.html.erb
|
91
|
+
- app/views/dash_myadventist/signups/new.html.erb
|
92
|
+
- config/locales/en.yml
|
93
|
+
- config/routes.rb
|
94
|
+
- lib/dash_myadventist.rb
|
95
|
+
- lib/dash_myadventist/engine.rb
|
96
|
+
- lib/dash_myadventist/version.rb
|
97
|
+
- lib/tasks/dash_myadventist_tasks.rake
|
98
|
+
homepage: http://adventistmedia.org.au
|
99
|
+
licenses:
|
100
|
+
- MIT
|
101
|
+
metadata: {}
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 2.6.13
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: Dash addon for Myadventist.
|
122
|
+
test_files: []
|