def inform_new_student(student): path_to_templates = config_get_section_attribute('DIRECTORIES', 'path_to_templates') student_email_templates = read_in_templates(path_to_templates + '/student_new_account') sender = '"DragonNet Admin" <*****@*****.**>' sf = NS(student) email = Email(config_get_section_attribute('EMAIL', 'domain')) email.define_sender('*****@*****.**', "DragonNet Admin") email.use_templates(student_email_templates) email.make_subject(sf("New Student in Homeroom {homeroom}, {lastfirst}")) homeroom_teacher = student.homeroom_teacher if homeroom_teacher: email.add_to(homeroom_teacher.email) # ssis does not want this feature #for guardian_email in student.guardian_emails: # email.add_to(guardian_email) # for class_teacher in student.get_teachers_as_list(): # email.add_to(class_teacher + '@ssis-suzhou.net') # if student.grade in [11, 12]: # email.add_cc('*****@*****.**') # email.add_cc('*****@*****.**') # elif student.grade in [6, 7, 8, 9, 10]: # email.add_cc('*****@*****.**') email.add_bcc('*****@*****.**') email.add_bcc('*****@*****.**') email.define_fields(sf) email.send()
def __init__(self): """ Does the work of reading in basic information from file, creates native Python structures StudentNumber\tHomeroom\tLastFirst\tguardianemails """ self.settings = define_command_line_arguments( 'verbose', 'log_level', 'dry_run', 'teachers', 'courses', 'students', 'email_list', 'families', 'parents', 'automagic_emails', 'profiles', 'input_okay', 'updaters', 'enroll_cohorts', 'enroll_courses', 'remove_enrollments', inspect_student=False) self.logger = logging.getLogger(self.__class__.__name__) self.path_to_powerschool = config_get_section_attribute('DIRECTORIES', 'path_to_powerschool_dump') self.path_to_output = config_get_section_attribute('DIRECTORIES', 'path_to_output') self.student_info_file = AutoSendFile('dist', 'studentinfo') self.student_info_controller = Controller(Student) self.course_info_controller = Controller(Course) self.teacher_info_controller = Controller(Teacher) self.schedule_info_controller = Controller(Schedule) self.allocation_info_controller = Controller(Allocation) self.user_data = ServerInfo().get_student_info() self.read_in() homerooms = None self._secondary_homerooms = None self._elementary_homerooms = None self.get_homerooms() self.get_secondary_homerooms()
def __init__(self, school, unique): """ Main task here is to set self.path """ self.logger = logging.getLogger(self.__class__.__name__) path_to_powerschool = config_get_section_attribute('DIRECTORIES', 'path_to_powerschool_dump') if not path_to_powerschool: raise NotImplemented("Something wrong with the powerschool directory information") self.school = school self.unique = unique self.convert_entities = HTMLParser().unescape self.debug = config_get_section_attribute('DEBUGGING', 'print_autosend') # Dynamically look at the directory and use the latest version path = path_to_powerschool + '/' + version_format.format(minor_version='', **locals()) path = path.split(os.path.sep)[-1] candidates = [g for g in [f.split(os.path.sep)[-1] for f in os.listdir(path_to_powerschool)] if path in g] candidates = sorted(candidates) if not candidates: self.debug and self.logger.warning("Autosend file not present for {} {}\ncontent method set to yield nothing".format(self.school, self.unique)) self.content = lambda *args, **kwargs: [] return final = candidates[-1] self.path = path_to_powerschool + '/' + final self.debug and self.logger.warning('Autosend: {}_{}\nParsing this file: {}'.format(school, unique, self.path))
def __init__(self): sf = NS() sf.db_name = config_get_section_attribute('MOODLE', 'db_name') sf.db_username = config_get_section_attribute('MOODLE', 'db_username') sf.db_password = config_get_section_attribute('MOODLE', 'db_password') sf.db_host = config_get_section_attribute('MOODLE', 'db_host') self.db = postgresql.open(sf('pq://{db_username}:{db_password}@{db_host}/{db_name}')) self.sql = self.db.prepare
def post_to_wordpress(self, url, blog, author, hour, format=True): """ SIMPLISTIC WAY TO GET WHAT COULD BE AN EMAIL ONTO A WORDPRESS BLOG REQUIRES wp-cli https://github.com/wp-cli/wp-cli """ if format: self.prepare_formatting() path_to_wordpress = config_get_section_attribute('SITES', 'path_to_docroot', required=True) path_to_wpcli = config_get_section_attribute('SITES', 'path_to_wpcli', required=True) if not url: wordpress_url = config_get_section_attribute('SITES', 'url', required=True) else: wordpress_url = url # Get the user information first command = "{} --path={} user get {} --format=json ".format(path_to_wpcli, path_to_wordpress, author) to_call = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) result, err = to_call.communicate() import json user = json.loads(result.decode()) # Now clean up the html, add links if not there and remove errant tags, also clean up for passing on try: from lxml.html.clean import Cleaner from lxml.html.clean import autolink_html except ImportError: click.secho('We need lxml!', fg='red') content = self.get_html() cleaner = Cleaner(remove_tags=['p', 'div']) # Moodle's editor has loads of lonely p and div tags content = cleaner.clean_html(content) content = autolink_html(content) replace_apostrophes = "'\\''" content = content.replace("'", replace_apostrophes).replace('\r', ' ') # escape apostrophes for bash date_as_string = '{}-{}-{} {}:{}:00'.format(self.date.year, self.date.month, self.date.day, hour.tm_hour, hour.tm_min) d = { 'title': self.get_subject(), # remove the 'Student Notices for' part 'author': user['ID'], 'content': content, 'date': date_as_string, 'blog': blog, 'url': wordpress_url, 'path_to_wpcli': path_to_wpcli, 'path_to_docroot': path_to_wordpress } command = """{path_to_wpcli} post create --path={path_to_docroot} --post_type=post --post_title='{title}' --post_content='{content}' --post_author={author} --post_status=future --post_date='{date}' --url={url}/{blog}""".format(**d) subprocess.call(command, shell=True)
def remove_user_from_all_groups(self, user): """ Used in old_* accounts functions """ debug = config_get_section_attribute('DEBUGGING', 'inspect_soft_deletion_groups') for group in user.groups: self.logger.warning("Removing old_student {} from group {} ".format(user, group)) self.moodlemod.remove_user_from_group(user.idnumber, group.idnumber)
def check_for_keep_username_startswith(self, user): with_what = config_get_section_attribute('MOODLE', 'keep_username_startswith') if not with_what: return False with_what = with_what.split(',') for this in with_what: if user.username.startswith(this): return True return False
def process_courses(self): debug = config_get_section_attribute('DEBUGGING', 'print_courses') for course in self.district_courses.content(): new = self.courses.make_without_conversion( course.idnumber, course.fullname, course.grade, course.database_id ) debug and self.logger.warning(new) if debug: from IPython import embed embed()
def process(self): # Basically just calls every process_x method we have debug = config_get_section_attribute('DEBUGGING', 'print_process') order = ['students', 'teachers', 'parents', 'parent_links', 'cohorts', 'courses', 'schedules', 'mrbs_editors'] for o in order: method_name = 'process_{}'.format(o) method = getattr(self, method_name) debug and self.logger.warning(method) method() self._processed = True
def __init__(self): self.logger = logging.getLogger(self.__class__.__name__) self.logger.warn('Started at {}'.format( datetime.datetime.now() ) ) self.arguments = define_command_line_arguments(*self.switches, **self.strings) self.config = config self.tree = InfoController() if 'DEFAULTS' in self.config.sections(): for key in self.config['DEFAULTS']: setattr(self, key, self.config.getboolean('DEFAULTS', key)) self.email_server = None # TODO: Figure out if this is really needed if self.config.has_section("EMAIL"): self.email_server = self.config['EMAIL'].get('domain') if not self.email_server: self.email_server = 'localhost' have_email_section = self.config.has_section('EMAIL') have_moodle_section = self.config.has_section('MOODLE') # moodle link self.server_information = ServerInfo() # required paths self.path_to_powerschool = config_get_section_attribute('DIRECTORIES', 'path_to_powerschool_dump') self.path_to_output = config_get_section_attribute('DIRECTORIES', 'path_to_output') self.path_to_errors = config_get_section_attribute('DIRECTORIES', 'path_to_errors')
def inform_parent_username_changed(parent, password): """ parent is object """ path_to_templates = config_get_section_attribute('DIRECTORIES', 'path_to_templates') parent_email_templates = read_in_templates(path_to_templates + '/parent_username_changed') email = Email(config_get_section_attribute('EMAIL', 'domain')) email.define_sender('*****@*****.**', "DragonNet Admin") email.use_templates(parent_email_templates) email.make_subject("Notification of updated SSIS DragonNet username") email.add_to(parent.email) for student in parent.children: if student.is_korean: email.add_language('kor') if student.is_chinese: email.add_language('chi') email.add_bcc('*****@*****.**') email.add_bcc('*****@*****.**') email.define_field('username', parent.email) email.define_field('salutation', 'Dear SSIS Parent') email.define_field('password', password) email.send()
def inform_new_parent(parent): """ parent is object """ path_to_templates = config_get_section_attribute('DIRECTORIES', 'path_to_templates') parent_email_templates = read_in_templates(path_to_templates + '/parent_new_account') email = Email(config_get_section_attribute('EMAIL', 'domain')) email.define_sender('*****@*****.**', "DragonNet Admin") email.use_templates(parent_email_templates) email.make_subject("Your SSIS DragonNet Parent Account") for parent_email in parent.emails: email.add_to(parent_email) for student in parent.children: if student.is_korean: email.add_language('kor') if student.is_chinese: email.add_language('chi') email.add_bcc('*****@*****.**') email.add_bcc('*****@*****.**') email.define_field('username', parent.email) email.define_field('salutation', 'Dear Parent') email.send()
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 email_user(path_to_users, username=None, idnumber=None): """ Check to see if user has their account set up or not. """ if path_to_users == 'path_to_users': from psmdlsyncer.settings import config_get_section_attribute path_to_users = config_get_section_attribute('DIRECTORIES', 'path_to_users') import os yes = "User has an account in this system" no = "User does NOT have an account system" _list = os.listdir(path_to_users) if idnumber and idnumber in _list: click.echo(yes) return if username and username in _list: click.echo(yes) return click.echo(no)
def process_schedules(self): """ Schedule should just have the keys for student and teachers """ for school in ['elementary', 'secondary']: self.logger.warning('{} processing {} schedule'.format(self.__class__.__name__, school)) # calls both secondary_schedule.content, elementary_schedule.content method = getattr(self, "{}_schedule".format(school)) for schedule in method.content(): self.default_logger('Processing {} schedule: {}'.format(school, schedule)) course_key, period_info, section_number, teacher_key, student_key = schedule course = self.courses.get(course_key, self.convert_course) student = self.students.get_key(student_key) # Do some sanity checks if not student: self.default_logger("Student not found, sometimes happens for some odd reason {}".format(student_key)) continue if not course: self.logger.debug("Course not found! {}".format(course_key)) continue if course.exclude: self.default_logger("Course {} has been excluded!".format(course_key)) # And so we should skip this schedule entirely! continue teacher = self.teachers.get_key(teacher_key) if not teacher: self.logger.warning("Teacher not found! {}".format(teacher_key)) continue group = self.groups.make_group(student, course, teacher, section_number, period_info) if not group: self.logger.warning("Group not found! {}".format(section_number)) continue self.associate(course, teacher, group, student) if student.login_method == 'manual': self.online_portfolios.make(student.idnumber) if str(config_get_section_attribute('DEBUGGING', 'inspect_teacher_schedule')) == teacher_key: self.logger.warning('{}\n{}\n{}\n'.format(teacher, group, student)) from IPython import embed embed()
def student_emails(path_to_output, user_id, group_id): """ Output into a file stuff needed for PowerSchool to read in via AutoCom """ from psmdlsyncer.settings import config, config_get_section_attribute from psmdlsyncer.sql import MoodleDBSession path_to_powerschool = config_get_section_attribute('DIRECTORIES', 'path_to_powerschool_dump') db = MoodleDBSession() with open(path_to_output, 'w') as _file: for student in db.users_enrolled_in_this_cohort('studentsALL'): if student.idnumber and student.username and student.email: if student.idnumber != '99999': _file.write('{},{},{}\n'.format(student.idnumber, student.username, student.email)) import os os.chown(path_to_output, int(user_id), int(group_id))
def init(self): # Setup formatting templates for emails, can be overridden if different look required # The default below creates a simple list format # Need two {{ and }} because it goes through a parser later at another layer # Also, since it goes to an email, CSS is avoided self.start_html_tag = '<html>' self.end_html_tag = "</html>" self.header_pre_tag = '<h3>' self.header_post_tag = "</h3>" self.begin_section_tag = "<ul>" self.end_section_tag = "</ul>" self.begin_list_tag = '<li>' self.end_list_tag = "</li>" self.colon = ":" self.attachment_header = 'Attachments' self.email_editing = False self.server = config_get_section_attribute('EMAIL', 'domain') if not self.server: print("Using localhost for mail server") self.server = 'localhost' self.name = self.__class__.__name__.replace("_", " ") # Class-specific settings, which are delegated to sub-classes self.define() # Initial values month = self.date.month day = self.date.day year = self.date.year if self.section_field: self.section_field_object = FieldObject(self.database_name, self.section_field) self.section_field_default_value = self.section_field_object.default_value() else: self.section_field_object = None self.section_field_default_value = None self.start_date_field = StartDateField(self.database_name, 'Start Date') self.end_date_field = EndDateField(self.database_name, 'End Date') self.process() self.edit_word = "Edit"
def membership(username): from psmdlsyncer.settings import config_get_section_attribute from functools import partial import os # Set up directory and path checks with partials path_to_postfix = config_get_section_attribute('DIRECTORIES', 'path_to_postfix', required=True) os.chdir(path_to_postfix) resolve_this = partial(os.path.join, os.getcwd()) for this_one in os.listdir('.'): full_path = resolve_this(this_one) if os.path.isdir(full_path): os.chdir(full_path) for file_name in os.listdir('.'): group, _ = os.path.splitext(file_name) with open(os.path.join(os.getcwd(), file_name)) as _file: for line in _file: if username in line: click.echo(group)
def go(self, **kwargs): debug = config_get_section_attribute('DEBUGGING', 'print_dispatches') for item in self.subtract(): if self.template and hasattr(item, 'status'): if item.status in ['new_teacher', 'new_student']: self._repeat = True dispatch = self.template.get(item.status) else: dispatch = None if dispatch: debug and print(item) if self.teachersonly: if item.right and hasattr(item.right, 'idnumber') and self.right.teachers.get_key(item.right.idnumber): dispatch(item) elif self.studentsonly: if item.right and hasattr(item.right, 'idnumber') and self.right.students.get_key(item.right.idnumber): dispatch(item) else: dispatch(item) else: #TODO: Handle unrecognized statuses here self.logger.warning("This item wasn't handled, because a handler ({}) wasn't defined!".format(item.status))
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!")
from psmdlsyncer.settings import config_get_section_attribute import datetime import re output = config_get_section_attribute('DIRECTORIES', 'path_to_output') def out(line): with open(output + '/mail_stats.txt', 'a') as f: f.write(str(line) + '\n') today = datetime.datetime.today().strftime('%b %d') out("-----------") out(today) students = {} pop3 = {} imap = {} count = 0 with open('/var/log/dovecot.log') as f: for line in f: if re.match(r'^'+today, line): userinfo = re.sub(r'^(.*?)Login: user=<', '', line) userinfo = re.sub(r'>.*', '', userinfo) userinfo = userinfo.strip('\n').strip() if not ' ' in userinfo: if not userinfo in students: students[userinfo] = 0 students[userinfo] += 1 pop = re.match(r'.* pop3.*', line) if pop: if not userinfo in list(pop3.keys()): pop3[userinfo] = 0
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 __init__(self, school, unique): self.school = school self.unique = unique self.path_to_passwd = config_get_section_attribute('EMAIL', 'path_to_passwd')
from psmdlsyncer.settings import config_get_section_attribute from psmdlsyncer.sql import MoodleDBConnection import postgresql import datetime convert = datetime.datetime.fromtimestamp output = config_get_section_attribute("DIRECTORIES", "path_to_output") def out(line): with open(output + "/account_stats.txt", "a") as f: f.write(str(line) + "\n") out(datetime.datetime.today()) has = 0 cannot = 0 last_week = 0 last_month = 0 oneweekago = datetime.datetime.today() - datetime.timedelta(days=7) onemonthago = datetime.datetime.today() - datetime.timedelta(days=30) dnet = MoodleDBConnection() raw = dnet.call_sql("select lastaccess,lastlogin,idnumber from ssismdl_user where idnumber like '%P' and deleted=0") total = len(raw) for line in raw: lastaccess, lastlogin, idnumber = line lastaccess_date = convert(lastaccess) lastlogin_date = convert(lastlogin)
def __init__(self): super().__init__() self.default_logger = self.logger.debug self.new_email_cmd = config_get_section_attribute('DIRECTORIES', 'path_to_newstudent_script')
from psmdlsyncer.settings import config, config_get_section_attribute print('done') import csv path_to_students = config_get_section_attribute('DIRECTORIES', 'path_to_powerschool_dump') path_to_students += '/ssis_dist_studentinfo_v4.0' with open(path_to_students) as _file: readin = csv.reader(_file, delimiter='\t') for line in readin: print(line)
def process_schedules(self): super().process_schedules() path = None if config.has_section("EMAIL"): path = config_get_section_attribute('DIRECTORIES', 'path_to_postfix') if not path: path = self.output_path + '/postfix' ns = NS2() 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 = [] koreanstudentsSEC = [] chinesestudentsSEC = [] usebccparentsCHINESE = [] usebccparentsCHINESEELEM = [] usebccparentsCHINESESEC = [] usebccparentsCHINESEGRADE = defaultdict(list) usebccparentsKOREAN = [] usebccparentsKOREANELEM = [] usebccparentsKOREANSEC = [] usebccparentsKOREANGRADE = defaultdict(list) usebccparentsJAPANESE = [] usebccparentsJAPANESEELEM = [] usebccparentsJAPANESESEC = [] usebccparentsJAPANESEGRADE = defaultdict(list) # SWA DISTRIBUTION LISTS usebccparentsSWA = [] usebccstudentsSWA = [] usebccparentsNOTSWA = [] usebccparentsSWAGRADE = defaultdict(list) usebccstudentsSWAGRADE = defaultdict(list) usebccparentsGERMAN = [] usebccparentsNOTGERMAN = [] # 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) for student in self.students.get_objects(): 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) parentlink[student.username].extend( student.guardian_emails ) teacherlink[student.username].extend(student.teacher_emails) hrlink[student.username].append(student.homeroom_teacher_email) 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.groups: classes[group.idnumber].append(student.email) classesPARENTS[group.idnumber].extend(student.guardian_emails) if student.is_korean: koreanstudentsSEC.append( student.email ) if student.is_chinese: chinesestudentsSEC.append( student.email ) if student.is_chinese and not excluded_from_chinese_list(student): 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_german: usebccparentsGERMAN.extend( student.guardian_emails ) else: usebccparentsNOTGERMAN.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 ) else: usebccparentsNOTSWA.extend( student.guardian_emails ) # 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}usebccparentsNOTSWA{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsNOTSWA) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsGERMAN{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsGERMAN) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccparentsNOTGERMAN{EXT}'), 'w') as f: f.write( '\n'.join(usebccparentsNOTGERMAN) ) with open( ns('{PATH}{SLASH}special{SLASH}usebccstudentsSWA{EXT}'), 'w') as f: f.write( '\n'.join(usebccstudentsSWA) ) with open( ns('{PATH}{SLASH}special{SLASH}koreanstudentsSEC{EXT}'), 'w') as f: f.write( '\n'.join(koreanstudentsSEC) ) with open( ns('{PATH}{SLASH}special{SLASH}chinesestudentsSEC{EXT}'), 'w') as f: f.write( '\n'.join(chinesestudentsSEC) ) 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', 'usebccparentsNOTSWA', 'usebccparentsNOTGERMAN', 'usebccparentsGERMAN', 'koreanstudentsSEC', 'chinesestudentsSEC']: 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.teachers.get_objects(): 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]) )
import logging import re import os import csv from psmdlsyncer.settings import config_get_section_attribute from html.parser import HTMLParser # This is the version of the autosend files # With each increase of number in the version, means that something about the fields have changed from within autosend major_version = 4 prefix = config_get_section_attribute('AUTOSEND', 'prefix') version_format = "{prefix}_{{school}}_{{unique}}_v{major_version}.{{minor_version}}".format(prefix=prefix, major_version=major_version) class AutoSendImport: def __init__(self, school, unique): """ Main task here is to set self.path """ self.logger = logging.getLogger(self.__class__.__name__) path_to_powerschool = config_get_section_attribute('DIRECTORIES', 'path_to_powerschool_dump') if not path_to_powerschool: raise NotImplemented("Something wrong with the powerschool directory information") self.school = school self.unique = unique self.convert_entities = HTMLParser().unescape
result = 100 + trans[re.sub("[0-9]", "", what)] elif "7" in what: result = 200 + trans[re.sub("[0-9]", "", what)] elif "8" in what: result = 300 + trans[re.sub("[0-9]", "", what)] elif "9" in what: result = 400 + trans[re.sub("[0-9]", "", what)] elif "10" in what: result = 500 + trans[re.sub("[0-9]", "", what)] elif "11" in what: result = 600 + trans[re.sub("[0-9]", "", what)] elif "12" in what: result = 700 + trans[re.sub("[0-9]", "", what)] elif re.sub("[1..9]", "", what): result = ord(re.sub("[1..9]", "", what)[0]) return result area = config_get_section_attribute("EMAIL", "aliases_path") area += "/homerooms" import os user = os.listdir(area) for item in user: item = item.strip() item = item.replace(".txt", "@student.ssis-suzhou.net") item = '<a href="mailto:?bcc={0}">{0}</a><br />'.format(item) print(item)
""" """ import re path_to_mail_log = '/var/log/mail.log' from psmdlsyncer.settings import config_get_section_attribute, \ define_command_line_arguments from psmdlsyncer.html_email import Email from psmdlsyncer.utils import NS from collections import defaultdict from xml.sax.saxutils import escape args = define_command_line_arguments('stdout', 'no_emails') output = config_get_section_attribute('DIRECTORIES', 'path_to_output') domain = config_get_section_attribute('EMAIL', 'domain') if not domain: domain = 'localhost' def out(line): with open(output + '/bounce_stats.txt', 'a') as f: f.write(str(line) + '\n') class Bounce: def __init__(self): self.count = 0 self.messages = [] self.key = "" def __repr__(self): return self.key + ': ' + str(self.count) + '\n' + str(self.messages) bounces = defaultdict(Bounce) for line in open(path_to_mail_log): for search_item in ['status=bounced', 'status=deferred']: