def __sub__(self, other): if self.grade != other.grade: ns = NS() ns.status = 'course_grade_changed' ns.left = self ns.right = other ns.param = other.grade yield ns
def __repr__(self): ns = NS() ns.homerooms = " ".join(self.homeroom) ns.emails = ", ".join(self.emails) ns.parents_of = "Parents of " + ", ".join(self.children_ids) ns.family_id = self.family_id ns.ID = self.ID ns.homerooms = "(" + ", ".join(self.homeroom) + ")" ns.courses = "{} courses".format(len(self.courses)) ns.groups = "{} groups".format(len(self.groups)) return ns("<Parent {ID}: {parents_of} {homerooms}>")
def __repr__(self): ns = NS() ns.ID = self.ID ns.username = self.username ns.homeroom = self.homeroom #ns.firstrow = "+ " #ns.midrow = "\n| " #ns.lastrow="\n| " #ns.lastfirst = self.lastfirst #ns.email = self.email #ns.homeroom = self.homeroom #ns.teachers = ", ".join(self.teacher_names) #ns.courses = ", ".join(self.course_names) #ns.groups = ", ".join(self.group_names) #ns.cohorts = ", ".join(self.cohorts) return ns("<Student {ID}/{homeroom}: {username}>") #, {homeroom}{midrow}{lastfirst}") # \
def __sub__(self, other): if self.children != other.children: for to_add in set(other.children) - set(self.children): ns = NS() ns.status = "associate_child_to_parent" ns.left = self ns.right = other ns.param = NS() ns.param.child = to_add ns.param.parent = self.parent_idnumber yield ns for to_remove in set(self.children) - set(other.children): ns = NS() ns.status = "deassociate_child_from_parent" ns.left = self ns.right = other ns.param = NS() ns.param.child = to_remove ns.param.parent = self.parent_idnumber yield ns
def __repr__(self): ns = NS() ns.emails = ", ".join(self.emails) ns.parents_of = "Parents of " + ", ".join(self.children_ids) ns.homerooms = "(" + self._homeroom + ")" ns.family_id = self.family_id ns.ID = self.ID return ns("<MoodleParent {ID}: {parents_of} {homerooms}>")
def __init__(self, verbose=False): #TODO: Get this info from standard settings and config self.verbose = verbose self.logger = logging.getLogger(self.__class__.__name__) self.default_logger = self.logger.debug self.sf = NS() self.email_accounts = config_get_section_attribute('EMAIL', 'check_accounts') self.moodle_accounts = config_get_section_attribute('MOODLE', 'sync') # TODO: Depreciate this stupid dry run thingie, make it a logging feature instead self.dry_run = config_get_section_attribute('DEFAULTS', 'dry_run') self.path_to_cli = config_get_section_attribute('MOODLE', 'path_to_cli') self.path_to_php = config_get_section_attribute('MOODLE', 'path_to_php') if not self.path_to_php: self.path_to_php = '/usr/bin/php' # Moodle requires any php files to be run from the admin/cli directory os.chdir(self.path_to_cli) # And now, spawn it cmd = "{} {}/phpclimoodle.php".format(self.path_to_php, self.path_to_cli) self.process = pexpect.spawn(cmd) self.process.delaybeforesend = 0 # speed things up a bit, eh? self.process.timeout = 3600 self.process.expect_exact('?: ') # not sure why this works the first time
def get_students_filter(self, **kwargs): l = list(self.student_info_controller.keys()) for key in self.student_info_controller.keys(): this = self.get_student(key) if not this: continue if this.compare_kwargs(**kwargs): yield this def check_is_in_preferred_list(this): return this.compare_kwargs(num=35263) if __name__ == "__main__": students = Students() print('Full Name,User Name,Email\n') for student_key in students.get_student_keys(): student = students.get_student(student_key) sf = NS() sf.take_dict(student) if student.grade == 5: print(sf('{first} {last},{username},{email}')) #students.courses_output() #print("Here are the ones with ???:") #students.output_filter(check_is_in_preferred_list) #students.teachers_output() #students.courses_output() #students.students_output()
def go(self): path = None if self.config.has_section("EMAIL"): path = config_get_section_attribute('DIRECTORIES', 'path_to_postfix') if not path: path = self.output_path + '/postfix' ns = self.make_ns() ns.PATH = path ns.EXT = '.txt' ns.INCLUDE = ' :include:' # The clear_folder routine erases all files in a certain folder # That has implications for postfix (when we're on the server), because # if you delete the .db files then postfix won't work. That is bad. # So, tell clear_folder to exclude them exclude_db_files = lambda x: x.endswith('.db') self.logger.debug("Clearing folders in postfix") clear_folder( ns.PATH, exclude=exclude_db_files) clear_folder(ns('{PATH}/grades')) clear_folder(ns('{PATH}/homerooms')) clear_folder(ns('{PATH}/classes')) clear_folder(ns('{PATH}/parentlink')) clear_folder(ns('{PATH}/teacherlink')) clear_folder(ns('{PATH}/special')) clear_folder(ns('{PATH}/departments')) clear_folder(ns('{PATH}/activities')) special_directory = [] self.logger.debug("Setting up largest mailing lists first") for item in ['ALL', 'SEC', 'ELEM', 'KOREAN', 'CHINESE']: ns.this = item special_directory.append( ns('usebccparents{this}{COLON}{INCLUDE}{PATH}{SLASH}special{SLASH}usebccparents{this}{EXT}') ) with open( ns('{PATH}/special{EXT}'), 'w') as f: f.write( "\n".join(special_directory) ) usebccparentsALL = [] usebccstudentsALL = [] usebccparentsELEM = [] usebccparentsSEC = [] usebccstudentsSEC = [] usebccparentsCHINESE = [] usebccparentsCHINESEELEM = [] usebccparentsCHINESESEC = [] usebccparentsCHINESEGRADE = defaultdict(list) usebccparentsKOREAN = [] usebccparentsKOREANELEM = [] usebccparentsKOREANSEC = [] usebccparentsKOREANGRADE = defaultdict(list) usebccparentsJAPANESE = [] usebccparentsJAPANESEELEM = [] usebccparentsJAPANESESEC = [] usebccparentsJAPANESEGRADE = defaultdict(list) # SWA DISTRIBUTION LISTS usebccparentsSWA = [] usebccstudentsSWA = [] usebccparentsSWAGRADE = defaultdict(list) usebccstudentsSWAGRADE = defaultdict(list) # HR AND GRADE usebccparentsHOMEROOM = defaultdict(list) usebccparentsGRADE = defaultdict(list) usebccparentsHOMEROOM = defaultdict(list) usebccstudentsELEM = defaultdict(list) usebccstudentsGRADE = defaultdict(list) usebccstudentsHOMEROOM = defaultdict(list) parentlink = defaultdict(list) teacherlink = defaultdict(list) teachersGRADE = defaultdict(list) hrlink = defaultdict(list) classes = defaultdict(list) classesPARENTS = defaultdict(list) special = defaultdict(list) self.logger.debug('Clearing the table on moodle') self.server_information.create_temp_storage('student_email_info', 'list', 'email') self.server_information.empty_temp_storage('student_email_info') if self.arguments.update_moodle: write_db = self.server_information.add_temp_storage else: write_db = do_nothing self.logger.debug("Setting email lists") for student in self.tree.students: ns.homeroom = student.homeroom ns.grade = student.grade # TODO: Check for now grade or homeroom and warn if student.grade is "" or student.grade is None: self.logger.warn("This student does not have a grade:\n{}".format(student)) if not student.homeroom: self.logger.warn("This student does not have a homeroom:\n{}".format(student)) # USE ns.grade BECAUSE student.grade IS AN INTEGER # TODO: DO WE MAKE student.grade A STRING? # OR PUT THIS IN THE OBJECT SOMEWHOW? if ns.grade <= 0: ns.grade = {0: 'K', -1: 'R', -2: 'G', -3:'PK', -4:'N'}.get(ns.grade, None) usebccparentsALL.extend( student.guardian_emails ) ns.grade and usebccparentsGRADE[ns.grade].extend(student.guardian_emails) ns.homeroom and usebccparentsHOMEROOM[ns.homeroom].extend(student.guardian_emails) if student.is_elementary: usebccparentsELEM.extend(student.guardian_emails) if student.is_secondary: usebccparentsSEC.extend(student.guardian_emails) usebccstudentsSEC.append(student.email) if ns.grade: usebccstudentsGRADE[ns.grade].append(student.email) teachersGRADE[ns.grade].extend(student.teacher_emails) if student.homeroom: usebccstudentsHOMEROOM[ns.homeroom].append(student.email) parentlink[student.username].extend( student.guardian_emails ) teacherlink[student.username].extend(student.teacher_emails) hrlink[student.username].append(student.homeroom_teacher_email) for group in student.group_names: classes[group].append(student.email) classesPARENTS[group].extend(student.guardian_emails) if student.is_chinese: usebccparentsCHINESE.extend( student.guardian_emails ) student.is_secondary and usebccparentsCHINESESEC.extend( student.guardian_emails ) student.is_elementary and usebccparentsCHINESEELEM.extend( student.guardian_emails ) usebccparentsCHINESEGRADE[ns.grade].extend( student.guardian_emails ) if student.is_korean: usebccparentsKOREAN.extend( student.guardian_emails ) student.is_secondary and usebccparentsKOREANSEC.extend( student.guardian_emails ) student.is_elementary and usebccparentsKOREANELEM.extend( student.guardian_emails ) usebccparentsKOREANGRADE[ns.grade].extend( student.guardian_emails ) if student.is_japanese: usebccparentsJAPANESE.extend( student.guardian_emails ) student.is_secondary and usebccparentsJAPANESESEC.extend( student.guardian_emails ) student.is_elementary and usebccparentsJAPANESEELEM.extend( student.guardian_emails ) usebccparentsJAPANESEGRADE[ns.grade].extend( student.guardian_emails ) if student.is_SWA: usebccparentsSWA.extend( student.guardian_emails ) usebccstudentsSWA.append( student.email ) usebccparentsSWAGRADE[ns.grade].extend( student.guardian_emails ) usebccstudentsSWAGRADE[ns.grade].append( student.email ) for ns.email in set(usebccparentsALL): write_db('student_email_info', list='usebccparentsALL', email=ns.email) for ns.email in set(usebccparentsSEC): write_db('student_email_info', list='usebccparentsSEC', email=ns.email) for ns.email in set(usebccparentsELEM): write_db('student_email_info', list='usebccparentsELEM', email=ns.email) for ns.email in set(usebccparentsSWA): write_db('student_email_info', list='usebccparentsSWA', email=ns.email) for ns.email in set(usebccstudentsSWA): write_db('student_email_info', list='usebccstudentsSWA', email=ns.email) for ns.grade in usebccparentsGRADE: for ns.email in set(usebccparentsGRADE[ns.grade]): write_db('student_email_info', list=ns('usebccparents{grade}'), email=ns('{email}')) for ns.grade in usebccstudentsGRADE: for ns.email in set(usebccstudentsGRADE[ns.grade]): write_db('student_email_info', list=ns('usebccstudents{grade}'), email=ns('{email}')) for ns.grade in teachersGRADE: for ns.email in set(teachersGRADE[ns.grade]): write_db('student_email_info', list=ns('teachers{grade}'), email=ns('{email}')) for ns.homeroom in usebccparentsHOMEROOM: for ns.email in set(usebccparentsHOMEROOM[ns.homeroom]): write_db('student_email_info', list=ns('usebccparents{homeroom}'), email=ns('{email}')) for ns.homeroom in usebccstudentsHOMEROOM: for ns.email in set(usebccstudentsHOMEROOM[ns.homeroom]): write_db('student_email_info', list=ns('usebccstudents{homeroom}'), email=ns('{email}')) for ns.student in teacherlink: for ns.email in set(teacherlink[ns.student]): write_db('student_email_info', list=ns('{student}TEACHERS'), email=ns('{email}')) for ns.student in parentlink: for ns.email in set(parentlink[ns.student]): write_db('student_email_info', list=ns('{student}PARENTS'), email=ns('{email}')) for ns.student in hrlink: for ns.email in set(hrlink[ns.student]): write_db('student_email_info', list=ns('{student}HR'), email=ns('{email}')) for ns.klass in classes: for ns.email in classes[ns.klass]: write_db('student_email_info', list=ns('{klass}'), email=ns('{email}')) for ns.klass in classesPARENTS: for ns.email in classes[ns.klass]: write_db('student_email_info', list=ns('{klass}PARENTS'), email=ns('{email}')) # GRADES directory_write = [] for ns.grade in usebccparentsGRADE: directory_write.append( ns('usebccparents{grade}{COLON}{INCLUDE}{PATH}{SLASH}grades{SLASH}usebccparents{grade}{EXT}') ) with open( ns('{PATH}{SLASH}grades{SLASH}usebccparents{grade}{EXT}'), 'w') as f: f.write( '\n'.join(set(usebccparentsGRADE[ns.grade])) ) for ns.grade in usebccstudentsGRADE: directory_write.append( ns('usebccstudents{grade}{COLON}{INCLUDE}{PATH}{SLASH}grades{SLASH}usebccstudents{grade}{EXT}') ) with open( ns('{PATH}{SLASH}grades{SLASH}usebccstudents{grade}{EXT}'), 'w') as f: f.write( '\n'.join(set(usebccstudentsGRADE[ns.grade])) ) for ns.grade in teachersGRADE: directory_write.append( ns('teachers{grade}{COLON}{INCLUDE}{PATH}{SLASH}grades{SLASH}teachers{grade}{EXT}') ) with open( ns('{PATH}{SLASH}grades{SLASH}teachers{grade}{EXT}'), 'w') as f: f.write( '\n'.join(set(teachersGRADE[ns.grade])) ) with open( ns('{PATH}{SLASH}grades{EXT}'), 'w') as f: f.write( '\n'.join(directory_write) ) #HS # HOMEROOMS directory_write = [] for ns.homeroom in usebccparentsHOMEROOM: directory_write.append( ns('usebccparents{homeroom}{COLON}{INCLUDE}{PATH}{SLASH}homerooms{SLASH}usebccparents{homeroom}{EXT}') ) with open( ns('{PATH}{SLASH}homerooms{SLASH}usebccparents{homeroom}{EXT}'), 'w') as f: f.write( '\n'.join(set(usebccparentsHOMEROOM[ns.homeroom])) ) for ns.homeroom in usebccstudentsHOMEROOM: directory_write.append( ns('usebccstudents{homeroom}{COLON}{INCLUDE}{PATH}{SLASH}homerooms{SLASH}usebccstudents{homeroom}{EXT}') ) with open( ns('{PATH}{SLASH}homerooms{SLASH}usebccstudents{homeroom}{EXT}'), 'w') as f: f.write( '\n'.join(set(usebccstudentsHOMEROOM[ns.homeroom])) ) with open( ns('{PATH}{SLASH}homerooms{EXT}'), 'w') as f: f.write( '\n'.join(directory_write) ) # TEACHERLINK directory_write = [] for ns.student in teacherlink: directory_write.append( ns('{student}TEACHERS{COLON}{INCLUDE}{PATH}{SLASH}teacherlink{SLASH}{student}TEACHERS{EXT}') ) with open( ns('{PATH}{SLASH}teacherlink{SLASH}{student}TEACHERS{EXT}'), 'w') as f: f.write( '\n'.join(set(teacherlink[ns.student])) ) with open( ns('{PATH}{SLASH}teacherlink{EXT}'), 'w') as f: f.write( '\n'.join(directory_write) ) # PARENTLINK directory_write = [] for ns.student in parentlink: directory_write.append( ns('{student}PARENTS{COLON}{INCLUDE}{PATH}{SLASH}parentlink{SLASH}{student}PARENTS{EXT}') ) with open( ns('{PATH}{SLASH}parentlink{SLASH}{student}PARENTS{EXT}'), 'w') as f: f.write( '\n'.join(set(parentlink[ns.student])) ) with open( ns('{PATH}{SLASH}parentlink{EXT}'), 'w') as f: f.write( '\n'.join(directory_write) ) # HRLINK directory_write = [] for ns.student in hrlink: if hrlink[ns.student]: # not all kids have a homeroom teacher.... directory_write.append( ns('{student}HR{COLON}{INCLUDE}{PATH}{SLASH}homeroomlink{SLASH}{student}HR{EXT}') ) with open( ns('{PATH}{SLASH}homeroomlink{SLASH}{student}HR{EXT}'), 'w') as f: try: f.write( '\n'.join(set(hrlink[ns.student])) ) except TypeError: pass with open( ns('{PATH}{SLASH}homeroomlink{EXT}'), 'w') as f: f.write( '\n'.join(directory_write) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsALL{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsALL) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsSEC{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsSEC) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsELEM{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsELEM) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsCHINESE{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsCHINESE) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsCHINESESEC{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsCHINESESEC) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsCHINESEELEM{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsCHINESEELEM) ) for ns.grade in usebccparentsCHINESEGRADE: with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsCHINESE{grade}{EXT}'), 'w') as f: f.write( '\n'.join(set(usebccparentsCHINESEGRADE[ns.grade])) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsKOREAN{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsKOREAN) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsKOREANELEM{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsKOREANSEC) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsKOREANSEC{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsKOREANSEC) ) for ns.grade in usebccparentsKOREANGRADE: with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsKOREAN{grade}{EXT}'), 'w') as f: f.write( '\n'.join(set(usebccparentsKOREANGRADE[ns.grade])) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsJAPANESE{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsJAPANESE) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsJAPANESESEC{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsJAPANESESEC) ) for ns.grade in usebccparentsJAPANESEGRADE: with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsJAPANESE{grade}{EXT}'), 'w') as f: f.write( '\n'.join(set(usebccparentsJAPANESEGRADE[ns.grade])) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsSWA{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsSWA) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccstudentsSWA{EXT}'), 'w') as f: f.write( '\n'.join(usebccstudentsSWA) ) with open( ns('{PATH}{SLASH}special{EXT}'), 'w') as f: for ns.this in ['usebccparentsALL', 'usebccparentsSEC', 'usebccparentsELEM', 'usebccparentsKOREAN', 'usebccparentsKOREANSEC', 'usebccparentsKOREANELEM', 'usebccparentsCHINESE', 'usebccparentsCHINESESEC', 'usebccparentsCHINESEELEM', 'usebccparentsJAPANESE', 'usebccparentsJAPANESESEC', 'usebccparentsJAPANESEELEM', 'usebccparentsSWA', 'usebccstudentsSWA']: f.write( ns('{this}{COLON}{INCLUDE}{PATH}{SLASH}special{SLASH}{this}{EXT}{NEWLINE}') ) for ns.grade in usebccparentsKOREANGRADE: f.write( ns('usebccparentsKOREAN{grade}{COLON}{INCLUDE}{PATH}{SLASH}special{SLASH}usebccparentsKOREAN{grade}{EXT}{NEWLINE}') ) for ns.grade in usebccparentsCHINESEGRADE: f.write( ns('usebccparentsCHINESE{grade}{COLON}{INCLUDE}{PATH}{SLASH}special{SLASH}usebccparentsCHINESE{grade}{EXT}{NEWLINE}') ) for ns.grade in usebccparentsJAPANESEGRADE: f.write( ns('usebccparentsJAPANESE{grade}{COLON}{INCLUDE}{PATH}{SLASH}special{SLASH}usebccparentsJAPANESE{grade}{EXT}{NEWLINE}') ) # CLASSES directory_write = [] for ns.klass in classes: directory_write.append( ns('{klass}{COLON}{INCLUDE}{PATH}{SLASH}classes{SLASH}{klass}{EXT}') ) for ns.klass in classesPARENTS: directory_write.append( ns('{klass}PARENTS{COLON}{INCLUDE}{PATH}{SLASH}classes{SLASH}{klass}PARENTS{EXT}') ) with open( ns('{PATH}{SLASH}classes{EXT}'), 'w') as f: f.write( '\n'.join(directory_write) ) for ns.klass in classes: with open( ns('{PATH}{SLASH}classes{SLASH}{klass}{EXT}'), 'w') as f: f.write( '\n'.join(set(classes[ns.klass])) ) for ns.klass in classesPARENTS: with open( ns('{PATH}{SLASH}classes{SLASH}{klass}PARENTS{EXT}'), 'w') as f: f.write( '\n'.join(set(classesPARENTS[ns.klass])) ) self.logger.debug("Set up department batch emails") ## SETUP DEPARTMENTS, including by homeroom teachers depart_dict = {} homeroom_teachers_dict = {} for teacher in self.tree.teachers: departments = teacher.get_departments() for department in departments: d_email_name = department_email_names.get(department) if not d_email_name: continue if not d_email_name in list(depart_dict.keys()): heads = department_heads.get(department, []) # returns a list depart_dict[d_email_name] = [] for head in heads: self.logger.debug("Adding {} (the head) into department {}".format(head, d_email_name)) depart_dict[d_email_name].append(head + "@ssis-suzhou.net") if teacher and not teacher.email in depart_dict[d_email_name]: self.logger.debug("Adding {} into department {}".format(teacher, d_email_name)) depart_dict[d_email_name].append(teacher.email) if teacher.homeroom: ns.homeroom = teacher.homeroom if not teacher.homeroom in homeroom_teachers_dict.keys(): homeroom_teachers_dict[teacher.homeroom] = True setup_postfix = ns('{PATH}/departments{EXT}') with open(setup_postfix, 'a') as f: f.write(ns("homeroomteachers{homeroom}: :include:{PATH}/departments/homeroomteachers{homeroom}{EXT}\n")) setup_postfix = ns('{PATH}/departments/homeroomteachers{homeroom}{EXT}') with open(setup_postfix, 'a') as f: f.write(teacher.email + '\n') for ns.department in list(depart_dict.keys()): # department is now actually the email name we want to use setup_postfix = ns('{PATH}/departments{EXT}') with open(setup_postfix, 'a') as f: f.write( ns("{department}: :include:{PATH}/departments/{department}{EXT}\n") ) setup_postfix = ns('{PATH}/departments/{department}{EXT}') with open(setup_postfix, 'w') as f: f.write( "\n".join(depart_dict[ns.department]) ) # SETUP SECONDARY ACTIVITIES results = self.server_information.get_all_users_activity_enrollments() ns = NS() ns.domain = 'student.ssis-suzhou.net' activities_postfix = defaultdict(list) activities_postfix_parents = defaultdict(list) for result in results: activity_name, student_key = result student = self.tree.student_from_ID(student_key) if not student: # in case of outlyer continue if not student: self.logger.warning('This student is listed as having enrolled into an activity, ' + \ 'but no longer seems to be available at school. Ignored. {}'.format(student_key)) continue activities_postfix[activity_name].append(student.email) activities_postfix_parents[activity_name].append(student.parent_link_email) # DO THE ACTIVITY EMAILS ns.path = config_get_section_attribute('DIRECTORIES', 'path_to_postfix') ns.base = 'activities' ns.SUFFIX = "ACT" ns.EXT = '.txt' ns.INCLUDE = ':include:' ns.activities_path = ns('{path}{SLASH}activities') with open(ns('{path}{SLASH}{base}{EXT}'), 'w'): pass for activity_name in activities_postfix: ns.handle = name_to_email(activity_name) ns.full_email = ns('{handle}{SUFFIX}') with open(ns('{path}{SLASH}{base}{EXT}'), 'a') as f: f.write(ns('{full_email}{COLON}{SPACE}{INCLUDE}' + \ '{activities_path}{SLASH}{full_email}{EXT}{NEWLINE}')) with open(ns('{activities_path}{SLASH}{full_email}{EXT}'), 'a') as f: f.write("\n".join(activities_postfix[activity_name])) ns.SUFFIX = "ACTPARENTS" for activity_name in activities_postfix_parents: ns.handle = name_to_email(activity_name) ns.full_email = ns('{handle}{SUFFIX}') with open(ns('{path}{SLASH}{base}{EXT}'), 'a') as f: f.write(ns('{full_email}{COLON}{SPACE}{INCLUDE}' + \ '{activities_path}{SLASH}{full_email}{EXT}{NEWLINE}')) with open(ns('{activities_path}{SLASH}{full_email}{EXT}'), 'a') as f: f.write("\n".join(activities_postfix_parents[activity_name])) # run newaliases command on exit if we're on the server newaliases_path = False if self.config.has_section('EMAIL'): newaliases_path = self.config['EMAIL'].get('newaliases_path') if newaliases_path: self.logger.info("Running newaliases") p = subprocess.Popen(newaliases_path, shell=True) self.logger.info(p.communicate()) else: self.logger.warn("newaliases not run!")
def no_email(self, student): sf = NS(student) sf.new_student_cmd = self.new_email_cmd self.shell( sf("/bin/bash {new_student_cmd} {num} {username} '{lastfirst}'") )
where = line.index(search_item) message = line[ (where+ len(search_item)+1): -1] match = re.search("orig_to=<(.*?)>", line) if match: orig_to = match.group(1) if args.stdout: print(to_who) print(orig_to) bounce = bounces[to_who] bounce.key = escape(to_who) bounce.count += 1 bounce.messages.append(escape(message)) email = Email(domain) email.add_to('*****@*****.**') email.make_subject("Bounces") email.define_sender('DragonNet Admin <*****@*****.**>') html = "<html>" for bounce in bounces: ns = NS(bounces[bounce]) ns.messages = "<br />".join(ns.messages) ns.BR = '<br />' html += ns('<p>Email{COLON}{SPACE}{key}{SPACE} ' \ 'How many bounces{COLON}{SPACE}{count}{BR}<i>{messages}</i></p>') html+= "</html>" email.define_content(html) if not args.no_emails: email.send() if args.stdout: print(email.htmls['en'])
def __sub__(self, other): for item in super().__sub__(other): yield item # Handle cohorts (site-wide groups) for to_add in set(other.cohort_idnumbers) - set(self.cohort_idnumbers): ns = NS() ns.status = 'add_to_cohort' ns.left = self ns.right = other ns.param = to_add yield ns for to_remove in set(self.cohort_idnumbers) - set(other.cohort_idnumbers): ns = NS() ns.status = 'remove_from_cohort' ns.left = self ns.right = other ns.param = to_remove yield ns # Other things attrs = ['username', 'email', 'homeroom'] for attr in attrs: if not getattr(self, attr) == getattr(other, attr): ns = NS() ns.status = attr+'_changed' ns.left = self ns.right = other ns.param = getattr(other, attr) yield ns for course in set(other.enrollments.keys()) - set(self.enrollments.keys()): for group in other.enrollments[course]: ns = NS() ns.status = 'enrol_parent_into_course' ns.left = self ns.right = other to_add = NS() to_add.course = course to_add.group = group ns.param = to_add yield ns for course in set(self.enrollments.keys()) and set(other.enrollments.keys()): #TODO: Check that parents are being put into courses as well as the groups self_groups = self.enrollments.get(course, []) other_groups = other.enrollments.get(course, []) for group in other_groups: if not group.idnumber in [g.idnumber for g in self_groups]: ns = NS() ns.status = 'add_to_group' ns.left = self ns.right = other to_add = NS() to_add.course = course to_add.group = group ns.param = to_add yield ns for group in self_groups: if not group.idnumber in [g.idnumber for g in other_groups]: ns = NS() ns.status = 'remove_from_group' ns.left = self ns.right = other to_remove = NS() to_remove.course = course to_remove.group = group ns.param = to_remove yield ns for course in set(self.enrollments.keys()) - set(other.enrollments.keys()): for group in self.enrollments.get(course, []): ns = NS() ns.status = 'deenrol_parent_from_course' ns.left = self ns.right = other to_remove = NS() to_remove.course = course to_remove.group = group ns.param = to_remove yield ns
def __init__(self): super().__init__() self.raw = self.sql("select distinct usr.firstname, usr.lastname, dr.timecreated, dc.content, dc.fieldid, dc.recordid from ssismdl_data_content dc " + "join ssismdl_data_records dr on dc.recordid = dr.id " + "join ssismdl_user usr on dr.userid = usr.id " + "join ssismdl_data_fields df on dc.fieldid = df.id " + "join ssismdl_data d on df.dataid = 4 order by dc.recordid")() record_ids = [] path_to_probe = config_get_section_attribute("DIRECTORIES", 'path_to_output') path_to_probe += '/probe/' for line in self.raw: r_id = line[k_record_id] if not r_id in record_ids: record_ids.append( r_id ) # teachers holds the data organized by teachers teachers = defaultdict(list) # powerschool variable holds the data that will actually be written to file powerschool = ['Student_Number\tTest_Date\tGrade_Level\tReading_Age_1\tScore_2\tCategory_3\tIndications_3\tDifferential_1'] # reads in student info from powerschool autosend student_info = Tree() # loop through the records in the database module, match them up with the student info # and export the data accordingly for record_id in record_ids: this_entry = [ i for i in self.raw if i[k_record_id] == record_id ] if this_entry: entry = NS() entry.teacher = this_entry[0][0] + " " + this_entry[0][1] entry.date = timestamp_to_python_date(this_entry[0][2]) entry.date_entered = entry.date.strftime('%m/%d/%Y') entry.test_date = {2012:make_date(2012, 10, 15), 2013:make_date(2013, 5, 15)}.get(entry.date.year) entry.test_date_output = entry.test_date.strftime('%m/%d/%Y') for row in this_entry: field_id = row[k_field_id] if field_id == k_student_name: entry.student = row[k_content] entry.powerschoolid = entry.student match = re.search( '\((.*) (.*)\)', entry.student) if match: entry.homeroom, entry.powerschoolid = match.groups() entry.grade = re.sub('[A-Z]', '', entry.homeroom) else: entry.homeroom = '' entry.grade = -1 elif field_id == k_percentage: entry.percent = row[k_content] elif field_id == k_analysis: entry.analysis = ', '.join(row[k_content].split('##')) if row[k_content] else "" elif field_id == k_type: entry.type = row[k_content] elif field_id == k_set: entry.set = row[k_content] if not entry.set: print(this_entry) entry.reading_age = reading_age_from_set.get(entry.set) # gets the student class that has autosend data student = student_info.get_student(str(entry.powerschoolid)) if not student: # student no longer at ssis continue if not entry.reading_age: # no longer in the system (left) just skip it # what about that dude's data!? print("Something wrong with the data of this student") continue date_to_age = lambda x: float(x.days) / 365.25 entry.age = date_to_age(entry.test_date - student.birthday) entry.differential = round(entry.reading_age - entry.age, 2) teachers[entry.teacher].append( entry ) powerschool.append( entry('{powerschoolid}{TAB}{test_date_output}{TAB}{grade}{TAB}{reading_age}{TAB}{percent}{TAB}{type}{TAB}{analysis}{TAB}{differential}') ) with open(path_to_probe + 'powerschool.txt', 'w') as f: f.write( "\n".join(powerschool) ) for teacher in teachers: with open(path_to_probe + '{}.txt'.format(teacher), 'w') as f: entries = teachers[teacher] entries.sort(key=lambda x: x.student) for entry in entries: f.write(entry.student+ '\n') f.write("\tSet: {}\n".format(entry.set)) f.write("\tPercent: {}\n".format(entry.percent)) f.write("\tAnalysis: {}\n".format(entry.analysis)) f.write("\tType: {}\n".format(entry.type)) f.write('\n')
def __sub__(self, other): for item in super().__sub__(other): yield item # Handle cohorts (site-wide groups) for to_add in set(other.cohort_idnumbers) - set(self.cohort_idnumbers): ns = NS() ns.status = 'add_to_cohort' ns.left = self ns.right = other ns.param = to_add yield ns # for to_remove in set(self.cohort_idnumbers) - set(other.cohort_idnumbers): # ns = NS() # ns.status = 'remove_from_cohort' # ns.left = self # ns.right = other # ns.param = to_remove # yield ns # Other things attrs = ['username'] for attr in attrs: if not getattr(self, attr) == getattr(other, attr): ns = NS() ns.status = attr+'_changed' ns.left = self ns.right = other ns.param = getattr(other, attr) yield ns for course in set(other.enrollments.keys()) - set(self.enrollments.keys()): for group in other.enrollments[course]: ns = NS() ns.status = 'enrol_teacher_into_course' ns.left = self ns.right = other to_add = NS() to_add.course = course to_add.group = group ns.param = to_add yield ns # Go through each course that they share, and check that # they have the same groups, if not, do what's right for course in set(self.enrollments.keys()) and set(other.enrollments.keys()): self_groups = self.enrollments[course] other_groups = other.enrollments[course] for group in other_groups: if not group.idnumber in [g.idnumber for g in self_groups]: ns = NS() ns.status = 'add_to_group' ns.left = self ns.right = other to_add = NS() to_add.course = course to_add.group = group ns.param = to_add yield ns
class CallPHP: """ Interfaces with php file phpclimoodle.php """ def __init__(self, verbose=False): #TODO: Get this info from standard settings and config self.verbose = verbose self.logger = logging.getLogger(self.__class__.__name__) self.default_logger = self.logger.debug self.sf = NS() self.email_accounts = config_get_section_attribute('EMAIL', 'check_accounts') self.moodle_accounts = config_get_section_attribute('MOODLE', 'sync') # TODO: Depreciate this stupid dry run thingie, make it a logging feature instead self.dry_run = config_get_section_attribute('DEFAULTS', 'dry_run') self.path_to_cli = config_get_section_attribute('MOODLE', 'path_to_cli') self.path_to_php = config_get_section_attribute('MOODLE', 'path_to_php') if not self.path_to_php: self.path_to_php = '/usr/bin/php' # Moodle requires any php files to be run from the admin/cli directory os.chdir(self.path_to_cli) # And now, spawn it cmd = "{} {}/phpclimoodle.php".format(self.path_to_php, self.path_to_cli) self.process = pexpect.spawn(cmd) self.process.delaybeforesend = 0 # speed things up a bit, eh? self.process.timeout = 3600 self.process.expect_exact('?: ') # not sure why this works the first time def command(self, routine, cmd): """ Interfaces with pexpect """ self.verbose and print('sending {} {}'.format(routine, cmd)) try: self.process.sendline(routine + ' ' + cmd) except OSError: if routine == "QUIT": return # this is expected, nevermind if self.process.isalive(): self.logger.warning("Huh. Error but it's still alive!") else: self.logger.warning("The other side just up and died") # We know that the phpclimoodle file returns a plus if it's all good # and a negative if not, handle accordingly success_string = '\+.*' error_string = '-\d+ .*' try: which = self.process.expect([success_string, error_string]) except Exception as e: which = 1 self.logger.critical(self.process.after) raise e self.verbose and print("which {}".format(which)) if which == 0: pass elif which == 1: the_string = self.process.after.decode('utf-8')[:-5] self.logger.warning(the_string) # make sure this is a warning else: self.logger.critical(self.process.after.decode('utf-8')) # This will probably be something essential exit() self.verbose and input() def create_new_course(self, idnumber, fullname): self.command('create_new_course', "{} '{}'".format(idnumber, fullname)) def create_online_portfolio(self, idnumber): self.command('create_online_portfolio', '{}'.format(idnumber)) def create_account(self, username, email, firstname, lastname, idnumber, auth='manual'): self.sf.define(username=username, email=email, firstname=firstname, lastname=lastname, idnumber=idnumber, auth=auth) to_pass = self.sf("{username} '{email}' '{firstname}' '{lastname}' {idnumber} {auth}") self.command('create_account', to_pass) def delete_account(self, useridnumber): print("Deleteing {}".format(useridnumber)) self.command('delete_account', useridnumber) def create_group_for_course(self, course_id, group_name): self.command('create_group_for_course {} {}'.format(course_id, group_name)) def create_inactive_account(self, username, email, firstname, lastname, idnumber): """ CREATE A 'SUSPENDED' ACCOUNT (MAKES MORE SENSE TO CALL IT INACTIVE WHEN CREATING IT) SIMPLY BY PASSING nologin TO THE FUNCTION OTHERWISE, SAME AS create_account """ self.sf.define(username=username, email=email, firstname=firstname, lastname=lastname, idnumber=idnumber) to_pass = self.sf("{username} {email} '{firstname}' '{lastname}' {idnumber} nologin") self.command('create_account', to_pass) def enrol_user_into_course(self, idnumber, shortname, group_id, group_name, role): self.sf.define(idnumber=idnumber, shortname=shortname, group_id=group_id, group_name=group_name, role=role) to_pass = self.sf("{idnumber} '{shortname}' '{group_id}' '{group_name}' {role}") self.command('enrol_user_in_course', to_pass) def unenrol_user_from_course(self, idnumber, course): self.sf.define(idnumber=idnumber, course=course) self.command('deenrol_user_from_course', self.sf('{idnumber} {course}')) def add_user_to_cohort(self, useridnumber, cohortidnumber): self.sf.define(useridnumber=useridnumber, cohortidnumber=cohortidnumber) to_pass = self.sf("{useridnumber} '{cohortidnumber}'") self.command('add_user_to_cohort', to_pass) def remove_user_from_cohort(self, useridnumber, cohortidnumber): self.sf.define(useridnumber=useridnumber, cohortidnumber=cohortidnumber) to_pass = self.sf("{useridnumber} '{cohortidnumber}'") self.command('remove_user_from_cohort', to_pass) def new_cohort(self, cohortidnumber, cohortname): self.command("create_cohort {} '{}'".format(cohortidnumber, cohortname)) def add_user_to_group(self, userid, group_id): self.sf.define(userid=userid, group_id=group_id) to_pass = self.sf("{userid} '{group_id}'") self.command('add_user_to_group', to_pass) def remove_user_from_group(self, userid, group_id): self.sf.define(userid=userid, group_id=group_id) to_pass = self.sf("{userid} '{group_id}'") self.command('remove_user_from_group', to_pass) def add_group(self, group_id, group_name, course_id): self.sf.define(group_id=group_id, group_name=group_name, course_id=course_id) to_pass = self.sf("{course_id} '{group_id}' '{group_name}'") self.command('create_group_for_course', to_pass) def delete_group(self, group, course): self.sf.define(group=group, course=course) to_pass = self.sf("{course} '{group}'") self.command('delete_group_for_course', to_pass) def change_username(self, idnumber, new_name): self.command('change_username', "{} {}".format(idnumber, new_name)) def change_parent_username(self, idnumber, new_username, password): self.command('change_parent_username', "{} {} {}".format(idnumber, new_username, password)) def associate_child_to_parent(self, idnumber, child_idnumber): self.command('associate_child_to_parent', "{} {}".format(idnumber, child_idnumber)) def __del__(self): """ Kill the spawned process """ if self.process.isalive: try: self.command('QUIT', '') except: pass
try: where = long_name.index(')') except ValueError: where = -1 where += 1 long_name = long_name[where:].strip().lower() return re.sub('[^a-z]', '', long_name) if __name__ == "__main__": students = Tree() db = MoodleDBConnection() sf = NS() results = db.get_all_users_activity_enrollments() sf.domain = 'student.ssis-suzhou.net' sf.AT = '@' from collections import defaultdict postfix = defaultdict(list) activities = defaultdict(list) homerooms = defaultdict( lambda : defaultdict(list) ) # PARSE RESULTS for result in results: activity_name, student_key = result student = students.get_student(student_key) if not student: