From 8acb4903e9e42223df196dfdeaa5a1f15835aebf Mon Sep 17 00:00:00 2001 From: Noah Date: Fri, 16 Jan 2026 21:08:17 -0500 Subject: [PATCH 01/10] bump stuff --- requirements.in | 4 ++-- requirements.txt | 59 ++++++++++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/requirements.in b/requirements.in index dcb502e..14fc826 100644 --- a/requirements.in +++ b/requirements.in @@ -1,8 +1,8 @@ alembic~=1.15.1 astroid~=3.3.9 blinker~=1.4 -csh_ldap>=2.3.1 -ddtrace~=3.2.1 +csh_ldap>=2.5.3 +ddtrace~=4.2.1 Flask~=3.1.0 Flask-Migrate~=2.1.1 Flask-Gzip~=0.2 diff --git a/requirements.txt b/requirements.txt index 6508a12..dc93cb8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # This file was autogenerated by uv via the following command: -# uv pip compile requirements.in +# uv pip compile requirements.in -o requirements.txt alembic==1.15.2 # via # -r requirements.in @@ -15,11 +15,11 @@ blinker==1.9.0 # -r requirements.in # flask # sentry-sdk -build==1.3.0 +build==1.4.0 # via pip-tools bytecode==0.17.0 # via ddtrace -certifi==2025.10.5 +certifi==2026.1.4 # via # requests # sentry-sdk @@ -27,16 +27,16 @@ cffi==2.0.0 # via cryptography charset-normalizer==3.4.4 # via requests -click==8.3.0 +click==8.3.1 # via # -r requirements.in # flask # pip-tools cryptography==46.0.3 # via oic -csh-ldap==2.4.0 +csh-ldap==2.5.3 # via -r requirements.in -ddtrace==3.2.3 +ddtrace==4.2.1 # via -r requirements.in defusedxml==0.7.1 # via oic @@ -66,13 +66,13 @@ flask-sqlalchemy==3.1.1 # flask-migrate future==1.0.0 # via pyjwkest -greenlet==3.2.4 +greenlet==3.3.0 # via sqlalchemy -gunicorn==20.1.0 +gunicorn==22.0.0 # via -r requirements.in idna==3.11 # via requests -importlib-metadata==8.7.0 +importlib-metadata==8.7.1 # via opentelemetry-api importlib-resources==6.5.2 # via flask-pyoidc @@ -111,21 +111,21 @@ oic==1.6.1 # via # -r requirements.in # flask-pyoidc -opentelemetry-api==1.38.0 +opentelemetry-api==1.39.1 # via ddtrace packaging==25.0 - # via build -pip==25.2 + # via + # build + # gunicorn +pip==25.3 # via pip-tools pip-tools==7.4.1 # via -r requirements.in -platformdirs==4.5.0 +platformdirs==4.5.1 # via pylint -protobuf==6.33.0 - # via ddtrace psycopg2-binary==2.9.11 # via -r requirements.in -pyasn1==0.6.1 +pyasn1==0.6.2 # via # pyasn1-modules # python-ldap @@ -137,11 +137,11 @@ pycryptodomex==3.23.0 # via # oic # pyjwkest -pydantic==2.12.3 +pydantic==2.12.5 # via pydantic-settings -pydantic-core==2.41.4 +pydantic-core==2.41.5 # via pydantic -pydantic-settings==2.11.0 +pydantic-settings==2.12.0 # via oic pyjwkest==1.4.4 # via oic @@ -153,11 +153,11 @@ pyproject-hooks==1.2.0 # pip-tools python-dateutil==2.6.1 # via -r requirements.in -python-dotenv==1.1.1 +python-dotenv==1.2.1 # via pydantic-settings python-editor==1.0.4 # via -r requirements.in -python-ldap==3.4.0 +python-ldap==3.4.5 # via csh-ldap requests==2.32.5 # via @@ -167,30 +167,27 @@ requests==2.32.5 sentry-sdk==2.24.1 # via -r requirements.in setuptools==80.9.0 - # via - # gunicorn - # pip-tools + # via pip-tools six==1.17.0 # via # -r requirements.in # pyjwkest # python-dateutil # structlog -sqlalchemy==2.0.44 +sqlalchemy==2.0.45 # via # -r requirements.in # alembic # flask-sqlalchemy -srvlookup==2.0.0 +srvlookup==3.0.0 # via csh-ldap structlog==18.1.0 # via -r requirements.in -tomlkit==0.13.3 +tomlkit==0.14.0 # via pylint typing-extensions==4.15.0 # via # alembic - # ddtrace # opentelemetry-api # pydantic # pydantic-core @@ -200,11 +197,11 @@ typing-inspection==0.4.2 # via # pydantic # pydantic-settings -urllib3==2.5.0 +urllib3==2.6.3 # via # requests # sentry-sdk -werkzeug==3.1.3 +werkzeug==3.1.5 # via # -r requirements.in # flask @@ -214,7 +211,5 @@ wrapt==1.17.3 # via # -r requirements.in # ddtrace -xmltodict==1.0.2 - # via ddtrace zipp==3.23.0 # via importlib-metadata From dadb28ac40f78a3296d70f4dbf404ac3621705b7 Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 00:22:29 -0500 Subject: [PATCH 02/10] add type hints to ldap.py --- conditional/util/ldap.py | 46 +++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/conditional/util/ldap.py b/conditional/util/ldap.py index 98cb853..74e79d1 100644 --- a/conditional/util/ldap.py +++ b/conditional/util/ldap.py @@ -1,12 +1,14 @@ from conditional import ldap from conditional.util.cache import service_cache +from csh_ldap import CSHGroup, CSHMember -def _ldap_get_group_members(group): + +def _ldap_get_group_members(group: str) -> list[CSHMember]: return ldap.get_group(group).get_members() -def _ldap_is_member_of_group(member, group): +def _ldap_is_member_of_group(member: CSHMember, group: str) -> bool: group_list = member.get("memberOf") for group_dn in group_list: if group == group_dn.split(",")[0][3:]: @@ -14,18 +16,18 @@ def _ldap_is_member_of_group(member, group): return False -def _ldap_add_member_to_group(account, group): +def _ldap_add_member_to_group(account: CSHMember, group: str): if not _ldap_is_member_of_group(account, group): ldap.get_group(group).add_member(account, dn=False) -def _ldap_remove_member_from_group(account, group): +def _ldap_remove_member_from_group(account: CSHMember, group: str): if _ldap_is_member_of_group(account, group): ldap.get_group(group).del_member(account, dn=False) @service_cache(maxsize=256) -def _ldap_is_member_of_directorship(account, directorship): +def _ldap_is_member_of_directorship(account: CSHMember, directorship: str): directors = ldap.get_directorship_heads(directorship) for director in directors: if director.uid == account.uid: @@ -34,32 +36,32 @@ def _ldap_is_member_of_directorship(account, directorship): @service_cache(maxsize=1024) -def ldap_get_member(username): +def ldap_get_member(username: str) -> CSHMember: return ldap.get_member(username, uid=True) @service_cache(maxsize=1024) -def ldap_get_active_members(): +def ldap_get_active_members() -> list[CSHMember]: return _ldap_get_group_members("active") @service_cache(maxsize=1024) -def ldap_get_intro_members(): +def ldap_get_intro_members() -> list[CSHMember]: return _ldap_get_group_members("intromembers") @service_cache(maxsize=1024) -def ldap_get_onfloor_members(): +def ldap_get_onfloor_members() -> list[CSHMember]: return _ldap_get_group_members("onfloor") @service_cache(maxsize=1024) -def ldap_get_current_students(): +def ldap_get_current_students() -> list[CSHMember]: return _ldap_get_group_members("current_student") @service_cache(maxsize=128) -def ldap_get_roomnumber(account): +def ldap_get_roomnumber(account) -> str: try: return account.roomNumber except AttributeError: @@ -67,57 +69,57 @@ def ldap_get_roomnumber(account): @service_cache(maxsize=128) -def ldap_is_active(account): +def ldap_is_active(account) -> bool: return _ldap_is_member_of_group(account, 'active') @service_cache(maxsize=128) -def ldap_is_bad_standing(account): +def ldap_is_bad_standing(account) -> bool: return _ldap_is_member_of_group(account, 'bad_standing') @service_cache(maxsize=128) -def ldap_is_alumni(account): +def ldap_is_alumni(account) -> bool: # If the user is not active, they are an alumni. return not _ldap_is_member_of_group(account, 'active') @service_cache(maxsize=128) -def ldap_is_eboard(account): +def ldap_is_eboard(account) -> bool: return _ldap_is_member_of_group(account, 'eboard') @service_cache(maxsize=128) -def ldap_is_rtp(account): +def ldap_is_rtp(account) -> bool: return _ldap_is_member_of_group(account, 'rtp') @service_cache(maxsize=128) -def ldap_is_intromember(account): +def ldap_is_intromember(account) -> bool: return _ldap_is_member_of_group(account, 'intromembers') @service_cache(maxsize=128) -def ldap_is_onfloor(account): +def ldap_is_onfloor(account) -> bool: return _ldap_is_member_of_group(account, 'onfloor') @service_cache(maxsize=128) -def ldap_is_financial_director(account): +def ldap_is_financial_director(account) -> bool: return _ldap_is_member_of_directorship(account, 'Financial') @service_cache(maxsize=128) -def ldap_is_eval_director(account): +def ldap_is_eval_director(account) -> bool: return _ldap_is_member_of_directorship(account, 'Evaluations') @service_cache(maxsize=256) -def ldap_is_current_student(account): +def ldap_is_current_student(account) -> bool: return _ldap_is_member_of_group(account, 'current_student') -def ldap_set_housingpoints(account, housing_points): +def ldap_set_housingpoints(account, housing_points) -> bool: account.housingPoints = housing_points ldap_get_current_students.cache_clear() ldap_get_member.cache_clear() From a3bb5805c4d7856d59e1cffdf1a7f1126e6d2a7f Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 01:07:08 -0500 Subject: [PATCH 03/10] more sane ldap queries --- conditional/util/ldap.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/conditional/util/ldap.py b/conditional/util/ldap.py index 74e79d1..d2b039c 100644 --- a/conditional/util/ldap.py +++ b/conditional/util/ldap.py @@ -9,11 +9,7 @@ def _ldap_get_group_members(group: str) -> list[CSHMember]: def _ldap_is_member_of_group(member: CSHMember, group: str) -> bool: - group_list = member.get("memberOf") - for group_dn in group_list: - if group == group_dn.split(",")[0][3:]: - return True - return False + return ldap.get_group(group).check_member(member) def _ldap_add_member_to_group(account: CSHMember, group: str): @@ -28,18 +24,13 @@ def _ldap_remove_member_from_group(account: CSHMember, group: str): @service_cache(maxsize=256) def _ldap_is_member_of_directorship(account: CSHMember, directorship: str): - directors = ldap.get_directorship_heads(directorship) - for director in directors: - if director.uid == account.uid: - return True - return False - + return account.in_group(f'eboard-{directorship}', dn=True) +# TODO: try in_group(ldap.get_group(f'eboard-{directorship}')) and profile @service_cache(maxsize=1024) def ldap_get_member(username: str) -> CSHMember: return ldap.get_member(username, uid=True) - @service_cache(maxsize=1024) def ldap_get_active_members() -> list[CSHMember]: return _ldap_get_group_members("active") From ffed487283eb65f78e9654145e9935bad83dac6f Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 12:19:06 -0500 Subject: [PATCH 04/10] improved gatekeep calculations --- conditional/blueprints/dashboard.py | 3 +- conditional/util/member.py | 93 +++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/conditional/blueprints/dashboard.py b/conditional/blueprints/dashboard.py index 527e8dd..c180bb1 100644 --- a/conditional/blueprints/dashboard.py +++ b/conditional/blueprints/dashboard.py @@ -36,7 +36,8 @@ def display_dashboard(user_dict=None): log.info('display dashboard') # Get the list of voting members. - can_vote = get_voting_members() + + can_vote = get_gatekeep_passed() data = {} data['username'] = user_dict['account'].uid diff --git a/conditional/util/member.py b/conditional/util/member.py index b1a26b8..040c8e3 100644 --- a/conditional/util/member.py +++ b/conditional/util/member.py @@ -1,4 +1,5 @@ from datetime import datetime +from sqlalchemy import func, or_ from conditional import start_of_year from conditional.models.models import CommitteeMeeting @@ -161,6 +162,98 @@ def req_cm(member): return 15 return 30 +def get_gatekeep_passed(): + 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) + + active_members = set(ldap_get_active_members()) + intro_memberes = set(ldap_get_intro_members()) + + coop_members = CurrentCoops.query.filter( + CurrentCoops.date_created > start_of_year(), + CurrentCoops.semester == semester, + ).with_entities( + func.array_agg(CurrentCoops.uid) + ).scalar() + + # have to do this because if it's none then set constructor screams + if coop_members == None: + coop_members = set() + else: + coop_members = set(coop_members) + + passed_fall_members = FreshmanEvalData.query.filter( + FreshmanEvalData.freshman_eval_result == "Passed", + FreshmanEvalData.eval_date > start_of_year(), + ).with_entities( + func.array_agg(FreshmanEvalData.uid) + ).scalar() + + if (passed_fall_members == None): + passed_fall_members = set() + else: + passed_fall_members = set(passed_fall_members) + + elligible_members = (active_members - intro_memberes - coop_members) | passed_fall_members + + passing_dm = set(member.uid for member in MemberCommitteeAttendance.query.join( + CommitteeMeeting, + MemberCommitteeAttendance.meeting_id == CommitteeMeeting.id + ).with_entities( + MemberCommitteeAttendance.uid, + CommitteeMeeting.timestamp, + CommitteeMeeting.approved, + ).filter( + CommitteeMeeting.approved, + CommitteeMeeting.timestamp >= semester_start + ).with_entities( + MemberCommitteeAttendance.uid + ).group_by( + MemberCommitteeAttendance.uid + ).having( + func.count(MemberCommitteeAttendance.uid) >= 6 + ).with_entities( + MemberCommitteeAttendance.uid + ).all()) + + passing_ts = set(member.uid for member in MemberSeminarAttendance.query.join( + TechnicalSeminar, + MemberSeminarAttendance.seminar_id == TechnicalSeminar.id + ).filter( + TechnicalSeminar.approved, + TechnicalSeminar.timestamp >= semester_start + ).with_entities( + MemberSeminarAttendance.uid + ).group_by( + MemberSeminarAttendance.uid + ).having( + func.count(MemberSeminarAttendance.uid) >= 2 + ).all()) + + passing_hm = set(member.uid for member in MemberHouseMeetingAttendance.query.join( + HouseMeeting, + MemberHouseMeetingAttendance.meeting_id == HouseMeeting.id + ).filter( + HouseMeeting.date >= semester_start, or_( + MemberHouseMeetingAttendance.attendance_status == 'Attended', + MemberHouseMeetingAttendance.attendance_status == 'Excused' + ) + ).with_entities( + MemberHouseMeetingAttendance.uid + ).group_by( + MemberHouseMeetingAttendance.uid + ).having( + func.count(MemberHouseMeetingAttendance.uid) >= 2 + ).all()) + + passing_reqs = passing_dm | passing_ts | passing_hm + + return elligible_members & passing_reqs + def gatekeep_status(username): if datetime.today() < datetime(start_of_year().year, 12, 31): semester = "Fall" From 89f7571abbd9606b5a6034b422990247eefb81a2 Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 13:10:49 -0500 Subject: [PATCH 05/10] improve housing queue calculations --- conditional/util/housing.py | 46 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/conditional/util/housing.py b/conditional/util/housing.py index 74a9200..8d93b16 100644 --- a/conditional/util/housing.py +++ b/conditional/util/housing.py @@ -2,8 +2,7 @@ from conditional.models.models import InHousingQueue from conditional.models.models import OnFloorStatusAssigned -from conditional.util.ldap import ldap_get_current_students -from conditional.util.ldap import ldap_is_onfloor +from conditional.util.ldap import ldap_get_member, ldap_is_current_student def get_housing_queue(is_eval_director=False): @@ -12,23 +11,34 @@ def get_housing_queue(is_eval_director=False): # and {'time': } is the value. We are doing a left # outer join on the two tables to get a single result that has # both the member's UID and their on-floor datetime. - in_queue = {entry.uid: {'time': entry.onfloor_granted} for entry - in InHousingQueue.query.outerjoin(OnFloorStatusAssigned, - OnFloorStatusAssigned.uid == InHousingQueue.uid)\ - .with_entities(InHousingQueue.uid, OnFloorStatusAssigned.onfloor_granted)\ - .all()} + in_queue = { + entry.uid: { + 'time': entry.onfloor_granted + } for entry in InHousingQueue.query.outerjoin( + OnFloorStatusAssigned, + OnFloorStatusAssigned.uid == InHousingQueue.uid + ).with_entities( + InHousingQueue.uid, + OnFloorStatusAssigned.onfloor_granted + ).all() + } + + # CSHMember accounts that are in queue + potential_accounts = [ldap_get_member(username) for username in in_queue] # Populate a list of dictionaries containing the name, username, - # and on-floor datetime for each member who has on-floor status, - # is not already assigned to a room and is in the above query. - queue = [{"uid": account.uid, - "name": account.cn, - "points": account.housingPoints, - "time": in_queue.get(account.uid, {}).get('time', datetime.now()) or datetime.now(), - "in_queue": account.uid in in_queue} - for account in ldap_get_current_students() - if ldap_is_onfloor(account) and (is_eval_director or account.uid in in_queue) - and account.roomNumber is None] + # and on-floor datetime for each current studetn who has on-floor status + # and is not already assigned to a room + queue = [ + { + "uid": account.uid, + "name": account.cn, + "points": account.housingPoints, + "time": in_queue.get(account.uid, {}).get('time', datetime.now()) or datetime.now(), + "in_queue": account.uid in in_queue + } for account in potential_accounts + if ldap_is_current_student(account) and (is_eval_director or account.roomNumber is None) + ] # Sort based on time (ascending) and then points (decending). queue.sort(key=lambda m: m['time']) @@ -40,7 +50,7 @@ def get_housing_queue(is_eval_director=False): def get_queue_position(username): queue = get_housing_queue() try: - index = next(index for (index, d) in enumerate(get_housing_queue()) + index = next(index for (index, d) in enumerate(queue) if d["uid"] == username) + 1 except (KeyError, StopIteration): index = None From 2add2e76ec4c9eb318572ca73c4fc6ed878bd720 Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 13:39:42 -0500 Subject: [PATCH 06/10] reorganize directorships calculations --- conditional/blueprints/dashboard.py | 2 +- conditional/util/member.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/conditional/blueprints/dashboard.py b/conditional/blueprints/dashboard.py index c180bb1..6e6d51d 100644 --- a/conditional/blueprints/dashboard.py +++ b/conditional/blueprints/dashboard.py @@ -16,7 +16,7 @@ from conditional.util.ldap import ldap_is_active from conditional.util.ldap import ldap_is_intromember from conditional.util.ldap import ldap_is_onfloor -from conditional.util.member import get_freshman_data, get_voting_members, get_cm, get_hm, req_cm +from conditional.util.member import get_freshman_data, get_voting_members, get_gatekeep_passed, get_cm, get_hm, req_cm logger = structlog.get_logger() diff --git a/conditional/util/member.py b/conditional/util/member.py index 040c8e3..01c7688 100644 --- a/conditional/util/member.py +++ b/conditional/util/member.py @@ -118,11 +118,8 @@ def get_onfloor_members(): def get_cm(member): - c_meetings = [{ - "uid": cm.uid, - "timestamp": cm.timestamp, - "committee": cm.committee - } for cm in CommitteeMeeting.query.join( + + query_result = CommitteeMeeting.query.join( MemberCommitteeAttendance, MemberCommitteeAttendance.meeting_id == CommitteeMeeting.id ).with_entities( @@ -133,7 +130,14 @@ def get_cm(member): CommitteeMeeting.timestamp > start_of_year(), MemberCommitteeAttendance.uid == member.uid, CommitteeMeeting.approved == True # pylint: disable=singleton-comparison - ).all()] + ).all() + + c_meetings = [{ + "uid": cm.uid, + "timestamp": cm.timestamp, + "committee": cm.committee + } for cm in query_result] + return c_meetings From 764af0f7b0d7301be3b9490d89e69635a47f922b Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 14:25:51 -0500 Subject: [PATCH 07/10] fix calculations and remove old function --- conditional/blueprints/dashboard.py | 4 +-- conditional/util/member.py | 44 +++++++---------------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/conditional/blueprints/dashboard.py b/conditional/blueprints/dashboard.py index 6e6d51d..9b3fc17 100644 --- a/conditional/blueprints/dashboard.py +++ b/conditional/blueprints/dashboard.py @@ -16,7 +16,7 @@ from conditional.util.ldap import ldap_is_active from conditional.util.ldap import ldap_is_intromember from conditional.util.ldap import ldap_is_onfloor -from conditional.util.member import get_freshman_data, get_voting_members, get_gatekeep_passed, get_cm, get_hm, req_cm +from conditional.util.member import get_freshman_data, get_voting_memberse, get_cm, get_hm, req_cm logger = structlog.get_logger() @@ -37,7 +37,7 @@ def display_dashboard(user_dict=None): # Get the list of voting members. - can_vote = get_gatekeep_passed() + can_vote = get_voting_memberse() data = {} data['username'] = user_dict['account'].uid diff --git a/conditional/util/member.py b/conditional/util/member.py index 01c7688..e829735 100644 --- a/conditional/util/member.py +++ b/conditional/util/member.py @@ -21,34 +21,6 @@ from conditional.util.ldap import ldap_is_intromember from conditional.util.ldap import ldap_get_member - -@service_cache(maxsize=1024) -def get_voting_members(): - - if datetime.today() < datetime(start_of_year().year, 12, 31): - semester = 'Fall' - else: - semester = 'Spring' - - active_members = set(member.uid for member in ldap_get_active_members()) - intro_members = set(member.uid for member in ldap_get_intro_members()) - on_coop = set(member.uid for member in CurrentCoops.query.filter( - CurrentCoops.date_created > start_of_year(), - CurrentCoops.semester == semester).all()) - voting_set = active_members - intro_members - on_coop - - passed_fall = FreshmanEvalData.query.filter( - FreshmanEvalData.freshman_eval_result == "Passed", - FreshmanEvalData.eval_date > start_of_year() - ).distinct() - - for intro_member in passed_fall: - voting_set.add(intro_member.uid) - - voting_list = list(username for username in voting_set if gatekeep_status(username)["result"]) - return voting_list - - @service_cache(maxsize=1024) def get_members_info(): members = ldap_get_current_students() @@ -166,7 +138,8 @@ def req_cm(member): return 15 return 30 -def get_gatekeep_passed(): +@service_cache(maxsize=256) +def get_voting_memberse(): if datetime.today() < datetime(start_of_year().year, 12, 31): semester = "Fall" semester_start = datetime(start_of_year().year,6,1) @@ -175,7 +148,7 @@ def get_gatekeep_passed(): semester_start = datetime(start_of_year().year + 1,1,1) active_members = set(ldap_get_active_members()) - intro_memberes = set(ldap_get_intro_members()) + intro_members = set(ldap_get_intro_members()) coop_members = CurrentCoops.query.filter( CurrentCoops.date_created > start_of_year(), @@ -202,7 +175,10 @@ def get_gatekeep_passed(): else: passed_fall_members = set(passed_fall_members) - elligible_members = (active_members - intro_memberes - coop_members) | passed_fall_members + active_not_intro = active_members - intro_members + active_not_intro = set(map(lambda member: member.uid, active_not_intro)) + + elligible_members = (active_not_intro - coop_members) | passed_fall_members passing_dm = set(member.uid for member in MemberCommitteeAttendance.query.join( CommitteeMeeting, @@ -244,17 +220,17 @@ def get_gatekeep_passed(): ).filter( HouseMeeting.date >= semester_start, or_( MemberHouseMeetingAttendance.attendance_status == 'Attended', - MemberHouseMeetingAttendance.attendance_status == 'Excused' + # MemberHouseMeetingAttendance.attendance_status == 'Excused' ) ).with_entities( MemberHouseMeetingAttendance.uid ).group_by( MemberHouseMeetingAttendance.uid ).having( - func.count(MemberHouseMeetingAttendance.uid) >= 2 + func.count(MemberHouseMeetingAttendance.uid) >= 6 ).all()) - passing_reqs = passing_dm | passing_ts | passing_hm + passing_reqs = passing_dm & passing_ts & passing_hm return elligible_members & passing_reqs From 1c549c8527bce7e1597c2b3461d6bc4d5420c590 Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 14:34:53 -0500 Subject: [PATCH 08/10] fix linting --- conditional/util/housing.py | 4 ++-- conditional/util/ldap.py | 5 ++--- conditional/util/member.py | 12 ++++++------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/conditional/util/housing.py b/conditional/util/housing.py index 8d93b16..f62f06c 100644 --- a/conditional/util/housing.py +++ b/conditional/util/housing.py @@ -18,7 +18,7 @@ def get_housing_queue(is_eval_director=False): OnFloorStatusAssigned, OnFloorStatusAssigned.uid == InHousingQueue.uid ).with_entities( - InHousingQueue.uid, + InHousingQueue.uid, OnFloorStatusAssigned.onfloor_granted ).all() } @@ -28,7 +28,7 @@ def get_housing_queue(is_eval_director=False): # Populate a list of dictionaries containing the name, username, # and on-floor datetime for each current studetn who has on-floor status - # and is not already assigned to a room + # and is not already assigned to a room queue = [ { "uid": account.uid, diff --git a/conditional/util/ldap.py b/conditional/util/ldap.py index d2b039c..01cb53d 100644 --- a/conditional/util/ldap.py +++ b/conditional/util/ldap.py @@ -1,9 +1,8 @@ +from csh_ldap import CSHMember + from conditional import ldap from conditional.util.cache import service_cache -from csh_ldap import CSHGroup, CSHMember - - def _ldap_get_group_members(group: str) -> list[CSHMember]: return ldap.get_group(group).get_members() diff --git a/conditional/util/member.py b/conditional/util/member.py index e829735..8d987c5 100644 --- a/conditional/util/member.py +++ b/conditional/util/member.py @@ -158,9 +158,9 @@ def get_voting_memberse(): ).scalar() # have to do this because if it's none then set constructor screams - if coop_members == None: + if coop_members is None: coop_members = set() - else: + else: coop_members = set(coop_members) passed_fall_members = FreshmanEvalData.query.filter( @@ -170,7 +170,7 @@ def get_voting_memberse(): func.array_agg(FreshmanEvalData.uid) ).scalar() - if (passed_fall_members == None): + if passed_fall_members is None: passed_fall_members = set() else: passed_fall_members = set(passed_fall_members) @@ -195,7 +195,7 @@ def get_voting_memberse(): ).group_by( MemberCommitteeAttendance.uid ).having( - func.count(MemberCommitteeAttendance.uid) >= 6 + func.count(MemberCommitteeAttendance.uid) >= 6 #pylint: disable=not-callable ).with_entities( MemberCommitteeAttendance.uid ).all()) @@ -211,7 +211,7 @@ def get_voting_memberse(): ).group_by( MemberSeminarAttendance.uid ).having( - func.count(MemberSeminarAttendance.uid) >= 2 + func.count(MemberSeminarAttendance.uid) >= 2 #pylint: disable=not-callable ).all()) passing_hm = set(member.uid for member in MemberHouseMeetingAttendance.query.join( @@ -227,7 +227,7 @@ def get_voting_memberse(): ).group_by( MemberHouseMeetingAttendance.uid ).having( - func.count(MemberHouseMeetingAttendance.uid) >= 6 + func.count(MemberHouseMeetingAttendance.uid) >= 6 #pylint: disable=not-callable ).all()) passing_reqs = passing_dm & passing_ts & passing_hm From a4a80608997ca8e1c0572fc36253347d85d4926c Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 15:34:32 -0500 Subject: [PATCH 09/10] oops fix typo --- conditional/blueprints/dashboard.py | 4 ++-- conditional/util/member.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conditional/blueprints/dashboard.py b/conditional/blueprints/dashboard.py index 9b3fc17..1a75d46 100644 --- a/conditional/blueprints/dashboard.py +++ b/conditional/blueprints/dashboard.py @@ -16,7 +16,7 @@ from conditional.util.ldap import ldap_is_active from conditional.util.ldap import ldap_is_intromember from conditional.util.ldap import ldap_is_onfloor -from conditional.util.member import get_freshman_data, get_voting_memberse, get_cm, get_hm, req_cm +from conditional.util.member import get_freshman_data, get_voting_members, get_cm, get_hm, req_cm logger = structlog.get_logger() @@ -37,7 +37,7 @@ def display_dashboard(user_dict=None): # Get the list of voting members. - can_vote = get_voting_memberse() + can_vote = get_voting_members() data = {} data['username'] = user_dict['account'].uid diff --git a/conditional/util/member.py b/conditional/util/member.py index 8d987c5..2960648 100644 --- a/conditional/util/member.py +++ b/conditional/util/member.py @@ -139,7 +139,7 @@ def req_cm(member): return 30 @service_cache(maxsize=256) -def get_voting_memberse(): +def get_voting_members(): if datetime.today() < datetime(start_of_year().year, 12, 31): semester = "Fall" semester_start = datetime(start_of_year().year,6,1) From 98a8317c33c3fe70fdfc6184731f75774999c2ba Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 17 Jan 2026 15:37:24 -0500 Subject: [PATCH 10/10] squish lines together --- conditional/util/housing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conditional/util/housing.py b/conditional/util/housing.py index f62f06c..b620340 100644 --- a/conditional/util/housing.py +++ b/conditional/util/housing.py @@ -50,8 +50,7 @@ def get_housing_queue(is_eval_director=False): def get_queue_position(username): queue = get_housing_queue() try: - index = next(index for (index, d) in enumerate(queue) - if d["uid"] == username) + 1 + index = next(index for (index, d) in enumerate(queue) if d["uid"] == username) + 1 except (KeyError, StopIteration): index = None return index, len(queue)