Add admin panel and make it work for user resource

This commit is contained in:
riggraz
2019-08-21 16:13:39 +02:00
parent 462002c416
commit ecc0d1cb27
17 changed files with 321 additions and 4 deletions

View File

@@ -28,8 +28,12 @@ gem 'jbuilder', '~> 2.7'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false
# Authentication
gem 'devise', git: 'https://github.com/plataformatec/devise'
# Administration panel
gem "administrate", git: "https://github.com/thoughtbot/administrate.git"
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]

View File

@@ -9,6 +9,23 @@ GIT
responders
warden (~> 1.2.3)
GIT
remote: https://github.com/thoughtbot/administrate.git
revision: fcf46ae4e6989ceb1b091791fec754a67da0f32c
specs:
administrate (0.11.0)
actionpack (>= 4.2)
actionview (>= 4.2)
activejob (>= 4.2)
activerecord (>= 4.2)
autoprefixer-rails (>= 6.0)
datetime_picker_rails (~> 0.0.7)
jquery-rails (>= 4.0)
kaminari (>= 1.0)
momentjs-rails (~> 2.8)
sassc-rails (~> 2.1)
selectize-rails (~> 0.6)
GEM
remote: https://rubygems.org/
specs:
@@ -69,6 +86,8 @@ GEM
zeitwerk (~> 2.1, >= 2.1.8)
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
autoprefixer-rails (9.6.1)
execjs
bcrypt (3.1.13)
bindex (0.8.1)
bootsnap (1.4.4)
@@ -87,8 +106,11 @@ GEM
rake (< 13.0)
concurrent-ruby (1.1.5)
crass (1.0.4)
datetime_picker_rails (0.0.7)
momentjs-rails (>= 2.8.1)
diff-lcs (1.3)
erubi (1.8.0)
execjs (2.7.0)
factory_bot (5.0.2)
activesupport (>= 4.2.0)
factory_bot_rails (5.0.2)
@@ -101,6 +123,22 @@ GEM
concurrent-ruby (~> 1.0)
jbuilder (2.9.1)
activesupport (>= 4.2.0)
jquery-rails (4.3.5)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
kaminari (1.1.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.1.1)
kaminari-actionview (1.1.1)
actionview
kaminari-core (= 1.1.1)
kaminari-activerecord (1.1.1)
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
@@ -117,6 +155,8 @@ GEM
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.11.3)
momentjs-rails (2.20.1)
railties (>= 3.1)
msgpack (1.3.1)
nio4r (2.4.0)
nokogiri (1.10.4)
@@ -194,6 +234,15 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sassc (2.1.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
selectize-rails (0.12.6)
selenium-webdriver (3.142.3)
childprocess (>= 0.5, < 2.0)
rubyzip (~> 1.2, >= 1.2.2)
@@ -242,6 +291,7 @@ PLATFORMS
ruby
DEPENDENCIES
administrate!
bootsnap (>= 1.4.2)
byebug
capybara (>= 2.15)

View File

@@ -0,0 +1,31 @@
# All Administrate controllers inherit from this `Admin::ApplicationController`,
# making it the ideal place to put authentication logic or other
# before_actions.
#
# If you want to add pagination or other controller-level concerns,
# you're free to overwrite the RESTful controller actions.
module Admin
class ApplicationController < Administrate::ApplicationController
before_action :authenticate_admin
def authenticate_admin
unless user_signed_in?
flash[:alert] = "You must be logged in to access this page."
redirect_to new_user_session_path
return
end
unless current_user.moderator? || current_user.admin?
flash[:alert] = "You do not have the privilegies to access this page."
redirect_to root_path
return
end
end
# Override this value to specify the number of elements to display at a time
# on index pages. Defaults to 20.
# def records_per_page
# params[:per_page] || 20
# end
end
end

View File

@@ -0,0 +1,88 @@
module Admin
class UsersController < Admin::ApplicationController
# Overwrite any of the RESTful controller actions to implement custom behavior
# For example, you may want to send an email after a foo is updated.
#
# def update
# foo = Foo.find(params[:id])
# foo.update(params[:foo])
# send_foo_updated_email
# end
# Override this method to specify custom lookup behavior.
# This will be used to set the resource for the `show`, `edit`, and `update`
# actions.
#
# def find_resource(param)
# Foo.find_by!(slug: param)
# end
# Override this if you have certain roles that require a subset
# this will be used to set the records shown on the `index` action.
#
# def scoped_resource
# if current_user.super_admin?
# resource_class
# else
# resource_class.with_less_stuff
# end
# end
# See https://administrate-prototype.herokuapp.com/customizing_controller_actions
# for more information
def authenticate_admin
super # apply the generic rules for authentication in the admin panel...
# ...plus this one
unless current_user.admin?
flash[:alert] = "You do not have the privilegies to access this page."
redirect_to root_path
return
end
end
# overwrite default create
def create
user = User.new(user_params)
user.skip_confirmation! # automatically confirm user email
if user.save
flash[:notice] = translate_with_resource("create.success")
redirect_to admin_user_path(user)
else
render :new, locals: {
page: Administrate::Page::Form.new(dashboard, user),
}
end
end
# overwrite default update
def update
user = User.find(params[:user][:id])
if params[:user][:password].empty?
user.assign_attributes(user_params.except(:password))
else
user.assign_attributes(user_params)
end
user.skip_reconfirmation! # automatically reconfirm user email
if user.save
flash[:notice] = translate_with_resource("update.success")
redirect_to admin_user_path(user)
else
render :new, locals: {
page: Administrate::Page::Form.new(dashboard, user),
}
end
end
private
def user_params
params.require(:user).permit(:full_name, :email, :role, :password)
end
end
end

View File

@@ -0,0 +1,83 @@
require "administrate/base_dashboard"
class UserDashboard < Administrate::BaseDashboard
# ATTRIBUTE_TYPES
# a hash that describes the type of each of the model's fields.
#
# Each different type represents an Administrate::Field object,
# which determines how the attribute is displayed
# on pages throughout the dashboard.
ATTRIBUTE_TYPES = {
id: IdField,
email: Field::String,
password: Field::Password,
encrypted_password: Field::String,
reset_password_token: Field::String,
reset_password_sent_at: Field::DateTime,
remember_created_at: Field::DateTime,
confirmation_token: Field::String,
confirmed_at: Field::DateTime,
confirmation_sent_at: Field::DateTime,
unconfirmed_email: Field::String,
created_at: Field::DateTime,
updated_at: Field::DateTime,
role: RoleField,
full_name: Field::String,
}.freeze
# COLLECTION_ATTRIBUTES
# an array of attributes that will be displayed on the model's index page.
#
# By default, it's limited to four items to reduce clutter on index pages.
# Feel free to add, remove, or rearrange items.
COLLECTION_ATTRIBUTES = %i[
full_name
email
role
].freeze
# SHOW_PAGE_ATTRIBUTES
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = %i[
id
full_name
email
role
password
created_at
updated_at
confirmed_at
confirmation_sent_at
unconfirmed_email
].freeze
# FORM_ATTRIBUTES
# an array of attributes that will be displayed
# on the model's form (`new` and `edit`) pages.
FORM_ATTRIBUTES = %i[
id
full_name
email
role
password
].freeze
# COLLECTION_FILTERS
# a hash that defines filters that can be used while searching via the search
# field of the dashboard.
#
# For example to add an option to search for open resources by typing "open:"
# in the search field:
#
# COLLECTION_FILTERS = {
# open: ->(resources) { where(open: true) }
# }.freeze
COLLECTION_FILTERS = {}.freeze
# Overwrite this method to customize how users are displayed
# across all pages of the admin dashboard.
#
# def display_resource(user)
# "User ##{user.id}"
# end
end

7
app/fields/id_field.rb Normal file
View File

@@ -0,0 +1,7 @@
require "administrate/field/base"
class IdField < Administrate::Field::Base
def to_s
data.to_s
end
end

13
app/fields/role_field.rb Normal file
View File

@@ -0,0 +1,13 @@
require "administrate/field/base"
class RoleField < Administrate::Field::Base
def to_s
data.to_s
end
def select_field_values(form_builder)
form_builder.object.class.public_send(attribute.to_s.pluralize).keys.map do |v|
[v.titleize, v]
end
end
end

View File

@@ -1,4 +1,8 @@
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable
enum role: [:user, :moderator, :admin]
after_initialize :set_default_role, if: :new_record?
@@ -12,8 +16,4 @@ class User < ApplicationRecord
gravatar_id = Digest::MD5::hexdigest(email.downcase)
"https://secure.gravatar.com/avatar/#{gravatar_id}"
end
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable
end

View File

@@ -0,0 +1,19 @@
<%#
# Navigation
This partial is used to display the navigation in Administrate.
By default, the navigation contains navigation links
for all resources in the admin dashboard,
as defined by the routes in the `admin/` namespace
%>
<nav class="navigation" role="navigation">
<%= link_to "⇦ Back to site", root_path, class: "navigation__link", "data-turbolinks": "false" %>
<% Administrate::Namespace.new(namespace).resources.each do |resource| %>
<%= link_to(
display_resource_name(resource),
[namespace, resource_index_route_key(resource)],
class: "navigation__link navigation__link--#{nav_link_state(resource)}"
) %>
<% end %>
</nav>

View File

@@ -0,0 +1 @@
<%= f.text_field field.attribute, hidden: :true %>

View File

@@ -0,0 +1 @@
<%= field.to_s %>

View File

@@ -0,0 +1 @@
<%= field.to_s %>

View File

@@ -0,0 +1,6 @@
<div class="field-unit__label">
<%= f.label field.attribute %>
</div>
<div class="field-unit__field">
<%= f.select field.attribute, field.select_field_values(f) %>
</div>

View File

@@ -0,0 +1 @@
<%= field.to_s.titleize %>

View File

@@ -0,0 +1 @@
<%= field.to_s.titleize %>

View File

@@ -8,6 +8,11 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ml-auto">
<% if user_signed_in? %>
<% if current_user.moderator? || current_user.admin? %>
<li class="nav-item">
<%= link_to "Admin Panel", admin_root_path, class: "nav-link", 'data-turbolinks': 'false' %>
</li>
<% end %>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= image_tag(current_user.gravatar_url, class: "gravatar", alt: current_user.full_name, size: 24) %>

View File

@@ -1,4 +1,10 @@
Rails.application.routes.draw do
root to: 'static_pages#home'
namespace :admin do
root to: "users#index"
resources :users
end
devise_for :users
end