From 9c8cd3c176e64c9ef4fffdb2a0f57475e068abbf Mon Sep 17 00:00:00 2001 From: Romain Lebbadi-Breteau <romain@lebbadi.fr> Date: Tue, 29 Aug 2023 23:32:01 -0400 Subject: [PATCH] Small fixes --- .gitignore | 3 +- data/update | 4 +- db/empty.sql | 10 +- db/updatedb.pl | 90 +++++++-------- emailer/emailer.py | 269 +++++++++++++++++++++++---------------------- refresh_semester | 14 ++- web/lib.php | 28 +++-- 7 files changed, 212 insertions(+), 206 deletions(-) diff --git a/.gitignore b/.gitignore index 62b388c..587bb48 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,8 @@ count.txt *.pyc *.o .svn/ -sopti/triplet/xml/ +triplet/xml/ +data/*.csv # http://www.gnu.org/software/automake diff --git a/data/update b/data/update index 2c11db9..597e5e1 100755 --- a/data/update +++ b/data/update @@ -8,8 +8,8 @@ fi touch lock; -COURSE_URL="https://www.polymtl.ca/public/Horaire/horsage.csv" -CLOSED_URL="https://www.polymtl.ca/public/Horaire/fermes.csv" +COURSE_URL="https://cours.polymtl.ca/Horaire/public/horsage.csv" +CLOSED_URL="https://cours.polymtl.ca/Horaire/public/fermes.csv" WGETFAIL=0 # false wget -O "courses.csv.new" $COURSE_URL 2> /dev/null || WGETFAIL=1; diff --git a/db/empty.sql b/db/empty.sql index 19d7dd6..1b146da 100644 --- a/db/empty.sql +++ b/db/empty.sql @@ -14,7 +14,7 @@ CREATE TABLE `courses` ( `title` char(100) default NULL, PRIMARY KEY (`unique`), KEY `symbol` (`symbol`) -) TYPE=MyISAM; +); -- -- Dumping data for table `courses` @@ -33,7 +33,7 @@ CREATE TABLE `courses_semester` ( PRIMARY KEY (`unique`), KEY `semester_index` (`semester`), KEY `course_index` (`course`) -) TYPE=MyISAM; +); -- -- Dumping data for table `courses_semester` @@ -58,7 +58,7 @@ CREATE TABLE `groups` ( KEY `name_index` (`name`), KEY `tol_index` (`theory_or_lab`), KEY `course_semester_index` (`course_semester`) -) TYPE=MyISAM; +); -- -- Dumping data for table `groups` @@ -79,7 +79,7 @@ CREATE TABLE `periods` ( `weekday` char(10) NOT NULL default '', PRIMARY KEY (`unique`), KEY `group` (`group`) -) TYPE=MyISAM; +); -- -- Dumping data for table `periods` @@ -95,7 +95,7 @@ CREATE TABLE `semesters` ( `code` char(10) NOT NULL default '', `pretty_name` char(15) NOT NULL default '', PRIMARY KEY (`unique`) -) TYPE=MyISAM; +); -- -- Dumping data for table `semesters` diff --git a/db/updatedb.pl b/db/updatedb.pl index 7142df1..0ec4f73 100755 --- a/db/updatedb.pl +++ b/db/updatedb.pl @@ -13,7 +13,7 @@ use Unicode::String qw(utf8 latin1 utf16); @fields_periods = ('room', 'weekday', 'time', 'week'); $CONFIG_DIR='..'; -$CURRENT_SEMESTER='H2005'; +$CURRENT_SEMESTER='A2023'; %CONFIG=(); sub warning { @@ -43,17 +43,17 @@ sub retrieve_closed { $_ =~ s/[\n\r]*$//s; my @fields = split(/;/); - + if(scalar(@fields) != 6) { die("bad field count"); } - + $closed_sections->{$fields[1]}->{$fields[2]}->{$fields[3]} = 1; } - + print("Closing Closed CSV...\n"); close CLOSEDFILE; - + return $closed_sections; } @@ -71,38 +71,38 @@ sub retrieve_teachers { $_ = utf8($_)->latin1; $_ =~ s/[\n\r]*$//s; my @fields = split(/;/); - + if(scalar(@fields) != 4) { die("bad field count"); } - + $teacher_data->{$fields[0]}->{$fields[1]}->{$fields[2]} = $fields[3]; } - + print("Closing teachers CSV...\n"); close TEACHERFILE; - + return $teacher_data; } sub read_config { print "Opening config file...\n"; open(CONFIGFILE, "<" . $CONFIG_DIR . "/sopti.conf") or die("error opening config file"); - + while(<CONFIGFILE>) { chomp; $line = $_; - + # remove comments $line =~ s/([^#]*)#.*/\1/; - + if($line =~ /^[ \t]*$/) { next; } - + my $varname; my $varval; - + if($line =~ /^[ \t]*[^ \t]+[ \t]+[^ \t"]+[ \t]*$/) { $varname = $line; $varval = $line; @@ -119,14 +119,14 @@ sub read_config { else { die("invalid config file line: $line\n"); } - + $CONFIG{$varname} = $varval; } - + print "Closing config file...\n"; close CONFIGFILE; - + open(SEMFILE, "<" . $CONFIG_DIR . "/semester.conf") or die error("opening semester file"); $sem = <SEMFILE>; $sem = trim($sem); @@ -136,13 +136,13 @@ sub read_config { sub main() { print("DATABASE UPDATE\n"); - + read_config; $CURRENT_SEMESTER=$CONFIG{'default_semester'}; - + print("Connecting to database...\n"); $dbh = DBI->connect('dbi:mysql:database=' . $CONFIG{'db.schema'}, $CONFIG{'db.username'}, $CONFIG{'db.password'}) or die(DBI->errstr); - + # print("Creating replacement tables...\n"); # $dbh->do('CREATE TABLE courses_new LIKE courses') or die $dbh->errstr; # $dbh->do('CREATE TABLE courses_semester_new LIKE courses_semester') or die $dbh->errstr; @@ -158,11 +158,11 @@ sub main() { else { $current_semester_unique = $semester_result->[0][0]; } - + # Download the courses table print("Downloading courses table...\n"); $courses_table_ref = $dbh->selectall_hashref('SELECT * FROM courses', 'symbol'); - + # Download the courses_semester table # Index the hash by course symbol (ex: ING1040) print("Downloading courses_semester table...\n"); @@ -177,7 +177,7 @@ sub main() { my $course_semester = $row->{'course_semester'}; my $name = $row->{'name'}; my $theory_or_lab = $row->{'theory_or_lab'}; - + $groups_table_ref->{$course_semester}->{$name}->{$theory_or_lab} = $row; } @@ -189,13 +189,13 @@ sub main() { foreach $row (@{$periods_table_array}) { my $group = $row->{'group'}; my $period_code = $row->{'period_code'}; - + $periods_table_ref->{$group}->{$period_code} = $row; } - + my $closed_sections = retrieve_closed(); my $teacher_data = retrieve_teachers(); - + print("Opening CSV...\n"); open(DATAFILE, "<../data/courses.csv") or die("error opening data file"); $i=0; @@ -211,17 +211,17 @@ sub main() { $_ =~ s/[\n\r]*$//s; @fields = split(/;/); - + if(scalar(@fields) != scalar(@fields_csv)) { print(scalar(@fields), " != ", scalar(@fields_csv), "\n"); die("bad field count"); } - + # Transfer current line in a hash for($j=0; $j<scalar(@fields); $j++) { $current_line{$fields_csv[$j]} = $fields[$j]; } - + # Modifiy the CSV data if($current_line{'week'} eq 'I') { $current_line{'week'}='B1'; @@ -243,7 +243,7 @@ sub main() { else { $current_line{'closed'} = 0; } - + # Merge the teacher data if(exists $teacher_data->{$current_line{'symbol'}}->{$current_line{'group'}}->{$current_line{'theory_or_lab'}}) { $current_line{'teacher'} = $teacher_data->{$current_line{'symbol'}}->{$current_line{'group'}}->{$current_line{'theory_or_lab'}}; @@ -251,7 +251,7 @@ sub main() { else { $current_line{'teacher'} = ""; } - + # Update the courses table $current_course_entry = $courses_table_ref->{$current_line{'symbol'}}; if($courses_done{$current_line{'symbol'}} != 1) { @@ -277,11 +277,11 @@ sub main() { } } } - + $courses_done{$current_line{'symbol'}} = 1; $current_course_entry->{'used'} = 1; # Mark as used because it was in the CSV } - + # Update the courses_semester table $current_course_semester_entry = $courses_semester_table_ref->{$current_line{'symbol'}}; if($courses_semester_done{$current_line{'symbol'}} != 1) { @@ -309,11 +309,11 @@ sub main() { } } } - + $courses_semester_done{$current_line{'symbol'}} = 1; $current_course_semester_entry->{'used'} = 1; # Mark as used because it was in the CSV } - + # Update the groups table $current_course_semester_unique = $current_course_semester_entry->{'unique'}; $current_group_entry = $groups_table_ref->{$current_course_semester_unique}->{$current_line{'group'}}->{$current_line{'theory_or_lab'}}; @@ -322,7 +322,7 @@ sub main() { # course not in DB, add it warning("[INSERT][groups] Group $current_line{'symbol'}, $current_line{'group'}, $current_line{'theory_or_lab'} was not in groups table; adding it"); $dbh->do("INSERT INTO groups (course_semester, name, theory_or_lab, places_room, places_group, closed, teacher) VALUES (\"$current_course_semester_unique\", \"$current_line{'group'}\", \"$current_line{'theory_or_lab'}\", \"$current_line{'places_room'}\", \"$current_line{'places_group'}\", \"$current_line{'closed'}\", \"$current_line{'teacher'}\")") or die $dbh->errstr; - + # get the unique of the new entry my $unique = $dbh->selectall_arrayref("SELECT groups.unique FROM groups WHERE course_semester=\"$current_course_semester_unique\" AND name=\"$current_line{'group'}\" AND theory_or_lab=\"$current_line{'theory_or_lab'}\""); if(scalar(@$unique) != 1) { @@ -342,11 +342,11 @@ sub main() { } } } - + $groups_done{$current_line{'symbol'}}->{$current_line{'group'}}->{$current_line{'theory_or_lab'}} = 1; $current_group_entry->{'used'} = 1; # Mark as used because it was in the CSV } - + # Update the periods table $current_group_unique = $current_group_entry->{'unique'}; $current_period_entry = $periods_table_ref->{$current_group_unique}->{$current_line{'period_code'}}; @@ -363,10 +363,10 @@ sub main() { $dbh->do("UPDATE periods SET $field=\"$current_line{$field}\" WHERE periods.unique=\"$current_period_entry->{'unique'}\"") or die $dbh->errstr; } } - + $current_period_entry->{'used'} = 1; } - + # if($course_sem_done{$course_symbol} != '1') { # $dbh->do("INSERT INTO courses_new (symbol, title) VALUES (\"$course_symbol\", \"$course_title\")") or die $dbh->errstr; # $course_sem_done{$course_symbol} = '1'; @@ -374,7 +374,7 @@ sub main() { $i++; } close DATAFILE; - + # Check for unused courses while ( my ($symbol, $entry) = each(%{$courses_table_ref}) ) { if($entry->{'used'} != 1) { @@ -390,7 +390,7 @@ sub main() { $dbh->do("DELETE FROM courses_semester WHERE courses_semester.unique=\"$entry->{'unique'}\"") or die $dbh->errstr; } } - + # Check for unused groups while ( my ($symbol, $entry1) = each(%{$groups_table_ref}) ) { while ( my ($group_unique, $entry2) = each(%{$entry1}) ) { @@ -402,7 +402,7 @@ sub main() { } } } - + # Check for unused periods while ( my ($group_unique, $entry1) = each(%{$periods_table_ref}) ) { while ( my ($period_code, $entry2) = each(%{$entry1}) ) { @@ -412,7 +412,7 @@ sub main() { } } } - + # print("Commiting changes...\n"); # $dbh->do(q{RENAME TABLE # courses TO courses_old, @@ -422,7 +422,7 @@ sub main() { # }) or die $dbh->errstr; # # Race condition if other update process starts here # $dbh->do(q{DROP TABLE courses_old, courses_semester_old}); - + print("Disconnecting...\n"); $dbh->disconnect(); print("done.\n"); diff --git a/emailer/emailer.py b/emailer/emailer.py index f15f4c9..f9d4743 100644 --- a/emailer/emailer.py +++ b/emailer/emailer.py @@ -19,16 +19,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -Emailer.py is a program to send emails from a database of notification +Emailer.py is a program to send emails from a database of notification requests. -It is part of the SOPTI (School Schedule Optimizer) package written +It is part of the SOPTI (School Schedule Optimizer) package written by Pierre-Marc Fournier <pmf@users.sf.net> -Emailer.py reads notification requests from a table in the sopti -database, checks if the groups for those requests have space -available and if it is the case notifies by email the person who -made the request that they can go change their schedule. After -sending the email, the program removes that entry from the database. +Emailer.py reads notification requests from a table in the sopti +database, checks if the groups for those requests have space +available and if it is the case notifies by email the person who +made the request that they can go change their schedule. After +sending the email, the program removes that entry from the database. The program can log and print relevant parts of its operation. See `emailer.py -h` for information on this. @@ -36,7 +36,7 @@ See `emailer.py -h` for information on this. Some aspects of its operation can also be changed via a configuration file (see the example config file in the distribution) -The table that contains the notfications is filled via a php script +The table that contains the notfications is filled via a php script embeded in the SOPTI web interface. CVS information: @@ -67,7 +67,7 @@ def main(): configuration= Configuration.getInstance() logging= configuration["loggingModule"] random.seed() - + configuration["stats"]= { "emailsSuccessfully" : 0, # emails were sent "emailsFailed" : 0, # emails could not be sent @@ -76,40 +76,41 @@ def main(): "remainingNotifications" : 0, # notifications are still remaining in the database "remainingGroups" : 0, # notifications are still remaining in the database "remainingEmails" : 0, } # notifications are still remaining in the database - + # The notifications to be sent are fetched from the database logging.debug("Connecting to the database server \"%s\"..." % (configuration["DB"]["host"],)) - + try: connection= MySQLdb.connect(**configuration["DB"]) - + connection.autocommit(True) + connection.query(""" - select - `notifications`.`unique`, - `notifications`.`email`, - `groups`.`unique`, - `groups`.`name`, - `groups`.`theory_or_lab`, - `groupsT`.`teacher`, - `groupsL`.`teacher`, - `courses_semester`.`course_type`, - `courses`.`symbol`, - `courses`.`title` - from `notifications` - inner join `groups` on - `notifications`.`group` = `groups`.`unique` - left join `groups` as `groupsT` on - `groups`.`course_semester` = `groupsT`.`course_semester` and - `groups`.`name` = `groupsT`.`name` and - `groupsT`.`theory_or_lab` = 'C' - left join `groups` as `groupsL` on - `groups`.`course_semester` = `groupsL`.`course_semester` and - `groups`.`name` = `groupsL`.`name` and - `groupsL`.`theory_or_lab` = 'L' - inner join `courses_semester` on - `groups`.`course_semester` = `courses_semester`.`unique` - inner join `courses` on - `courses_semester`.`course` = `courses`.`unique` + select + `notifications`.`unique`, + `notifications`.`email`, + `groups`.`unique`, + `groups`.`name`, + `groups`.`theory_or_lab`, + `groupsT`.`teacher`, + `groupsL`.`teacher`, + `courses_semester`.`course_type`, + `courses`.`symbol`, + `courses`.`title` + from `notifications` + inner join `groups` on + `notifications`.`group` = `groups`.`unique` + left join `groups` as `groupsT` on + `groups`.`course_semester` = `groupsT`.`course_semester` and + `groups`.`name` = `groupsT`.`name` and + `groupsT`.`theory_or_lab` = 'C' + left join `groups` as `groupsL` on + `groups`.`course_semester` = `groupsL`.`course_semester` and + `groups`.`name` = `groupsL`.`name` and + `groupsL`.`theory_or_lab` = 'L' + inner join `courses_semester` on + `groups`.`course_semester` = `courses_semester`.`unique` + inner join `courses` on + `courses_semester`.`course` = `courses`.`unique` where `groups`.`closed` = '0' order by `notifications`.`email` """) @@ -119,7 +120,7 @@ def main(): else: logging.debug("OK") notifications= list(connection.store_result().fetch_row(maxrows= 0, how= 2)) - + # The emails are sent try: logging.debug("Connecting to SMTP server \"%s:%d\"..." % (configuration["SMTP"]["host"], int(configuration["SMTP"]["port"]),)) @@ -130,14 +131,14 @@ def main(): return 1 else: logging.debug("OK") - + # the list of the notification entries that were successfully sent successfulNotifications= list() # the list of the notification entries that could not be sent because of recepient refused errors refusedNotifications= list() # a group of notifications that are to be sent to the same email address notificationGroup= list() - + while len(notifications) or len(notificationGroup): #TODO: verifier si c'est slow enlever le premier element au lieu du dernier if not len(notificationGroup) or (len(notifications) and notifications[0]["notifications.email"] == notificationGroup[0]["notifications.email"]): @@ -145,39 +146,39 @@ def main(): continue else: hasher= hmac.new( - configuration["general"]["pepper"], - notificationGroup[0]["notifications.email"], + configuration["general"]["pepper"], + notificationGroup[0]["notifications.email"], digestmod=hashlib.sha1) # build the notification email if len(notificationGroup) == 1: # for a single notification msg= email.MIMEText.MIMEText( - configuration["emailIntro"]["singular"] + + configuration["emailIntro"]["singular"] + configuration["emailCourse"]["text"] % getTemplateValues(notificationGroup[0]) + (configuration["emailOutro"]["singular"] % { - "email" : notificationGroup[0]["notifications.email"], + "email" : notificationGroup[0]["notifications.email"], "hash" : hasher.hexdigest(), "baseurl" : configuration["general"]["baseurl"],})) - + msg["Subject"]= configuration["emailSubject"]["singular"] msg["From"]= "%s <%s>" % (configuration["sender"]["name"], configuration["sender"]["address"],) msg["To"]= notificationGroup[0]["notifications.email"] else: - # for many notifications that are to be sent to + # for many notifications that are to be sent to # the same address msg= email.MIMEText.MIMEText( - configuration["emailIntro"]["plural"] + + configuration["emailIntro"]["plural"] + "".join([configuration["emailCourse"]["text"] % getTemplateValues(notification) for notification in notificationGroup]) + configuration["emailOutro"]["plural"] % { - "email" : urllib.quote(notificationGroup[0]["notifications.email"]), + "email" : urllib.quote(notificationGroup[0]["notifications.email"]), # a period (.) at the end of the line is also replaced otherwise it is left out of the link by some mail readers "hash" : hasher.hexdigest(), "baseurl" : configuration["general"]["baseurl"],}) - + msg["Subject"]= configuration["emailSubject"]["plural"] msg["From"]= "%s <%s>" % (configuration["sender"]["name"], configuration["sender"]["address"],) msg["To"]= notificationGroup[0]["notifications.email"] - + # send the notification email infoMesg= "Sending a notification to %s" % (msg["To"],) if len(notificationGroup) == 1: @@ -185,79 +186,79 @@ def main(): else: infoMesg += " for groups " + ", ".join([str(notification["groups.unique"]) for notification in notificationGroup]) logging.info(infoMesg) - + try: if not configuration["general"]["dry-run"]: smtp.sendmail(configuration["sender"]["address"], msg["To"], msg.as_string()) except smtplib.SMTPSenderRefused, message: logging.error("SMTP error %d: %s" % (message[0], message[1])) logging.error("The program will not try sending any more emails, consider changing your \"from\" address or you SMTP server") - + smtp.quit() connection.close() logging.shutdown() - + return 1 except smtplib.SMTPRecipientsRefused, message: message= message[0].values()[0] logging.error("SMTP Recipient refused error %d: %s" % (message[0], message[1])) - + configuration["stats"]["groupsFailed"]+= len(notificationGroup) configuration["stats"]["emailsFailed"]+= 1 - + if len(notificationGroup) == 1: refusedNotifications.append({ - "notifications.unique" : notificationGroup[0]["notifications.unique"], - "notifications.email" : notificationGroup[0]["notifications.email"], + "notifications.unique" : notificationGroup[0]["notifications.unique"], + "notifications.email" : notificationGroup[0]["notifications.email"], "notifications.group" : notificationGroup[0]["groups.unique"],}) else: refusedNotifications.extend([{ - "notifications.unique" : notification["notifications.unique"], - "notifications.email" : notification["notifications.email"], - "notifications.group" : notification["groups.unique"],} + "notifications.unique" : notification["notifications.unique"], + "notifications.email" : notification["notifications.email"], + "notifications.group" : notification["groups.unique"],} for notification in notificationGroup]) - + except smtplib.SMTPDataError, message: logging.error("SMTP Data error %d: %s" % (message[0], message[1])) - + configuration["stats"]["groupsFailed"]+= len(notificationGroup) configuration["stats"]["emailsFailed"]+= 1 else: if len(notificationGroup) == 1: successfulNotifications.append({ - "notifications.unique" : notificationGroup[0]["notifications.unique"], - "notifications.email" : notificationGroup[0]["notifications.email"], + "notifications.unique" : notificationGroup[0]["notifications.unique"], + "notifications.email" : notificationGroup[0]["notifications.email"], "notifications.group" : notificationGroup[0]["groups.unique"],}) else: successfulNotifications.extend([{ - "notifications.unique" : notification["notifications.unique"], - "notifications.email" : notification["notifications.email"], - "notifications.group" : notification["groups.unique"],} + "notifications.unique" : notification["notifications.unique"], + "notifications.email" : notification["notifications.email"], + "notifications.group" : notification["groups.unique"],} for notification in notificationGroup]) - + configuration["stats"]["emailsSuccessfully"]+= 1 - + notificationGroup= list() - + smtp.quit() - + configuration["stats"]["groupsSuccessfully"]= len(successfulNotifications) - - # The notifications that have been successfully sent are + + # The notifications that have been successfully sent are # cleared from the database # The notifications that generated a recipient refused message may # be cleared as well depending on the configuration logging.info("Cleaning the DB...") - + if configuration["general"]["clearRecipientsRefused"]: successfulNotifications.extend(refusedNotifications) - + if len(successfulNotifications): if not configuration["general"]["dry-run"]: try: connection.query(""" - delete - from `notifications` - where `unique` in (""" + ", ".join([str(notification["notifications.unique"]) for notification in successfulNotifications]) + """) + delete + from `notifications` + where `unique` in (""" + ", ".join([str(notification["notifications.unique"]) for notification in successfulNotifications]) + """) limit """ + str(len(successfulNotifications))) except MySQLdb.MySQLError, message: logging.error("MySQL error %d: %s" % (message[0], message[1])) @@ -265,125 +266,125 @@ def main(): for notification in successfulNotifications: logging.dbentries( "erased from `notifications` values(%d, %d, '%s')" % ( - notification["notifications.unique"], - notification["notifications.group"], + notification["notifications.unique"], + notification["notifications.group"], notification["notifications.email"],)) logging.info("%d rows have been removed" % (connection.affected_rows(), )) else: logging.info("0 rows have been removed") else: logging.info("nothing to be done") - + # statistics are processed try: connection.query(""" - select - count(*) + select + count(*) from `notifications` """) except MySQLdb.MySQLError, message: logging.error("MySQL error %d: %s" % (message[0], message[1])) else: configuration["stats"]["remainingNotifications"]= int(connection.store_result().fetch_row()[0][0]) - + try: # subquerry version # if your database server supports subqueries you might want to use this block instead of the next - #~ connection.query(""" - #~ select - #~ count(*) - #~ from ( - #~ select - #~ count(*) - #~ from `notifications` - #~ group by `group`) - #~ as `subTable` - #~ """) + connection.query(""" + select + count(*) + from ( + select + count(*) + from `notifications` + group by `group`) + as `subTable` + """) # safe version #~ connection.query("""create temporary table if not exists `_groups` (`group` int(11) not null)""") #~ connection.query("""truncate table `_groups`""") #~ connection.query("""insert into `_groups` (`group`) select count(*) from `notifications` group by `group`""") #~ connection.query("""select count(*) from `_groups`""") # temporary table version - connection.query("""create temporary table `_groups` (`group` int(11) not null) select count(*) from `notifications` group by `group`""") - connection.query("""select count(*) from `_groups`""") + # connection.query("""create temporary table `_groups` (`group` int(11) not null) select count(*) from `notifications` group by `group`""") + # connection.query("""select count(*) from `_groups`""") except MySQLdb.MySQLError, message: logging.error("MySQL error %d: %s" % (message[0], message[1])) else: configuration["stats"]["remainingGroups"]= int(connection.store_result().fetch_row()[0][0]) - + try: # subquerry version # if your database server supports subqueries you might want to use this block instead of the next - #~ connection.query(""" - #~ select - #~ count(*) - #~ from ( - #~ select - #~ count(*) - #~ from `notifications` - #~ group by `email`) - #~ as `subTable` - #~ """) + connection.query(""" + select + count(*) + from ( + select + count(*) + from `notifications` + group by `email`) + as `subTable` + """) # temporary table version - connection.query("""create temporary table `_emails` (`email` varchar(60) not null) select count(*) from `notifications` group by `email`""") - connection.query("""select count(*) from `_emails`""") + # connection.query("""create temporary table `_emails` (`email` varchar(60) not null) select count(*) from `notifications` group by `email`""") + # connection.query("""select count(*) from `_emails`""") except MySQLdb.MySQLError, message: logging.error("MySQL error %d: %s" % (message[0], message[1])) else: configuration["stats"]["remainingEmails"]= int(connection.store_result().fetch_row()[0][0]) - + logging.summary("Summary for emailer run #%s:" % (configuration["runNumber"],)) logging.summary("Started at %s" % (time.asctime(configuration["startTime"]), )) logging.summary("Finished at %s" % (time.asctime(), )) if configuration["stats"]["groupsSuccessfully"]: logging.summary( - ("%d group notification" + - (configuration["stats"]["groupsSuccessfully"] > 1 and "s were " or " was ") + + ("%d group notification" + + (configuration["stats"]["groupsSuccessfully"] > 1 and "s were " or " was ") + "sent successfully in %d email" + - (configuration["stats"]["emailsSuccessfully"] > 1 and ["s"] or [""])[0]) % + (configuration["stats"]["emailsSuccessfully"] > 1 and ["s"] or [""])[0]) % (configuration["stats"]["groupsSuccessfully"], configuration["stats"]["emailsSuccessfully"],)) if configuration["stats"]["groupsFailed"]: logging.summary( - ("%d group notification" + - (configuration["stats"]["groupsFailed"] > 1 and "s " or " ") + - "distributed in %d email" + - (configuration["stats"]["emailsFailed"] > 1 and "s " or " ") + - "FAILED to be sent") % + ("%d group notification" + + (configuration["stats"]["groupsFailed"] > 1 and "s " or " ") + + "distributed in %d email" + + (configuration["stats"]["emailsFailed"] > 1 and "s " or " ") + + "FAILED to be sent") % (configuration["stats"]["groupsFailed"], configuration["stats"]["emailsFailed"],)) logging.summary( - ("%d notification" + - (configuration["stats"]["remainingNotifications"] > 1 and "s are " or " is ") + - "still in the database spreaded over %d group" + - (configuration["stats"]["remainingGroups"] > 1 and "s " or " ") + - "and %d email" + - (configuration["stats"]["remainingEmails"] > 1 and ["s"] or [""])[0]) % + ("%d notification" + + (configuration["stats"]["remainingNotifications"] > 1 and "s are " or " is ") + + "still in the database spreaded over %d group" + + (configuration["stats"]["remainingGroups"] > 1 and "s " or " ") + + "and %d email" + + (configuration["stats"]["remainingEmails"] > 1 and ["s"] or [""])[0]) % (configuration["stats"]["remainingNotifications"], configuration["stats"]["remainingGroups"], configuration["stats"]["remainingEmails"],)) - + connection.close() logging.shutdown() def getTemplateValues(notification): configuration= Configuration.getInstance() - + values= { - "symbol" : notification["courses.symbol"], - "title" : notification["courses.title"], + "symbol" : notification["courses.symbol"], + "title" : notification["courses.title"], "name" : notification["groups.name"],} - + if notification["courses_semester.course_type"] == "TL": - values["theory_or_lab"]= "combinée théorique et laboratoire" - values["teacher"]= "\n\tThéorie: %s\n\tLab: %s" % (notification["groupsT.teacher"], notification["groupsL.teacher"],) + values["theory_or_lab"]= "combin�e th�orique et laboratoire" + values["teacher"]= "\n\tTh�orie: %s\n\tLab: %s" % (notification["groupsT.teacher"], notification["groupsL.teacher"],) elif notification["groups.theory_or_lab"] == "C": - values["theory_or_lab"]= "théorique" + values["theory_or_lab"]= "th�orique" values["teacher"]= notification["groupsT.teacher"] elif notification["groups.theory_or_lab"] == "L": values["theory_or_lab"]= "laboratoire" values["teacher"]= notification["groupsL.teacher"] else: raise(Exception("Unknown course type")) - + return values diff --git a/refresh_semester b/refresh_semester index ec0f784..3c0422b 100755 --- a/refresh_semester +++ b/refresh_semester @@ -1,8 +1,13 @@ #!/bin/bash +if [ "$EUID" -ne 0 ]; then + echo -e "\033[31mERROR : You must run this as the root user 😡" + exit -1 +fi + function mailbadmonth() { - echo -e "Hi, this is sopti at $(hostname). I just refused to update the semester to $1 because this is not the right time of the year.\n\nHave a nice day." | mail -s "Refusing to change semester" pierre-marc.fournier@polymtl.ca + echo -e "Hi, this is sopti at $(hostname). I just refused to update the semester to $1 because this is not the right time of the year.\n\nHave a nice day." } SOPTI_DIR=$(dirname $0) @@ -43,7 +48,7 @@ if [ "$SEM" != "$(<$SOPTI_DIR/semester.conf)" ]; then mailbadmonth "$SEM" exit 0 fi - PRETTY="Été" + PRETTY="Été" fi if [ "${SEM:0:1}" = "A" ]; then if [ "$month" -lt "6" -o "$month" -gt "9" ]; then @@ -64,10 +69,11 @@ if [ "$SEM" != "$(<$SOPTI_DIR/semester.conf)" ]; then echo "Writing new semester to config file" echo "$SEM" >$SOPTI_DIR/semester.conf - $SOPTI_DIR/db/updatedb.pl + cd $SOPTI_DIR/db + ./updatedb.pl echo -e "Hi, this is sopti at $(hostname). This is to let you know I just updated the semester to $SEM.\n\nHave a nice day." | mail -s "Semester updated to $SEM" infra@exec.step.polymtl.ca - + fi diff --git a/web/lib.php b/web/lib.php index f544d7f..3e5f1e0 100644 --- a/web/lib.php +++ b/web/lib.php @@ -1,6 +1,4 @@ <?php -error_reporting(0); - require_once('config.php'); $CONFIG_VARS=array(); @@ -34,7 +32,7 @@ function admin_error($msg) <html> <head> - <title>Générateur d'horaires - Erreur interne</title> + <title>G�n�rateur d'horaires - Erreur interne</title> <link rel="stylesheet" type="text/css" href="sopti.css"> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> @@ -43,8 +41,8 @@ function admin_error($msg) <center> -<img src="genhor_sm.png" alt="Générateur d'horaires"> -<p style="font-size: 15px;">Générateur d'horaires</p> +<img src="genhor_sm.png" alt="G�n�rateur d'horaires"> +<p style="font-size: 15px;">G�n�rateur d'horaires</p> </center> <div style="background-color: #ffbbbb;"> @@ -52,7 +50,7 @@ function admin_error($msg) <p align="center"><?php echo $msg; ?></p> </div> -<p align="center">L'administrateur a été informé de cette erreur. +<p align="center">L'administrateur a �t� inform� de cette erreur. </body> </html> @@ -72,7 +70,7 @@ function error($msg) <html> <head> - <title>Générateur d'horaires - Erreur</title> + <title>G�n�rateur d'horaires - Erreur</title> <link rel="stylesheet" type="text/css" href="sopti.css"> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> @@ -81,8 +79,8 @@ function error($msg) <center> -<img src="genhor_sm.png" alt="Générateur d'horaires"> -<p><font size="+2">Générateur d'horaires</font> +<img src="genhor_sm.png" alt="G�n�rateur d'horaires"> +<p><font size="+2">G�n�rateur d'horaires</font> </center> <div style="background-color: #ffbbbb;"> @@ -90,7 +88,7 @@ function error($msg) <p align="center"><?php echo $msg; ?></p> </div> -<p align="center">Si possible, utiliser le bouton précédent de votre navigateur pour revenir en arrière et corriger l'erreur. +<p align="center">Si possible, utiliser le bouton pr�c�dent de votre navigateur pour revenir en arri�re et corriger l'erreur. </body> </html> @@ -240,8 +238,8 @@ function print_schedule($sch, $schedno) </tr> </table> </td></tr> - <tr><th rowspan="2">Sigle</th><th rowspan="2">Titre</th><th colspan="2">Théorie</th><th colspan="2">Lab</th></tr> - <tr><th class="subheader">Section</th><th class="subheader">Chargé</th><th class="subheader">Section</th><th class="subheader">Chargé</th><th class="subheader"></th></tr> + <tr><th rowspan="2">Sigle</th><th rowspan="2">Titre</th><th colspan="2">Th�orie</th><th colspan="2">Lab</th></tr> + <tr><th class="subheader">Section</th><th class="subheader">Charg�</th><th class="subheader">Section</th><th class="subheader">Charg�</th><th class="subheader"></th></tr> <tr><td colspan="7" style="background-color: black; height: 1px;"></td></tr> <?php @@ -264,11 +262,11 @@ function print_schedule($sch, $schedno) } elseif($group_data[$req['symbol']]['course_type'] == 'TL') { if($req['th_grp'] != $req['lab_grp']) { - error("Horaire illégal; th_grp != lab_grp pour un cours TL"); + error("Horaire ill�gal; th_grp != lab_grp pour un cours TL"); } if(!isset($group_data[$req['symbol']]['theory'][$req['th_grp']])) { - error("Groupe théorique introuvable: " . $req['symbol'] . "/" . $req['th_grp']); + error("Groupe th�orique introuvable: " . $req['symbol'] . "/" . $req['th_grp']); } if(!isset($group_data[$req['symbol']]['lab'][$req['lab_grp']])) { error("Groupe lab introuvable: " . $req['symbol'] . "/" . $req['lab_grp']); @@ -278,7 +276,7 @@ function print_schedule($sch, $schedno) } elseif($group_data[$req['symbol']]['course_type'] == 'TLS') { if(!isset($group_data[$req['symbol']]['theory'][$req['th_grp']])) { - error("Groupe théorique introuvable: " . $req['symbol'] . "/" . $req['th_grp']); + error("Groupe th�orique introuvable: " . $req['symbol'] . "/" . $req['th_grp']); } if(!isset($group_data[$req['symbol']]['lab'][$req['lab_grp']])) { error("Groupe lab introuvable: " . $req['symbol'] . "/" . $req['lab_grp']); -- GitLab