Example #1
0
    def handle_timeout(self):
        """
        Force remove a job from jobs_active when no finished was received for a
        given timout interval.
        """

        timeout_after = 300  #in seconds

        time_now = time.time()
        to_delete = []

        for job_tuple, job_info in self.jobs_active.items():
            dispatch = job_info["dispatch"]
            time_since_dispatch = dispatch - time_now
            if time_since_dispatch > timeout_after:
                to_delete.append(job_tuple)

        for job_tuple in to_delete:
            del self.jobs_active[job_tuple]

            logmsg = (
                "Dropped a submission for User {0}, TaskNr {1} as the tester "
                "did not return a finished message after 5 minutes. This "
                "submission email will not be moved to the archive!")
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "WARNING")
Example #2
0
def check_and_init_db_table(dbname, tablename, fields):
    """
    Check if a table exists, if not create it with fields.
    """

    cur, con = c.connect_to_db(dbname, logger_queue, "autosub.py")

    data = {'name': tablename}
    sql_cmd = "SELECT name FROM sqlite_master WHERE type == 'table' AND name = :name"
    cur.execute(sql_cmd, data)
    res = cur.fetchall()

    if res:
        logmsg = 'table ' + tablename + ' exists'
        c.log_a_msg(logger_queue, "autosub.py", logmsg, "DEBUG")
        #TODO: in this case, we might want to check if one entry per task is already
        # there, and add new empty entries in case a task does not have one. This is only
        # a problem, if the number of tasks in the config file is changed AFTER the
        # TaskStats table has been changed!

        con.close()

        return 0
    else:
        logmsg = 'table ' + tablename + ' does not exist'
        c.log_a_msg(logger_queue, "autosub.py", logmsg, "DEBUG")

        data = {'fields': fields}
        sql_cmd = "CREATE TABLE {0}({1})".format(tablename, fields)
        cur.execute(sql_cmd)
        con.commit()

        con.close()

        return 1
Example #3
0
    def a_question_was_asked(self, user_email, mail, messageid):
        """"
        Process a question that was asked by a user.
        """

        mail_subject = str(mail['subject'])

        logmsg = 'The user has a question, please take care of that!'
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
        c.send_email(self.sender_queue, user_email, "", "Question", "", "", "")

        # was the question asked to a specific task_nr that is valid?
        search_obj = re.search('[0-9]+', mail_subject, )

        if (search_obj != None) and int(search_obj.group()) <= c.get_num_tasks(self.coursedb, \
                                            self.logger_queue, self.name):
            fwd_mails = self.get_taskoperator_emails(search_obj.group())

        else:
            fwd_mails = self.get_admin_emails()

        for mail_address in fwd_mails:
            c.send_email(self.sender_queue, mail_address, "", "QFwd", "", mail, messageid)

        c.increment_db_statcounter(self.semesterdb, 'nr_questions_received', \
                                   self.logger_queue, self.name)
Example #4
0
    def get_registration_deadline(self):
        """
        Get the registration deadline datetime.

        Return datetime, if not found return 1 hour from now.
        """

        curc, conc = c.connect_to_db(self.dbs["course"], self.queues["logger"],
                                     self.name)
        sql_cmd = ("SELECT Content FROM GeneralConfig " \
                   "WHERE ConfigItem == 'registration_deadline'")
        curc.execute(sql_cmd)
        deadline_string = str(curc.fetchone()[0])

        conc.close()

        format_string = '%Y-%m-%d %H:%M:%S'
        if deadline_string != 'NULL':
            return datetime.datetime.strptime(deadline_string, format_string)

        else:
            # there is no deadline set, just assume it is in 1h from now.
            date = datetime.datetime.now() + datetime.timedelta(0, 3600)

            logmsg = "No Registration Deadline found, assuming: " + str(date)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")

            return date
Example #5
0
    def run(self):
        logmsg = "Starting " + self.name
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "INFO")

        while True:
            self.activator_loop()
            time.sleep(1800)  # it's more than enough to check every half hour
Example #6
0
    def get_scriptpath(self, task_nr):
        """
        Get the path to the tester script for task task_nr.
        Returns None if not proper config.
        """

        curc, conc = c.connect_to_db(self.dbs["course"], self.queues["logger"], self.name)

        data = {'task_nr': task_nr}
        sql_cmd = ("SELECT TaskName, TestExecutable FROM TaskConfiguration "
                   "WHERE TaskNr == :task_nr")
        curc.execute(sql_cmd, data)
        res = curc.fetchone()

        if not res:
            logmsg = ("Failed to fetch Configuration for TaskNr: {0} from the "
                      "database! Table TaskConfiguration corrupted?").format(task_nr)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")

            scriptpath = None
        else:
            task_name = res[0]
            tester_name = res[1]

            scriptpath = self.tasks_dir + "/" + task_name + "/" + tester_name

        conc.close()
        return scriptpath
Example #7
0
    def assemble_email(self, msg, message_text, attachments):
        """
        assemble e-mail content
        """
        msg.attach(MIMEText(message_text, 'plain', 'utf-8'))

        # If the message is a task description, we might want to
        # add some attachments.  These ar given as a list by the
        # attachments parameter
        logmsg = "List of attachements: {0}".format(attachments)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        if str(attachments) != 'None':
            for next_attachment in attachments:
                try:
                    part = MIMEBase('application', "octet-stream")
                    part.set_payload(open(next_attachment, "rb").read())
                    encoders.encode_base64(part)
                    part.add_header('Content-Disposition', 'attachment; filename="{0}"'.format(os.path.basename(next_attachment)))
                    msg.attach(part)
                except:
                    logmsg = "Faild to add an attachement: {0}".format(next_attachment)
                    c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        # The following message my be helpful during debugging - but
        # if you use attachments, your log-file will grow very fast
        # therefore it was commented out.
#        logmsg = "Prepared message: \n" + str(msg)
#        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
        return msg
Example #8
0
    def assemble_email(self, msg, message_text, attachments):
        """
        assemble e-mail content
        """
        msg.attach(MIMEText(message_text, 'plain', 'utf-8'))

        # If the message is a task description, we might want to
        # add some attachments.  These ar given as a list by the
        # attachments parameter
        logmsg = "List of attachements: {0}".format(attachments)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        if str(attachments) != 'None':
            for next_attachment in attachments:
                try:
                    part = MIMEBase('application', "octet-stream")
                    part.set_payload(open(next_attachment, "rb").read())
                    encoders.encode_base64(part)
                    part.add_header(
                        'Content-Disposition',
                        'attachment; filename="{0}"'.format(
                            os.path.basename(next_attachment)))
                    msg.attach(part)
                except:
                    logmsg = "Faild to add an attachement: {0}".format(
                        next_attachment)
                    c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        # The following message my be helpful during debugging - but
        # if you use attachments, your log-file will grow very fast
        # therefore it was commented out.
        # logmsg = "Prepared message: \n" + str(msg)
        # c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
        return msg
Example #9
0
def check_and_init_db_table(dbname, tablename, fields):
    """
    Check if a table exists, if not create it with fields.
    """

    cur, con = c.connect_to_db(dbname, logger_queue, "autosub.py")

    data = {'name': tablename}
    sql_cmd = ("SELECT name FROM sqlite_master "
               "WHERE type == 'table' AND name = :name")
    cur.execute(sql_cmd, data)
    res = cur.fetchall()

    if res:
        logmsg = 'table ' + tablename + ' exists'
        c.log_a_msg(logger_queue, "autosub.py", logmsg, "DEBUG")

        return 0

    logmsg = 'table ' + tablename + ' does not exist'
    c.log_a_msg(logger_queue, "autosub.py", logmsg, "DEBUG")

    data = {'fields': fields}
    sql_cmd = "CREATE TABLE {0}({1})".format(tablename, fields)
    cur.execute(sql_cmd)
    con.commit()

    con.close()

    return 1
Example #10
0
    def read_specialmessage(self, msgname):
        """
        read a special message from the DB
        """

        curc, conc = c.connect_to_db(self.dbs["course"], \
                                     self.queues["logger"], \
                                     self.name)

        data = {'msgname': msgname}
        sql_cmd = ("SELECT EventText FROM SpecialMessages "
                   "WHERE EventName = :msgname")
        curc.execute(sql_cmd, data)
        res = curc.fetchone()
        conc.close()

        if not res:
            logmsg = ("Error reading the Specialmessage named {0} from the "
                      "database").format(msgname)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")

            message = "Hi something went wrong. Please contact the course admin"
        else:
            message = str(res[0])

        return message
Example #11
0
    def run(self):
        logmsg = "Starting " + self.name
        c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

        while True:
            self.activator_loop()
            time.sleep(3600) # it's more than enough to check every hour!
Example #12
0
    def backup_message(self, messageid):
        """
        trigger  archivation of an e-mail
        """
        logmsg = "request backup of message with messageid: {0}".format(messageid)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        self.arch_queue.put(dict({"mid": messageid}))
Example #13
0
    def backup_message(self, messageid):
        """
        trigger  archivation of an e-mail
        """
        logmsg = "request backup of message with messageid: {0}".format(
            messageid)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        self.arch_queue.put(dict({"mid": messageid}))
Example #14
0
    def archive_message(self, message_id, is_finished_job=False):
        """
        trigger archivation of an e-mail
        """

        logmsg = "request archiving of message with message_id {0}".format(message_id)
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")

        c.archive_message(self.queues['archive'], message_id, is_finished_job)
Example #15
0
    def run(self):
        """
        Thread code for the generator thread.
        """

        c.log_a_msg(self.logger_queue, self.name, "Task Generator thread started", "INFO")

        while True:
            self.generator_loop()
Example #16
0
    def run(self):
        """
        Thread code for the generator thread.
        """

        c.log_a_msg(self.logger_queue, self.name,
                    "Task Generator thread started", "INFO")

        while True:
            self.generator_loop()
Example #17
0
    def run(self):
        """
        the thread code is just a tight loop that waits on the sender_queue
	for some work.
        """
        c.log_a_msg(self.logger_queue, self.name, \
                    "Starting Mail Sender Thread!", "INFO")

        while True:
            self.handle_next_mail()
Example #18
0
    def run(self):
        """
        the thread code is just a tight loop that waits on the sender_queue
	    for some work.
        """
        c.log_a_msg(self.queues["logger"], self.name, \
                    "Starting Mail Sender Thread!", "INFO")

        while True:
            self.handle_next_mail()
Example #19
0
    def check_last_log_entry(self, logmsg, loglvl):
        common.log_a_msg(self.logger_queue, "testlogger", logmsg, loglvl)
        time.sleep(.25) # give the logger some time...

        with open(self.lfile, "r") as fd_log:
            for line in fd_log.readlines():
                #nothing - only interested in the very last line!
                pass

            self.assertNotEqual(line.find(logmsg), str(-1))
            self.assertNotEqual(line.find(loglvl), str(-1))
Example #20
0
 def check_and_create_table(self, cur, tablename):
     data = {'Table': tablename}
     sql_cmd = "SELECT name FROM sqlite_master WHERE type == 'table' AND name == :Table;"
     cur.execute(sql_cmd, data)
     res = cur.fetchall()
     if res:
         logmsg = "table {0} exists".format(tablename)
         c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
     else:
         logmsg = "table {0} does not exist ... creating it now".format(tablename)
         c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
         sql_cmd = "CREATE TABLE {0} (TimeStamp STRING PRIMARY KEY, value INT)".format(tablename)
         cur.execute(sql_cmd)
Example #21
0
    def idmap_new_emails(self, m):
        """
        Search for new (unseen) e-mails from the Inbox.

        Return a mapping as dict that assigns each Message-Id its UID.

        Note: This is done with read rights. All unread flags are unset.
        """
        # Debug Log Message
        logmsg = ("Start looking for unseen mails")
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")

        try:
            m.select("Inbox", readonly=False)
        except Exception as e:
            logmsg = "Failed to select inbox with error: " + str(e)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return {}

        idmap = dict()

        try:
            resp, data = m.uid('search', None, "UNSEEN")
        except Exception as e:
            logmsg = "Failed to get messages from inbox with IMAP error: " + str(
                e)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return {}

        if resp == 'OK':
            for uid in data[0].split():
                try:
                    typ, msg_data = m.uid('fetch', uid, "(BODY[HEADER])")
                except Exception as e:
                    logmsg = "Failed to fetch from inbox with error {0}.".format(
                        str(e))
                    c.log_a_msg(self.queues["logger"], self.name, logmsg,
                                "ERROR")
                    return {}

                mail = email.message_from_bytes(msg_data[0][1])
                idmap[mail['Message-ID']] = uid

            return idmap

        else:
            logmsg = (
                "Failed to get messages from inbox. Got response from IMAP "
                "server: {0} ").format(resp)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return {}
Example #22
0
    def action_by_subject(self, user_id, user_email, messageid, mail,
                          mail_subject):

        if re.search('[Rr][Ee][Ss][Uu][Ll][Tt]', mail_subject):
            ###############
            #   RESULT    #
            ###############
            searchObj = re.search('[0-9]+', mail_subject)
            if searchObj == None:
                # Result + no number
                logmsg = ("Got a kind of message I do not understand. "
                          "Sending a usage mail...")
                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                c.send_email(self.sender_queue, user_email, "", "Usage", "", \
                             "", messageid)
                return

            #Result + number
            task_nr = searchObj.group()

            self.a_result_was_submitted(user_id, user_email, task_nr, messageid, \
                                        mail)

        elif re.search('[Qq][Uu][Ee][Ss][Tt][Ii][Oo][Nn]', mail_subject):
            ###############
            #   QUESTION  #
            ###############
            self.a_question_was_asked(user_id, user_email, mail, messageid)

        elif re.search('[Ss][Tt][Aa][Tt][Uu][Ss]', mail_subject):
            ###############
            #   STATUS    #
            ###############
            self.a_status_is_requested(user_id, user_email, messageid)

        elif (self.allow_skipping == True) and re.search(
                '[Ss][Kk][Ii][Pp]', mail_subject):
            ####################
            # SKIP, IF ALLOWED #
            ####################
            self.skip_was_requested(user_id, user_email, messageid)

        else:
            #####################
            #   DEFAULT ACTION  #
            #####################
            logmsg = ("Got a kind of message I do not understand. "
                      "Sending a usage mail...")
            c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
            c.send_email(self.sender_queue, user_email, "", "Usage", "", \
                         "", messageid)
Example #23
0
    def run(self):
        """
        Thread code for the fetcher thread.
        """

        c.log_a_msg(self.queues["logger"], self.name,
                    "Starting Mail Fetcher Thread!", "INFO")

        logmsg = "Imapserver: '" + self.imap_info["server"] + "'"
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")

        # Setting server timeout for mail server
        socket.setdefaulttimeout(self.imap_info["timeout"])

        logmsg = "Setting server timeout for mail server to {0} seconds".format(
            self.imap_info["timeout"])
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")

        # This thread is running as a daemon thread, this is the while(1) loop that is
        # running until the thread is stopped by the main thread
        while True:
            self.loop_code()

        logmsg = "Exiting fetcher - this should NEVER happen!"
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
Example #24
0
    def read_text_file(self, path_to_msg):
        """
        read a text file
        """
        try:
            fpin = open(path_to_msg, 'r')
            message_text = fpin.read()
            fpin.close()
        except:
            message_text = "Even the static file was not available!"
            c.log_a_msg(self.logger_queue, self.name, \
                        "Failed to read from config file", "WARNING")

        return message_text
Example #25
0
    def read_text_file(self, path_to_msg):
        """
        read a text file
        """
        try:
            fpin = open(path_to_msg, 'r')
            message_text = fpin.read()
            fpin.close()
        except:
            message_text = "Even the static file was not available!"
            c.log_a_msg(self.logger_queue, self.name, \
                        "Failed to read from config file", "WARNING")

        return message_text
Example #26
0
    def connect_to_imapserver(self):
        """
        Connect to configured IMAP server.
        """

        try:
            # connecting to the imap server
            m = imaplib.IMAP4_SSL(self.imapserver)
            m.login(self.autosub_user, self.autosub_pwd)
        except imaplib.IMAP4.abort:
            logmsg = ("Login to server was aborted (probably a server-side problem). "
                      "Trying to connect again ...")
            c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
            #m.close()
            return 0
        except imaplib.IMAP4.error:
            logmsg = ("Got an error when trying to connect to the imap server. "
                      "Trying to connect again ...")
            c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
            return 0
        except:
            logmsg = ("Got an unknown exception when trying to connect to the imap "\
                      "server. Trying to connect again ...")
            c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
            return 0

        logmsg = "Successfully logged into imap server"
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        return m
Example #27
0
    def handle_job(self, nextjob):
        """
        Run the test script for the given submission and act on the test result
        """

        task_nr = str(nextjob.get('task_nr'))
        user_id = str(nextjob.get('user_id'))
        user_email = str(nextjob.get('user_email'))
        message_id = str(nextjob.get('message_id'))

        logmsg = "{0} got a new job: {1} from the user with id {2}".format(self.name, task_nr, \
                                                                           user_id)
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "INFO")

        # get the task parameters
        task_params = self.get_task_parameters(user_id, task_nr)

        # get the path to the test script
        scriptpath = self.get_scriptpath(task_nr)

        # get the configured common file
        configured_backend_interface = self.get_configured_backend_interface(
            task_nr)

        if not scriptpath:
            logmsg = "Could not fetch test script from database"
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return

        if not os.path.isfile(scriptpath):
            logmsg = "Test script does not exist"
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return

        # run the test script and log the stderr and stdout
        command = [
            scriptpath, user_id, task_nr, task_params,
            configured_backend_interface
        ]
        logmsg = "Running test script with arguments: {0}".format(command)
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")

        # Popen in asynch, but communicate waits
        process = Popen(command, stdout=PIPE, stderr=PIPE)
        test_msg, test_error = process.communicate()
        test_msg = test_msg.decode('UTF-8')
        test_error = test_error.decode('UTF-8')
        test_res = process.returncode
        log_src = "Tester{0}({1})".format(str(task_nr), user_id)

        if test_msg:
            c.log_task_msg(self.queues["logger"], log_src, test_msg, "INFO")
        if test_error:
            c.log_task_error(self.queues["logger"], log_src, test_error,
                             "ERROR")

        # act based on the result
        self.handle_test_result(test_res, user_id, user_email, task_nr,
                                message_id)
Example #28
0
    def fetch_all_emails(self, m):
        """
        Fetch all emails.

        Return list of mailids.
        """

        try:
            m.select(mailbox='Inbox', readonly=False)
        except:
            logmsg = "Failed to select inbox"
            c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

        resp, items = m.search(None, 'All')
        return items[0].split()
Example #29
0
    def run(self):
        """
        Thread code for the worker thread.
        """

        logmsg = "Starting " + self.name
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "INFO")

        while True:
            logmsg = self.name + ": waiting for a new job."
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "INFO")

            # blocking wait on job queue
            nextjob = self.queues["job"].get(True)

            self.handle_job(nextjob)
Example #30
0
    def fetch_all_emails(self, m):
        """
        Fetch all emails.

        Return list of mailids.
        """

        try:
            m.select(mailbox='Inbox', readonly=False)
        except:
            logmsg = "Failed to select inbox"
            c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")
            return []

        resp, items = m.search(None, 'All')
        return items[0].split()
Example #31
0
    def check_and_set_last_done(self, curs, cons, userid):
        """
        The LastDone flag is used to mark users who have successfully solved
        all tasks.
        """
        data = {'uid': userid}
        sql_cmd = "SELECT LastDone FROM Users WHERE UserId == :uid;"
        curs.execute(sql_cmd, data)
        res = curs.fetchone()
        logmsg = "RES: "+ str(res[0])
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        if str(res[0]) == 'None':
            data = {'uid': str(userid), 'now': str(int(time.time()))}
            sql_cmd = "UPDATE Users SET LastDone = datetime(:now, 'unixepoch', 'localtime') WHERE UserId == :uid;"
            curs.execute(sql_cmd, data)
            cons.commit()
Example #32
0
    def disconnect_from_imapserver(self, m):
        """
        Disconnect from existing imap connection
        """

        # m==0 is only possible in test-code (e.g. load_test.py)
        if m != 0:
            try:
                m.close()
                m.logout()
                logmsg = "closed connection to imap server"
                c.log_a_msg(self.queues["logger"], self.name, logmsg, "INFO")
            except Exception as e:
                logmsg = (
                    "Got an error when trying to disconnect from the imap "
                    "server: {0}").format(str(e))
                c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
Example #33
0
 def send_out_email(self, recipient, message, msg_type):
     """
     connect to the smtp server and send out an e-mail
     """
     try:
         # port 465 doesn't seem to work!
         server = smtplib.SMTP(self.smtpserver, 587)
         server.ehlo()
         server.starttls()
         server.login(self.autosub_user, self.mail_pwd)
         server.sendmail(self.mail_user, recipient, message)
         server.close()
         c.log_a_msg(self.logger_queue, self.name, "Successfully sent an e-mail of type '{0}'!".format(msg_type), "DEBUG")
         c.increment_db_statcounter(self.semesterdb, 'nr_mails_sent', \
                                    self.logger_queue, self.name)
     except:
         c.log_a_msg(self.logger_queue, self.name, "Failed to send out an e-mail of type '{0}'!".format(msg_type), "ERROR")
Example #34
0
    def fetch_new_emails(self, m):
        """
        Fetch new (unseen e-mails from the Inbox.

        Return list of mailids
        """

        try:
            m.select("Inbox") # here you a can choose a mail box like INBOX instead
            # use m.list() to get all the mailboxes
        except:
            logmsg = "Failed to select inbox"
            c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

        # you could filter using the IMAP rules here
        # (check http://www.example-code.com/csharp/imap-search-critera.asp)
        resp, items = m.search(None, "UNSEEN")
        return items[0].split()
Example #35
0
    def loop_code(self):
        """
        The code run in the while True loop of the mail fetcher thread.
        """

        m = self.connect_to_imapserver()

        if m != 0:
            self.archive_processed(m)
            self.handle_timeout()
            self.handle_backlogged(m)
            self.handle_new(m)
            self.disconnect_from_imapserver(m)

        # Debug Log Message
        logmsg = ("Start new sleep period")
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")

        time.sleep(self.poll_period)
Example #36
0
    def clean_taskconfig(self):
        conc = lite.connect(self.coursedb)
        curc = conc.cursor()
        #Drop the task configuration table (start clean)
        try:
            sqlcmd = "DROP table TaskConfiguration"
            curc.execute(sqlcmd)
            conc.commit()
        except:
            logmsg = "No Table TaskConfiguration?"
            c.log_a_msg(self.logger_queue, "Debugger", logmsg, "DEBUG")

        sqlcmd = ("CREATE TABLE TaskConfiguration (TaskNr INT PRIMARY KEY, "
                  "TaskStart DATETIME, TaskDeadline DATETIME, PathToTask TEXT, "
                  "GeneratorExecutable TEXT, TestExecutable TEXT, Score INT, "
                  "TaskOperator TEXT, TaskActive BOOLEAN);")
        curc.execute(sqlcmd)
        conc.commit()
        conc.close()
Example #37
0
    def fetch_new_emails(self, m):
        """
        Fetch new (unseen e-mails from the Inbox.

        Return list of mailids
        """

        try:
            m.select(
                "Inbox")  # here you a can choose a mail box like INBOX instead
            # use m.list() to get all the mailboxes
        except:
            logmsg = "Failed to select inbox"
            c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")
            return []

        # you could filter using the IMAP rules here
        # (check http://www.example-code.com/csharp/imap-search-critera.asp)
        resp, items = m.search(None, "UNSEEN")
        return items[0].split()
Example #38
0
    def connect_to_imapserver(self):
        """
        Connect to configured IMAP server.
        """

        try:
            # connecting to the imap server
            if self.imap_info["security"] == 'ssl':
                server = imaplib.IMAP4_SSL(self.imap_info["server"],
                                           int(self.imap_info["port"]))
            else:
                server = imaplib.IMAP4(self.imap_info["server"],
                                       int(self.imap_info["port"]))

            if self.imap_info["security"] == 'starttls':
                server.starttls()

            server.login(self.imap_info["user"], self.imap_info["passwd"])
        except imaplib.IMAP4.abort:
            logmsg = "Login to server was aborted with security= " + self.imap_info["security"] + \
                     " , port= " + str(self.imap_info["port"])
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return 0
        except imaplib.IMAP4.error:
            logmsg = "Got an error when trying to connect to the imap server with" + \
                     " security= " + self.imap_info["security"] + " , port= " + str(self.imap_info["port"])
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return 0
        except Exception as e:
            logmsg = str(e)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            logmsg = "Got an unknown exception when trying to connect to the imap " + \
                     "server with security= " + self.imap_info["security"] + " , port= " + str(self.imap_info["port"])
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return 0

        logmsg = "Successfully logged into imap server with security= " + self.imap_info["security"] + \
                 " , port= " + str(self.imap_info["port"])
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "INFO")

        return server
Example #39
0
    def a_task_is_requested(self, user_id, user_email, task_nr, message_id):
        """
        Process a request for a certain task_nr. Check if that task
        exists, if it is active, and if the deadline has not passed
        yet. If yes put in generator queue.
        """

        logmsg = "Processing a Task Request, UserId:{0} TaskNr:{1}"\
                 .format(user_id, task_nr)
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "INFO")

        #task with this task_nr exists?
        is_task = c.is_valid_task_nr(self.dbs["course"], task_nr, self.queues["logger"], \
                                     self.name)

        if not is_task:
            # task_nr is not valid
            c.send_email(self.queues["sender"], user_email, "", "InvalidTask", str(task_nr), \
                         "", message_id)
            return

        # get time now, deadline and starttime of task
        time_now = datetime.datetime.now()
        starttime = c.get_task_starttime(self.dbs["course"], task_nr, \
                                         self.queues["logger"], self.name)
        deadline = c.get_task_deadline(self.dbs["course"], task_nr, \
                                       self.queues["logger"], self.name)

        if not (starttime <= time_now):
            # task not active yet
            logmsg = ("Task not active")
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")
            c.send_email(self.queues["sender"], user_email, "", "TaskNotActive", \
                         str(task_nr), "", message_id)
            return

        if deadline < time_now:
            # deadline passed for that task_nr!
            logmsg = ("Deadline passed")
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")
            c.send_email(self.queues["sender"], user_email, "", "DeadTask", \
                         str(task_nr), "", message_id)
            return

        logmsg = ("Calling Generator to create"
                  "TaskNr:{0} for UserId:{1}").format(task_nr, user_id)
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "DEBUG")

        c.generate_task(self.queues["generator"], user_id, task_nr, user_email, \
                        message_id)
Example #40
0
    def idmap_all_emails(self, m):
        """
        Search for all emails.

        Return a mapping as dict that assigns each Message-Id its UID.

        Note: This is done readonly to preserve unread flags.
        """

        try:
            m.select(mailbox='Inbox', readonly=True)
        except Exception as e:
            logmsg = "Failed to select inbox with error " + str(e)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return {}

        idmap = dict()

        try:
            resp, items = m.uid('search', None, "ALL")
        except Exception as e:
            logmsg = "Failed to get messages from inbox with IMAP error: " + str(
                e)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return {}

        if resp == 'OK':
            for uid in items[0].split():
                try:
                    typ, msg_data = m.uid('fetch', uid, "(BODY[HEADER])")
                except Exception as e:
                    logmsg = ("Failed to fetch message with uid {0} from "
                              "inbox with error {1} ").format(uid, str(e))
                    c.log_a_msg(self.queues["logger"], self.name, logmsg,
                                "ERROR")
                    return {}

                mail = email.message_from_bytes(msg_data[0][1])
                idmap[mail['Message-ID']] = uid

            return idmap

        else:
            logmsg = (
                "Failed to get messages from inbox. Got response from IMAP "
                "server: {0} ").format(resp)
            c.log_a_msg(self.queues["logger"], self.name, logmsg, "ERROR")
            return {}
Example #41
0
    def a_status_is_requested(self, user_id, user_email, messageid):
        """
        Tell sender to send out a status email.
        """
        logmsg = ("STATUS requested: User with UserId:{0}, Email: {1}").format(\
                 user_id, user_email)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        curs, cons = c.connect_to_db(self.semesterdb, self.logger_queue,
                                     self.name)

        data = {'user_id': user_id}
        sql_cmd = "SELECT CurrentTask FROM Users WHERE UserId == :user_id"
        curs.execute(sql_cmd, data)
        res = curs.fetchone()
        current_task = res[0]

        cons.close()

        c.send_email(self.sender_queue, user_email, user_id, "Status", current_task, \
                     "", messageid)
        c.increment_db_statcounter(self.semesterdb, 'nr_status_requests', \
                                   self.logger_queue, self.name)
Example #42
0
    def check_if_whitelisted(self, user_email):
        """
        Check if the given e-mail address is in the whitelist.
        """

        curs, cons = c.connect_to_db(self.semesterdb, self.logger_queue, self.name)

        data = {'Email': user_email}
        sql_cmd = "SELECT * FROM WhiteList WHERE Email == :Email"
        curs.execute(sql_cmd, data)
        res = curs.fetchone()

        cons.close()

        if res != None:
            return 1
        else:
            logmsg = "Got Mail from a User not on the WhiteList: " + user_email
            c.log_a_msg(self.logger_queue, self.name, logmsg, "Warning")
            c.increment_db_statcounter(self.semesterdb, 'nr_non_registered', \
                                       self.logger_queue, self.name)

            return 0
Example #43
0
    def check_if_whitelisted(self, user_email):
        """
        Check if the given e-mail address is in the whitelist.
        """

        curs, cons = c.connect_to_db(self.dbs["semester"],
                                     self.queues["logger"], self.name)

        data = {'Email': user_email}
        sql_cmd = "SELECT * FROM WhiteList WHERE Email == :Email"
        curs.execute(sql_cmd, data)
        res = curs.fetchone()

        cons.close()

        if res != None:
            return True

        logmsg = "Got mail from a user not on the WhiteList: " + user_email
        c.log_a_msg(self.queues["logger"], self.name, logmsg, "Warning")
        c.increment_db_statcounter(self.dbs["semester"], 'nr_non_registered', \
                                   self.queues["logger"], self.name)

        return False
Example #44
0
    def add_new_user(self, user_name, user_email):
        """
        Add the necessary entries to database for a newly registered user.
        """

        curs, cons = c.connect_to_db(self.semesterdb, self.logger_queue, self.name)

        logmsg = 'New Account: User: %s' % user_name
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        data = {'Name': user_name, 'Email': user_email, 'TimeNow': str(int(time.time()))}
        sql_cmd = ("INSERT INTO Users "
                   "(UserId, Name, Email, FirstMail, LastDone, CurrentTask) "
                   "VALUES(NULL, :Name, :Email, datetime(:TimeNow, 'unixepoch', 'localtime')"
                   ", NULL, 1)")
        curs.execute(sql_cmd, data)
        cons.commit()

        # the new user has now been added to the database. Next we need
        # to send him an email with the first task.

        # read back the new users UserId and create a directory for putting his
        # submissions in.
        data = {'Email': user_email}
        sql_cmd = "SELECT UserId FROM Users WHERE Email = :Email"
        curs.execute(sql_cmd, data)
        res = curs.fetchone()
        user_id = str(res[0])
        dir_name = 'users/'+ user_id
        c.check_dir_mkdir(dir_name, self.logger_queue, self.name)

        cons.close()

        # NOTE: messageid is empty, cause this will be sent out by the welcome message!
        curc, conc = c.connect_to_db(self.coursedb, self.logger_queue, self.name)

        sql_cmd = "SELECT GeneratorExecutable FROM TaskConfiguration WHERE TaskNr == 1"
        curc.execute(sql_cmd)
        res = curc.fetchone()

        conc.close()

        if res != None:
            logmsg = "Calling Generator Script: " + str(res[0])
            c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
            logmsg = "UserID " + user_id + ",UserEmail " + user_email
            c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
            self.gen_queue.put(dict({"user_id": user_id, "user_email": user_email, \
                                     "task_nr": "1", "message_id": ""}))
        else:
            # If there is no generator script, we assume, that there is a static
            # description.txt which shall be used.
            c.send_email(self.sender_queue, user_email, user_id, "Task", "1", "", "")
Example #45
0
    def run(self):
        """
        Thread code for the fetcher thread.
        """

        c.log_a_msg(self.logger_queue, self.name, "Starting Mail Fetcher Thread!", "INFO")

        logmsg = "Imapserver: '" + self.imapserver + "'"
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        # This thread is running as a daemon thread, this is the while(1) loop that is
        # running until the thread is stopped by the main thread
        while True:
            self.loop_code()

        logmsg = "Exiting fetcher - this should NEVER happen!"
        c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
Example #46
0
    def run(self):
        """
        Thread code for the worker thread.
        """

        logmsg = "Starting " + self.name
        c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

        while True:
            logmsg = self.name + ": waiting for a new job."
            c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")
            nextjob = self.job_queue.get(True)
            if nextjob:
                tasknr = nextjob.get("taskNr")
                user_id = nextjob.get("UserId")
                user_email = nextjob.get("UserEmail")
                message_id = nextjob.get("MessageId")

                logmsg = self.name + "got a new job: {0} from the user with id: {1}".format(str(tasknr), str(user_id))
                c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

                # check if there is a test executable configured in the
                # database -- if not fall back on static test script.
                curc, conc = c.connect_to_db(self.coursedb, self.logger_queue, self.name)
                try:
                    data = {"tasknr": tasknr}
                    sql_cmd = "SELECT TestExecutable FROM TaskConfiguration WHERE TaskNr == :tasknr"
                    curc.execute(sql_cmd, data)
                    testname = curc.fetchone()
                except:
                    logmsg = "Failed to fetch TestExecutable for TaskNr: {0}".format(tasknr)
                    logmsg = logmsg + " from the Database! Table TaskConfiguration corrupted?"
                    c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")

                if testname != None:
                    try:
                        data = {"tasknr": tasknr}
                        sql_cmd = "SELECT PathToTask FROM TaskConfiguration WHERE TaskNr == :tasknr"
                        curc.execute(sql_cmd, data)
                        path = curc.fetchone()
                        scriptpath = str(path[0]) + "/" + str(testname[0])
                    except:  # if a testname was given, then a Path should be
                        # there as well!
                        logmsg = "Failed to fetch Path to Tasknr: {0}".format(tasknr)
                        logmsg = "{0} from the Database! Table TaskConfiguration corrupted?".format(logmsg)
                        c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")

                else:  # in case no testname was given, we fall back to the
                    # static directory structure
                    scriptpath = "tasks/task" + str(tasknr) + "/./tests.sh"
                conc.close()

                # get the task parameters
                task_params = self.get_task_parameters(user_id, tasknr)

                # run the test script
                logmsg = "Running test script: " + scriptpath
                c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")
                command = '{0} {1} {2} "{3}" >> autosub.stdout 2>>autosub.stderr'.format(
                    scriptpath, user_id, tasknr, task_params
                )
                test_res = os.system(command)

                if test_res:  # not 0 returned

                    logmsg = "Test failed! User: {0} Task: {1}".format(user_id, tasknr)
                    logmsg = logmsg + " return value:" + str(test_res)
                    c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

                    c.send_email(
                        self.sender_queue, str(user_email), str(user_id), "Failed", str(tasknr), "", str(message_id)
                    )

                    if test_res == 512:  # Need to read up on this but os.system() returns
                        # 256 when the script returns 1 and 512 when the script returns 2, 768 when 3!
                        logmsg = "SecAlert: This test failed due to probable attack by user!"
                        c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

                        c.send_email(
                            self.sender_queue,
                            str(user_email),
                            str(user_id),
                            "SecAlert",
                            str(tasknr),
                            "",
                            str(message_id),
                        )

                    elif test_res == 768:
                        logmsg = "TaskAlert: This test for TaskNr {0} and User {1} failed due an error with task/testbench analyzation!".format(
                            tasknr, user_id
                        )
                        c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

                        c.send_email(
                            self.sender_queue,
                            str(user_email),
                            str(user_id),
                            "TaskAlert",
                            str(tasknr),
                            "",
                            str(message_id),
                        )

                else:  # 0 returned

                    logmsg = "Test succeeded! User: {0} Task: {1}".format(user_id, tasknr)
                    c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

                    # Notify, the user that the submission was successful
                    c.send_email(self.sender_queue, str(user_email), str(user_id), "Success", str(tasknr), "", "")

                    curc, conc = c.connect_to_db(self.coursedb, self.logger_queue, self.name)

                    currenttask = int(c.user_get_current_task(self.semesterdb, user_id, self.logger_queue, self.name))

                    # Next, a new Task is generated -- but only if a new task
                    # exists AND if a generator script exists  (otherwise
                    # static task description is assumed, AND if users current
                    # task < the task that shall be generated (no Task has yet
                    # been generated for this user yet).

                    if currenttask < int(tasknr) + 1:
                        try:
                            data = {"tasknr": str(int(tasknr) + 1)}
                            sql_cmd = "SELECT GeneratorExecutable FROM TaskConfiguration WHERE TaskNr == :tasknr"
                            curc.execute(sql_cmd, data)
                            res = curc.fetchone()
                        except:
                            logmsg = "Failed to fetch Generator Script for Tasknr: {0}".format(tasknr)
                            logmsg = logmsg + "from the Database! Table TaskConfiguration corrupted?"
                            c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
                        finally:
                            conc.close()

                        task_start = c.get_task_starttime(self.coursedb, int(tasknr) + 1, self.logger_queue, self.name)

                        if task_start < datetime.datetime.now():
                            if res != None:  # generator script for this task configured?
                                logmsg = "Calling Generator Script: " + str(res[0])
                                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                                logmsg = "UserID {0}, UserEmail {1}".format(user_id, user_email)
                                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

                                self.gen_queue.put(
                                    dict(
                                        {
                                            "user_id": str(user_id),
                                            "user_email": str(user_email),
                                            "task_nr": str(int(tasknr) + 1),
                                            "messageid": "",
                                        }
                                    )
                                )
                            else:
                                c.send_email(
                                    self.sender_queue,
                                    str(user_email),
                                    str(user_id),
                                    "Task",
                                    str(int(tasknr) + 1),
                                    "",
                                    str(message_id),
                                )

                        else:
                            c.send_email(
                                self.sender_queue,
                                str(user_email),
                                str(user_id),
                                "CurLast",
                                str(int(tasknr) + 1),
                                "",
                                str(message_id),
                            )
Example #47
0
    def activator_loop(self):
        curc, conc = c.connect_to_db(self.coursedb, self.logger_queue, \
                                     self.name)

        # first we need to know, for which tasks, the message has already
        # been sent out
        sql_cmd = "SELECT * FROM TaskConfiguration WHERE TaskActive==0;"
        curc.execute(sql_cmd)
        res = curc.fetchone()
        while res != None:
            tasknr = res[0]
            logmsg = "Task {0} is still inactive".format(str(tasknr))
            c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")
            # check if a tasks start time has come
            task_starttime = datetime.datetime.strptime(res[1], c.format_string)
            if task_starttime < datetime.datetime.now():
                # first, let's set the task active!
                data = {'tasknr': tasknr}
                sql_cmd = "UPDATE TaskConfiguration SET TaskActive = 1 WHERE TaskNr == :tasknr;"
                curc.execute(sql_cmd, data)
                conc.commit()

                # next, check if any users are waiting for that task
                curs, cons = c.connect_to_db(self.semesterdb, \
                                             self.logger_queue, self.name)
                data = {'tasknr': tasknr}
                sqlcmd = "SELECT * FROM Users WHERE CurrentTask == :tasknr;"
                curs.execute(sqlcmd, data)
                nextuser = curs.fetchone()
                while nextuser != None:
                    logmsg = "The next example is sent to User {0} now.".format(tasknr)
                    c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")
                    uid = nextuser[0]
                    user_email = nextuser[2]

                    try:
                        data = {'tasknr': tasknr}
                        sql_cmd = "SELECT GeneratorExecutable FROM TaskConfiguration WHERE TaskNr == :tasknr;"
                        curc.execute(sql_cmd, data)
                        res = curc.fetchone()
                    except:
                        logmsg = "Failed to fetch Generator Script for Tasknr: "+ str(tasknr)
                        logmsg = logmsg + "from the Database! Table TaskConfiguration corrupted?"
                        c.log_a_msg(self.logger_queue, self.name, \
                                    logmsg, "ERROR")

                    if res != None:
                        logmsg = "Calling Generator Script: {0}".format(res[0])
                        c.log_a_msg(self.logger_queue, self.name, \
                                    logmsg, "DEBUG")

                        logmsg = "UserID {0}, UserEmail{1}".format(uid, \
                                                                   user_email)
                        c.log_a_msg(self.logger_queue, self.name, \
                                    logmsg, "DEBUG")
                        self.gen_queue.put(dict({"UserId": str(uid), \
                                                 "UserEmail": str(user_email), \
                                                 "TaskNr": str(tasknr), \
                                                 "MessageId": ""}))
                    else:
                        c.send_email(self.sender_queue, str(user_email), \
                                     str(uid), "Task", str(tasknr), "", "")

                    nextuser = curs.fetchone()

                cons.close()

            res = curc.fetchone()

        conc.close()
Example #48
0
    def generator_loop(self):
        """
        Loop code for the generator thread
        """

        #blocking wait on gen_queue
        next_gen_msg = self.gen_queue.get(True)
        logmsg = "gen_queue content:" + str(next_gen_msg)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        task_nr = next_gen_msg.get('task_nr')
        user_id = next_gen_msg.get('user_id')
        user_email = next_gen_msg.get('user_email')
        messageid = next_gen_msg.get('messageid')

        #generate the directory for the task
        task_dir = 'users/' + str(user_id) + "/Task"+str(task_nr)
        c.check_dir_mkdir(task_dir, self.logger_queue, self.name)

        #generate the task description
        desc_dir = task_dir + "/desc"
        c.check_dir_mkdir(desc_dir, self.logger_queue, self.name)

        # check if there is a generator executable configured in the database
        # if not fall back on static generator script.
        curc, conc = c.connect_to_db(self.coursedb, self.logger_queue, self.name)

        data = {'TaskNr': task_nr}
        sql_cmd = ("SELECT GeneratorExecutable FROM TaskConfiguration "
                   "WHERE TaskNr== :TaskNr")
        curc.execute(sql_cmd, data)
        generatorname = curc.fetchone()

        if generatorname != None:
            data = {'TaskNr': task_nr}
            sql_cmd = "SELECT PathToTask FROM TaskConfiguration WHERE TaskNr == :TaskNr"
            curc.execute(sql_cmd, data)
            path = curc.fetchone()
            scriptpath = str(path[0]) + "/" + str(generatorname[0])
        else:
            scriptpath = "tasks/task" + str(task_nr) + "/./generator.sh"

        challenge_mode = self.get_challenge_mode()

        command = scriptpath + " " + str(user_id) + " " + str(task_nr) + " " + \
                  self.submission_email + " " + str(challenge_mode) + " " + \
                  self.semesterdb + " >> autosub.stdout 2>>autosub.stderr"

        logmsg = "generator command: {0}".format(command)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
        generator_res = os.system(command)

        if generator_res:
            logmsg = "Failed to call generator script, return value: " + \
                     str(generator_res)
            c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        logmsg = "Generated individual task for user/tasknr:" + str(user_id) + "/" + \
                 str(task_nr)
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        c.send_email(self.sender_queue, str(user_email), str(user_id), \
                     "Task", str(task_nr), "Your personal example", str(messageid))

        conc.close()
Example #49
0
    def test_loop_code(self):
        sender_queue = queue.Queue(10)
        gen_queue = queue.Queue(10)
        ta = TaskActivator(
            "testactivator", gen_queue, sender_queue, self.logger_queue, "testcourse.db", "testsemester.db"
        )

        curc, conc = c.connect_to_db("testcourse.db", self.logger_queue, "testcode")
        this_time_yesterday = str(datetime.datetime.now() - datetime.timedelta(1)).split(".")[0]
        this_time_tomorrow = str(datetime.datetime.now() + datetime.timedelta(1)).split(".")[0]
        this_time_nextmonth = str(datetime.datetime.now() + datetime.timedelta(30)).split(".")[0]

        # Drop the task configuration table (start clean)
        sqlcmd = "DROP table TaskConfiguration"
        try:
            curc.execute(sqlcmd)
            conc.commit()
        except:
            logmsg = "No Table TaskConfiguration?"
            c.log_a_msg(self.logger_queue, "Debugger", logmsg, "DEBUG")

        sqlcmd = (
            "CREATE TABLE TaskConfiguration (TaskNr INT PRIMARY KEY, "
            "TaskStart DATETIME, TaskDeadline DATETIME, "
            "PathToTask TEXT, GeneratorExecutable TEXT, "
            "TestExecutable TEXT, Score INT, TaskOperator TEXT, "
            "TaskActive BOOLEAN);"
        )
        curc.execute(sqlcmd)
        conc.commit()

        # test case 1: no effect -- nothing to do here for the activator thread
        self.add_task(
            curc,
            conc,
            1,
            this_time_yesterday,
            this_time_tomorrow,
            "/home/testuser/path/to/task/implementation",
            "generator.sh",
            "tester.sh",
            "5",
            "[email protected]",
            "1",
        )

        # test case 2: only a logmsg, there is an inactive task, however its starttime has not
        #    come (yet)
        self.add_task(
            curc,
            conc,
            2,
            this_time_tomorrow,
            this_time_nextmonth,
            "/home/testuser/path/to/task/implementation",
            "generator.sh",
            "tester.sh",
            "5",
            "[email protected]",
            "0",
        )

        ta.activator_loop()

        # nothing to test for case 1

        # check expected log message for  test case 2
        logmsg = self.logger_queue.get(True)
        self.assertEqual(logmsg.get("loggername"), "testactivator")
        self.assertEqual(logmsg.get("msg"), "Task 2 is still inactive")
        self.assertEqual(logmsg.get("type"), "INFO")

        # test case 3: only a logmsg, there is an inactive task, however its starttime has not
        #    come (yet)
        this_time_plus3s = str(datetime.datetime.now() + datetime.timedelta(0, 3)).split(".")[0]
        self.add_task(
            curc,
            conc,
            3,
            this_time_tomorrow,
            this_time_plus3s,
            "/home/testuser/path/to/task/implementation",
            "generator.sh",
            "tester.sh",
            "5",
            "[email protected]",
            "0",
        )

        ta.activator_loop()
        # check expected log message for  test case 2
        logmsg = self.logger_queue.get(True)
        self.assertEqual(logmsg.get("loggername"), "testactivator")
        self.assertEqual(logmsg.get("msg"), "Task 2 is still inactive")
        self.assertEqual(logmsg.get("type"), "INFO")
        # check expected log message for  test case 3
        logmsg = self.logger_queue.get(True)
        self.assertEqual(logmsg.get("loggername"), "testactivator")
        self.assertEqual(logmsg.get("msg"), "Task 3 is still inactive")
        self.assertEqual(logmsg.get("type"), "INFO")

        time.sleep(10)
        ta.activator_loop()
        # check expected log message for  test case 2
        logmsg = self.logger_queue.get(True)
        self.assertEqual(logmsg.get("loggername"), "testactivator")
        self.assertEqual(logmsg.get("msg"), "Task 2 is still inactive")
        self.assertEqual(logmsg.get("type"), "INFO")
        # check expected log message for  test case 3
        logmsg = self.logger_queue.get(True)
        self.assertEqual(logmsg.get("loggername"), "testactivator")
        self.assertEqual(logmsg.get("msg"), "Task 3 is still inactive")
        self.assertEqual(logmsg.get("type"), "INFO")
Example #50
0
    def loop_code(self):
        """
        The code run in the while True loop of the mail fetcher thread.
        """

        m = self.connect_to_imapserver()

        if m != 0:
            curs, cons = c.connect_to_db(self.semesterdb, self.logger_queue, self.name)
            items = self.fetch_new_emails(m)

            # iterate over all new e-mails and take action according to the structure
            # of the subject line
            for emailid in items:

                c.increment_db_statcounter(self.semesterdb, 'nr_mails_fetched', \
                                           self.logger_queue, self.name)

                # fetching the mail, "`(RFC822)`" means "get the whole stuff", but you
                # can ask for headers only, etc
                resp, data = m.fetch(emailid, "(RFC822)")

                # parsing the mail content to get a mail object
                mail = email.message_from_bytes(data[0][1])

                mail_subject = str(mail['subject'])
                from_header = str(mail['From'])
                split_header = str(from_header).split("<")
                user_name = split_header[0]

                try:
                    user_email = str(split_header[1].split(">")[0])
                except:
                    user_email = str(mail['From'])

                messageid = mail.get('Message-ID')

                whitelisted = self.check_if_whitelisted(user_email)

                if whitelisted:
                    data = {'Email': user_email}
                    sql_cmd = "SELECT UserId FROM Users WHERE Email = :Email"
                    curs.execute(sql_cmd, data)
                    res = curs.fetchall()

                    if res:
                        logmsg = "Got mail from an already known user!"
                        c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")

                        #TODO: Does sending a mail "Result bla" without number crash this?
                        if re.search('[Rr][Ee][Ss][Uu][Ll][Tt]', mail_subject):
                            searchObj = re.search('[0-9]+', mail_subject, )
                            if int(searchObj.group()) <= c.get_num_tasks(self.coursedb, \
                                    self.logger_queue, self.name):
                                logmsg = "Processing a Result, UserId:{0} TaskNr:{1}"\
                                         .format(user_email, searchObj.group())
                                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                                self.take_new_results(user_email, searchObj.group(), \
                                                      mail, messageid)
                            else:
                                logmsg = ("Given Task number is higher than actual Number"
                                          "of Tasks!")
                                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                                c.send_email(self.sender_queue, user_email, "", \
                                             "InvalidTask", "", "", messageid)
                        elif re.search('[Qq][Uu][Ee][Ss][Tt][Ii][Oo][Nn]', mail_subject):
                            self.a_question_was_asked(user_email, mail, messageid)
                        elif re.search('[Ss][Tt][Aa][Tt][Uu][Ss]', mail_subject):
                            self.a_status_is_requested(user_email, messageid)
                        else:
                            logmsg = ("Got a kind of message I do not understand. "
                                      "Sending a usage mail...")
                            c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                            c.send_email(self.sender_queue, user_email, "", "Usage", "", \
                                         "", messageid)

                    else:
                        reg_deadline = self.get_registration_deadline()

                        if reg_deadline > datetime.datetime.now():
                            self.add_new_user(user_name, user_email)
                            c.send_email(self.sender_queue, user_email, "", "Welcome", \
                                         "", "", messageid)
                        else:
                            c.send_email(self.sender_queue, user_email, "", "RegOver", \
                                         "", "", messageid)

                else:
                    c.send_email(self.sender_queue, user_email, "", "NotAllowed", \
                                 "", "", messageid)

            try:
                m.close()
            except imaplib.IMAP4.abort:
                logmsg = ("Closing connection to server was aborted "
                          "(probably a server-side problem). Trying to connect again ...")
                c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
                #m.close()
            except imaplib.IMAP4.error:
                logmsg = ("Got an error when trying to connect to the imap server."
                          "Trying to connect again ...")
                c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
            except:
                logmsg = ("Got an unknown exception when trying to connect to the "
                          "imap server. Trying to connect again ...")
                c.log_a_msg(self.logger_queue, self.name, logmsg, "ERROR")
            finally:
                logmsg = "closed connection to imapserver"
                c.log_a_msg(self.logger_queue, self.name, logmsg, "INFO")


            # check if messages have been handled and need to be archived now
            try:
                next_send_msg = self.arch_queue.get(False)
            except:
                next_send_msg = 'NONE'

            if next_send_msg != 'NONE':
                c.log_a_msg(self.logger_queue, self.name, "moving a message!!!!!!!", \
                            "INFO")
                m = self.connect_to_imapserver()

                for next_msg in next_send_msg:
                    email_ids = self.fetch_all_emails(m)

                    for emailid in email_ids:
                        typ, msg_data = m.fetch(str(int(emailid)), "(BODY[HEADER])")
                        mail = email.message_from_bytes(msg_data[0][1])
                        if mail['Message-ID'] == next_send_msg.get('mid'):
                            logmsg = "Moving Message with ID: {0}"\
                                     .format(mail['Message-ID'])
                            c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

                            resp, data = m.fetch(emailid, "(UID)")
                            pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)')
                            match = pattern_uid.match(str(data[0]).split("'")[1])
                            msg_uid = match.group('uid')

                            result = m.uid('COPY', msg_uid, 'archive_vels')

                            if result[0] == 'OK':
                                mov, data = m.uid('STORE', msg_uid, '+FLAGS', \
                                                  '(\Deleted)')
                                m.expunge()
                            break

                # m==0 is only possible in test-code (e.g. load_test.py)
                if m != 0:
                    m.logout()

            cons.close()

        time.sleep(self.poll_period)
