revise_auth-jets 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -3
  3. data/Rakefile +3 -0
  4. data/app/config/routes.rb +18 -1
  5. data/app/controllers/admin/dashboard_controller.rb +5 -0
  6. data/app/controllers/admin/users_controller.rb +54 -0
  7. data/app/controllers/admin_controller.rb +16 -0
  8. data/app/controllers/api/base_controller.rb +42 -0
  9. data/app/controllers/api/v1/mes_controller.rb +11 -0
  10. data/app/controllers/revise_auth/email_controller.rb +8 -4
  11. data/app/controllers/revise_auth/password_controller.rb +2 -2
  12. data/app/controllers/revise_auth/registrations_controller.rb +3 -2
  13. data/app/controllers/revise_auth/sessions_controller.rb +2 -1
  14. data/app/controllers/revise_auth_controller.rb +1 -1
  15. data/app/views/admin/dashboard/show.html.erb +22 -0
  16. data/app/views/admin/shared/_desktop_header.html.erb +15 -0
  17. data/app/views/admin/shared/_mobile_header.html.erb +16 -0
  18. data/app/views/admin/shared/_nav_links.html.erb +8 -0
  19. data/app/views/admin/users/index.html.erb +43 -0
  20. data/app/views/admin/users/show.html.erb +73 -0
  21. data/app/views/layouts/admin_application.html.erb +78 -0
  22. data/app/views/main/authenticated.html.erb +1 -1
  23. data/app/views/revise_auth/registrations/edit.html.erb +8 -5
  24. data/app/views/revise_auth/sessions/new.html.erb +1 -1
  25. data/lib/generators/revise_auth/model_generator.rb +14 -5
  26. data/lib/generators/revise_auth/templates/README +1 -2
  27. data/lib/generators/revise_auth/views_generator.rb +7 -1
  28. data/lib/revise_auth/api_model.rb +46 -0
  29. data/lib/revise_auth/authentication.rb +1 -1
  30. data/lib/revise_auth/engine.rb +1 -0
  31. data/lib/revise_auth/model.rb +4 -4
  32. data/lib/revise_auth/routes.rb +49 -49
  33. data/lib/revise_auth/version.rb +1 -1
  34. data/lib/revise_auth-jets.rb +1 -0
  35. metadata +15 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad5830138b573376c725bdd2f4cf927451b5ba9f561b45cd88b5235e438459d6
4
- data.tar.gz: 6458c724a0afcd5164c6cb1a3d822fdcfc7da9f3d22234057a24b2e6e4d7d90a
3
+ metadata.gz: 4d7f8607296f85c60596d66ab6b170ed3013a7c576df2d3ce42e7a8f42d25e1e
4
+ data.tar.gz: c28a1cf711470e29022bbab31597d5ac108182cf81bf49b8c08f6a371683b68e
5
5
  SHA512:
6
- metadata.gz: a1b995b99756a0626ac174ccbba43aa4444f2136c87f91482192799e9f53baf00702e9ce73534af5302050eb75a4fb2024dcab1ce94de030f1fe978ebe94fc78
7
- data.tar.gz: 4d4503bbdd0025ae4a5a966bb82ea0740a251190d1e5b1514f287ae0704b9edc1ed683100a118e81eeed7d264782090572a69aa1bb76ebc9b4e6b0e1837c7b7f
6
+ metadata.gz: afa893fe4641ca6d245730c128fe2a9fdc6d564bc9d7ac3c5ae6d1b66bda242d2bd49f223b359517ae80d71c81c5c48b017291d3ffb3d923cee297f4e2e8a2c5
7
+ data.tar.gz: 7c466b2cf6849ce8336388931a3865d61ce4d0bc46abc8077f4d7da1d25e5a3e194d8b96a9b412ec520b8c684ddc9b25f40886e4b5f513642c4155ea4cf55a08
data/README.md CHANGED
@@ -12,12 +12,17 @@ bundle add "revise_auth-jets"
12
12
 
13
13
  And then execute the following to generate a `User` model (optionally adding other fields such as `first_name` and `last_name`):
14
14
  ```bash
15
- $ jets g revise_auth:model User first_name last_name
15
+ $ jets g revise_auth:model User
16
16
  $ jets db:migrate
17
17
  $ jets g revise_auth:views
18
18
  ```
19
19
 
20
- Add ActiveRecord::Base.signed_id_verifier_secret = "custom_verfifier_secret" in your initializers. Set this as an env var
20
+ Add
21
+ ```
22
+ require "active_record"
23
+ ActiveRecord::Base.signed_id_verifier_secret = "custom_verfifier_secret"
24
+ ```
25
+ in your initializers. Set this as an env var
21
26
 
22
27
 
23
28
  Create your app/mailer/application_mailer.rb
@@ -45,7 +50,7 @@ ex:
45
50
  password: 'YOUR_PASS',
46
51
  authentication: 'plain'}
47
52
  ```
48
- To get your stmp pass follow these steps
53
+ To get your stmp pass follow these steps
49
54
 
50
55
  You need to make a password for specific app
51
56
 
data/Rakefile CHANGED
@@ -1,3 +1,6 @@
1
+ require "jets"
2
+ Jets.load_tasks
3
+
1
4
  require "bundler/setup"
2
5
  require "bundler/gem_tasks"
3
6
  require "rake/testtask"
data/app/config/routes.rb CHANGED
@@ -4,7 +4,6 @@ Jets.application.routes.draw do
4
4
  get "authenticated", to: "main#authenticated", as: :authenticated
5
5
 
6
6
  scope module: :revise_auth do
7
-
8
7
  get "sign_up", to: "registrations#new", as: :sign_up
9
8
  post "sign_up", to: "registrations#create"
10
9
  get "login", to: "sessions#new", as: :login
@@ -23,6 +22,24 @@ Jets.application.routes.draw do
23
22
  delete "logout", to: "sessions#delete"
24
23
  end
25
24
 
25
+ # Admin Routes
26
+ namespace :admin do
27
+ # resource :users
28
+ get "users/:id", to: "users#show", as: :admin_users_show
29
+ patch "users", to: "users#update", as: :admin_users
30
+ delete "users/:id", to: "users#delete", as: :admin_users
31
+ get "users", to: "users#index", as: :admin_users
32
+ get "dashboard", to: "dashboard#show", as: :admin
33
+ root "dashboard#show"
34
+ end
35
+
36
+ # API routes
37
+ namespace :api do
38
+ namespace :v1 do
39
+ resource :me, only: :show
40
+ end
41
+ end
42
+
26
43
  # The jets/public#show controller can serve static utf8 content out of the public folder.
27
44
  # Note, as part of the deploy process Jets uploads files in the public folder to s3
28
45
  # and serves them out of s3 directly. S3 is well suited to serve static assets.
@@ -0,0 +1,5 @@
1
+ class Admin::DashboardController < AdminController
2
+ def show
3
+ @users = User.all
4
+ end
5
+ end
@@ -0,0 +1,54 @@
1
+ class Admin::UsersController < AdminController
2
+ before_action :set_user, only: [:show, :edit, :destroy, :switch]
3
+
4
+ def index
5
+ @users = User.all
6
+ end
7
+
8
+ # GET /accounts/1
9
+ def show
10
+ @tokens = @user.api_tokens
11
+ end
12
+
13
+ def create
14
+ end
15
+
16
+ def update
17
+ @user = User.find(params[:user][:id])
18
+ email = @user.email
19
+ @user.update(email_params)
20
+ if email != params[:user][:unconfirmed_email]
21
+ @user.confirmation_sent_at = Time.now
22
+ @user.save
23
+ @user.send_confirmation_instructions
24
+ # flash[:notice] = I18n.t("revise_auth.confirmation_email_sent", email: current_user.unconfirmed_email)
25
+ end
26
+ redirect_back(fallback_location: root_path)
27
+ end
28
+
29
+ # GET /accounts/new
30
+ def new
31
+ @user = User.new
32
+ end
33
+
34
+ # GET /accounts/1/edit
35
+ def edit
36
+ end
37
+
38
+ # DELETE /accounts/1
39
+ def delete
40
+ ApiToken.find_by(token: params[:id]).destroy
41
+ redirect_back(fallback_location: root_path)
42
+ end
43
+
44
+ private
45
+
46
+ def email_params
47
+ params.require(:user).permit(:first_name, :last_name, :unconfirmed_email)
48
+ end
49
+
50
+ # Use callbacks to share common setup or constraints between actions.
51
+ def set_user
52
+ @user = User.find(params[:id])
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ class AdminController < ReviseAuthController
2
+ layout "admin_application"
3
+ before_action :authenticate_admin
4
+ before_action :gravatar_url
5
+
6
+ def authenticate_admin
7
+ redirect_to "/", alert: "Not authorized." unless current_user&.admin?
8
+ end
9
+
10
+ def gravatar_url
11
+ options = {}
12
+ hash = Digest::MD5.hexdigest(current_user.email&.downcase || "")
13
+ options.reverse_merge!(default: :mp, rating: :pg, size: 48)
14
+ @grav = "https://secure.gravatar.com/avatar/#{hash}.png?#{options.to_param}"
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ class Api::BaseController < ApplicationController
2
+ include ReviseAuth::Authentication
3
+ skip_before_action :verify_authenticity_token
4
+ prepend_before_action :authenticate_api_token!
5
+ rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
6
+ rescue_from ActionController::ParameterMissing, with: :handle_parameter_missing
7
+
8
+ private
9
+
10
+ def record_not_found
11
+ render json: {error: "Record Not Found"}, status: :not_found
12
+ end
13
+
14
+ def handle_parameter_missing(exception)
15
+ render json: {error: exception.message}, status: :bad_request
16
+ end
17
+
18
+ def authenticate_api_token!
19
+ if user_from_token
20
+ login(user_from_token)
21
+ else
22
+ render status: :unauthorized, json: {}
23
+ end
24
+ end
25
+
26
+ def token_from_header
27
+ request.headers.fetch("authorization", "").split(" ").last
28
+ end
29
+
30
+ def api_token
31
+ @_api_token ||= ApiToken.find_by(token: token_from_header)
32
+ end
33
+
34
+ # Only for use within authenticate_api_token! above
35
+ # Use current_user/Current.user or current_account/Current.account within app controllers
36
+ def user_from_token
37
+ if api_token.present?
38
+ api_token.touch(:last_used_at)
39
+ api_token.user
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ # Just a demo api controller you can remove this
2
+ class Api::V1::MesController < Api::BaseController
3
+ def show
4
+ render json: current_user
5
+ end
6
+
7
+ def destroy
8
+ current_user.destroy
9
+ render json: {}
10
+ end
11
+ end
@@ -4,7 +4,7 @@ class ReviseAuth::EmailController < ReviseAuthController
4
4
  # GET /profile/email?confirmation_token=abcdef
5
5
  def show
6
6
  if User.find_by(confirmation_token: params[:confirmation_token])&.confirm_email_change
7
- #flash[:notice] = I18n.t("revise_auth.email_confirmed")
7
+ # flash[:notice] = I18n.t("revise_auth.email_confirmed")
8
8
  redirect_to(user_signed_in? ? profile_path : root_path)
9
9
  else
10
10
  redirect_to root_path, alert: I18n.t("revise_auth.email_confirm_failed")
@@ -12,9 +12,13 @@ class ReviseAuth::EmailController < ReviseAuthController
12
12
  end
13
13
 
14
14
  def update
15
- if current_user.update(email_params)
15
+ email = current_user.email
16
+ current_user.update(email_params)
17
+ if email != params[:user][:unconfirmed_email]
18
+ current_user.confirmation_sent_at = Time.now
19
+ current_user.save
16
20
  current_user.send_confirmation_instructions
17
- #flash[:notice] = I18n.t("revise_auth.confirmation_email_sent", email: current_user.unconfirmed_email)
21
+ # flash[:notice] = I18n.t("revise_auth.confirmation_email_sent", email: current_user.unconfirmed_email)
18
22
  end
19
23
 
20
24
  redirect_to profile_path
@@ -23,6 +27,6 @@ class ReviseAuth::EmailController < ReviseAuthController
23
27
  private
24
28
 
25
29
  def email_params
26
- params.require(:user).permit(:unconfirmed_email)
30
+ params.require(:user).permit(:first_name, :last_name, :unconfirmed_email)
27
31
  end
28
32
  end
@@ -3,7 +3,7 @@ class ReviseAuth::PasswordController < ReviseAuthController
3
3
 
4
4
  def update
5
5
  if current_user.update(password_params)
6
- #flash[:notice] = I18n.t("revise_auth.password_changed")
6
+ # flash[:notice] = I18n.t("revise_auth.password_changed")
7
7
  end
8
8
 
9
9
  redirect_to profile_path
@@ -17,7 +17,7 @@ class ReviseAuth::PasswordController < ReviseAuthController
17
17
 
18
18
  def validate_current_password
19
19
  unless current_user.authenticate(params[:current_password])
20
- #flash[:alert] = I18n.t("revise_auth.incorrect_password")
20
+ # flash[:alert] = I18n.t("revise_auth.incorrect_password")
21
21
  render "revise_auth/registrations/edit", status: :unprocessable_entity
22
22
  end
23
23
  end
@@ -9,6 +9,7 @@ class ReviseAuth::RegistrationsController < ReviseAuthController
9
9
  @user = User.new(sign_up_params)
10
10
  if @user.save
11
11
  login(@user)
12
+ current_user.api_tokens.first_or_create(name: ApiToken::APP_NAME)
12
13
  redirect_to root_path
13
14
  else
14
15
  render :new, status: :unprocessable_entity
@@ -35,10 +36,10 @@ class ReviseAuth::RegistrationsController < ReviseAuthController
35
36
  private
36
37
 
37
38
  def sign_up_params
38
- params.require(:user).permit(:name, :email, :password, :password_confirmation)
39
+ params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
39
40
  end
40
41
 
41
42
  def profile_params
42
- params.require(:user).permit(:name)
43
+ params.require(:user).permit(:first_name, :last_name)
43
44
  end
44
45
  end
@@ -5,9 +5,10 @@ class ReviseAuth::SessionsController < ReviseAuthController
5
5
  def create
6
6
  if (user = User.authenticate_by(email: params[:email], password: params[:password]))
7
7
  login(user)
8
+ current_user.api_tokens.first_or_create(name: ApiToken::APP_NAME)
8
9
  redirect_to root_path
9
10
  else
10
- #flash[:alert] = I18n.t("revise_auth.invalid_email_or_password")
11
+ # flash[:alert] = I18n.t("revise_auth.invalid_email_or_password")
11
12
  render :new, status: :unprocessable_entity
12
13
  end
13
14
  end
@@ -1,4 +1,4 @@
1
- require 'revise_auth-jets'
1
+ require "revise_auth-jets"
2
2
  class ReviseAuthController < ApplicationController
3
3
  # Return true if it's a revise_auth_controller. false to all controllers unless
4
4
  # the controllers defined inside revise_auth. Useful if you want to apply a before
@@ -0,0 +1,22 @@
1
+ <main class="w-full flex-grow p-6">
2
+ <h1 class="text-3xl text-black pb-6">Dashboard</h1>
3
+
4
+ <div class="flex flex-wrap mt-6">
5
+ <div class="w-full lg:w-1/2 pr-0 lg:pr-2">
6
+ <p class="text-xl pb-3 flex items-center">
7
+ <i class="fas fa-plus mr-3"></i> Active Users
8
+ </p>
9
+ <div class="p-6 bg-white">
10
+ <%= @users.where('updated_at > ?', 1.month.ago).count %>
11
+ </div>
12
+ </div>
13
+ <div class="w-full lg:w-1/2 pl-0 lg:pl-2 mt-12 lg:mt-0">
14
+ <p class="text-xl pb-3 flex items-center">
15
+ <i class="fas fa-check mr-3"></i> All Users
16
+ </p>
17
+ <div class="p-6 bg-white">
18
+ <%= @users.count %>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </main>
@@ -0,0 +1,15 @@
1
+ <header class="w-full items-center bg-white py-2 px-6 hidden sm:flex">
2
+ <div class="w-1/2"></div>
3
+
4
+ <div class="relative w-1/2 flex justify-end">
5
+ <button onclick="hideMenu()" class="realtive z-10 w-12 h-12 rounded-full overflow-hidden border-4 border-gray-400 hover:border-gray-300 focus:border-gray-300 focus:outline-none">
6
+ <img src="<%= @grav %>">
7
+ </button>
8
+ <div id="menuBtn" class="absolute w-32 bg-white rounded-lg shadow-lg py-2 mt-16" style="display: none;">
9
+ <%= link_to "Profile", profile_path, class: "block px-4 py-2 account-link hover:text-white" %>
10
+ <%= link_to "Log out", '/logout', method: :delete, class: "block px-4 py-2 account-link hover:text-white" %>
11
+ </div>
12
+ </div>
13
+ </header>
14
+
15
+
@@ -0,0 +1,16 @@
1
+ <header class="w-full bg-sidebar py-5 px-6 sm:hidden">
2
+ <div class="flex items-center justify-between">
3
+ <%= link_to "Admin", admin_path, class: "text-white text-3xl font-semibold uppercase hover:text-gray-300"%>
4
+
5
+ <button onclick="hideMenuMobile()" class="text-white text-3xl focus:outline-none">
6
+ <i id="bars" class="fas fa-bars" style="display: block;"></i>
7
+ <i id="times" class="fas fa-times" style="display: none;"></i>
8
+ </button>
9
+ </div>
10
+
11
+ <!-- Dropdown Nav -->
12
+ <nav id="dropdownNav" class="flex flex-col pt-4" style="display: none;">
13
+ <%= render partial: "admin/shared/nav_links" %>
14
+ </nav>
15
+ </header>
16
+
@@ -0,0 +1,8 @@
1
+ <%= link_to admin_path, class: "flex items-center text-white opacity-75 hover:opacity-100 py-4 pl-6 nav-item" do %>
2
+ <i class="fas fa-tachometer-alt mr-3"></i>
3
+ Dashboard
4
+ <% end %>
5
+ <%= link_to admin_users_path, class: "flex items-center text-white opacity-75 hover:opacity-100 py-4 pl-6 nav-item" do %>
6
+ <i class="fas fa-user mr-3"></i>
7
+ User
8
+ <% end %>
@@ -0,0 +1,43 @@
1
+ <main class="w-full flex-grow p-6">
2
+ <h1 class="text-3xl text-black pb-6">Users</h1>
3
+ <div class="w-full mt-6">
4
+ <p class="text-xl pb-3 flex items-center">
5
+ <i class="fas fa-list mr-3"></i> User Table
6
+ </p>
7
+ <div class="bg-white overflow-auto">
8
+ <table class="min-w-full bg-white">
9
+ <thead class="bg-gray-800 text-white">
10
+ <tr>
11
+ <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Edit</th>
12
+ <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Name</th>
13
+ <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Last name</th>
14
+ <th class="text-left py-3 px-4 uppercase font-semibold text-sm">Email</td>
15
+ </tr>
16
+ </thead>
17
+ <tbody class="text-gray-700">
18
+ <% @users.each_with_index do |user, index| %>
19
+ <% if index.even? %>
20
+ <tr>
21
+ <td class="w-1/3 text-left py-3 px-4">
22
+ <a class="btn btn-sm" href="/admin/users/<%=user.id%>">
23
+ Edit
24
+ </a>
25
+ </td>
26
+ <td class="w-1/3 text-left py-3 px-4"><%= user.first_name %></td>
27
+ <td class="w-1/3 text-left py-3 px-4"><%= user.last_name %></td>
28
+ <td class="text-left py-3 px-4"><a class="hover:text-blue-500" href="mailto:jonsmith@mail.com"><%= user.email %></a></td>
29
+ </tr>
30
+ <% else %>
31
+ <tr class="bg-gray-200">
32
+ <td class="w-1/3 text-left py-3 px-4"><%= link_to "Edit", admin_users_show_path(user.id)%></td>
33
+ <td class="w-1/3 text-left py-3 px-4"><%= user.first_name %></td>
34
+ <td class="w-1/3 text-left py-3 px-4"><%= user.last_name %></td>
35
+ <td class="text-left py-3 px-4"><a class="hover:text-blue-500" href="mailto:jonsmith@mail.com"><%= user.email %></a></td>
36
+ </tr>
37
+ <% end %>
38
+ <% end %>
39
+ </table>
40
+ </div>
41
+ </div>
42
+ </main>
43
+
@@ -0,0 +1,73 @@
1
+ <main class="w-full flex-grow p-6">
2
+ <div class="w-full mt-12">
3
+ <p class="text-xl pb-3 flex items-center">
4
+ <i class="fas fa-list mr-3"></i> User
5
+ </p>
6
+ <div class="bg-white overflow-auto">
7
+
8
+ <%= form_with model: @user, local: true, url: admin_users_path do |form| %>
9
+ <table class="text-left w-full border-collapse">
10
+ <thead>
11
+ <tr>
12
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Created At</th>
13
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">First Name</th>
14
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Last Name</th>
15
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Email</th>
16
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Submit</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <tr class="hover:bg-grey-lighter">
21
+ <%= form.hidden_field :id %>
22
+ <td class="py-4 px-6 border-b border-grey-light"><%= @user.created_at %></td>
23
+ <td class="py-4 px-6 border-b border-grey-light">
24
+ <%= form.text_field :first_name, autofocus: true, autocomplete: "name", placeholder: "Steve", class: "form-control" %>
25
+ </td>
26
+ <td class="py-4 px-6 border-b border-grey-light">
27
+ <%= form.text_field :last_name, autofocus: true, autocomplete: "name", placeholder: "Jobs", class: "form-control" %>
28
+ </td>
29
+ <td class="py-4 px-6 border-b border-grey-light">
30
+ <%= form.email_field :unconfirmed_email, autocomplete: "email", placeholder: "you@example.com", class: "form-control" %>
31
+ </td>
32
+ <td class="py-4 px-6 border-b border-grey-light">
33
+ <%= form.submit "Submit", class: "btn btn-primary btn-expanded" %>
34
+ </td>
35
+ </tr>
36
+ </tbody>
37
+ </table>
38
+ <% end %>
39
+ </div>
40
+ </div>
41
+
42
+ <div class="w-full mt-12">
43
+ <p class="text-xl pb-3 flex items-center">
44
+ <i class="fas fa-list mr-3"></i> ApiTokens
45
+ </p>
46
+ <div class="bg-white overflow-auto">
47
+ <table class="text-left w-full border-collapse">
48
+ <thead>
49
+ <tr>
50
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Created At</th>
51
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Expires At</th>
52
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Token</th>
53
+ <th class="py-4 px-6 bg-grey-lightest font-bold uppercase text-sm text-grey-dark border-b border-grey-light">Delete</th>
54
+ </tr>
55
+ </thead>
56
+ <tbody>
57
+ <% @tokens.each do |token| %>
58
+ <tr class="hover:bg-grey-lighter">
59
+ <td class="py-4 px-6 border-b border-grey-light"><%= token.created_at %></td>
60
+ <td class="py-4 px-6 border-b border-grey-light"><%= token.expires_at%></td>
61
+ <td class="py-4 px-6 border-b border-grey-light"><%= token.token %></td>
62
+ <td class="py-4 px-6 border-b border-grey-light">
63
+ <a data-confirm="Are you sure?" data-method="delete" class="btn btn-sm" href="/admin/users/<%=token.token%>">
64
+ <i class="fa-regular fa-trash-can mr-3"></i>
65
+ </a>
66
+ </td>
67
+ </tr>
68
+ <% end %>
69
+ </tbody>
70
+ </table>
71
+ </div>
72
+ </div>
73
+ </main>
@@ -0,0 +1,78 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6
+ <meta name="theme-color" content="#000000">
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
+ <%= csrf_meta_tags %>
9
+ <title>Jets App</title>
10
+ <%= javascript_pack_tag "application" %>
11
+ <%= stylesheet_pack_tag "theme" %>
12
+
13
+ <link rel="shortcut icon" href="<%= favicon_path %>">
14
+ <style>
15
+ @import url('https://fonts.googleapis.com/css?family=Karla:400,700&display=swap');
16
+ .font-family-karla { font-family: karla; }
17
+ .bg-sidebar { background: #3d68ff; }
18
+ .cta-btn { color: #3d68ff; }
19
+ .upgrade-btn { background: #1947ee; }
20
+ .upgrade-btn:hover { background: #0038fd; }
21
+ .active-nav-link { background: #1947ee; }
22
+ .nav-item:hover { background: #1947ee; }
23
+ .account-link:hover { background: #3d68ff; }
24
+ </style>
25
+
26
+ </head>
27
+ <body>
28
+ <div class="col-md-9 content-body">
29
+ <div class="bg-gray-100 font-family-karla flex">
30
+ <aside class="relative bg-sidebar h-screen w-64 hidden sm:block shadow-xl">
31
+ <div class="p-6">
32
+ <%= link_to "Admin", admin_path, class: "text-white text-3xl font-semibold uppercase hover:text-gray-300"%>
33
+ </div>
34
+ <nav class="text-white text-base font-semibold pt-3">
35
+ <%= render partial: "admin/shared/nav_links" %>
36
+ </aside>
37
+ <div class="w-full flex flex-col h-screen overflow-y-hidden">
38
+ <!-- Desktop Header -->
39
+ <%= render partial: "admin/shared/desktop_header" %>
40
+ <!-- Mobile Header & Nav -->
41
+ <%= render partial: "admin/shared/mobile_header" %>
42
+ <div class="w-full overflow-x-hidden border-t flex flex-col">
43
+ <%= yield %>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </body>
49
+ <!-- Font Awesome -->
50
+ <script defer src="https://kit.fontawesome.com/0e5ab6a736.js" crossorigin="anonymous"></script>
51
+
52
+ <script>
53
+ function hideMenuMobile() {
54
+ var x = document.getElementById("bars");
55
+ var y = document.getElementById("times");
56
+ var z = document.getElementById("dropdownNav");
57
+ if (x.style.display === "none") {
58
+ x.style.display = "block";
59
+ y.style.display = "none";
60
+ z.style.display = "none";
61
+ } else {
62
+ y.style.display = "block";
63
+ z.style.display = "block";
64
+ x.style.display = "none";
65
+ }
66
+ }
67
+
68
+ function hideMenu() {
69
+ var x = document.getElementById("menuBtn");
70
+ if (x.style.display === "none") {
71
+ x.style.display = "block";
72
+ } else {
73
+ x.style.display = "none";
74
+ }
75
+ }
76
+ </script>
77
+
78
+ </html>
@@ -3,7 +3,7 @@
3
3
 
4
4
  <% if user_signed_in? %>
5
5
  <%= link_to "Profile", profile_path %>
6
- <%= button_to "Log out", 'logout', method: :delete %>
6
+ <%= button_to "Log out", '/logout', method: :delete %>
7
7
  <% else %>
8
8
  <%= link_to "Sign Up", sign_up_path %>
9
9
  <%= link_to "Log in", login_path %>
@@ -2,18 +2,21 @@
2
2
  <div class="mb-4 text-center">
3
3
  <h2 class="mb-1">Profile</h2>
4
4
  </div>
5
-
6
-
7
5
  <%= form_with model: current_user, local: true, url: profile_email_path do |form| %>
8
6
  <%= render "shared/error_messages", resource: current_user %>
9
7
  <div class="form-group">
10
- <%= form.label :name, "Full name" %>
11
- <%= form.text_field :name, autofocus: true, autocomplete: "name", placeholder: "Steve Jobs", class: "form-control" %>
8
+ <%= form.label :first_name, "First name" %>
9
+ <%= form.text_field :first_name, autofocus: true, autocomplete: "name", placeholder: "Steve", class: "form-control" %>
10
+ </div>
11
+
12
+ <div class="form-group">
13
+ <%= form.label :last_name, "Last name" %>
14
+ <%= form.text_field :last_name, autofocus: true, autocomplete: "name", placeholder: "Jobs", class: "form-control" %>
12
15
  </div>
13
16
 
14
17
  <div class="form-group">
15
18
  <%= form.label :email %>
16
- <%= form.email_field :email, autocomplete: "email", placeholder: "you@example.com", class: "form-control" %>
19
+ <%= form.email_field :unconfirmed_email, autocomplete: "email", placeholder: "you@example.com", class: "form-control" %>
17
20
  </div>
18
21
 
19
22
  <div class="mt-2 form-group">
@@ -21,7 +21,7 @@
21
21
  </div>
22
22
 
23
23
  <div class="form-group">
24
- <%= f.submit "SIgn In", class: "btn btn-primary btn-expanded" %>
24
+ <%= f.submit "Sign In", class: "btn btn-primary btn-expanded" %>
25
25
  </div>
26
26
  <% end %>
27
27
 
@@ -11,20 +11,26 @@ module ReviseAuth
11
11
  argument :attributes, type: :array, default: [], banner: "field:type field:type"
12
12
 
13
13
  def initialize(args, *options)
14
- @original_attributes = args[1..] || []
15
14
  super
16
15
  end
17
16
 
18
17
  def generate_model
19
- model_attributess = model_attributes.join(', ').gsub(':index', '').gsub(',', '')
18
+ model_attributess = model_attributes.join(", ").delete(",")
19
+ puts "Adding #{name}"
20
20
  puts "jets g model #{name} #{model_attributess}"
21
21
  system "jets g model #{name} #{model_attributess}"
22
- #generate :model, name, *model_attributes
22
+ puts "Adding ApiToken"
23
+ system "jets g model ApiTokens #{name.downcase}:references token:string:uniq name:string metadata:jsonb transient:boolean last_used_at:datetime expires_at:datetime"
24
+ # generate :model, name, *model_attributes
23
25
  end
24
26
 
25
27
  def add_revise_auth_model
28
+ prepend_to_file "app/models/api_token.rb", "require 'revise_auth-jets'\n"
29
+ inject_into_class "app/models/api_token.rb", "ApiToken", " include ReviseAuth::ApiModel\n"
30
+
26
31
  prepend_to_file model_path, "require 'revise_auth-jets'\n"
27
32
  inject_into_class model_path, class_name, " include ReviseAuth::Model\n"
33
+ inject_into_class model_path, class_name, " has_many :api_tokens, dependent: :destroy\n"
28
34
  end
29
35
 
30
36
  def add_uniq_to_email_index
@@ -51,13 +57,16 @@ module ReviseAuth
51
57
 
52
58
  def model_attributes
53
59
  [
54
- "email:string:index",
60
+ "email:string:uniq",
55
61
  "password_digest:string",
62
+ "first_name:string",
63
+ "last_name:string",
64
+ "admin:boolean",
56
65
  "confirmation_token:string",
57
66
  "confirmed_at:datetime",
58
67
  "confirmation_sent_at:datetime",
59
68
  "unconfirmed_email:string"
60
- ] + @original_attributes
69
+ ]
61
70
  end
62
71
  end
63
72
  end
@@ -1,8 +1,7 @@
1
1
  🚚 Your Revise auth database model has been generated!
2
2
 
3
3
  Next step:
4
- Add "add_index :users, :email, unique: true" at the bottom of the change method
4
+ Add t.jsonb :metadata, default: {} and t.boolean :transient, default: false into your ApiToken migration
5
5
  Run "jets db:migrate"
6
- Add ActiveRecord::Base.signed_id_verifier_secret = "custom_verfifier_secret" in your initializers/ Set this as an env var
7
6
  Add your stmp settings in your development.rb
8
7
  Run "jets g revise_auth:views"
@@ -12,11 +12,12 @@ module ReviseAuth
12
12
  end
13
13
 
14
14
  def copy_styles
15
- template "app/stylesheet/theme.scss", "app/javascripts/packs"
15
+ template "app/stylesheet/theme.scss", "app/javascript/packs/theme.scss"
16
16
  end
17
17
 
18
18
  def copy_controllers
19
19
  template "app/controllers/main_controller.rb", "app/controllers/main_controller.rb"
20
+ template "app/controllers/admin_controller.rb", "app/controllers/admin_controller.rb"
20
21
  template "app/controllers/revise_auth_controller.rb", "app/controllers/revise_auth_controller.rb"
21
22
  if options[:controllers]
22
23
  options[:controllers].each do |directory|
@@ -24,6 +25,8 @@ module ReviseAuth
24
25
  end
25
26
  else
26
27
  directory "app/controllers/revise_auth"
28
+ directory "app/controllers/api"
29
+ directory "app/controllers/admin"
27
30
  end
28
31
  end
29
32
 
@@ -33,8 +36,11 @@ module ReviseAuth
33
36
  directory "app/views/revise_auth/#{directory}"
34
37
  end
35
38
  else
39
+ directory "app/views/layouts"
36
40
  directory "app/views/revise_auth"
41
+ directory "app/views/admin"
37
42
  directory "app/views/main"
43
+ directory "app/views/shared"
38
44
  end
39
45
  end
40
46
  end
@@ -0,0 +1,46 @@
1
+ module ReviseAuth
2
+ module ApiModel
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ DEFAULT_NAME = "api_token" # standard:disable Lint/ConstantDefinitionInBlock
7
+ APP_NAME = "my_app" # standard:disable Lint/ConstantDefinitionInBlock
8
+
9
+ belongs_to :user
10
+
11
+ scope :sorted, -> { order("last_used_at DESC NULLS LAST, created_at DESC") }
12
+
13
+ has_secure_token :token
14
+
15
+ validates :name, presence: true
16
+
17
+ def can?(permission)
18
+ Array.wrap(data("permissions")).include?(permission)
19
+ end
20
+
21
+ def cant?(permission)
22
+ !can?(permission)
23
+ end
24
+
25
+ def data(key, default: nil)
26
+ (metadata || {}).fetch(key, default)
27
+ end
28
+
29
+ def expired?
30
+ expires_at? && Time.current >= expires_at
31
+ end
32
+
33
+ def touch_last_used_at
34
+ return if transient?
35
+ update(last_used_at: Time.current)
36
+ end
37
+
38
+ def generate_token
39
+ loop do
40
+ self.token = SecureRandom.hex(16)
41
+ break unless ApiToken.where(token: token).exists?
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -54,7 +54,7 @@ module ReviseAuth
54
54
  end
55
55
 
56
56
  def reset_session
57
- if session && session.respond_to?(:destroy)
57
+ if session&.respond_to?(:destroy)
58
58
  session.destroy
59
59
  else
60
60
  self.session = {}
@@ -1,3 +1,4 @@
1
+ require "jets"
1
2
  module ReviseAuth
2
3
  class Turbine < ::Jets::Turbine
3
4
  initializer :revise_auth_controller do
@@ -5,7 +5,7 @@ module ReviseAuth
5
5
  included do
6
6
  include Backports
7
7
 
8
- EMAIL_VERIFICATION_TOKEN_VALIDITY = 1.day
8
+ EMAIL_VERIFICATION_TOKEN_VALIDITY = 1.day # standard:disable Lint/ConstantDefinitionInBlock
9
9
 
10
10
  has_secure_password
11
11
  has_secure_token :confirmation_token
@@ -27,10 +27,10 @@ module ReviseAuth
27
27
  # Generates a confirmation token and send email to the user
28
28
  def send_confirmation_instructions
29
29
  # = breaks the query params
30
- token = generate_token_for.gsub("=", '')
30
+ token = generate_token_for.delete("=")
31
31
  self.confirmation_token = token
32
- self.save!
33
- ReviseAuth::Mailer.with(user: self.unconfirmed_email, token: token).confirm_email.deliver_later
32
+ save!
33
+ ReviseAuth::Mailer.with(user: unconfirmed_email, token: token).confirm_email.deliver_later
34
34
  end
35
35
 
36
36
  def confirm_email_change
@@ -1,49 +1,49 @@
1
- #module ActionDispatch::Routing
2
- # class Mapper
3
- # def revise_auth
4
- # scope module: :revise_auth do
5
- # revise_registration
6
-
7
- # get "login", to: "sessions#new"
8
- # post "login", to: "sessions#create"
9
-
10
- # revise_profile
11
-
12
- # patch "profile/email", to: "email#update"
13
- # patch "profile/password", to: "password#update"
14
-
15
- # # Email confirmation
16
- # get "profile/email", to: "email#show"
17
-
18
- # delete "logout", to: "sessions#destroy"
19
- # end
20
- # end
21
-
22
- # # Adds helpers for config/routes.rb to constraint routes with authentication
23
- # #
24
- # def authenticated
25
- # constraints ->(request) { ReviseAuth::RouteConstraint.new(request).user_signed_in? } do
26
- # yield
27
- # end
28
- # end
29
-
30
- # def unauthenticated
31
- # constraints ->(request) { !ReviseAuth::RouteConstraint.new(request).user_signed_in? } do
32
- # yield
33
- # end
34
- # end
35
-
36
- # private
37
-
38
- # def revise_registration
39
- # get "sign_up", to: "registrations#new"
40
- # post "sign_up", to: "registrations#create"
41
- # end
42
-
43
- # def revise_profile
44
- # get "profile", to: "registrations#edit"
45
- # patch "profile", to: "registrations#update"
46
- # delete "profile", to: "registrations#destroy"
47
- # end
48
- # end
49
- #end
1
+ # module ActionDispatch::Routing
2
+ # class Mapper
3
+ # def revise_auth
4
+ # scope module: :revise_auth do
5
+ # revise_registration
6
+
7
+ # get "login", to: "sessions#new"
8
+ # post "login", to: "sessions#create"
9
+
10
+ # revise_profile
11
+
12
+ # patch "profile/email", to: "email#update"
13
+ # patch "profile/password", to: "password#update"
14
+
15
+ # # Email confirmation
16
+ # get "profile/email", to: "email#show"
17
+
18
+ # delete "logout", to: "sessions#destroy"
19
+ # end
20
+ # end
21
+
22
+ # # Adds helpers for config/routes.rb to constraint routes with authentication
23
+ # #
24
+ # def authenticated
25
+ # constraints ->(request) { ReviseAuth::RouteConstraint.new(request).user_signed_in? } do
26
+ # yield
27
+ # end
28
+ # end
29
+
30
+ # def unauthenticated
31
+ # constraints ->(request) { !ReviseAuth::RouteConstraint.new(request).user_signed_in? } do
32
+ # yield
33
+ # end
34
+ # end
35
+
36
+ # private
37
+
38
+ # def revise_registration
39
+ # get "sign_up", to: "registrations#new"
40
+ # post "sign_up", to: "registrations#create"
41
+ # end
42
+
43
+ # def revise_profile
44
+ # get "profile", to: "registrations#edit"
45
+ # patch "profile", to: "registrations#update"
46
+ # delete "profile", to: "registrations#destroy"
47
+ # end
48
+ # end
49
+ # end
@@ -1,3 +1,3 @@
1
1
  module ReviseAuth
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.3"
3
3
  end
@@ -7,5 +7,6 @@ module ReviseAuth
7
7
  autoload :Backports, "revise_auth/backports"
8
8
  autoload :Current, "revise_auth/current"
9
9
  autoload :Model, "revise_auth/model"
10
+ autoload :ApiModel, "revise_auth/api_model"
10
11
  autoload :RouteConstraint, "revise_auth/route_constraint"
11
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: revise_auth-jets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremiah Parrack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-19 00:00:00.000000000 Z
11
+ date: 2023-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bcrypt
@@ -35,6 +35,11 @@ files:
35
35
  - README.md
36
36
  - Rakefile
37
37
  - app/config/routes.rb
38
+ - app/controllers/admin/dashboard_controller.rb
39
+ - app/controllers/admin/users_controller.rb
40
+ - app/controllers/admin_controller.rb
41
+ - app/controllers/api/base_controller.rb
42
+ - app/controllers/api/v1/mes_controller.rb
38
43
  - app/controllers/main_controller.rb
39
44
  - app/controllers/revise_auth/email_controller.rb
40
45
  - app/controllers/revise_auth/password_controller.rb
@@ -43,6 +48,13 @@ files:
43
48
  - app/controllers/revise_auth_controller.rb
44
49
  - app/mailers/revise_auth/mailer.rb
45
50
  - app/stylesheet/theme.scss
51
+ - app/views/admin/dashboard/show.html.erb
52
+ - app/views/admin/shared/_desktop_header.html.erb
53
+ - app/views/admin/shared/_mobile_header.html.erb
54
+ - app/views/admin/shared/_nav_links.html.erb
55
+ - app/views/admin/users/index.html.erb
56
+ - app/views/admin/users/show.html.erb
57
+ - app/views/layouts/admin_application.html.erb
46
58
  - app/views/main/authenticated.html.erb
47
59
  - app/views/main/index.html.erb
48
60
  - app/views/revise_auth/mailer/confirm_email.html.erb
@@ -62,6 +74,7 @@ files:
62
74
  - lib/generators/revise_auth/templates/README
63
75
  - lib/generators/revise_auth/views_generator.rb
64
76
  - lib/revise_auth-jets.rb
77
+ - lib/revise_auth/api_model.rb
65
78
  - lib/revise_auth/authentication.rb
66
79
  - lib/revise_auth/backports.rb
67
80
  - lib/revise_auth/current.rb