diff --git a/app/controllers/admin/shop_orders_controller.rb b/app/controllers/admin/shop_orders_controller.rb index 89b6d20e..729be5f5 100644 --- a/app/controllers/admin/shop_orders_controller.rb +++ b/app/controllers/admin/shop_orders_controller.rb @@ -339,4 +339,31 @@ def assign_user redirect_to admin_shop_orders_path(view: "fulfillment"), alert: "Failed to assign order" end end + + def cancel_hcb_grant + authorize :admin, :manage_users? + @order = ShopOrder.find(params[:id]) + + unless @order.shop_card_grant.present? + redirect_to admin_shop_order_path(@order), alert: "This order has no HCB grant to cancel" + return + end + + grant = @order.shop_card_grant + begin + HCBService.cancel_card_grant!(hashid: grant.hcb_grant_hashid) + + PaperTrail::Version.create!( + item_type: "ShopOrder", + item_id: @order.id, + event: "hcb_grant_canceled", + whodunnit: current_user.id, + object_changes: { hcb_grant_hashid: grant.hcb_grant_hashid, canceled_by: current_user.display_name }.to_json + ) + + redirect_to admin_shop_order_path(@order), notice: "HCB grant canceled successfully" + rescue => e + redirect_to admin_shop_order_path(@order), alert: "Failed to cancel HCB grant: #{e.message}" + end + end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 7dfc94ca..852ea294 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -306,6 +306,44 @@ def update redirect_to admin_user_path(@user) end + def cancel_all_hcb_grants + authorize :admin, :manage_users? + @user = User.find(params[:id]) + + grants = @user.shop_card_grants.where.not(hcb_grant_hashid: nil) + + if grants.empty? + redirect_to admin_user_path(@user), alert: "This user has no HCB grants to cancel" + return + end + + canceled_count = 0 + errors = [] + + grants.find_each do |grant| + begin + HCBService.cancel_card_grant!(hashid: grant.hcb_grant_hashid) + canceled_count += 1 + rescue => e + errors << "Grant #{grant.hcb_grant_hashid}: #{e.message}" + end + end + + PaperTrail::Version.create!( + item_type: "User", + item_id: @user.id, + event: "all_hcb_grants_canceled", + whodunnit: current_user.id, + object_changes: { canceled_count: canceled_count, canceled_by: current_user.display_name }.to_json + ) + + if errors.any? + redirect_to admin_user_path(@user), alert: "Canceled #{canceled_count} grants, but #{errors.count} failed: #{errors.first}" + else + redirect_to admin_user_path(@user), notice: "Successfully canceled #{canceled_count} HCB grant(s)" + end + end + private def user_params diff --git a/app/models/user.rb b/app/models/user.rb index 7821cdaa..b54d4f03 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -52,6 +52,7 @@ class User < ApplicationRecord has_many :projects, through: :memberships has_many :hackatime_projects, class_name: "User::HackatimeProject", dependent: :destroy has_many :shop_orders, dependent: :destroy + has_many :shop_card_grants, dependent: :destroy has_many :votes, dependent: :destroy has_many :reports, class_name: "Project::Report", foreign_key: :reporter_id, dependent: :destroy has_many :likes, dependent: :destroy diff --git a/app/views/admin/shop_orders/show.html.erb b/app/views/admin/shop_orders/show.html.erb index 79e0597e..8b8bdbf3 100644 --- a/app/views/admin/shop_orders/show.html.erb +++ b/app/views/admin/shop_orders/show.html.erb @@ -241,6 +241,18 @@

Card Grant

Card Grant ID: <%= @order.shop_card_grant_id %>
+ <% if @order.shop_card_grant&.hcb_grant_hashid.present? %> +
HCB Grant ID: <%= @order.shop_card_grant.hcb_grant_hashid %>
+
+ <%= link_to "View on HCB", @order.shop_card_grant.hcb_url, target: "_blank", class: "btn-primary", style: "margin-right: 0.5rem;" %> + <% if current_user.admin? && @order.fulfilled? %> +
+ <%= hidden_field_tag :authenticity_token, form_authenticity_token %> + +
+ <% end %> +
+ <% end %>
<% end %> diff --git a/app/views/admin/users/show.html.erb b/app/views/admin/users/show.html.erb index be848400..a1d4ef3f 100644 --- a/app/views/admin/users/show.html.erb +++ b/app/views/admin/users/show.html.erb @@ -140,6 +140,25 @@ <% end %> <% end %> + <% if current_user.admin? %> + <% has_grants = @user.shop_card_grants.where.not(hcb_grant_hashid: nil).exists? %> + + <% if has_grants %> + <%= render layout: "shared/modal", locals: { id: "cancel-grants-modal", title: "Cancel All HCB Grants", description: "This will cancel ALL HCB grants for #{@user.display_name}. This action cannot be undone!" } do %> +
+ <%= hidden_field_tag :authenticity_token, form_authenticity_token %> +

⚠️ Warning: This will cancel <%= @user.shop_card_grants.where.not(hcb_grant_hashid: nil).count %> grant(s).

+ +
+ <% end %> + <% end %> + <% end %> + <% if policy(:admin).ban_users? %> <% if @user.banned? %> <%= button_to "🔓 Unban User", unban_admin_user_path(@user), method: :post, class: "btn-primary slim" %> diff --git a/config/routes.rb b/config/routes.rb index efb75471..80a32351 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -186,6 +186,7 @@ def self.matches?(request) post :adjust_balance post :ban post :unban + post :cancel_all_hcb_grants post :impersonate end collection do @@ -216,6 +217,7 @@ def self.matches?(request) post :mark_fulfilled post :update_internal_notes post :assign_user + post :cancel_hcb_grant end end resources :audit_logs, only: [ :index, :show ]