Example #51
0
    def handle_next_mail(self):
        """
        parse the subject/content of a mail and take appropriate action.
        """
        #blocking wait on sender_queue
        next_send_msg = self.sender_queue.get(True)

        tasknr = str(next_send_msg.get('Task'))
        messageid = str(next_send_msg.get('MessageId'))
        uid = str(next_send_msg.get('UserId'))
        recipient = str(next_send_msg.get('recipient'))
        message_type = str(next_send_msg.get('message_type'))

        curs, cons = c.connect_to_db(self.semesterdb, self.logger_queue, \
                                     self.name)
        curc, conc = c.connect_to_db(self.coursedb, self.logger_queue, \
                                     self.name)

        attachments = []

        # prepare fields for the e-mail
        msg = MIMEMultipart()
        msg['From'] = self.mail_user
        msg['To'] = recipient
        logmsg = "RECIPIENT: " + recipient
        c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

        msg['Date'] = formatdate(localtime=True)

        if message_type == "Task":
            logmsg = "Task in send_queue: " + str(next_send_msg)
            c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
            numtasks = c.get_num_tasks(self.coursedb, \
                       self.logger_queue, self.name)
            ctasknr = c.user_get_current_task(self.semesterdb, uid, \
                                             self.logger_queue, self.name)
            if numtasks+1 == int(tasknr): # last task solved!
                msg['Subject'] = "Congratulations!"
                message_text = self.read_specialmessage('CONGRATS')

                if int(tasknr)-1 == int(ctasknr):
                    # statistics shall only be udated on the first
                    # successful submission
                    c.user_set_current_task(self.semesterdb, tasknr, uid, \
                                           self.logger_queue, self.name)
                    self.increment_db_taskcounter(curs, cons, 'NrSuccessful', \
                                                  str(int(tasknr)-1))
                    self.increment_db_taskcounter(curs, cons, 'NrSubmissions', \
                                                  str(int(tasknr)-1))
                    self.check_and_set_last_done(curs, cons, uid)

                msg = self.assemble_email(msg, message_text, '')
                self.send_out_email(recipient, msg.as_string(), message_type)
            else: # at least one more task to do: send out the description
                # only send the task description, after the first
                # successful submission
                if int(tasknr)-1 <= int(ctasknr) or int(ctasknr) == 1:
                    msg['Subject'] = "Description Task" + str(tasknr)

                    dl_text = "\nDeadline for this Task: {0}\n".format(c.get_task_deadline(self.coursedb, tasknr, self.logger_queue, self.name))

                    data = {'tasknr': str(tasknr)}
                    sql_cmd = "SELECT PathToTask FROM TaskConfiguration WHERE TaskNr == :tasknr;"
                    curc.execute(sql_cmd, data)
                    paths = curc.fetchone()

                    if not paths:
                        logmsg = "It seems, the Path to Task {0} is not configured.".format(tasknr)
                        c.log_a_msg(self.logger_queue, self.name, \
                                    logmsg, "WARNING")

                        message_text = "Sorry, but something went wrong... probably misconfiguration or missing configuration of Task {0}".format(tasknr)
                        msg = self.assemble_email(msg, message_text, '')
                        self.send_out_email(recipient, msg.as_string(), \
                                            message_type)
                    else:
                        path_to_task = str(paths[0])
                        path_to_msg = path_to_task + "/description.txt"
                        message_text = self.read_text_file(path_to_msg) \
                                       + dl_text

                        data = {'tasknr': str(tasknr), 'uid': uid}
                        sql_cmd = "SELECT TaskAttachments FROM UserTasks WHERE TaskNr == :tasknr AND UserId == :uid;"
                        curs.execute(sql_cmd, data)
                        res = curs.fetchone()

                        logmsg = "got the following attachments: " + str(res)
                        c.log_a_msg(self.logger_queue, self.name, logmsg, \
                                    "DEBUG")
                        if res:
                            attachments = str(res[0]).split()

                        # statistics shall only be udated on the first
                        # succesful submission
                        c.user_set_current_task(self.semesterdb, tasknr, uid, \
                                               self.logger_queue, self.name)
                        self.increment_db_taskcounter(curs, cons, \
                                                      'NrSuccessful', \
                                                      str(int(tasknr)-1))
                        self.increment_db_taskcounter(curs, cons, \
                                                      'NrSubmissions', \
                                                      str(int(tasknr)-1))

                        msg = self.assemble_email(msg, message_text, \
                                                  attachments)
                        self.send_out_email(recipient, msg.as_string(), \
                                            message_type)

            self.backup_message(messageid)

        elif message_type == "Failed":
            self.increment_db_taskcounter(curs, cons, 'NrSubmissions', tasknr)
            path_to_msg = "users/{0}/Task{1}".format(uid, tasknr)
            error_msg = self.read_text_file("{0}/error_msg".format(path_to_msg))
            msg['Subject'] = "Task" + tasknr + ": submission rejected"
            message_text = "Error report:\n\n""" + error_msg

            reply_attachments = []

            try:
                logmsg = "searching attachments in: {0}/error_attachments".format(path_to_msg)
                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                ats = os.listdir("{0}/error_attachments".format(path_to_msg))
                logmsg = "got the following attachments: {0}".format(ats)
                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                for next_attachment in ats:
                    reply_attachments.append("{0}/error_attachments/{1}".format(path_to_msg, next_attachment))
            except:
                logmsg = "no attachments for failed task."
                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")

            msg = self.assemble_email(msg, message_text, reply_attachments)
            self.send_out_email(recipient, msg.as_string(), message_type)
            self.backup_message(messageid)

        elif message_type == "SecAlert":
            admin_mails = self.get_admin_emails()
            for admin_mail in admin_mails:
                msg['To'] = admin_mail
                path_to_msg = "users/"+ uid + "/Task" + tasknr + "/error_msg"
                error_msg = self.read_text_file(path_to_msg)
                msg['Subject'] = "Autosub Security Alert User:"******"Error report:\n\n""" + error_msg
                msg = self.assemble_email(msg, message_text, '')
                self.send_out_email(admin_mail, msg.as_string(), message_type)
                self.backup_message(messageid)

        elif message_type == "TaskAlert":
            admin_mails = self.get_admin_emails()
            for admin_mail in admin_mails:
                msg['To'] = admin_mail
                msg['Subject'] = "Autosub Task Error Alert Task " \
                                 + tasknr + " User " + uid
                message_text = "Something went wrong with task/testbench analyzation for Task " + tasknr +" and User " + uid + " . Either the entity or testbench analyzation threw an error."
                msg = self.assemble_email(msg, message_text, '')
                self.send_out_email(admin_mail, msg.as_string(), message_type)
                self.backup_message(messageid)

        elif message_type == "Success":
            msg['Subject'] = "Task " + tasknr + " submitted successfully"
            message_text = "Congratulations!"
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
            #set first done if not set yet
            self.check_and_set_first_successful(curs, cons, uid, tasknr)

            # no backup of message -- this is done after the new task
            # description was sent to the user!
        elif message_type == "Status":
            msg['Subject'] = "Your Current Status"
            message_text = self.generate_status_update(curs, recipient)
            numtasks = c.get_num_tasks(self.coursedb, self.logger_queue, \
                                       self.name)
            if int(numtasks) >= int(tasknr):
                #also attach current task
                data = {'tasknr': str(tasknr), 'uid': uid}
                sql_cmd = "SELECT TaskAttachments FROM UserTasks WHERE TaskNr == :tasknr AND UserId == :uid;"
                curs.execute(sql_cmd, data)
                res = curs.fetchone()
                logmsg = "got the following attachments: " + str(res)
                c.log_a_msg(self.logger_queue, self.name, logmsg, "DEBUG")
                if res:
                    attachments = str(res[0]).split()
                msg = self.assemble_email(msg, message_text, attachments)
                self.send_out_email(recipient, msg.as_string(), message_type)
            else:
                msg = self.assemble_email(msg, message_text, attachments)
                self.send_out_email(recipient, msg.as_string(), message_type)

            self.backup_message(messageid)

        elif message_type == "InvalidTask":
            msg['Subject'] = "Invalid Task Number"
            message_text = self.read_specialmessage('INVALID')
            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "CurLast":
            # we still need to increment the users task counter!
            c.user_set_current_task(self.semesterdb, tasknr, uid, \
                                   self.logger_queue, self.name)
            msg['Subject'] = "Task{0} is not available yet".format(str(tasknr))
            message_text = self.read_specialmessage('CURLAST')
            message_text = "{0}\n\nThe Task is currently scheduled for: {1}".format(message_text, \
                   c.get_task_starttime(self.coursedb, str(tasknr), \
                   self.logger_queue, self.name))
            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "DeadTask":
            msg['Subject'] = "Deadline for Task{0} has passed.".format(str(tasknr))
            message_text = self.read_specialmessage('DEADTASK')
            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "Usage":
            msg['Subject'] = "Autosub Usage"
            message_text = self.read_specialmessage('USAGE')
            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "Question":
            msg['Subject'] = "Question received"
            message_text = self.read_specialmessage('QUESTION')
            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "QFwd":
            orig_mail = next_send_msg.get('Body')
            msg['Subject'] = "Question from " + orig_mail['from']

            if orig_mail.get_content_maintype() == 'multipart':
                part = orig_mail.get_payload(0)
                mbody = part.get_payload()
                message_text = "Original subject: " + orig_mail['subject'] + "\n\nNote: This e-mail contained attachments which have been removed!\n"
                message_text = "{0}\n\nOriginal body:\n{1}".format(message_text, mbody)
            else:
                mbody = orig_mail.get_payload()
                message_text = "Original subject: " + orig_mail['subject'] + \
                       "\n\nOriginal body:\n" + str(mbody)

            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "Welcome":
            msg['Subject'] = "Welcome!"
            message_text = self.read_specialmessage('WELCOME')
            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "RegOver":
            msg['Subject'] = "Registration Deadline has passed"
            message_text = self.read_specialmessage('REGOVER')
            self.backup_message(messageid)
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
        elif message_type == "NotAllowed":
            msg['Subject'] = "Registration Not Successful."
            message_text = self.read_specialmessage('NOTALLOWED')
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
            self.backup_message(messageid)
        else:
            c.log_a_msg(self.logger_queue, self.name, \
                        "Unkown Message Type in the sender_queue!", "ERROR")
            msg = self.assemble_email(msg, message_text, '')
            self.send_out_email(recipient, msg.as_string(), message_type)
            self.backup_message(messageid)

        cons.close()
        conc.close()