diff --git a/conditional/blueprints/attendance.py b/conditional/blueprints/attendance.py index 387b5b31..47531dfa 100644 --- a/conditional/blueprints/attendance.py +++ b/conditional/blueprints/attendance.py @@ -10,10 +10,12 @@ from conditional.models.models import FreshmanCommitteeAttendance from conditional.models.models import FreshmanHouseMeetingAttendance from conditional.models.models import FreshmanSeminarAttendance +from conditional.models.models import FreshmanSeminarHost from conditional.models.models import HouseMeeting from conditional.models.models import MemberCommitteeAttendance from conditional.models.models import MemberHouseMeetingAttendance from conditional.models.models import MemberSeminarAttendance +from conditional.models.models import MemberSeminarHost from conditional.models.models import TechnicalSeminar from conditional.util.auth import get_user from conditional.util.flask import render_template @@ -218,6 +220,8 @@ def submit_seminar_attendance(user_dict=None): seminar_name = post_data['name'] m_attendees = post_data['members'] f_attendees = post_data['freshmen'] + m_host = post_data['member_host'] + f_host = post_data['freshman_host'] timestamp = post_data['timestamp'] timestamp = datetime.strptime(timestamp, "%Y-%m-%d") @@ -230,10 +234,16 @@ def submit_seminar_attendance(user_dict=None): for m in m_attendees: log.info(f'Gave Attendance to {m} for {seminar_name}') db.session.add(MemberSeminarAttendance(m, seminar.id)) + for m in m_host: + log.info(f'Gave Host Credit to {m} for {seminar_name}') + db.session.add(MemberSeminarHost(m, seminar.id)) for f in f_attendees: log.info(f'Gave Attendance to freshman-{f} for {seminar_name}') db.session.add(FreshmanSeminarAttendance(f, seminar.id)) + for f in f_host: + log.info(f'Gave Host Credit to freshman-{f} for {seminar_name}') + db.session.add(FreshmanSeminarHost(f, seminar.id)) db.session.commit() return jsonify({"success": True}), 200 @@ -379,6 +389,18 @@ def get_seminar_attendees(meeting_id): FreshmanAccount.id == freshman).first().name) return attendees + def get_seminar_hosts(meeting_id): + hosts = [ldap_get_member(a.uid).displayName for a in + MemberSeminarHost.query.filter( + MemberSeminarHost.seminar_id == meeting_id).all()] + + for freshman in [a.fid for a in + FreshmanSeminarHost.query.filter( + FreshmanSeminarHost.seminar_id == meeting_id).all()]: + hosts.append(FreshmanAccount.query.filter( + FreshmanAccount.id == freshman).first().name) + return hosts + log = logger.new(request=request, auth_dict=user_dict) if not user_dict_is_eboard(user_dict): @@ -402,6 +424,7 @@ def get_seminar_attendees(meeting_id): "name": m.name, "dt_obj": m.timestamp, "date": m.timestamp.strftime("%a %m/%d/%Y"), + "hosts": get_seminar_hosts(m.id), "attendees": get_seminar_attendees(m.id), "type": "ts" } for m in TechnicalSeminar.query.filter( @@ -419,6 +442,7 @@ def get_seminar_attendees(meeting_id): "name": m.name, "dt_obj": m.timestamp, "date": m.timestamp.strftime("%a %m/%d/%Y"), + "hosts": get_seminar_hosts(m.id), "attendees": get_seminar_attendees(m.id) } for m in TechnicalSeminar.query.filter( TechnicalSeminar.timestamp > start_of_year(), @@ -433,6 +457,7 @@ def get_seminar_attendees(meeting_id): history=all_meetings, pending_cm=pend_cm, pending_ts=pend_ts, + all_ts=all_ts, num_pages=total_pages, current_page=int(page)) @@ -483,19 +508,33 @@ def alter_seminar_attendance(sid, user_dict=None): meeting_id = sid m_attendees = post_data['members'] f_attendees = post_data['freshmen'] + m_host = post_data['member_host'] + f_host = post_data['freshman_host'] FreshmanSeminarAttendance.query.filter( FreshmanSeminarAttendance.seminar_id == meeting_id).delete() + FreshmanSeminarHost.query.filter( + FreshmanSeminarHost.seminar_id == meeting_id).delete() + MemberSeminarAttendance.query.filter( MemberSeminarAttendance.seminar_id == meeting_id).delete() + MemberSeminarHost.query.filter( + MemberSeminarHost.seminar_id == meeting_id).delete() + for m in m_attendees: db.session.add(MemberSeminarAttendance(m, meeting_id)) + for m in m_host: + db.session.add(MemberSeminarHost(m, meeting_id)) + for f in f_attendees: db.session.add(FreshmanSeminarAttendance(f, meeting_id)) + for f in f_host: + db.session.add(FreshmanSeminarHost(f, meeting_id)) + db.session.flush() db.session.commit() return jsonify({"success": True}), 200 @@ -512,12 +551,25 @@ def get_cm_attendees(sid, user_dict=None): MemberSeminarAttendance.query.filter( MemberSeminarAttendance.seminar_id == sid).all()] + host = [{"value": a.uid, + "display": ldap_get_member(a.uid).displayName + } for a in + MemberSeminarHost.query.filter( + MemberSeminarHost.seminar_id == sid).all()] + for freshman in [{"value": a.fid, "display": FreshmanAccount.query.filter(FreshmanAccount.id == a.fid).first().name } for a in FreshmanSeminarAttendance.query.filter( FreshmanSeminarAttendance.seminar_id == sid).all()]: attendees.append(freshman) - return jsonify({"attendees": attendees}), 200 + + for freshman in [{"value": a.fid, + "display": FreshmanAccount.query.filter(FreshmanAccount.id == a.fid).first().name + } for a in FreshmanSeminarHost.query.filter( + FreshmanSeminarHost.seminar_id == sid).all()]: + host.append(freshman) + + return jsonify({"attendees": attendees, "host": host}), 200 log = logger.new(request=request, auth_dict=user_dict) log.info(f'Delete Technical Seminar {sid}') @@ -527,8 +579,12 @@ def get_cm_attendees(sid, user_dict=None): FreshmanSeminarAttendance.query.filter( FreshmanSeminarAttendance.seminar_id == sid).delete() + FreshmanSeminarHost.query.filter( + FreshmanSeminarHost.seminar_id == sid).delete() MemberSeminarAttendance.query.filter( MemberSeminarAttendance.seminar_id == sid).delete() + MemberSeminarHost.query.filter( + MemberSeminarHost.seminar_id == sid).delete() TechnicalSeminar.query.filter( TechnicalSeminar.id == sid).delete() diff --git a/conditional/blueprints/dashboard.py b/conditional/blueprints/dashboard.py index 44a88037..8ae51c71 100644 --- a/conditional/blueprints/dashboard.py +++ b/conditional/blueprints/dashboard.py @@ -6,6 +6,7 @@ from conditional.models.models import HouseMeeting from conditional.models.models import MemberHouseMeetingAttendance from conditional.models.models import MemberSeminarAttendance +from conditional.models.models import MemberSeminarHost from conditional.models.models import TechnicalSeminar from conditional.models.models import SpringEval from conditional.util.auth import get_user @@ -106,11 +107,21 @@ def display_dashboard(user_dict=None): MemberSeminarAttendance.uid == uid, ) if is_seminar_attendance_valid(s)] data['ts_total'] = len(t_seminars) + # technical seminars hosted + t_seminars_hosted = [s.seminar_id for s in + MemberSeminarHost.query.filter( + MemberSeminarHost.uid == uid, + ) if is_seminar_attendance_valid(s)] + data['ts_hosted_total'] = len(t_seminars_hosted) attendance = [m.name for m in TechnicalSeminar.query.filter( TechnicalSeminar.id.in_(t_seminars) )] + hosted = [m.name for m in TechnicalSeminar.query.filter( + TechnicalSeminar.id.in_(t_seminars_hosted) + )] data['ts_list'] = attendance + data['ts_hosted'] = hosted spring['mp_status'] = "Failed" for mp in data['major_projects']: @@ -164,6 +175,7 @@ def display_dashboard(user_dict=None): 'status': gatekeep_result, 'committee_meetings': gatekeep_info['c_meetings'], 'technical_seminars': gatekeep_info['t_seminars'], + 'technical_seminars_hosted': gatekeep_info['t_seminars_hosted'], 'hm_missed': gatekeep_info['h_meetings_missed'] } diff --git a/conditional/blueprints/gatekeep.py b/conditional/blueprints/gatekeep.py index c7fb0ae6..9d40d250 100644 --- a/conditional/blueprints/gatekeep.py +++ b/conditional/blueprints/gatekeep.py @@ -4,7 +4,7 @@ from conditional import start_of_year, auth from conditional.models.models import CommitteeMeeting, HouseMeeting, MemberCommitteeAttendance, \ - MemberSeminarAttendance, TechnicalSeminar + MemberSeminarAttendance, MemberSeminarHost, TechnicalSeminar from conditional.models.models import MemberHouseMeetingAttendance from conditional.util.auth import get_user from conditional.util.flask import render_template @@ -59,6 +59,23 @@ def display_spring_evals(internal=False, user_dict=None): MemberSeminarAttendance.uid ).all()} + ts_host_count = {row[0]: row[1] for row in MemberSeminarHost.query.join( + TechnicalSeminar, + MemberSeminarHost.seminar_id == TechnicalSeminar.id + ).with_entities( + MemberSeminarHost.uid, + TechnicalSeminar.timestamp, + TechnicalSeminar.approved, + ).filter( + TechnicalSeminar.approved, + TechnicalSeminar.timestamp >= semester_start + ).with_entities( + MemberSeminarHost.uid, + func.count(MemberSeminarHost.uid) #pylint: disable=not-callable + ).group_by( + MemberSeminarHost.uid + ).all()} + hm_missed = {row[0]: row[1] for row in MemberHouseMeetingAttendance.query.join( HouseMeeting, MemberHouseMeetingAttendance.meeting_id == HouseMeeting.id @@ -93,8 +110,9 @@ def display_spring_evals(internal=False, user_dict=None): cm_attended_count = cm_count.get(uid, 0) ts_attended_count = ts_count.get(uid, 0) + ts_hosted_count = ts_host_count.get(uid, 0) - passing = len(member_missed_hms) <= 1 and cm_attended_count >= 6 and ts_attended_count >= 2 + passing = len(member_missed_hms) <= 1 and cm_attended_count >= 6 and (ts_attended_count >= 2 or ts_hosted_count >= 1) status = 'disenfranchised' @@ -107,8 +125,10 @@ def display_spring_evals(internal=False, user_dict=None): 'status': status, 'committee_meetings': cm_attended_count, 'technical_seminars': ts_attended_count, + 'technical_seminars_hosted': ts_hosted_count, 'req_meetings': 6, 'req_seminars': 2, + 'req_seminars_hosted': 1, 'house_meetings_missed': member_missed_hms, } @@ -128,4 +148,5 @@ def display_spring_evals(internal=False, user_dict=None): members=gk_members, gatekeep_active=gatekeep_active, req_meetings=6, - req_seminars=2) + req_seminars=2, + req_seminars_hosted=1) diff --git a/conditional/blueprints/intro_evals.py b/conditional/blueprints/intro_evals.py index 262ae18b..397b5c5c 100644 --- a/conditional/blueprints/intro_evals.py +++ b/conditional/blueprints/intro_evals.py @@ -9,10 +9,12 @@ from conditional.models.models import FreshmanEvalData from conditional.models.models import FreshmanHouseMeetingAttendance from conditional.models.models import FreshmanSeminarAttendance +from conditional.models.models import FreshmanSeminarHost from conditional.models.models import HouseMeeting from conditional.models.models import MemberCommitteeAttendance from conditional.models.models import MemberHouseMeetingAttendance from conditional.models.models import MemberSeminarAttendance +from conditional.models.models import MemberSeminarHost from conditional.models.models import TechnicalSeminar from conditional.util.auth import get_user from conditional.util.flask import render_template @@ -70,7 +72,23 @@ def get_intro_members_without_accounts(): TechnicalSeminar.name ).all() + freshman_ts_host_query = FreshmanSeminarHost.query.join( + TechnicalSeminar, + FreshmanSeminarHost.seminar_id == TechnicalSeminar.id + ).with_entities( + FreshmanSeminarHost.fid, + TechnicalSeminar.timestamp, + TechnicalSeminar.approved + ).filter( + TechnicalSeminar.approved, + TechnicalSeminar.timestamp >= semester_start + ).with_entities( + FreshmanSeminarHost.fid, + TechnicalSeminar.name + ).all() + freshman_ts_attendance_dict = {} + freshman_ts_host_dict = {} for row in freshman_ts_attendance_query: if not row[0] in freshman_ts_attendance_dict: @@ -78,6 +96,12 @@ def get_intro_members_without_accounts(): freshman_ts_attendance_dict[row[0]].append(row[1]) + for row in freshman_ts_host_query: + if not row[0] in freshman_ts_host_dict: + freshman_ts_host_dict[row[0]] = [] + + freshman_ts_host_dict[row[0]].append(row[1]) + # freshmen who don't have accounts freshman_accounts = list(FreshmanAccount.query.filter( FreshmanAccount.eval_date >= semester_start)) @@ -114,6 +138,7 @@ def get_intro_members_without_accounts(): 'committee_meetings_passed': cms_attended >= 6, 'house_meetings_missed': missed_hms, 'technical_seminars': freshman_ts_attendance_dict.get(freshman_account.id, []), + 'technical_seminars_hosted': freshman_ts_host_dict.get(freshman_account.id, []), 'social_events': '', 'comments': "", 'ldap_account': False, @@ -183,13 +208,35 @@ def display_intro_evals(internal=False, user_dict=None): TechnicalSeminar.name ).all() + account_ts_hosted_query = MemberSeminarHost.query.join( + TechnicalSeminar, + MemberSeminarHost.seminar_id == TechnicalSeminar.id + ).with_entities( + MemberSeminarHost.uid, + TechnicalSeminar.timestamp, + TechnicalSeminar.approved + ).filter( + TechnicalSeminar.approved, + TechnicalSeminar.timestamp >= semester_start + ).with_entities( + MemberSeminarHost.uid, + TechnicalSeminar.name + ).all() + account_ts_attendance_dict = {} + account_ts_hosted_dict = {} for row in account_ts_attendance_query: if not row[0] in account_ts_attendance_dict: account_ts_attendance_dict[row[0]] = [] account_ts_attendance_dict[row[0]].append(row[1]) + + for row in account_ts_hosted_query: + if not row[0] in account_ts_hosted_dict: + account_ts_hosted_dict[row[0]] = [] + + account_ts_hosted_dict[row[0]].append(row[1]) # freshmen who have accounts for member in members: @@ -229,6 +276,7 @@ def display_intro_evals(internal=False, user_dict=None): 'committee_meetings_passed': cms_attended >= 6, 'house_meetings_missed': member_missed_hms, 'technical_seminars': account_ts_attendance_dict.get(uid, []), + 'technical_seminars_hosted': account_ts_hosted_dict.get(uid, []), 'social_events': freshman_data.social_events, 'comments': freshman_data.other_notes, 'ldap_account': True, diff --git a/conditional/blueprints/member_management.py b/conditional/blueprints/member_management.py index 17adaddc..5fa8f8de 100644 --- a/conditional/blueprints/member_management.py +++ b/conditional/blueprints/member_management.py @@ -13,7 +13,9 @@ from conditional.models.models import FreshmanCommitteeAttendance from conditional.models.models import MemberCommitteeAttendance from conditional.models.models import FreshmanSeminarAttendance +from conditional.models.models import FreshmanSeminarHost from conditional.models.models import MemberSeminarAttendance +from conditional.models.models import MemberSeminarHost from conditional.models.models import FreshmanHouseMeetingAttendance from conditional.models.models import MemberHouseMeetingAttendance from conditional.models.models import HouseMeeting @@ -422,6 +424,9 @@ def member_management_deleteuser(fid, user_dict=None): for fts in FreshmanSeminarAttendance.query.filter(FreshmanSeminarAttendance.fid == fid): db.session.delete(fts) + for ftsh in FreshmanSeminarHost.query.filter(FreshmanSeminarHost.fid == fid): + db.session.delete(ftsh) + for fhm in FreshmanHouseMeetingAttendance.query.filter(FreshmanHouseMeetingAttendance.fid == fid): db.session.delete(fhm) @@ -464,6 +469,9 @@ def member_management_upgrade_user(user_dict=None): for fts in FreshmanSeminarAttendance.query.filter(FreshmanSeminarAttendance.fid == fid): db.session.add(MemberSeminarAttendance(uid, fts.seminar_id)) + + for ftsh in FreshmanSeminarHost.query.filter(FreshmanSeminarHost.fid == fid): + db.session.add(MemberSeminarHost(uid, ftsh.seminar_id)) for fhm in FreshmanHouseMeetingAttendance.query.filter(FreshmanHouseMeetingAttendance.fid == fid): # Don't duplicate HM attendance records diff --git a/conditional/models/models.py b/conditional/models/models.py index f3a52072..7f4d3769 100644 --- a/conditional/models/models.py +++ b/conditional/models/models.py @@ -106,6 +106,28 @@ def __init__(self, name, timestamp, approved): self.active = True +class MemberSeminarHost(db.Model): + __tablename__ = 'member_seminar_host' + id = Column(Integer, primary_key=True) + uid = Column(String(32), nullable=False, index=True) + seminar_id = Column(ForeignKey('technical_seminars.id'), nullable=False) + + def __init__(self, uid, seminar_id): + self.uid = uid + self.seminar_id = seminar_id + + +class FreshmanSeminarHost(db.Model): + __tablename__ = 'freshman_seminar_host' + id = Column(Integer, primary_key=True) + fid = Column(ForeignKey('freshman_accounts.id', ondelete="cascade"), nullable=False, index=True) + seminar_id = Column(ForeignKey('technical_seminars.id'), nullable=False) + + def __init__(self, fid, seminar_id): + self.fid = fid + self.seminar_id = seminar_id + + class MemberSeminarAttendance(db.Model): __tablename__ = 'member_seminar_attendance' id = Column(Integer, primary_key=True) diff --git a/conditional/templates/attendance_history.html b/conditional/templates/attendance_history.html index 7f50fb6a..0b534f1f 100644 --- a/conditional/templates/attendance_history.html +++ b/conditional/templates/attendance_history.html @@ -42,7 +42,12 @@
{{seminar["date"]}}
+
Host: + {% for name in seminar["hosts"] %} + {{name}}{% if not loop.last %}, {% endif %} + {% endfor %} +
+Attendees: {% for name in seminar["attendees"] %} {{name}}{% if not loop.last %}, {% endif %} {% endfor %} @@ -68,7 +73,14 @@
{{meeting["date"]}}
+ {% if meeting in all_ts %} +
Host: + {% for name in meeting["hosts"] %} + {{name}}{% if not loop.last %}, {% endif %} + {% endfor %} +
+ {% endif %} +Attendees: {% for name in meeting["attendees"] %} {{name}}{% if not loop.last %}, {% endif %} {% endfor %} @@ -121,6 +133,10 @@