Select Git revision
mssql.lib.php
composite_user.py 8.11 KiB
import csv
from typing import ClassVar, Collection, Dict, List, Set
from api.canvas_classes import CanvasUser
from api.canvas_classes import CanvasCourse
from api.gitlab_classes import GitlabUser
from course import Course
NO_PARTNERING_LIST_MAXIMUM = 10
class CompositeUser:
canvas_user: CanvasUser
gitlab_user: GitlabUser
sortable_name: str
readable_name: str
NUID: int
canvas_username: str
gitlab_username: str
canvas_email: str
gitlab_email: str
graylist: Set[str]
blacklist: Set[str]
candidate_teammates: Set[str]
instances: ClassVar[Dict[str, "CompositeUser"]] = {}
def __init__(self, student_dictionary: Dict[str, str], graylist: Collection[str], blacklist: Collection[str]):
self.canvas_user: CanvasUser = None
self.gitlab_user: GitlabUser = None
self.sortable_name: str = student_dictionary['SortableName']
self.readable_name: str = student_dictionary['ReadableName']
self.NUID: int = int(student_dictionary['NUID'])
self.canvas_username: str = student_dictionary['CanvasUsername']
self.gitlab_username: str = student_dictionary['GitlabUsername']
self.canvas_email: str = student_dictionary['CanvasEmail']
self.gitlab_email: str = student_dictionary['GitlabEmail']
self.graylist: Set[str] = set(graylist)
self.blacklist: Set[str] = set(blacklist)
self.candidate_teammates: Set[str] = None
CompositeUser.instances[self.canvas_email] = self
CompositeUser.instances[self.gitlab_email] = self
CompositeUser.instances[self.canvas_username] = self
CompositeUser.instances[self.gitlab_username] = self
@classmethod
def initialize_composite_user(cls, canvas_student: CanvasUser, gitlab_student: GitlabUser) -> "CompositeUser":
student: Dict[str, str] = {'SortableName': canvas_student.get_sortable_name(),
'ReadableName': canvas_student.get_name(),
'NUID': str(canvas_student.get_nuid()),
'CanvasUsername': canvas_student.get_username(),
'CanvasEmail': canvas_student.get_email(),
'GitlabUsername': gitlab_student.get_username(),
'GitlabEmail': gitlab_student.get_email()}
return CompositeUser(student, [], [])
def get_canvas_user(self) -> CanvasUser:
if self.canvas_user is None:
# self.canvas_user = CanvasUser(self.NUID) # n.b., can retrieve own user but not arbitrary user
all_students: List[CanvasUser] = CanvasCourse(Course.canvas_course_id).get_students()
self.canvas_user = list(filter(lambda s: s.get_username() == self.canvas_username, all_students))[0]
return self.canvas_user
def get_gitlab_user(self) -> GitlabUser:
if self.gitlab_user is None:
self.gitlab_user = GitlabUser(self.gitlab_username)
return self.gitlab_user
def set_gitlab_email(self, email: str) -> None:
self.gitlab_email = email
def tentatively_pair_with(self, username: str) -> None:
self.candidate_teammates = {username}
def tentatively_team_with(self, usernames: Collection[str]) -> None:
self.candidate_teammates = set(usernames)
def commit_team(self) -> None: # TODO: Will want to re-visit this based on tracking by project
self.graylist = self.graylist.union(self.candidate_teammates)
def discard_team(self) -> None:
self.candidate_teammates = None
def has_blacklist(self) -> bool:
return len(self.blacklist) > 0
def is_blacklist_compatible(self, other: "CompositeUser") -> bool:
return other.get_canvas_user().get_name() not in self.blacklist and \
self.get_canvas_user().get_name() not in other.blacklist
def is_graylist_compatible(self, other: "CompositeUser") -> bool:
return other.get_canvas_user().get_name() not in self.graylist and \
self.get_canvas_user().get_name() not in other.graylist
def __repr__(self) -> str:
if self.canvas_email == self.gitlab_email:
return f'{self.readable_name}, gitlab @{self.gitlab_username}, email <{self.canvas_email}>'
else:
return f'{self.readable_name}, gitlab @{self.gitlab_username},' \
f' email <{self.canvas_email}> <{self.gitlab_email}>'
def __eq__(self, other: "CompositeUser") -> bool:
# if isinstance(other, CompositeUser):
return self.canvas_username == other.canvas_username
# else:
# return False
def __ne__(self, other: "CompositeUser") -> bool:
return not self.__eq__(other)
def __hash__(self) -> int:
return hash(self.canvas_username)
@classmethod
def get_user(cls, username_or_email: str) -> "CompositeUser":
return cls.instances[username_or_email]
# TODO: Will want to re-visit these based on tracking graylist by project...
@staticmethod
def read_student_csv(filename: str) -> Set["CompositeUser"]:
students: Set[CompositeUser] = set()
with open(filename, mode='r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for csv_student in csv_reader:
graylist: Set[str] = set()
blacklist: Set[str] = set()
for count in range(NO_PARTNERING_LIST_MAXIMUM):
former_partner: str = csv_student[f'Graylist{count}']
undesired_partner: str = csv_student[f'Blacklist{count}']
if former_partner != "":
graylist.add(former_partner)
if undesired_partner != "":
blacklist.add(undesired_partner)
student = CompositeUser(csv_student, graylist, blacklist)
students.add(student)
canvas_students: List[CanvasUser] = CanvasCourse(Course.canvas_course_id).get_students()
for canvas_student in canvas_students:
composite_student = list(filter(lambda s: s.canvas_username == canvas_student.get_username(), students))[0]
composite_student.canvas_user = canvas_student
return students
@staticmethod
def write_student_csv(students: Set["CompositeUser"], filename: str) -> None:
with open(filename, mode='w') as csv_file:
fieldnames = ['SortableName', 'ReadableName', 'NUID',
'CanvasUsername', 'CanvasEmail',
'GitlabUsername', 'GitlabEmail']
for count in range(NO_PARTNERING_LIST_MAXIMUM):
fieldnames.append(f'Graylist{count}')
for count in range(NO_PARTNERING_LIST_MAXIMUM):
fieldnames.append(f'Blacklist{count}')
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
writer.writeheader()
for student in students:
student_dictionary = {'SortableName': student.sortable_name.strip(),
'ReadableName': student.readable_name.strip(),
'NUID': student.NUID,
'CanvasUsername': student.canvas_username,
'CanvasEmail': student.canvas_email,
'GitlabUsername': student.gitlab_username,
'GitlabEmail': student.gitlab_email}
count = 0
for former_partner in student.graylist:
student_dictionary[f'Graylist{count}'] = former_partner
count += 1
# while count < NO_PARTNERING_LIST_MAXIMUM:
# student_dictionary.update({f'Graylist{count}': ''})
# count += 1
count = 0
for undesired_partner in student.blacklist:
student_dictionary[f'Blacklist{count}'] = undesired_partner
count += 1
# while count < NO_PARTNERING_LIST_MAXIMUM:
# student_dictionary.update({f'Blacklist{count}': ''})
# count += 1
writer.writerow(student_dictionary)