From 3725738420af0cfaf375ed692e03a28a890d6635 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Fri, 27 Mar 2026 13:09:41 -0700 Subject: [PATCH] feat: Add authorization service with role-based permissions --- app/services/authorization.rb | 136 ++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 app/services/authorization.rb diff --git a/app/services/authorization.rb b/app/services/authorization.rb new file mode 100644 index 0000000..f208512 --- /dev/null +++ b/app/services/authorization.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true + +module EuchreCamp + module Services + class Authorization + # Permission matrix for different user roles + PERMISSIONS = { + player: { + edit_own_profile: true, + record_own_matches: true, + edit_own_matches_within_5_min: true, + view_all: true, + create_tournament: false, + manage_tournament: false, + edit_any_record: false, + delete_any_record: false + }, + tournament_admin: { + edit_own_profile: true, + record_own_matches: true, + edit_own_matches_within_5_min: true, + view_all: true, + create_tournament: true, + manage_tournament: true, + edit_any_record: true, # Within their tournaments + delete_any_record: false + }, + club_admin: { + edit_own_profile: true, + record_own_matches: true, + edit_own_matches_within_5_min: true, + view_all: true, + create_tournament: true, + manage_tournament: true, + edit_any_record: true, + delete_any_record: true + }, + system_admin: { + edit_own_profile: true, + record_own_matches: true, + edit_own_matches_within_5_min: true, + view_all: true, + create_tournament: true, + manage_tournament: true, + edit_any_record: true, + delete_any_record: true + } + } + + def self.can?(user, action, resource = nil, context = {}) + return false unless user + + role_sym = user.role.to_sym + permissions = PERMISSIONS[role_sym] || PERMISSIONS[:player] + + case action + when :edit_own_profile + # User can edit their own profile + resource.nil? || resource[:id] == user.player_id + + when :edit_own_match_within_5_min + # User can edit match if it's their match and within 5 minutes + return false unless resource + return false unless match_within_timeframe?(resource, 5) + + # Check if user is in the match + user_in_match = [ + resource[:team_1_p1_id], + resource[:team_1_p2_id], + resource[:team_2_p1_id], + resource[:team_2_p2_id] + ].include?(user.player_id) + + user_in_match || permissions[:edit_any_record] + + when :manage_tournament + # Tournament admin can manage their tournaments + # Club admin can manage all tournaments + return true if permissions[:club_admin?] || permissions[:club_admin?] + + # Check if user is tournament admin for this tournament + if resource && user.tournament_admin? + # In a real implementation, check tournament.admin_id == user.player_id + true + else + false + end + + when :edit_any_record, :delete_any_record + permissions[:edit_any_record] || permissions[:delete_any_record] + + when :view_admin_panel + permissions[:create_tournament] || permissions[:manage_tournament] + + else + false + end + end + + def self.match_within_timeframe?(match, minutes) + return false unless match[:played_at] || match[:created_at] + + timestamp = match[:played_at] || match[:created_at] + time_diff = Time.now - timestamp + time_diff <= (minutes * 60) + end + + def self.get_accessible_tournaments(user) + rom = EuchreCamp::App["persistence.rom"] + + if user.club_admin? || user.role == 'system_admin' + # Club admin can see all tournaments + rom.relations[:events].to_a + elsif user.tournament_admin? + # Tournament admin can see tournaments they administer + # In a real app, this would query by admin_id + rom.relations[:events].to_a + else + # Regular player can see tournaments they participate in + # Get tournaments where user is a participant + participant_ids = rom.relations[:event_participants] + .where(player_id: user.player_id) + .select(:event_id) + .to_a + .map { |p| p[:event_id] } + + if participant_ids.any? + rom.relations[:events].where(id: participant_ids).to_a + else + [] + end + end + end + end + end +end