Skip to content
Snippets Groups Projects
Commit c4a34bd7 authored by Hague Matthew UXAC009's avatar Hague Matthew UXAC009
Browse files

add(moodle): extend select users to cope with new email format

parent 43de24c4
Branches
No related tags found
No related merge requests found
...@@ -36,6 +36,8 @@ import os ...@@ -36,6 +36,8 @@ import os
import re import re
import sys import sys
from dataclasses import dataclass
from typing import Dict, List, Optional, Set from typing import Dict, List, Optional, Set
from selenium import webdriver from selenium import webdriver
...@@ -100,7 +102,15 @@ class Browser: ...@@ -100,7 +102,15 @@ class Browser:
for c in cookie_jar for c in cookie_jar
] ]
class LDAPEmailGetter: @dataclass(frozen=True, eq=True)
class StudentInfo:
email : str
login : Optional[str]
def login_email(self):
return f"{self.login}@live.rhul.ac.uk"
class LDAPStudentInfoGetter:
def __init__(self, mod_codes : List[str]): def __init__(self, mod_codes : List[str]):
self._mod_codes = mod_codes self._mod_codes = mod_codes
...@@ -109,30 +119,26 @@ class LDAPEmailGetter: ...@@ -109,30 +119,26 @@ class LDAPEmailGetter:
PASS_CMD, stderr=subprocess.DEVNULL PASS_CMD, stderr=subprocess.DEVNULL
).decode("ascii").strip() ).decode("ascii").strip()
self._numbers_to_email = None self._numbers_to_info = None
def lookup(self, number : str) -> Optional[str]: def lookup(self, number : str) -> Optional[StudentInfo]:
numbers_to_email = self._get_numbers_to_email() numbers_to_info = self._get_numbers_to_info()
return numbers_to_info.get(number)
if number in numbers_to_email: def _get_numbers_to_info(self) -> Dict[str, StudentInfo]:
return numbers_to_email[number]
else:
return None
def _get_numbers_to_email(self) -> Dict[str, str]:
"""Get student ID num to email in lower case from LDAP""" """Get student ID num to email in lower case from LDAP"""
if self._numbers_to_email is not None: if self._numbers_to_info is not None:
return self._numbers_to_email return self._numbers_to_info
self._numbers_to_email = dict() self._numbers_to_info = dict()
if len(self._mod_codes) == 0: if len(self._mod_codes) == 0:
return self._numbers_to_email return self._numbers_to_info
if self._username is None: if self._username is None:
return self._numbers_to_email return self._numbers_to_info
if self._password is None: if self._password is None:
return self._numbers_to_email return self._numbers_to_info
try: try:
with ldap3.Connection( with ldap3.Connection(
...@@ -143,19 +149,22 @@ class LDAPEmailGetter: ...@@ -143,19 +149,22 @@ class LDAPEmailGetter:
mod_filter = f"(memberOf=CN=MG_STU_RC_{mod_code}," \ mod_filter = f"(memberOf=CN=MG_STU_RC_{mod_code}," \
"OU=prog-section,OU=student,OU=Distribution Lists," \ "OU=prog-section,OU=student,OU=Distribution Lists," \
"OU=MIIS Managed,DC=cc,DC=rhul,DC=local)" "OU=MIIS Managed,DC=cc,DC=rhul,DC=local)"
student_attrs = ["mail", "extensionAttribute3"] student_attrs = ["mail", "extensionAttribute3", "extensionAttribute2"]
conn.search(LDAP_BASE, mod_filter, attributes=student_attrs) conn.search(LDAP_BASE, mod_filter, attributes=student_attrs)
for student in conn.entries: for student in conn.entries:
self._numbers_to_email[student.extensionAttribute3.value] \ self._numbers_to_info[student.extensionAttribute3.value] \
= student.mail.value.lower() = StudentInfo(
student.mail.value.lower(),
student.extensionAttribute2.value.lower()
)
except Exception as e: except Exception as e:
print("WARNING: LDAP connection failed", e) print("WARNING: LDAP connection failed", e)
return self._numbers_to_email return self._numbers_to_info
def select_users( def select_users(
browser : Browser, emails : Set[str], page_url : str browser : Browser, info : Set[StudentInfo], page_url : str
): ):
"""Select the users on the given page """Select the users on the given page
:param browser: a logged in Moodle browser object :param browser: a logged in Moodle browser object
...@@ -180,41 +189,46 @@ def select_users( ...@@ -180,41 +189,46 @@ def select_users(
email_nodes = browser.driver.find_elements(By.CSS_SELECTOR, email_css) email_nodes = browser.driver.find_elements(By.CSS_SELECTOR, email_css)
to_check_emails = set(i.email for i in info) \
| set(i.login_email() for i in info if i.login)
checked_emails = set() checked_emails = set()
for email_node in email_nodes: for email_node in email_nodes:
email = email_node.text.lower() email = email_node.text.lower()
if email in emails: if email in to_check_emails:
email_node.find_element( email_node.find_element(
By.XPATH, "parent::*//input[@type='checkbox']" By.XPATH, "parent::*//input[@type='checkbox']"
).click() ).click()
checked_emails.add(email) checked_emails.add(email)
print(len(checked_emails), "emails selected") print(len(checked_emails), "emails selected")
for email in emails - checked_emails: for i in info:
print("WARNING: did not select", email) if (
i.email not in checked_emails
and i.login_email() not in checked_emails
):
print("WARNING: did not select", i.email)
def get_emails(mod_codes : List[str], id_file_csv : str): def get_info(mod_codes : List[str], id_file_csv : str) -> Set[StudentInfo]:
"""Returns emails in lower case""" """Returns emails in lower case"""
emails = set() info = set()
email_getter = LDAPEmailGetter(mod_codes) info_getter = LDAPStudentInfoGetter(mod_codes)
with open(id_file_csv) as f: with open(id_file_csv) as f:
for row in csv.DictReader(f): for row in csv.DictReader(f):
id = row["ID"].lower() id = row["ID"].lower()
if "@" in id: if "@" in id:
emails.add(id) info.add(StudentInfo(id, None))
elif re.match(r"\d+", id): elif re.match(r"\d+", id):
email = email_getter.lookup(id) student_info = info_getter.lookup(id)
if email is not None: if student_info is not None:
emails.add(email) info.add(student_info)
else: else:
print("WARNING: could not look up", id) print("WARNING: could not look up", id)
else: else:
print("WARNING: unrecognised ID format", id) print("WARNING: unrecognised ID format", id)
return emails return info
def main(argv): def main(argv):
"""Go, go, go!""" """Go, go, go!"""
...@@ -228,7 +242,7 @@ def main(argv): ...@@ -228,7 +242,7 @@ def main(argv):
id_file_csv = argv[1] id_file_csv = argv[1]
assignment_page_url = argv[2] assignment_page_url = argv[2]
emails = get_emails(mod_codes, id_file_csv) emails = get_info(mod_codes, id_file_csv)
with Browser() as browser: with Browser() as browser:
browser.login() browser.login()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment