Skip to content

Commit 89cec4e

Browse files
committed
Add admin area
Admin users can be created via a new task bin/rails fasp_base:create_admin[<email>] and then sign in at `/admin/session/new`. They will see a list of users and can activate / deactivate them. Deactivated users can no longer sign in.
1 parent 4bd8909 commit 89cec4e

34 files changed

+515
-10
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title><%= content_for(:title) || "Debug Provider" %></title>
5+
<meta name="viewport" content="width=device-width,initial-scale=1">
6+
<meta name="apple-mobile-web-app-capable" content="yes">
7+
<%= csrf_meta_tags %>
8+
<%= csp_meta_tag %>
9+
10+
<%= yield :head %>
11+
12+
<link rel="manifest" href="/manifest.json">
13+
<link rel="icon" href="/icon.png" type="image/png">
14+
<link rel="icon" href="/icon.svg" type="image/svg+xml">
15+
<link rel="apple-touch-icon" href="/icon.png">
16+
<%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
17+
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
18+
<%= javascript_importmap_tags %>
19+
</head>
20+
21+
<body>
22+
<header class="bg-blue-100">
23+
<nav class="container mx-auto p-4 flex justify-between">
24+
<div class="flex gap-8">
25+
<p class="font-bold text-gray-600 px-2 py-1">
26+
Debug Provider
27+
</p>
28+
<% if admin_signed_in? %>
29+
<%= nav_link_to t(".users"), fasp_base.admin_users_path %>
30+
<% end %>
31+
</div>
32+
<div class="flex gap-8">
33+
<% if admin_signed_in? %>
34+
<%= nav_link_to t(".sign_out"), fasp_base.admin_session_path, data: {turbo_method: :delete} %>
35+
<% end %>
36+
</div>
37+
</nav>
38+
</header>
39+
<main class="container mx-auto mt-8 px-5">
40+
<%= notification(notice) if notice %>
41+
<%= notification(alert, type: :alert) if alert %>
42+
43+
<%= yield %>
44+
</main>
45+
</body>
46+
</html>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# This migration comes from fasp_base (originally 20250507095511)
2+
class CreateFaspBaseAdminUsers < ActiveRecord::Migration[8.0]
3+
def change
4+
create_table :fasp_base_admin_users do |t|
5+
t.string :email, null: false, index: { unique: true }
6+
t.string :password_digest
7+
8+
t.timestamps
9+
end
10+
end
11+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# This migration comes from fasp_base (originally 20250507143155)
2+
class AddActiveToUsers < ActiveRecord::Migration[8.0]
3+
def change
4+
add_column :fasp_base_users, :active, :boolean, null: false, default: true
5+
end
6+
end

debug_fasp/db/schema.rb

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module FaspBase
2+
module AdminAuthentication
3+
extend ActiveSupport::Concern
4+
5+
included do
6+
helper_method :current_admin_user
7+
helper_method :admin_signed_in?
8+
9+
before_action :require_admin_authentication
10+
end
11+
12+
class_methods do
13+
def skip_admin_authentication(**options)
14+
skip_before_action :require_admin_authentication, **options
15+
end
16+
end
17+
18+
private
19+
20+
def current_admin_user
21+
@current_admin_user ||= AdminUser.find_by(id: session[:admin_user_id])
22+
end
23+
24+
def current_admin_user=(admin_user)
25+
session[:admin_user_id] = admin_user.id
26+
@current_admin_user = admin_user
27+
end
28+
29+
def admin_signed_in?
30+
current_admin_user.present?
31+
end
32+
33+
def require_admin_authentication
34+
return if admin_signed_in?
35+
36+
respond_to do |format|
37+
format.html { redirect_to fasp_base.new_admin_session_path }
38+
format.json { head status: 401 }
39+
end
40+
end
41+
end
42+
end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module FaspBase
2+
class Admin::ActivationsController < Admin::BaseController
3+
before_action :load_user
4+
5+
def create
6+
@user.activate!
7+
8+
respond_to do |format|
9+
format.html { redirect_to fasp_base.admin_users_path, notice: t(".success") }
10+
format.json { head :created }
11+
end
12+
end
13+
14+
def destroy
15+
@user.deactivate!
16+
17+
respond_to do |format|
18+
format.html { redirect_to fasp_base.admin_users_path, notice: t(".success") }
19+
format.json { head :no_content }
20+
end
21+
end
22+
23+
private
24+
25+
def load_user
26+
@user = User.find(params[:user_id])
27+
end
28+
end
29+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module FaspBase
2+
class Admin::BaseController < ActionController::Base
3+
include AdminAuthentication
4+
5+
helper Rails.application.helpers
6+
helper FaspBase::ApplicationHelper
7+
8+
layout "layouts/admin"
9+
10+
default_form_builder FaspBase::FormBuilder
11+
end
12+
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module FaspBase
2+
class Admin::InvitationCodesController < Admin::BaseController
3+
end
4+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module FaspBase
2+
class Admin::SessionsController < Admin::BaseController
3+
skip_admin_authentication
4+
5+
def new
6+
end
7+
8+
def create
9+
if admin_user = AdminUser.authenticate_by(params.permit(:email, :password))
10+
self.current_admin_user = admin_user
11+
12+
redirect_to fasp_base.admin_users_path
13+
else
14+
redirect_to fasp_base.new_admin_session_path,
15+
alert: t(".failure")
16+
end
17+
end
18+
19+
def destroy
20+
reset_session
21+
22+
redirect_to fasp_base.admin_new_session_path,
23+
notice: t(".success")
24+
end
25+
end
26+
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module FaspBase
2+
class Admin::SettingsController < Admin::BaseController
3+
end
4+
end

0 commit comments

Comments
 (0)