Admin protetto, dashboard KPI e aggiornamenti sito marketing.

Login admin con cambio password, metriche server (CPU/RAM/disco/banda), grafici e statistiche streaming; sezione piani ridimensionata.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-26 18:18:47 +02:00
parent 3d3420cc4a
commit 3a5649f482
26 changed files with 983 additions and 55 deletions

View File

@@ -0,0 +1,25 @@
module Admin
class AuthController < Admin::BaseController
skip_before_action :require_admin_login, only: %i[new create]
def new
redirect_to admin_root_path if admin_logged_in?
end
def create
account = AdminAccount.find_by(username: params[:username]&.strip)
if account&.authenticate(params[:password])
session[:admin_account_id] = account.id
redirect_to session.delete(:admin_return_to) || admin_root_path, notice: "Accesso effettuato"
else
flash.now[:alert] = "Username o password non validi"
render :new, status: :unauthorized
end
end
def destroy
reset_session
redirect_to admin_login_path, notice: "Disconnesso"
end
end
end

View File

@@ -1,6 +1,30 @@
module Admin
class BaseController < ActionController::Base
layout "admin"
protect_from_forgery with: :null_session
protect_from_forgery with: :exception
before_action :require_admin_login
include ::AdminHelper
helper_method :current_admin_account, :admin_logged_in?
private
def require_admin_login
return if admin_logged_in?
session[:admin_return_to] = request.fullpath unless request.path == admin_login_path
redirect_to admin_login_path, alert: "Accedi per continuare"
end
def current_admin_account
return unless session[:admin_account_id]
@current_admin_account ||= AdminAccount.find_by(id: session[:admin_account_id])
end
def admin_logged_in?
current_admin_account.present?
end
end
end

View File

@@ -1,8 +1,19 @@
module Admin
class DashboardController < Admin::BaseController
def index
@teams = Team.includes(:matches).order(:name)
@active_sessions = StreamSession.where(status: %w[live reconnecting connecting]).includes(:match)
@stats = DashboardStats.new.call
@host = HostMetrics.new.sample!
@active_sessions = StreamSession
.where(status: DashboardStats::ACTIVE_STATUSES)
.includes(match: :team)
.order(started_at: :desc)
@teams = Team.includes(:matches).order(:name).limit(8)
end
def metrics
host = HostMetrics.new.sample!
stats = DashboardStats.new.call
render json: { host: host, stats: stats, at: Time.current.iso8601 }
end
end
end

View File

@@ -0,0 +1,30 @@
module Admin
class PasswordsController < Admin::BaseController
def edit
end
def update
unless current_admin_account.authenticate(params[:current_password])
flash.now[:alert] = "Password attuale non corretta"
return render :edit, status: :unprocessable_entity
end
if params[:password].blank? || params[:password].length < 8
flash.now[:alert] = "La nuova password deve avere almeno 8 caratteri"
return render :edit, status: :unprocessable_entity
end
if params[:password] != params[:password_confirmation]
flash.now[:alert] = "Le password non coincidono"
return render :edit, status: :unprocessable_entity
end
if current_admin_account.update(password: params[:password])
redirect_to admin_root_path, notice: "Password aggiornata"
else
flash.now[:alert] = current_admin_account.errors.full_messages.to_sentence
render :edit, status: :unprocessable_entity
end
end
end
end