chore: init commit

in worker.../repo/GITFOLDER.zip is the .git folder.
This commit is contained in:
2026-08-11 14:44:09 -04:00
parent 0012380fd3
commit 392781f7aa
781 changed files with 65944 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
# frozen_string_literal: true
module Admin
class AnnouncementsController < BaseController
before_action :set_announcement, only: %i[show edit update destroy]
def index
sort_column = params[:sort].presence || "created_at"
sort_direction = params[:direction] == "desc" ? :desc : :asc
@announcements = Announcement.reorder(sort_column => sort_direction)
@breadcrumbs = [
{ label: "Announcements" }
]
end
def show
@breadcrumbs = [
{ label: "Announcements", path: admin_announcements_path },
{ label: @announcement.title }
]
end
def new
@announcement = Announcement.new
@breadcrumbs = [
{ label: "Announcements", path: admin_announcements_path },
{ label: "New Announcement" }
]
end
def edit
@breadcrumbs = [
{ label: "Announcements", path: admin_announcements_path },
{ label: @announcement.title, path: admin_announcement_path(@announcement) },
{ label: "Edit" }
]
end
def create
@announcement = Announcement.new(announcement_params)
if @announcement.save
redirect_to admin_announcement_path(@announcement), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Announcements", path: admin_announcements_path },
{ label: "New Announcement" }
]
render :new, status: :unprocessable_content
end
end
def update
if @announcement.update(announcement_params)
redirect_to admin_announcement_path(@announcement), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Announcements", path: admin_announcements_path },
{ label: @announcement.title, path: admin_announcement_path(@announcement) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
@announcement.destroy
redirect_to admin_announcements_path, notice: t(".notice")
end
private
def set_announcement
@announcement = Announcement.find(params.expect(:id))
end
def announcement_params
params.expect(announcement: %i[title content featured])
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
# Base controller for in-house admin.
# All Admin controllers inherit from this controller.
module Admin
class BaseController < ApplicationController
layout "admin"
before_action :authenticate_admin
private
def authenticate_admin
redirect_to root_path, alert: t("application.access_denied.admin_required") unless current_user&.admin?
end
# Apply sorting to a collection based on params
# @param collection [ActiveRecord::Relation] The base collection to sort
# @param default [String] The default column to sort by
# @return [ActiveRecord::Relation] The sorted collection
def apply_sorting(collection, default:)
sort_column = params[:sort].presence || default
sort_direction = params[:direction] == "desc" ? :desc : :asc
collection.reorder(sort_column => sort_direction)
end
end
end

View File

@@ -0,0 +1,83 @@
# frozen_string_literal: true
module Admin
class ClassroomsController < BaseController
before_action :set_classroom, only: %i[show edit update toggle_archive]
def index
@classrooms = apply_sorting(Classroom.all, default: "name")
@breadcrumbs = [
{ label: "Classrooms" }
]
end
def show
@breadcrumbs = [
{ label: "Classrooms", path: admin_classrooms_path },
{ label: @classroom.name }
]
end
def new
@classroom = Classroom.new
@breadcrumbs = [
{ label: "Classrooms", path: admin_classrooms_path },
{ label: "New Classroom" }
]
end
def edit
@breadcrumbs = [
{ label: "Classrooms", path: admin_classrooms_path },
{ label: @classroom.name, path: admin_classroom_path(@classroom) },
{ label: "Edit" }
]
end
def create
@classroom = Classroom.new(classroom_params)
if @classroom.save
redirect_to admin_classroom_path(@classroom), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Classrooms", path: admin_classrooms_path },
{ label: "New Classroom" }
]
render :new, status: :unprocessable_content
end
end
def update
if @classroom.update(classroom_params)
redirect_to admin_classroom_path(@classroom), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Classrooms", path: admin_classrooms_path },
{ label: @classroom.name, path: admin_classroom_path(@classroom) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def toggle_archive
authorize @classroom, :toggle_archive?
@classroom.update!(archived: !@classroom.archived)
flash[:notice] = @classroom.archived? ? "Classroom has been archived." : "Classroom has been activated."
redirect_to admin_classroom_path(@classroom)
end
private
def set_classroom
@classroom = Classroom.find(params.expect(:id))
end
def classroom_params
params.expect(classroom: [:name, :trading_enabled, :school_year_id, { grade_ids: [] }])
end
end
end

View File

@@ -0,0 +1,80 @@
# frozen_string_literal: true
module Admin
class ComponentDemoController < BaseController
# rubocop:disable Metrics/MethodLength
def index
# Demo data for table component - apply sorting before limit
@users = User.all
# Apply sorting if params present
if params[:sort].present?
direction = params[:direction] == "desc" ? :desc : :asc
@users = @users.order(params[:sort] => direction)
end
@users = @users.limit(10)
# Demo data for show component
@sample_user = User.first || User.new(
email: "demo@example.com",
name: "Demo User",
admin: true,
created_at: Time.current
)
# Demo breadcrumbs
@breadcrumbs = [
{ label: "Components", path: admin_component_demo_index_path },
{ label: "Demo" }
]
# Demo table columns
@columns = [
{ attribute: :id, label: "ID", sortable: true },
{ attribute: :email, label: "Email", sortable: true },
{ attribute: :name, label: "Name", sortable: true },
{ attribute: :admin, label: "Admin", sortable: true },
{ attribute: :created_at, label: "Created", sortable: true }
]
# Demo filters
@filters = [
{
name: :type,
label: "User Type",
options: [["All", ""], ["Admin", "admin"], ["Teacher", "teacher"], ["Student", "student"]]
},
{
name: :status,
label: "Status",
options: [["All", ""], ["Active", "active"], ["Inactive", "inactive"]]
}
]
end
# rubocop:enable Metrics/MethodLength
def show
@user = User.find(params.expect(:id))
@breadcrumbs = [
{ label: "Components", path: admin_component_demo_index_path },
{ label: "User Details" }
]
end
def form
@user = User.first || User.new(email: "", name: "", admin: false)
# Add validation errors for demo purposes if requested
if params[:show_errors] == "true"
@user.errors.add(:email, "can't be blank")
@user.errors.add(:name, "is too short (minimum is 3 characters)")
end
@breadcrumbs = [
{ label: "Components", path: admin_component_demo_index_path },
{ label: "Form Builder Demo" }
]
end
end
end

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
module Admin
class DashboardController < BaseController
def index
# Dashboard will show overview of admin resources
end
end
end

View File

@@ -0,0 +1,90 @@
# frozen_string_literal: true
module Admin
class PortfolioTransactionsController < BaseController
before_action :set_portfolio_transaction, only: %i[show edit update destroy]
def show
# TODO: FIX
# authorize @portfolio_transaction
@breadcrumbs = [
{ label: "Portfolio Transaction ##{@portfolio_transaction.id}" }
]
end
def new
@portfolio_transaction = PortfolioTransaction.new
# TODO: FIX
# authorize @portfolio_transaction
@breadcrumbs = [
{ label: "Portfolio Transactions", path: "#" },
{ label: "New" }
]
end
def edit
# TODO: Determine if explicit authorization is needed since BaseController already restricts to admins
# authorize @portfolio_transaction
@breadcrumbs = [
{ label: "Portfolio Transaction ##{@portfolio_transaction.id}",
path: admin_portfolio_transaction_path(@portfolio_transaction) },
{ label: "Edit" }
]
end
def create
@portfolio_transaction = PortfolioTransaction.new(portfolio_transaction_params)
# TODO: Determine if explicit authorization is needed since BaseController already restricts to admins
# authorize @portfolio_transaction
if @portfolio_transaction.save
redirect_to admin_portfolio_transaction_path(@portfolio_transaction),
notice: t(".notice")
else
@breadcrumbs = [
{ label: "Portfolio Transactions", path: "#" },
{ label: "New" }
]
render :new, status: :unprocessable_content
end
end
def update
# TODO: Determine if explicit authorization is needed since BaseController already restricts to admins
# authorize @portfolio_transaction
if @portfolio_transaction.update(portfolio_transaction_params)
redirect_to admin_portfolio_transaction_path(@portfolio_transaction),
notice: t(".notice")
else
@breadcrumbs = [
{ label: "Portfolio Transaction ##{@portfolio_transaction.id}",
path: admin_portfolio_transaction_path(@portfolio_transaction) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
# TODO: Determine if explicit authorization is needed since BaseController already restricts to admins
# authorize @portfolio_transaction
@portfolio_transaction.destroy
redirect_to admin_root_path, notice: t(".notice")
end
private
def set_portfolio_transaction
@portfolio_transaction = PortfolioTransaction.find(params.expect(:id))
end
def portfolio_transaction_params
params.expect(portfolio_transaction: %i[portfolio_id transaction_type reason description amount_cents])
end
end
end

View File

@@ -0,0 +1,111 @@
# frozen_string_literal: true
module Admin
class SchoolYearsController < BaseController
before_action :set_school_year, only: %i[show edit update destroy]
def index
@school_years = apply_sorting(SchoolYear.includes(:school, :year), default: "id")
@breadcrumbs = [
{ label: "School Years" }
]
end
def show
@breadcrumbs = [
{ label: "School Years", path: admin_school_years_path },
{ label: @school_year.to_s }
]
end
def new
@school_year = SchoolYear.new
@breadcrumbs = [
{ label: "School Years", path: admin_school_years_path },
{ label: "New School Year" }
]
end
def edit
@breadcrumbs = [
{ label: "School Years", path: admin_school_years_path },
{ label: @school_year.to_s, path: admin_school_year_path(@school_year) },
{ label: "Edit" }
]
end
def create
school = School.find_by(id: school_year_params[:school_id])
year = Year.find_by(id: school_year_params[:year_id])
unless school && year
@school_year = SchoolYear.new(school_year_params)
@school_year.valid?
return render_new_with_errors
end
@school_year = SchoolYear.create!(school:, year:)
if @school_year.persisted?
redirect_to admin_school_year_path(@school_year), notice: t(".notice")
else
render_new_with_errors
end
rescue ActiveRecord::RecordNotUnique
save_error(school_year_params)
render_new_with_errors
rescue ActiveRecord::RecordInvalid => e
@school_year = e.record
render_new_with_errors
end
def update
if @school_year.update(school_year_params)
redirect_to admin_school_year_path(@school_year), notice: t(".notice")
else
@breadcrumbs = [
{ label: "School Years", path: admin_school_years_path },
{ label: @school_year.to_s, path: admin_school_year_path(@school_year) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
if @school_year.destroy
redirect_to admin_school_years_path, notice: t(".notice")
else
redirect_to admin_school_years_path, alert: t(".delete_restricted")
end
rescue ActiveRecord::DeleteRestrictionError
redirect_to admin_school_years_path, alert: t(".delete_restricted")
end
private
def set_school_year
@school_year = SchoolYear.find(params.expect(:id))
end
def school_year_params
params.expect(school_year: %i[school_id year_id])
end
def render_new_with_errors
@breadcrumbs = [
{ label: "School Years", path: admin_school_years_path },
{ label: "New School Year" }
]
render :new, status: :unprocessable_content
end
def save_error(params)
@school_year = SchoolYear.new(params)
@school_year.valid?
@school_year.errors.add(:base, "A School year with this school and year already exists.")
end
end
end

View File

@@ -0,0 +1,97 @@
# frozen_string_literal: true
module Admin
class SchoolsController < BaseController
before_action :set_school, only: %i[show edit update destroy]
def index
sort_column = params[:sort].presence || "name"
sort_direction = params[:direction] == "desc" ? :desc : :asc
@schools = School.reorder(sort_column => sort_direction)
@breadcrumbs = [
{ label: "Schools" }
]
end
def show
@breadcrumbs = [
{ label: "Schools", path: admin_schools_path },
{ label: @school.name }
]
end
def new
@school = School.new
set_form_data
@breadcrumbs = [
{ label: "Schools", path: admin_schools_path },
{ label: "New School" }
]
end
def edit
set_form_data
@breadcrumbs = [
{ label: "Schools", path: admin_schools_path },
{ label: @school.name, path: admin_school_path(@school) },
{ label: "Edit" }
]
end
def create
year_ids = school_params[:year_ids]&.reject(&:blank?)
@school = School.new(school_params.except(:year_ids))
@school.year_ids = year_ids if year_ids.present?
if @school.save
redirect_to admin_school_path(@school), notice: t(".notice")
else
set_form_data
@breadcrumbs = [
{ label: "Schools", path: admin_schools_path },
{ label: "New School" }
]
render :new, status: :unprocessable_content
end
end
def update
year_ids = school_params[:year_ids]&.reject(&:blank?)
update_params = school_params.except(:year_ids)
update_params[:year_ids] = year_ids || []
if @school.update(update_params)
redirect_to admin_school_path(@school), notice: t(".notice")
else
set_form_data
@breadcrumbs = [
{ label: "Schools", path: admin_schools_path },
{ label: @school.name, path: admin_school_path(@school) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
@school.destroy
redirect_to admin_schools_path, notice: t(".notice")
end
private
def set_school
@school = School.find(params.expect(:id))
end
def set_form_data
@years = Year.ordered_by_start_year
end
def school_params
params.expect(school: [:name, { year_ids: [] }])
end
end
end

View File

@@ -0,0 +1,108 @@
# frozen_string_literal: true
module Admin
class StocksController < BaseController
before_action :set_stock, only: %i[show edit update destroy]
def index
@stocks = apply_sorting(Stock.all, default: "ticker")
@breadcrumbs = [
{ label: "Stocks" }
]
end
def show
@breadcrumbs = [
{ label: "Stocks", path: admin_stocks_path },
{ label: @stock.ticker }
]
end
def new
@stock = Stock.new
@breadcrumbs = [
{ label: "Stocks", path: admin_stocks_path },
{ label: "New Stock" }
]
end
def edit
@breadcrumbs = [
{ label: "Stocks", path: admin_stocks_path },
{ label: @stock.ticker, path: admin_stock_path(@stock) },
{ label: "Edit" }
]
end
def create
@stock = Stock.new(stock_params)
if @stock.save
redirect_to admin_stock_path(@stock), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Stocks", path: admin_stocks_path },
{ label: "New Stock" }
]
render :new, status: :unprocessable_content
end
end
def update
if @stock.update(stock_params)
redirect_to admin_stock_path(@stock), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Stocks", path: admin_stocks_path },
{ label: @stock.ticker, path: admin_stock_path(@stock) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
@stock.destroy
redirect_to admin_stocks_path, notice: t(".notice")
rescue ActiveRecord::DeleteRestrictionError => e
redirect_to admin_stocks_path, alert: "Cannot delete stock: #{e.message}"
end
private
def set_stock
@stock = Stock.find(params.expect(:id))
end
# rubocop:disable Metrics/MethodLength
def stock_params
params.expect(
stock: %i[
ticker
company_name
company_website
stock_exchange
description
price_cents
yesterday_price_cents
employees
industry
cash_flow
debt
debt_to_equity
profit_margin
sales_growth
industry_avg_debt_to_equity
industry_avg_profit_margin
industry_avg_sales_growth
management
competitor_names
archived
]
)
end
# rubocop:enable Metrics/MethodLength
end
end

View File

@@ -0,0 +1,235 @@
# frozen_string_literal: true
module Admin
# rubocop:disable Metrics/ClassLength
class StudentsController < BaseController
include SoftDeletableFiltering
before_action :set_student, only: %i[show edit update destroy add_transaction]
before_action :set_discarded_student, only: %i[restore]
def index
@students = apply_sorting(scoped_by_discard_status(Student), default: "username")
@breadcrumbs = [
{ label: "Students" }
]
end
def show
@attendance_entries = AttendanceEntryPresenter.for_student(@student)
@earnings_summary = EarningsSummary.new(@student.portfolio) if @student.portfolio.present?
@breadcrumbs = [
{ label: "Students", path: admin_students_path },
{ label: @student.username }
]
end
def new
@student = Student.new
@breadcrumbs = [
{ label: "Students", path: admin_students_path },
{ label: "New Student" }
]
end
def edit
@breadcrumbs = [
{ label: "Students", path: admin_students_path },
{ label: @student.username, path: admin_student_path(@student) },
{ label: "Edit" }
]
end
def create
@student = Student.new(student_params)
# Generate a memorable password if not provided
if @student.password.blank?
generated_password = MemorablePasswordGenerator.generate
@student.password = generated_password
@student.password_confirmation = generated_password
else
generated_password = @student.password
end
if @student.save
redirect_to admin_student_path(@student),
notice: t(".notice", username: @student.username, password: generated_password)
else
@breadcrumbs = [
{ label: "Students", path: admin_students_path },
{ label: "New Student" }
]
render :new, status: :unprocessable_content
end
end
def update
if @student.update(student_params)
redirect_to admin_student_path(@student), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Students", path: admin_students_path },
{ label: @student.username, path: admin_student_path(@student) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
username = @student.username
@student.discard
redirect_to admin_students_path, notice: t(".notice", username: username)
end
def restore
username = @student.username
@student.undiscard
redirect_to admin_students_path(discarded: true), notice: t(".notice", username: username)
end
def add_transaction
errors = validate_transaction_params
if errors.present?
redirect_to edit_admin_student_path(@student), alert: errors.join(", ")
else
transaction = PortfolioTransaction.new(
portfolio: @student.portfolio,
amount_cents: transaction_amount_cents,
transaction_type: transaction_type,
reason: transaction_reason,
description: transaction_description
)
if transaction.save
redirect_to admin_student_path(@student), notice: t(".notice")
else
redirect_to edit_admin_student_path(@student), alert: transaction.errors.full_messages.join(", ")
end
end
end
def import
return redirect_with_missing_file_error if params[:csv_file].blank?
begin
results = BulkStudentImportService.import_from_csv(params.expect(:csv_file).path)
redirect_with_import_results(results)
rescue CSV::MalformedCSVError => e
redirect_to admin_students_path, alert: "Invalid CSV format: #{e.message}"
end
end
def template
send_data BulkStudentImportService.generate_csv_template,
filename: "student_import_template.csv",
type: "text/csv",
disposition: "attachment"
end
private
def set_discarded_student
@student = Student.with_discarded.find(params.expect(:id))
end
def set_student
@student = Student.find(params.expect(:id))
end
def student_params
params.expect(student: %i[username classroom_id password password_confirmation])
end
def transaction_params
params.permit(:add_fund_amount, :transaction_type, :transaction_reason, :transaction_description)
end
def transaction_amount_cents
amount = transaction_params[:add_fund_amount]
amount.present? ? (amount.to_f * 100).to_i : nil
end
def transaction_type
transaction_params[:transaction_type]
end
def transaction_reason
transaction_params[:transaction_reason]
end
def transaction_description
transaction_params[:transaction_description]
end
def validate_transaction_params
errors = []
errors << t("admin.students.add_transaction.errors.transaction_type_blank") if transaction_type.blank?
errors << t("admin.students.add_transaction.errors.amount_blank") if transaction_amount_cents.blank?
errors << t("admin.students.add_transaction.errors.reason_blank") if transaction_reason.blank?
errors
end
def redirect_with_missing_file_error
redirect_to admin_students_path, alert: t(".errors.no_file")
end
def redirect_with_import_results(results)
return redirect_with_no_results_error if results.empty?
created, skipped, failed = partition_results(results)
success_messages = build_success_messages(created, skipped)
if failed.any?
redirect_with_mixed_results(success_messages, failed)
else
redirect_to admin_students_path, notice: success_messages.join(". ")
end
end
def redirect_with_no_results_error
redirect_to admin_students_path, alert: t(".errors.no_students")
end
def partition_results(results)
[
results.select(&:created?),
results.select(&:skipped?),
results.select(&:failed?)
]
end
def build_success_messages(created, skipped)
messages = []
messages << build_created_message(created) if created.any?
messages << build_skipped_message(skipped) if skipped.any?
messages
end
def build_created_message(created)
usernames = created.map { |item| item.student.username }
"Successfully created #{created.count} students: #{usernames.join(', ')}"
end
def build_skipped_message(skipped)
"Skipped #{skipped.count} existing usernames"
end
def redirect_with_mixed_results(success_messages, failed)
error_messages = failed.map { |item| "Row #{item.line_number}: #{item.error_message}" }
alert_message = "#{failed.count} errors occurred: #{error_messages.join(', ')}"
if success_messages.any?
redirect_to admin_students_path, notice: success_messages.join(". "), alert: alert_message
else
redirect_to admin_students_path, alert: alert_message
end
end
end
# rubocop:enable Metrics/ClassLength
end

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
module Admin
module Teachers
class DeactivationsController < BaseController
before_action :set_teacher
def create
username = @teacher.username
@teacher.discard
redirect_back_or_to admin_teachers_path, notice: t(".notice", username: username)
end
private
def set_teacher
@teacher = Teacher.find(params.expect(:teacher_id))
end
end
end
end

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
module Admin
module Teachers
class ReactivationsController < BaseController
before_action :set_teacher
def create
username = @teacher.username
@teacher.undiscard
redirect_back_or_to admin_teachers_path, notice: t(".notice", username: username)
end
private
def set_teacher
@teacher = Teacher.with_discarded.find(params.expect(:teacher_id))
end
end
end
end

View File

@@ -0,0 +1,115 @@
# frozen_string_literal: true
module Admin
class TeachersController < BaseController
include SoftDeletableFiltering
before_action :set_teacher, only: %i[show edit update destroy]
before_action :require_deactivated, only: %i[destroy]
def index
@teachers = apply_sorting(scoped_by_discard_status(Teacher), default: "username")
@breadcrumbs = [
{ label: "Teachers" }
]
end
def show
@breadcrumbs = [
{ label: "Teachers", path: admin_teachers_path },
{ label: @teacher.username }
]
end
def new
@teacher = Teacher.new
set_form_data
@breadcrumbs = [
{ label: "Teachers", path: admin_teachers_path },
{ label: "New Teacher" }
]
end
def edit
set_form_data
@breadcrumbs = [
{ label: "Teachers", path: admin_teachers_path },
{ label: @teacher.username, path: admin_teacher_path(@teacher) },
{ label: "Edit" }
]
end
def create
temp_password = Devise.friendly_token.first(20)
classroom_ids = teacher_params[:classroom_ids]&.reject(&:blank?)
@teacher = Teacher.new(teacher_params.except(:classroom_ids).merge(password: temp_password))
@teacher.classroom_ids = classroom_ids if classroom_ids.present?
if @teacher.save
@teacher.send_reset_password_instructions
redirect_to admin_teacher_path(@teacher), notice: t(".notice")
else
set_form_data
@breadcrumbs = [
{ label: "Teachers", path: admin_teachers_path },
{ label: "New Teacher" }
]
render :new, status: :unprocessable_content
end
end
def update
classroom_ids = teacher_params[:classroom_ids]&.reject(&:blank?)
update_params = teacher_params.except(:classroom_ids)
update_params[:classroom_ids] = classroom_ids if classroom_ids.present?
if @teacher.update(update_params)
redirect_to admin_teacher_path(@teacher), notice: t(".notice")
else
set_form_data
@breadcrumbs = [
{ label: "Teachers", path: admin_teachers_path },
{ label: @teacher.username, path: admin_teacher_path(@teacher) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
username = @teacher.username
@teacher.really_destroy!
redirect_to admin_teachers_path, notice: t(".notice", username: username)
end
private
def set_teacher
@teacher = Teacher.find(params.expect(:id))
end
def require_deactivated
return if @teacher.discarded?
redirect_to edit_admin_teacher_path(@teacher), alert: t("admin.teachers.destroy.must_be_deactivated")
end
def teacher_params
params.expect(teacher: [:email, :name, { classroom_ids: [] }])
end
def set_form_data
active_years = Year.current_school_year(Date.current)
@schools = School.joins(:school_years).where(school_years: { year_id: active_years.ids }).distinct.order(:name)
@selected_school_id = params[:school_id] || @teacher.classrooms.first&.school&.id
@classrooms = Classroom.active.joins(:school_year).where(school_years: { year_id: active_years.ids })
@classrooms = @classrooms.where(school_years: { school_id: @selected_school_id }) if @selected_school_id.present?
@classrooms = @classrooms.order(:name)
end
end
end

View File

@@ -0,0 +1,81 @@
# frozen_string_literal: true
module Admin
class UsersController < BaseController
before_action :set_user, only: %i[show edit update destroy]
def index
@users = apply_sorting(User.all, default: "username")
@breadcrumbs = [
{ label: "Users" }
]
end
def show
@breadcrumbs = [
{ label: "Users", path: admin_users_path },
{ label: @user.username }
]
end
def new
@user = User.new
@breadcrumbs = [
{ label: "Users", path: admin_users_path },
{ label: "New User" }
]
end
def edit
@breadcrumbs = [
{ label: "Users", path: admin_users_path },
{ label: @user.username, path: admin_user_path(@user) },
{ label: "Edit" }
]
end
def create
@user = User.new(user_params)
if @user.save
redirect_to admin_user_path(@user), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Users", path: admin_users_path },
{ label: "New User" }
]
render :new, status: :unprocessable_content
end
end
def update
if @user.update(user_params)
redirect_to admin_user_path(@user), notice: t(".notice")
else
@breadcrumbs = [
{ label: "Users", path: admin_users_path },
{ label: @user.username, path: admin_user_path(@user) },
{ label: "Edit" }
]
render :edit, status: :unprocessable_content
end
end
def destroy
@user.destroy
redirect_to admin_users_path, notice: t(".notice")
end
private
def set_user
@user = User.find(params.expect(:id))
end
def user_params
params.expect(user: %i[username email type admin classroom_id password password_confirmation])
end
end
end