import rules import datetime # PERMISSIONS # USER permissions """ USER permissions - There are 5 types of user: basic, pro, plan, coach, freecoach - These methods exist on user - user.rower - user.is_anonymous - user.is_staff - These methods exist on rower - rower.rowerplan - rower.protrialexpires - rower.plantrialexpires - rower.mycoachgroup - rower.coachinggroups - rower.team - These Rules apply to Rowers - Coach can have any number of groups - test_permissions.PermissionFreeCoach.test_coach_groupmanager - test_permissions.PermissionsBasicsTests.test_coach_groupmanager - test_permissions.PermissionsViewTests.test_coach_groups_create - Pro and Plan users can have one group and not more - test_permissions.PermissionsFreeCoach.test_pro_groupmanager - test_permissions.PermissionsViewTests.test_pro_groups_create - Free Coach user cannot have workouts - test_permissions.PermissionFreeCoach.test_add_workout_freecoach - Free coach can create more than one group - test_permissions.PermissionsFreeCoach.test_plan_groupmanager - Free Coach & Plan (Self Coach) can create planned sessions and team planned sessions - test_permissions.PermissionsFreeCoach.test_plan_create_session - test_permissions.PermissionsFreeCoach.test_coach_create_session - Pro cannot create planned sessions or team planned sessions - test_permissions.PermissionsViewTests.test_pro_create_session - Basic cannot join groups led by Free Coach - test_permissions.PermissionFreeCoach.test_add_basic_pro_or_plan - Coach can edit athlete settings (if in coachinggroup) - test_permissions.PermissionsViewTests.test_coach_edit_athlete_prefs - test_permissions.PermissionsViewTests.test_coach_edit_athlete_prefs_not - test_permissions.PermissionsViewTests.test_coach_edit_athlete_settings - test_permissions.PermissionsViewTests.test_coach_edit_athlete_settings_not - test_permissions.PermissionsViewTests.test_coach_edit_athlete_account - test_permissions.PermissionsViewTests.test_coach_edit_athlete_account_not - test_permissions.PermissionsViewTests.test_coach_edit_athlete_exportsettings - test_permissions.PermissionsViewTests.test_coach_edit_athlete_exportsettings_not - Coach can upload a workout on behalf of athlete - test_permissions.PermissionsViewTests.test_coach_edit_athlete_upload - test_permissions.PermissionsViewTests.test_coach_edit_athlete_upload_not - Pro and Plan cannot upload a workout on behalf of athlete - test_permissions.PermissionsViewTests.test_plan_edit_athlete_upload - Coach can run analytics for athlete - test_permissions.PermissionsViewTests.test_coach_edit_athlete_analysis - test_permissions.PermissionsViewTests.test_coach_edit_athlete_analysis_not - test_permissions.PermissionsViewTests.test_pro_edit_athlete_analysis - Pro and Plan user cannot run analysis for members of their groups - test_permissions.PermissionsViewTests.test_plan_edit_athlete_analysis - Pro and Plan user cannot edit athlete sessings - test_permissions.PermissionsViewTests.test_plan_edit_athlete_settings - test_permissions.PermissionsViewTests.test_pro_edit_athlete_settings - Self-Coach and Pro cannot create more than one group - test_permissions.PermissionsFreeCoach.test_plan_groupmanager - Pro users and higher can join group led by other Pro or higher user - test_permissions.PermissionsFreeCoach.test_add_proplan_pro_or_plan - Pro or basic cannot create planned sessions or team planned sessions - test_permissions.PermissionsFreeCoach.test_pro_create_plannedsession """ # used in can_plan_user @rules.predicate def user_is_not_basic(user): if user.rower.rowerplan != 'basic': return True if user.rower.protrialexpires >= datetime.date.today() and user.rower.plantrialexpires >= datetime.date.today(): return True return False @rules.predicate def user_is_basic(user): return not user_is_not_basic(user) @rules.predicate def can_start_trial(user): if user.is_anonymous: return False return user.rower.protrialexpires == datetime.date(1970,1,1) @rules.predicate def can_start_plantrial(user): if user.is_anonymous: return False return user.rower.plantrialexpires == datetime.date(1970,1,1) @rules.predicate def is_staff(user): return user.is_staff @rules.predicate def is_coach(user): return user.rower.rowerplan in ['coach','freecoach'] def is_paid_coach(user): return user.rower.rowerplan == 'coach' @rules.predicate def is_planmember(user): try: r = user.rower except AttributeError: return False return r.rowerplan in ['coach','plan'] # freecoach? @rules.predicate def is_promember(user): try: r = user.rower except AttributeError: return False return r.rowerplan in ['pro','coach','plan'] # freecoach? @rules.predicate def is_protrial(user): try: r = user.rower except AttributeError: return False if r.rowerplan == 'basic': return r.protrialexpires >= datetime.date.today() if r.rowerplan == 'freecoach': if r.mycoachgroup is not None: return len(r.mycoachgroup)>=4 return False ispromember = is_promember | is_protrial can_have_teams = ispromember | is_coach @rules.predicate def can_add_team(user): if is_coach(user): return True if ispromember(user) or is_planmember(user): otherteams = user.rower.get_managed_teams() if otherteams.count() == 0: return True return False @rules.predicate def can_add_plan(user): return isplanmember(user) or is_coach(user) @rules.predicate def can_add_workout(user): if user.is_anonymous: return False return user.rower.rowerplan != 'freecoach' @rules.predicate def is_plantrial(user): try: r = user.rower except AttributeError: return False if r.rowerplan in ['basic','pro']: return r.plantrialexpires >= datetime.date.today() if r.rowerplan == 'freecoach': if r.mycoachgroup is not None: return len(r.mycoachgroup)>=4 return False isplanmember = is_planmember | is_plantrial @rules.predicate def can_add_session(user): return isplanmember(user) or is_coach(user) # User / Coach relationships (Rower object) @rules.predicate def can_plan(user): if user.is_anonymous: return False if user.rower.rowerplan in ['plan','coach']: return True if user.rower.rowerplan in ['basic','pro']: return user.rower.plantrialexpires >= datetime.date.today() if user.rower.rowerplan == 'freecoach': if user.rower.mycoachgroup is not None: return len(user.rower.mycoachgroup)>=4 # checks if rower is coach of user (or is user himself) @rules.predicate def is_coach_user(usercoach,userrower): if usercoach == userrower: return True if not is_coach(usercoach): return False r = userrower.rower coaches = [] for group in r.coachinggroups.all(): newcoaches = group.get_coaches() for coach in newcoaches: coaches.append(coach) for coach in coaches: if usercoach.rower == coach: return True return False # checks if rower is coach of user (or is user himself) @rules.predicate def is_anonymous_or_coach(usercoach,userrower): print(usercoach,userrower) if usercoach == userrower: return True if userrower.is_anonymous and userrower.is_anonymous: return True if not is_coach(usercoach): return False r = userrower.rower coaches = [] for group in r.coachinggroups.all(): newcoaches = group.get_coaches() for coach in newcoaches: coaches.append(coach) for coach in coaches: if usercoach.rower == coach: return True return False # check if rower and user are members of the same team @rules.predicate def is_rower_team_member(user,rower): if user.rower == rower: return True teams = rower.team.all() for team in teams: if team.private == 'open': if team in user.rower.team.all(): return True if team.manager == user: return True return False @rules.predicate def can_add_workout_member(user,rower): if not user: return False if user.is_anonymous: return False if user == rower.user: return True # only below tested - need test user == rower.user return is_coach(user) and user.rower in rower.get_coaches() # check if user can plan for the rower @rules.predicate def can_plan_user(user,rower): # user must have planning permission if not can_plan(user): return False # if has planning permission, can always plan for himself if rower == user.rower: return True teams = user.rower.get_managed_teams() # free coach, plan etc cannot plan for basic if not is_paid_coach(user) and user_is_not_basic(user): for t in teams: if rower in t.rower.all(): return True # paying coach can plan for all kinds of rowers if is_paid_coach(user): for t in teams: if rower in t.rower.all(): return True return False rules.add_perm('rower.add_plan',can_plan_user) # replaces checkaccessplanuser rules.add_perm('rower.is_coach',is_coach_user) # replaces checkaccessuser rules.add_perm('rower.is_pro',ispromember) rules.add_perm('rower.is_staff',is_staff) # WORKOUT permissions """ WORKOUT permissions - These methods exist on Workout - workout.privacy - These rules apply to workouts - User can add, delete and change their own workouts - test_aworkouts - Coach can add and change workouts for their athletes, but not delete - test_permissions.PermissionsViewTests.test_coach_edit_athlete_upload - test_permissions.PermissionsViewTests.test_coach_edit_athlete_upload_not - Basic, Pro and Plan user can view but cannot add or change an athlete's workout - test_permissions.PermissionsViewTests.test_coach_edit_athlete_workout - test_permissions.PermissionsViewTests.test_plan_edit_athlete_upload - test_permissions.PermissionsViewTests.test_plan_edit_athlete_workout - test_permissions.PermissionsViewTests.test_basic_edit_athelte_workout - Anonymous users can view team members' workout (but not see list of workouts) - test_aworkouts - Rules for Workouts are transferred to objects related to the Workout, - Charts - Video Analysis - WorkoutComment? """ # check if user is owner or coach of owner of workout @rules.predicate def is_workout_user(user,workout): if user.is_anonymous: return False try: r = user.rower except AttributeError: return False if workout.user == r: return True return is_coach_user(user,workout.user.user) # check if user is in same team as owner of workout @rules.predicate def is_workout_team(user,workout): if user.is_anonymous: return False try: r = user.rower except AttributeError: return False if workout.user == r: return True return is_rower_team_member(user,workout.user) # check if user can see workout @rules.predicate def can_view_workout(user,workout): if workout.privacy != 'private': return True if user.is_anonymous: return False return user == workout.user.user can_change_workout = is_workout_user rules.add_perm('workout.change_workout',can_change_workout) # replaces checkworkoutuser rules.add_perm('workout.view_workout',can_view_workout) # replaces checkworkoutuserview # checkviewworkouts # PLANNING permissions """ - These rules apply to planning - Free coach can create planned sessions and team planned sessions - test_permissions.PermissionsViewTests.test_coach_create_session - Self coach and higher can create planned sessions and team planned sessions - test_permissions.PermissionsFreeCoach.test_plan_create_session - test_permissions.PermissionsFreeCoach.test_coach_create_session - Coach can create planned sessions and team planned sessions - test_permissions.PermissionsFreeCoach.test_plan_create_session - test_permissions.PermissionsFreeCoach.test_coach_create_session - Self Coach and higher can create planned sessions and team planned sessions - test_permissions.PermissionsViewTests.test_plan_create_session - Pro or Basic cannot create planned sessions or team planned sessions - test_permissions.PermissionsFreeCoach.test_pro_create_plannedsession - test_permissions.PermissionsFreeCoach.test_basic_create_plannedsession - WHO can comment (plannedsession_comment_view) - Only Session manager can change session - Strict View rules (stricter than workouts) - Basic user cannot manage a training plan - TrainingTarget - rules for view, add, change, delete - TrainingPlan - rules for view, add, change, delete - Cycle - inherits rules from TrainingPlan - PlannedSession - rules for view, add, change, delete, clone, save as template - check team - Special rules for Race (cannot be edited ex post) """ # Training Target rules # untested can_view_target to can_delete_target @rules.predicate def can_view_target(user,target): if user.is_anonymous: return False if user == target.manager.user: return True # a target's coach can view as well if is_coach_user(user,target.manager.user): return True # the object can view as well if user.rower in target.rowers.all(): return True @rules.predicate def can_change_target(user,target): if user.is_anonymous: return False return user == target.manager.user @rules.predicate def can_delete_target(user,target): if user.is_anonymous: return False return user == target.manager.user rules.add_perm('target.view_target',can_view_target) rules.add_perm('target.change_target',can_change_target) rules.add_perm('target.delete_target',can_delete_target) @rules.predicate def can_view_plan(user,plan): if user.is_anonymous: return False if user == plan.manager.user: return True # a plan's coach can view as well # below untested if is_coach_user(user,plan.manager.user): return True # the object can view as well if user.rower in plan.rowers.all(): return True @rules.predicate def can_change_plan(user,plan): if user.is_anonymous: return False return user == plan.manager.user # below untested @rules.predicate def can_delete_plan(user,plan): if user.is_anonymous: return False return user == plan.manager.user rules.add_perm('plan.view_plan',can_view_plan) rules.add_perm('plan.change_plan',can_change_plan) rules.add_perm('plan.delete_plan',can_delete_plan) rules.add_perm('plan.can_add_plan',can_add_plan) # untested @rules.predicate def can_view_cycle(user,cycle): try: return can_view_cycle(user,cycle.plan) except AttributeError: return can_view_plan(user,cycle.plan) return False @rules.predicate def can_change_cycle(user,cycle): try: return can_change_cycle(user,cycle.plan) except AttributeError: return can_change_plan(user,cycle.plan) return False @rules.predicate def can_delete_cycle(user,cycle): try: return can_delete_cycle(user,cycle.plan) except AttributeError: return can_delete_plan(user,cycle.plan) return False rules.add_perm('cycle.view_cycle',can_view_cycle) rules.add_perm('cycle.change_cycle',can_change_cycle) rules.add_perm('cycle.delete_cycle',can_delete_cycle) # check if user has view access to session @rules.predicate def can_view_session(user,session): if session.sessiontype in ['race','indoorrace']: return True if user.is_anonymous: return False # session manager can view session if user == session.manager: return True # if you're a rower in the session you can view it # below untested if user.rower in session.rower.all(): return True # coach users can view sessions created by their team members # below untested if is_coach(user): teams = user.rower.get_managed_teams() for t in teams: teamusers = [member.u for member in t.rower.all()] if session.manager in teamusers: return True return False @rules.predicate def can_change_session(user,session): if user.is_anonymous: return False # session part of a race should not be changed through the session interface if session.sessiontype in ['race','indoorrace']: return False if user == session.manager: return True return False @rules.predicate def can_delete_session(user,session): if user.is_anonymous: return False if session.sessiontype in ['race','indoorrace']: return False if user == session.manager: return True return False rules.add_perm('plannedsession.add_session',can_add_session) rules.add_perm('plannedsession.view_session',can_view_session) rules.add_perm('plannedsession.change_session',can_change_session) rules.add_perm('plannedsession.delete_session',can_delete_session) # TEAM (group) permissions """ - These methods exist on team - team.manager - team.private - These rules apply to a team - A Pro or Plan rower can be manager of only 1 team - test_permissions.PermissionsFreeCoach.test_pro_groupmanager - test_permissions.PermissionsViewTests.test_pro_groups_create - A coach can have any number of teams (as manager) - test_permissions.PermissionsBasicTest.test_coach_groupmanager - Basic user cannot manage a group - test_permissions.PermissionsFreeCoach.test_basic_groupmanager - Basic user cannot join groups led by Free Coach or Pro - test_permissions.PermissionFreeCoach.test_add_basic_pro_or_plan - Basic athletes can be member of Coach led group - test_permissions.PermissionsBasicTest.test_add_coach - Pro users (and higher) can join team led by other Pro (or higher) user - test_permissions.PermissionsFreeCoach.test_add_proplan_pro_or_plan - test_permissions.PermissionsViewTests.test_team_member_request_pro_pro - test_permissions.PermissionsViewTests.test_team_member_request_basic_pro - On downgrade, Coach users lose all but their oldest team (add test!) """ # check if user is manager of the team @rules.predicate def is_team_manager(user,team): return team.manager == user # check is user is member of team - untested @rules.predicate def is_team_member(user,team): members = team.rower.all() return user in [member.user for member in members] # check if user can view team @rules.predicate def can_view_team(user,team): # user based - below untested if user.rower.rowerplan == 'basic' and team.manager.rower.rowerplan != 'coach': return is_plantrial(user) or is_protrial(user) # team is public if team.private == 'open': return True # team is private - below untested return is_team_member(user,team) | is_team_manager(user,team) @rules.predicate def can_change_team(user,team): return is_team_manager(user,team) @rules.predicate def can_delete_team(user,team): return is_team_manager(user,team) @rules.predicate def can_join_team(user,team): return is_paid_coach(team.manager) or ispromember(user) # For Team functionality rules.add_perm('teams.view_team',can_view_team) rules.add_perm('teams.add_team',user_is_not_basic) rules.add_perm('teams.change_team',can_change_team) rules.add_perm('teams.delete_team',can_delete_team) # RACING permissions """ - VirtualRace - rules to add, view, delete, change - GeoCourse - rules to add, view, delete, change - RaceLogo """ @rules.predicate def can_change_course(user,course): if user.is_anonymous: return False return course.manager == user.rower # untested @rules.predicate def can_delete_course(user,course): if user.is_anonymous: return False return course.manager == user.rower @rules.predicate def can_delete_logo(user,logo): if user.is_anonymous: return False return logo.user == user @rules.predicate def can_change_race(user,race): if user.is_anonymous: return False return race.manager == user # everybody can view or add a course rules.add_perm('course.change_course',can_change_course) rules.add_perm('course.delete_course',can_delete_course) rules.add_perm('racelogo.delete_logo',can_delete_logo) # everybody can view a race rules.add_perm('virtualevent.change_race',can_change_race) # can races be deleted? # ANALYSIS permissions """ - Conditions - Alerts - rules to add, view, delete, change - cpdata """