Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions app/controllers/badge_batches_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# typed: false
# frozen_string_literal: true

class BadgeBatchesController < ApplicationController
before_action :require_admin
before_action :set_badge_batch, only: %i[show edit update]

def index
@badge_batches = BadgeBatch.includes(:badges).order(created_at: :desc)
end

def show
@badges = @badge_batch.badges.order(:id)
end

def new
@badge_batch = BadgeBatch.new
end

def create
count = badge_batch_params[:count].to_i
note = badge_batch_params[:note]

badge_batch = BadgeBatch.create!(note: note, count: count)

badge_ids = Badge.generate_random_ids(count)

timestamp = Time.current
badge_records = badge_ids.map do |id|
{id: id, badge_batch_id: badge_batch.id, created_at: timestamp,
updated_at: timestamp}
end
Badge.insert_all(badge_records)

flash[:success] = t("badges.messages.batch_created", count: count)
redirect_to badge_batch_path(badge_batch)
end

def edit
end

def update
if @badge_batch.update(note_param)
flash[:success] = t("badges.messages.batch_updated")
redirect_to badge_batch_path(@badge_batch)
else
render :edit
end
end

def search
query = params[:query]&.strip&.upcase

if query.blank?
redirect_to badge_batches_path
return
end

badge = Badge.find_by(id: query)

if badge
flash[:success] = t("badges.messages.search_success")
redirect_to badge_path(badge)
else
flash[:alert] = t("badges.messages.search_not_found", query: query)
redirect_to badge_batches_path
end
end

private

def set_badge_batch
@badge_batch = BadgeBatch.find(params[:id])
end

def badge_batch_params
params.require(:badge_batch).permit(:count, :note)
end

def note_param
params.require(:badge_batch).permit(:note)
end
end
34 changes: 34 additions & 0 deletions app/controllers/badges_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# typed: false
# frozen_string_literal: true

class BadgesController < ApplicationController
before_action :require_admin
before_action :set_badge, only: %i[show edit update]

def show
@badge_batch = @badge.badge_batch
@units = Unit.where(id: @badge.id)
end

def edit
end

def update
if @badge.update(note_params)
flash[:success] = t("badges.messages.badge_updated")
redirect_to badge_batch_path(@badge.badge_batch)
else
render :edit
end
end

private

def set_badge
@badge = Badge.find(params[:id])
end

def note_params
params.require(:badge).permit(:note)
end
end
3 changes: 2 additions & 1 deletion app/javascript/dirty_forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class DirtyForms {
formAction.includes("/login") ||
formAction.includes("/register") ||
formAction.includes("/safety_standards") ||
formAction.includes("/search")
formAction.includes("/search") ||
formAction.includes("/badge_batches")
) {
return;
}
Expand Down
10 changes: 10 additions & 0 deletions app/models/badge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# typed: true
# frozen_string_literal: true

class Badge < ApplicationRecord
extend T::Sig

include CustomIdGenerator

belongs_to :badge_batch
end
8 changes: 8 additions & 0 deletions app/models/badge_batch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# typed: true
# frozen_string_literal: true

class BadgeBatch < ApplicationRecord
extend T::Sig

has_many :badges, dependent: :destroy
end
45 changes: 38 additions & 7 deletions app/models/concerns/custom_id_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,50 @@ module CustomIdGenerator
class_methods do
extend T::Sig

sig do
params(scope_conditions: T::Hash[T.untyped, T.untyped]).returns(String)
end
def generate_random_id(scope_conditions = {})
sig { returns(String) }
def generate_random_id
loop do
raw_id = SecureRandom.alphanumeric(32).upcase
filtered_chars = raw_id.chars.reject do |char|
AMBIGUOUS_CHARS.include?(char)
end
id = filtered_chars.first(ID_LENGTH).join
next if id.length < ID_LENGTH
break id unless exists?({id: id}.merge(scope_conditions))
break id unless exists?(id: id)
end
end

sig { params(count: Integer).returns(T::Array[String]) }
def generate_random_ids(count)
return [] if count <= 0

needed = count
generated_ids = []

while needed > 0
# Generate a batch of candidate IDs
candidates = needed.times.map { generate_single_id_string }

# Check which ones already exist (single DB query)
existing = where(id: candidates).pluck(:id)
new_ids = candidates - existing

generated_ids.concat(new_ids)
needed -= new_ids.length
end

generated_ids.first(count)
end

sig { returns(String) }
def generate_single_id_string
loop do
raw_id = SecureRandom.alphanumeric(32).upcase
filtered_chars = raw_id.chars.reject do |char|
AMBIGUOUS_CHARS.include?(char)
end
id = filtered_chars.first(ID_LENGTH).join
return id if id.length == ID_LENGTH
end
end
end
Expand All @@ -39,7 +71,6 @@ def generate_random_id(scope_conditions = {})

sig { void }
def generate_custom_id
scope_conditions = respond_to?(:uniqueness_scope) ? uniqueness_scope : {}
self.id = self.class.generate_random_id(scope_conditions)
self.id = self.class.generate_random_id
end
end
1 change: 1 addition & 0 deletions app/views/admin/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<li><%= link_to t("navigation.users"), users_path %></li>
<li><%= link_to t("inspector_companies.titles.index"), inspector_companies_path %></li>
<li><%= link_to t("navigation.pages"), pages_path %></li>
<li><%= link_to t("navigation.badges"), badge_batches_path %></li>
<li><%= link_to t("navigation.jobs"), "/mission_control" %></li>
<li><%= link_to t("navigation.releases"), admin_releases_path %></li>
<li><%= link_to t("navigation.files"), admin_files_path %></li>
Expand Down
8 changes: 8 additions & 0 deletions app/views/badge_batches/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<%= render 'chobble_forms/form_context',
model: @badge_batch,
i18n_base: 'forms.badge_batch_edit',
url: badge_batch_path(@badge_batch) do |form| %>
<%= render 'chobble_forms/fieldset', legend_key: 'batch_details' do %>
<%= render 'chobble_forms/text_area', field: :note %>
<% end %>
<% end %>
63 changes: 63 additions & 0 deletions app/views/badge_batches/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<%= render 'shared/page_header', title: t("badges.titles.index") %>

<nav>
<%= link_to t("badges.buttons.new_batch"), new_badge_batch_path %>
</nav>

<%= form_with url: search_badge_batches_path, method: :get, data: { turbo: false }, id: "search-box" do |form| %>
<%= form.text_field :query,
placeholder: t('badges.search.placeholder'),
value: params[:query],
onkeyup: "if(event.key === 'Enter') this.form.submit();" %>
<% end %>

<% if @badge_batches.any? %>
<div class="table-list badge-batches-list">
<div class="table-list-header">
<%= render 'shared/table_column',
field: :id,
i18n_key: "badges.fields.id",
header: true %>
<%= render 'shared/table_column',
field: :count,
i18n_key: "badges.fields.count",
header: true %>
<%= render 'shared/table_column',
field: :created_at,
i18n_key: "badges.fields.created_at",
header: true %>
<%= render 'shared/table_column',
field: :note,
i18n_key: "badges.fields.note",
header: true %>
</div>

<ul class="table-list-items">
<% @badge_batches.each do |batch| %>
<li>
<%= link_to badge_batch_path(batch), class: "table-list-link" do %>
<%= render 'shared/table_column',
field: :id,
i18n_key: "badges.fields.id",
item: batch %>
<%= render 'shared/table_column',
field: :count,
i18n_key: "badges.fields.count",
item: batch %>
<%= render 'shared/table_column',
field: :created_at,
i18n_key: "badges.fields.created_at" do %>
<%= l(batch.created_at, format: :long) %>
<% end %>
<%= render 'shared/table_column',
field: :note,
i18n_key: "badges.fields.note",
item: batch %>
<% end %>
</li>
<% end %>
</ul>
</div>
<% else %>
<p><%= t("badges.messages.no_batches") %></p>
<% end %>
9 changes: 9 additions & 0 deletions app/views/badge_batches/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<%= render 'chobble_forms/form_context',
model: @badge_batch,
i18n_base: 'forms.badge_batch',
url: badge_batches_path do |form| %>
<%= render 'chobble_forms/fieldset', legend_key: 'batch_details' do %>
<%= render 'chobble_forms/number', field: :count, required: true %>
<%= render 'chobble_forms/text_area', field: :note %>
<% end %>
<% end %>
60 changes: 60 additions & 0 deletions app/views/badge_batches/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<%= render 'shared/page_header',
title: t("badges.titles.show", id: @badge_batch.id) %>

<nav>
<%= link_to t("badges.buttons.back"), badge_batches_path %>
<%= link_to t("badges.buttons.edit_batch"),
edit_badge_batch_path(@badge_batch) %>
</nav>

<article>
<p>
<strong><%= t("badges.fields.created_at") %>:</strong>
<%= l(@badge_batch.created_at, format: :long) %>
</p>

<p>
<strong><%= t("badges.fields.count") %>:</strong>
<%= @badge_batch.count %>
</p>

<p>
<strong><%= t("badges.fields.note") %>:</strong>
<%= @badge_batch.note %>
</p>
</article>

<% if @badges.any? %>
<div class="table-list badges-list">
<div class="table-list-header">
<%= render 'shared/table_column',
field: :badge_id,
i18n_key: "badges.fields.badge_id",
header: true %>
<%= render 'shared/table_column',
field: :note,
i18n_key: "badges.fields.note",
header: true %>
</div>

<ul class="table-list-items">
<% @badges.each do |badge| %>
<li>
<%= link_to edit_badge_path(badge), class: "table-list-link" do %>
<%= render 'shared/table_column',
field: :badge_id,
i18n_key: "badges.fields.badge_id" do %>
<%= badge.id %>
<% end %>
<%= render 'shared/table_column',
field: :note,
i18n_key: "badges.fields.note",
item: badge %>
<% end %>
</li>
<% end %>
</ul>
</div>
<% else %>
<p><%= t("badges.messages.no_badges") %></p>
<% end %>
13 changes: 13 additions & 0 deletions app/views/badges/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<header>
<h1><%= t("badges.titles.edit", id: @badge.id) %></h1>
</header>

<%= render 'chobble_forms/form_context',
model: @badge,
i18n_base: 'forms.badge',
url: badge_path(@badge),
method: :patch do |form| %>
<%= render 'chobble_forms/fieldset', legend_key: 'badge_details' do %>
<%= render 'chobble_forms/text_area', field: :note %>
<% end %>
<% end %>
Loading