dash_myadventist 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|