feat: add admin management features for cities
- Update menu labels for cities, countries, and regions - Introduce new entities for states and subregions in Admin Panel - Implement admin authentication for weather art generation - Modify application controller to check for admin user - Refactor view to display admin panel based on user permissions - Update routes to include weather art generation action These changes enhance the admin interface for better management of cities and related entities. The new admin checks ensure that only authorized users can generate weather art, improving security and functionality.
This commit is contained in:
parent
3237321db3
commit
b2551361d7
@ -1,5 +1,5 @@
|
|||||||
ActiveAdmin.register City do
|
ActiveAdmin.register City do
|
||||||
menu label: "City Manager", parent: "系统管理"
|
menu label: "Cities", parent: "数据管理"
|
||||||
controller do
|
controller do
|
||||||
def find_resource
|
def find_resource
|
||||||
scoped_collection.friendly.find(params[:id])
|
scoped_collection.friendly.find(params[:id])
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
ActiveAdmin.register Country do
|
ActiveAdmin.register Country do
|
||||||
menu label: "Country Manager", parent: "系统管理"
|
menu label: "Countries", parent: "数据管理"
|
||||||
controller do
|
controller do
|
||||||
def find_resource
|
def find_resource
|
||||||
scoped_collection.friendly.find(params[:id])
|
scoped_collection.friendly.find(params[:id])
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
ActiveAdmin.register Region do
|
ActiveAdmin.register Region do
|
||||||
menu label: "Region Manager", parent: "系统管理"
|
menu label: "Regions", parent: "数据管理"
|
||||||
# See permitted parameters documentation:
|
# See permitted parameters documentation:
|
||||||
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
|
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
|
||||||
#
|
#
|
||||||
|
19
app/admin/states.rb
Normal file
19
app/admin/states.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
ActiveAdmin.register State do
|
||||||
|
menu label: "States", parent: "数据管理"
|
||||||
|
|
||||||
|
# See permitted parameters documentation:
|
||||||
|
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
|
||||||
|
#
|
||||||
|
# Uncomment all parameters which should be permitted for assignment
|
||||||
|
#
|
||||||
|
# permit_params :name, :code, :country_id, :country_code, :fips_code, :iso2, :state_type, :level, :parent_id, :latitude, :longitude, :flag, :wiki_data_id
|
||||||
|
#
|
||||||
|
# or
|
||||||
|
#
|
||||||
|
# permit_params do
|
||||||
|
# permitted = [:name, :code, :country_id, :country_code, :fips_code, :iso2, :state_type, :level, :parent_id, :latitude, :longitude, :flag, :wiki_data_id]
|
||||||
|
# permitted << :other if params[:action] == 'create' && current_user.admin?
|
||||||
|
# permitted
|
||||||
|
# end
|
||||||
|
|
||||||
|
end
|
19
app/admin/subregions.rb
Normal file
19
app/admin/subregions.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
ActiveAdmin.register Subregion do
|
||||||
|
menu label: "SubRegions", parent: "数据管理"
|
||||||
|
|
||||||
|
# See permitted parameters documentation:
|
||||||
|
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
|
||||||
|
#
|
||||||
|
# Uncomment all parameters which should be permitted for assignment
|
||||||
|
#
|
||||||
|
# permit_params :name, :translations, :region_id, :flag, :wiki_data_id
|
||||||
|
#
|
||||||
|
# or
|
||||||
|
#
|
||||||
|
# permit_params do
|
||||||
|
# permitted = [:name, :translations, :region_id, :flag, :wiki_data_id]
|
||||||
|
# permitted << :other if params[:action] == 'create' && current_user.admin?
|
||||||
|
# permitted
|
||||||
|
# end
|
||||||
|
|
||||||
|
end
|
19
app/admin/users.rb
Normal file
19
app/admin/users.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
ActiveAdmin.register User do
|
||||||
|
menu label: "Users", parent: "数据管理"
|
||||||
|
|
||||||
|
# See permitted parameters documentation:
|
||||||
|
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
|
||||||
|
#
|
||||||
|
# Uncomment all parameters which should be permitted for assignment
|
||||||
|
#
|
||||||
|
# permit_params :email, :encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at, :admin
|
||||||
|
#
|
||||||
|
# or
|
||||||
|
#
|
||||||
|
# permit_params do
|
||||||
|
# permitted = [:email, :encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at, :admin]
|
||||||
|
# permitted << :other if params[:action] == 'create' && current_user.admin?
|
||||||
|
# permitted
|
||||||
|
# end
|
||||||
|
|
||||||
|
end
|
@ -66,6 +66,13 @@ class ApplicationController < ActionController::Base
|
|||||||
ahoy.track "Viewed Application", request.path_parameters
|
ahoy.track "Viewed Application", request.path_parameters
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def authenticate_admin_user!
|
||||||
|
unless current_user&.admin?
|
||||||
|
flash[:alert] = "您没有权限访问该页面。"
|
||||||
|
redirect_to root_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_locale
|
def set_locale
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
class CitiesController < ApplicationController
|
class CitiesController < ApplicationController
|
||||||
|
before_action :authenticate_user!, only: [:generate_weather_art]
|
||||||
|
before_action :require_admin, only: [:generate_weather_art]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@regions = Region.includes(:countries).order(:name)
|
@regions = Region.includes(:countries).order(:name)
|
||||||
@cities = City.includes(:country, country: :region).order(:name)
|
@cities = City.includes(:country, country: :region).order(:name)
|
||||||
@ -39,4 +42,26 @@ class CitiesController < ApplicationController
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def generate_weather_art
|
||||||
|
@city = City.friendly.find(params[:id])
|
||||||
|
GenerateWeatherArtWorker.perform_async(@city.id)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html do
|
||||||
|
flash[:notice] = "Weather art generation has been queued"
|
||||||
|
redirect_to @city
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def require_admin
|
||||||
|
unless current_user&.admin?
|
||||||
|
flash[:error] = "You are not authorized to perform this action"
|
||||||
|
redirect_to root_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -22,7 +22,7 @@ module ApplicationHelper
|
|||||||
}.to_json.html_safe if weather_art.image.attached?
|
}.to_json.html_safe if weather_art.image.attached?
|
||||||
end
|
end
|
||||||
|
|
||||||
def admin?
|
def current_user_is_admin?
|
||||||
current_user&.admin?
|
current_user&.admin?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,45 +1,58 @@
|
|||||||
<% if admin? %>
|
<!-- 主要统计信息后面添加 -->
|
||||||
<div class="card bg-warning/10 border border-warning/20 shadow-lg p-6">
|
<% if current_user_is_admin? %>
|
||||||
<div class="flex items-center gap-3 mb-4">
|
<div class="mt-8 p-6 bg-base-100/90 backdrop-blur-sm shadow-xl rounded-box">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-warning" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<h3 class="text-xl font-bold mb-4 flex items-center gap-2">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="font-display font-bold text-lg">Admin Panel</h3>
|
Admin Panel
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<!-- 统计数据 -->
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-6">
|
||||||
|
<div class="stat bg-base-200/50 rounded-box">
|
||||||
|
<div class="stat-title">Success Rate</div>
|
||||||
|
<div class="stat-value text-primary text-2xl">
|
||||||
|
<%= "hello" %>%
|
||||||
|
</div>
|
||||||
|
<div class="stat-desc">Generation Success Rate</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat bg-base-200/50 rounded-box">
|
||||||
|
<div class="stat-title">Last Generated</div>
|
||||||
|
<div class="stat-value text-2xl">
|
||||||
|
<%= time_ago_in_words(@city.weather_arts.last&.created_at) if @city.weather_arts.last %>
|
||||||
|
</div>
|
||||||
|
<div class="stat-desc">Time since last generation</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat bg-base-200/50 rounded-box">
|
||||||
|
<div class="stat-title">Failed Attempts</div>
|
||||||
|
<div class="stat-value text-error text-2xl">
|
||||||
|
<%= "hello" %>
|
||||||
|
</div>
|
||||||
|
<div class="stat-desc">Total failed generations</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<!-- 操作按钮 -->
|
||||||
<!-- 统计数据 -->
|
<div class="flex flex-wrap gap-4">
|
||||||
<div class="space-y-4">
|
<%= button_to generate_weather_art_city_path(@city),
|
||||||
<h4 class="font-semibold">Statistics</h4>
|
method: :post,
|
||||||
<div class="stats stats-vertical lg:stats-horizontal shadow">
|
class: "btn btn-primary gap-2" do %>
|
||||||
<div class="stat">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<div class="stat-title">Total Images</div>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||||
<div class="stat-value"><%= @weather_art.city.weather_arts.count %></div>
|
</svg>
|
||||||
</div>
|
Generate New Art
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<div class="stat">
|
<%= link_to edit_city_path(@city),
|
||||||
<div class="stat-title">Today's Images</div>
|
class: "btn btn-secondary gap-2" do %>
|
||||||
<div class="stat-value"><%= @weather_art.city.weather_arts.where("created_at >= ?", Time.zone.now.beginning_of_day).count %></div>
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
</div>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
</div>
|
</svg>
|
||||||
</div>
|
Edit City
|
||||||
|
<% end %>
|
||||||
<!-- 操作按钮 -->
|
|
||||||
<div class="space-y-4">
|
|
||||||
<h4 class="font-semibold">Actions</h4>
|
|
||||||
<div class="flex flex-wrap gap-4">
|
|
||||||
<%= button_to "Generate New Art", "#",
|
|
||||||
method: :post,
|
|
||||||
data: {
|
|
||||||
controller: "generate-art",
|
|
||||||
action: "generate-art#generate",
|
|
||||||
city_id: @weather_art.city.id
|
|
||||||
},
|
|
||||||
class: "btn btn-primary" %>
|
|
||||||
|
|
||||||
<%= link_to "Edit City", edit_city_path(@weather_art.city), class: "btn btn-secondary" %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
@ -71,6 +71,8 @@
|
|||||||
<div class="stat-desc mt-1">Total Weather Arts</div>
|
<div class="stat-desc mt-1">Total Weather Arts</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<%= render 'cities/admin_panel' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -108,7 +108,8 @@ ActiveAdmin.setup do |config|
|
|||||||
#
|
#
|
||||||
# This setting changes the method which Active Admin calls
|
# This setting changes the method which Active Admin calls
|
||||||
# (within the application controller) to return the currently logged in user.
|
# (within the application controller) to return the currently logged in user.
|
||||||
config.current_user_method = :current_admin_user
|
# config.current_user_method = :current_admin_user
|
||||||
|
config.current_user_method = :current_user
|
||||||
|
|
||||||
# == Logging Out
|
# == Logging Out
|
||||||
#
|
#
|
||||||
@ -120,13 +121,15 @@ ActiveAdmin.setup do |config|
|
|||||||
# will call the method to return the path.
|
# will call the method to return the path.
|
||||||
#
|
#
|
||||||
# Default:
|
# Default:
|
||||||
config.logout_link_path = :destroy_admin_user_session_path
|
# config.logout_link_path = :destroy_admin_user_session_path
|
||||||
|
config.logout_link_path = :destroy_user_session_path
|
||||||
|
|
||||||
# This setting changes the http method used when rendering the
|
# This setting changes the http method used when rendering the
|
||||||
# link. For example :get, :delete, :put, etc..
|
# link. For example :get, :delete, :put, etc..
|
||||||
#
|
#
|
||||||
# Default:
|
# Default:
|
||||||
# config.logout_link_method = :get
|
# config.logout_link_method = :get
|
||||||
|
config.logout_link_method = :delete
|
||||||
|
|
||||||
# == Root
|
# == Root
|
||||||
#
|
#
|
||||||
|
@ -24,7 +24,7 @@ Devise.setup do |config|
|
|||||||
# Configure the e-mail address which will be shown in Devise::Mailer,
|
# Configure the e-mail address which will be shown in Devise::Mailer,
|
||||||
# note that it will be overwritten if you use your own mailer class
|
# note that it will be overwritten if you use your own mailer class
|
||||||
# with default "from" parameter.
|
# with default "from" parameter.
|
||||||
config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
|
config.mailer_sender = "noreply@mail.frytea.com"
|
||||||
|
|
||||||
# Configure the class responsible to send e-mails.
|
# Configure the class responsible to send e-mails.
|
||||||
# config.mailer = 'Devise::Mailer'
|
# config.mailer = 'Devise::Mailer'
|
||||||
|
@ -7,6 +7,11 @@ Rails.application.routes.draw do
|
|||||||
resources :cities, only: [ :index, :show ] do
|
resources :cities, only: [ :index, :show ] do
|
||||||
resources :weather_arts, path: "weather", only: [ :show ], param: :slug
|
resources :weather_arts, path: "weather", only: [ :show ], param: :slug
|
||||||
end
|
end
|
||||||
|
resources :cities do
|
||||||
|
member do
|
||||||
|
post :generate_weather_art, param: :slug
|
||||||
|
end
|
||||||
|
end
|
||||||
resources :arts, only: [ :index ]
|
resources :arts, only: [ :index ]
|
||||||
|
|
||||||
# namespace :admin do
|
# namespace :admin do
|
||||||
@ -25,7 +30,8 @@ Rails.application.routes.draw do
|
|||||||
ActiveAdmin.routes(self)
|
ActiveAdmin.routes(self)
|
||||||
|
|
||||||
# mount Sidekiq::Web => '/sidekiq'
|
# mount Sidekiq::Web => '/sidekiq'
|
||||||
authenticate :admin_user do
|
# authenticate :admin_user do
|
||||||
|
authenticate :user, lambda { |u| u.admin? } do
|
||||||
mount Sidekiq::Web => "/admin/tasks"
|
mount Sidekiq::Web => "/admin/tasks"
|
||||||
end
|
end
|
||||||
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
||||||
|
Loading…
Reference in New Issue
Block a user