From 25d43f29d0c4fb602600f663f4af71b2fa23b231 Mon Sep 17 00:00:00 2001 From: shaeespring Date: Sun, 5 Oct 2025 21:02:27 -0400 Subject: [PATCH 1/6] gatekeep --- conditional/__init__.py | 37 +++++++++++++++++++++++++++++++++++-- config.env.py | 3 +++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/conditional/__init__.py b/conditional/__init__.py index 1c2f5ee9..d4d4c943 100644 --- a/conditional/__init__.py +++ b/conditional/__init__.py @@ -3,7 +3,7 @@ import structlog from csh_ldap import CSHLDAP -from flask import Flask, redirect, render_template, g +from flask import Flask, redirect, render_template, request, g from flask_migrate import Migrate from flask_gzip import Gzip from flask_pyoidc.flask_pyoidc import OIDCAuthentication @@ -56,7 +56,14 @@ def start_of_year(): # pylint: disable=C0413 -from .models.models import UserLog +from .models.models import ( + CommitteeMeeting, + MemberCommitteeAttendance, + MemberHouseMeetingAttendance, + MemberSeminarAttendance, + TechnicalSeminar, + UserLog, +) # Configure Logging @@ -159,6 +166,32 @@ def health(): return {'status': 'ok'} +@app.route("/gatekeep/") +def gatekeep_status(username): + token = request.headers.get("X-VOTE-TOKEN","") + if token != app.config["VOTE_TOKEN"]: + return "Users cannot access this page", 403 + # number of committee meetings attended + c_meetings = len([m.meeting_id for m in + MemberCommitteeAttendance.query.filter( + MemberCommitteeAttendance.uid == username + ) if CommitteeMeeting.query.filter( + CommitteeMeeting.id == m.meeting_id).first().approved]) + # technical seminar total + t_seminars = len([s.seminar_id for s in + MemberSeminarAttendance.query.filter( + MemberSeminarAttendance.uid == username + ) if TechnicalSeminar.query.filter( + TechnicalSeminar.id == s.seminar_id).first().approved]) + # house meeting total + h_meetings = len([(m.meeting_id, m.attendance_status) for m in + MemberHouseMeetingAttendance.query.filter( + MemberHouseMeetingAttendance.uid == username)]) + result = c_meetings >= 6 and t_seminars >= 2 and h_meetings >= 6 + return {"result": result}, 200 + + + @app.errorhandler(404) @app.errorhandler(500) @auth.oidc_auth("default") diff --git a/config.env.py b/config.env.py index 29c0689b..f8c419e4 100644 --- a/config.env.py +++ b/config.env.py @@ -52,3 +52,6 @@ # General config DUES_PER_SEMESTER = env.get("CONDITIONAL_DUES_PER_SEMESTER", 80) + +# Vote config +VOTE_TOKEN = env.get("CONDITIONAL_VOTE_TOKEN", "") From b9cb4fcedb2d55de862da2fcebe58ae7d136b6d0 Mon Sep 17 00:00:00 2001 From: shaeespring Date: Fri, 10 Oct 2025 23:42:46 -0400 Subject: [PATCH 2/6] voting status on dashboard --- conditional/util/member.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conditional/util/member.py b/conditional/util/member.py index 1c4ae8c5..5b5c9c4d 100644 --- a/conditional/util/member.py +++ b/conditional/util/member.py @@ -1,6 +1,6 @@ from datetime import datetime -from conditional import start_of_year +from conditional import gatekeep_status, start_of_year from conditional.models.models import CommitteeMeeting from conditional.models.models import CurrentCoops from conditional.models.models import FreshmanEvalData @@ -32,8 +32,8 @@ def get_voting_members(): on_coop = set(member.uid for member in CurrentCoops.query.filter( CurrentCoops.date_created > start_of_year(), CurrentCoops.semester == semester).all()) - voting_list = list(active_members - intro_members - on_coop) + voting_list = list(username for username in voting_list if gatekeep_status(username)) passed_fall = FreshmanEvalData.query.filter( FreshmanEvalData.freshman_eval_result == "Passed", From e7617e867cdf90ff347bd9a8b929ce835662ba3d Mon Sep 17 00:00:00 2001 From: shaeespring Date: Sun, 12 Oct 2025 07:03:39 -0400 Subject: [PATCH 3/6] adding more return information for vote to use --- conditional/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/conditional/__init__.py b/conditional/__init__.py index d4d4c943..556c0543 100644 --- a/conditional/__init__.py +++ b/conditional/__init__.py @@ -171,8 +171,8 @@ def gatekeep_status(username): token = request.headers.get("X-VOTE-TOKEN","") if token != app.config["VOTE_TOKEN"]: return "Users cannot access this page", 403 - # number of committee meetings attended - c_meetings = len([m.meeting_id for m in + # number of directorship meetings attended + d_meetings = len([m.meeting_id for m in MemberCommitteeAttendance.query.filter( MemberCommitteeAttendance.uid == username ) if CommitteeMeeting.query.filter( @@ -187,8 +187,11 @@ def gatekeep_status(username): h_meetings = len([(m.meeting_id, m.attendance_status) for m in MemberHouseMeetingAttendance.query.filter( MemberHouseMeetingAttendance.uid == username)]) - result = c_meetings >= 6 and t_seminars >= 2 and h_meetings >= 6 - return {"result": result}, 200 + result = d_meetings >= 6 and t_seminars >= 2 and h_meetings >= 6 + return {"result": result, + "h_meetings": h_meetings, + "c_meetings": d_meetings, + "t_seminars": t_seminars}, 200 From 5dc992c1b68f59822836e7f428b83bf629c697bb Mon Sep 17 00:00:00 2001 From: shaeespring Date: Tue, 14 Oct 2025 14:48:41 -0400 Subject: [PATCH 4/6] fix readability in dashboard --- conditional/templates/dashboard.html | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/conditional/templates/dashboard.html b/conditional/templates/dashboard.html index 3bfd8197..b8abfa96 100644 --- a/conditional/templates/dashboard.html +++ b/conditional/templates/dashboard.html @@ -15,12 +15,22 @@

{{ get_member_name(username) }}

{% if active %} - Active {% else %} - Inactive {% endif %} {% if onfloor %} - On-floor Status {% else %} - Off-floor Status {% endif %} {% if voting %} - Voting {% else %} - Non-Voting {% endif %} + Active + {% else %} + Inactive + {% endif %} + + {% if onfloor %} + On-floor Status + {% else %} + Off-floor Status + {% endif %} + + {% if voting %} + Voting + {% else %} + Non-Voting + {% endif %}
From 2e140fecad52965599d3ad04fff40733463955d7 Mon Sep 17 00:00:00 2001 From: shaeespring Date: Tue, 14 Oct 2025 23:37:26 -0400 Subject: [PATCH 5/6] account for semesters --- conditional/__init__.py | 107 +++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 23 deletions(-) diff --git a/conditional/__init__.py b/conditional/__init__.py index 556c0543..753c75fc 100644 --- a/conditional/__init__.py +++ b/conditional/__init__.py @@ -58,6 +58,9 @@ def start_of_year(): # pylint: disable=C0413 from .models.models import ( CommitteeMeeting, + CurrentCoops, + FreshmanEvalData, + HouseMeeting, MemberCommitteeAttendance, MemberHouseMeetingAttendance, MemberSeminarAttendance, @@ -137,7 +140,7 @@ def database_processor(logger, log_method, event_dict): # pylint: disable=unuse app.register_blueprint(co_op_bp) app.register_blueprint(log_bp) -from .util.ldap import ldap_get_member +from .util.ldap import ldap_get_member, ldap_is_active, ldap_is_intromember @app.route('/') @@ -168,30 +171,88 @@ def health(): @app.route("/gatekeep/") def gatekeep_status(username): - token = request.headers.get("X-VOTE-TOKEN","") + token = request.headers.get("X-VOTE-TOKEN", "") if token != app.config["VOTE_TOKEN"]: return "Users cannot access this page", 403 - # number of directorship meetings attended - d_meetings = len([m.meeting_id for m in - MemberCommitteeAttendance.query.filter( - MemberCommitteeAttendance.uid == username - ) if CommitteeMeeting.query.filter( - CommitteeMeeting.id == m.meeting_id).first().approved]) - # technical seminar total - t_seminars = len([s.seminar_id for s in - MemberSeminarAttendance.query.filter( - MemberSeminarAttendance.uid == username - ) if TechnicalSeminar.query.filter( - TechnicalSeminar.id == s.seminar_id).first().approved]) - # house meeting total - h_meetings = len([(m.meeting_id, m.attendance_status) for m in - MemberHouseMeetingAttendance.query.filter( - MemberHouseMeetingAttendance.uid == username)]) - result = d_meetings >= 6 and t_seminars >= 2 and h_meetings >= 6 - return {"result": result, - "h_meetings": h_meetings, - "c_meetings": d_meetings, - "t_seminars": t_seminars}, 200 + + if datetime.today() < datetime(start_of_year().year, 12, 31): + semester = "Fall" + semester_start = datetime(start_of_year().year,6,1) + else: + semester = "Spring" + semester_start = datetime(start_of_year().year + 1,1,1) + + # groups + ldap_member = ldap_get_member(username) + is_intro_member = ldap_is_intromember(ldap_member) + is_active_member = ldap_is_active(ldap_member) and not is_intro_member + + is_on_coop = ( + CurrentCoops.query.filter( + CurrentCoops.date_created > start_of_year(), + CurrentCoops.semester == semester, + CurrentCoops.uid == username, + ).first() + is not None + ) + + passed_fall = ( + FreshmanEvalData.query.filter( + FreshmanEvalData.freshman_eval_result == "Passed", + FreshmanEvalData.eval_date > start_of_year(), + FreshmanEvalData.uid == username, + ).first() + is not None + ) + eligibility_of_groups = (is_active_member and not is_on_coop) or passed_fall + + # number of directorship meetings attended in the current semester + d_meetings = ( + MemberCommitteeAttendance.query.join( + CommitteeMeeting, + MemberCommitteeAttendance.meeting_id == CommitteeMeeting.id, + ) + .filter( + MemberCommitteeAttendance.uid == username, + CommitteeMeeting.approved is True, + CommitteeMeeting.date >= semester_start, + ) + .count() + ) + # number of technical seminars attended in the current semester + t_seminars = ( + MemberSeminarAttendance.query.join( + TechnicalSeminar, + MemberSeminarAttendance.meeting_id == TechnicalSeminar.id, + ) + .filter( + MemberSeminarAttendance.uid == username, + TechnicalSeminar.approved is True, + TechnicalSeminar.date >= semester_start, + ) + .count() + ) + # number of house meetings attended in the current semester + h_meetings = ( + MemberHouseMeetingAttendance.query.join( + HouseMeeting, + MemberHouseMeetingAttendance.meeting_id == HouseMeeting.id, + ) + .filter( + MemberHouseMeetingAttendance.uid == username, + HouseMeeting.date >= semester_start + ) + .count() + ) + result = eligibility_of_groups and (d_meetings >= 6 and t_seminars >= 2 and h_meetings >= 6) + + return { + "result": result, + "h_meetings": h_meetings, + "c_meetings": d_meetings, + "t_seminars": t_seminars, + }, 200 + From af307ee3b8395ad8846b5bfdfaba6c884e9d4b54 Mon Sep 17 00:00:00 2001 From: shaeespring Date: Tue, 14 Oct 2025 23:38:35 -0400 Subject: [PATCH 6/6] remove frosh from voting lists if they don't have requirements after 6 weeks --- conditional/util/member.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/conditional/util/member.py b/conditional/util/member.py index 5b5c9c4d..69a6ac97 100644 --- a/conditional/util/member.py +++ b/conditional/util/member.py @@ -32,8 +32,7 @@ def get_voting_members(): on_coop = set(member.uid for member in CurrentCoops.query.filter( CurrentCoops.date_created > start_of_year(), CurrentCoops.semester == semester).all()) - voting_list = list(active_members - intro_members - on_coop) - voting_list = list(username for username in voting_list if gatekeep_status(username)) + voting_set = active_members - intro_members - on_coop passed_fall = FreshmanEvalData.query.filter( FreshmanEvalData.freshman_eval_result == "Passed", @@ -41,9 +40,9 @@ def get_voting_members(): ).distinct() for intro_member in passed_fall: - if intro_member.uid not in voting_list: - voting_list.append(intro_member.uid) + voting_set.add(intro_member.uid) + voting_list = list(username for username in voting_set if gatekeep_status(username)) return voting_list