Ejemplo n.º 1
0
def apply_button_rule(user, email, er_id, msg_schema_id, kargs):
    res = {'status': False}

    try:
        logger.info("here")
        imapAccount = ImapAccount.objects.get(email=email)
        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused

        er = EmailRule.objects.get(id=er_id)
        #  read from DB and convert to the type accordingly
        for key, value in kargs.iteritems():
            er_arg = EmailRule_Args.objects.get(rule=er, name=key)

            # parse datetime
            if er_arg.type == "datetime":
                try:
                    kargs[key] = datetime.datetime.strptime(
                        value, '%Y-%m-%dT%H:%M')
                except Exception:
                    res['code'] = key
                    raise TypeError

        mailbox = MailBox(imapAccount, imap, is_simulate=False)
        res = interpret_bypass_queue(mailbox,
                                     extra_info={
                                         "msg-id": msg_schema_id,
                                         "code": er.code,
                                         "shortcut": kargs,
                                         "rule_name": er.name
                                     })
        logger.info(kargs)
        logger.info(er.code)
        logger.info(res)
        res['status'] = True

    except ImapAccount.DoesNotExist:
        res['code'] = "Error during deleting the mode. Please refresh the page."
    except MailbotMode.DoesNotExist:
        res['code'] = "Error during deleting the mode. Please refresh the page."
    except TypeError:
        res['code'] = "Datetime %s is in wrong format!" % res['code']
    except Exception as e:
        logger.exception(e)
        res['code'] = msg_code['UNKNOWN_ERROR']
    return res
Ejemplo n.º 2
0
def run_shortcut(shortcuts, mailbox, original_message_schema, code_body):
    body = {"text": "", "html": ""}
    res = None
    for shortcut in shortcuts:
        extra_info={"msg-id": original_message_schema.id, "code": shortcut.code, "shortcut": code_body}

        res = interpret_bypass_queue(mailbox, extra_info={"msg-id": original_message_schema.id, "code": shortcut.code, "shortcut": code_body})
        logger.debug(res)

        for key, value in res['appended_log'].iteritems():
            if not value['error']:
                body["text"] = 'Your mail shortcut is successfully applied! \n'
                body["html"] = 'Your mail shortcut is successfully applied! <br>'
            else:
                body["text"] = 'Something went wrong! \n'
                body["html"] = 'Something went wrong! <br>'
                        
            body["text"] = body["text"] + value['log']
            body["html"] = body["html"] + value['log']
                
            logger.debug(body)

    return res, body
Ejemplo n.º 3
0
class Command(BaseCommand):
    args = ''
    help = 'Process email'

    # Auto-send messages to TEST_ACCOUNT_EMAIL and see the results match expected results by running multiple unit tests
    def handle(self, *args, **options):
        if len(args) == 0:
            print("option: send-test|run-test")
            print(
                "You should run `send-test` at least once prior to `run-test`")
            return

        test_emails = [
            {
                'subject':
                'test email %s ' %
                str(datetime.datetime.now().strftime("%m/%d %H:%M:%S,%f")),
                'from_addr':
                TEST_ACCOUNT_EMAIL,
                'to':
                "*****@*****.**",
                'cc':
                "",
                'bcc':
                "",
                'body_plain':
                'hello world',
                'body_html':
                'hi'
            },
            {
                'subject':
                'test email with emoji 🤷‍♀️ %s ' %
                str(datetime.datetime.now().strftime("%m/%d %H:%M:%S,%f")),
                'from_addr':
                TEST_ACCOUNT_EMAIL,
                'to':
                "[email protected], [email protected]",
                'cc':
                "[email protected], [email protected]",
                'bcc':
                "[email protected], [email protected], [email protected]",
                'body_plain':
                '😎',
                'body_html':
                '😎'
            },
        ]

        imapAccount = None
        imap = None

        # Auth to test email accountss
        try:
            imapAccount = ImapAccount.objects.get(email=TEST_ACCOUNT_EMAIL)
        except ImapAccount.DoesNotExist:
            login_imap(TEST_ACCOUNT_EMAIL,
                       TEST_ACCOUNT_PASSWORD,
                       'imap.gmail.com',
                       is_oauth=False)

            print(
                "Just created a YouPS account for a test account. It will take couple minutes to set up"
            )
            return

        try:
            auth_res = authenticate(imapAccount)
            if not auth_res['status']:
                raise ValueError(
                    'Something went wrong during authentication. Refresh and try again!'
                )

            imap = auth_res['imap']  # noqa: F841 ignore unused
        except Exception, e:
            print("failed logging into imap", str(e))
            return

        if args[0] == "send-test":
            mailbox = MailBox(imapAccount, imap, is_simulate=False)
            for i in range(len(test_emails)):
                test = test_emails[i]
                mailbox.send(subject="#%d " % i + test['subject'].decode('utf-8'), to=test['to'], cc=test['cc'], bcc=test['bcc'], \
                    body=test['body_plain'].decode('utf-8'), body_html=test['body_html'].decode('utf-8')) # TODO cc, bcc

            # index = 0
            # for t in test_emails:
            # #     # TODO send using django core
            # #     send_mail("#%d " % index + t['subject'].decode('utf-8'), t['body_plain'], TEST_ACCOUNT_EMAIL, [TEST_ACCOUNT_EMAIL])
            #     send_email("#%d " % index + t['subject'].decode('utf-8'), t['from_addr'], TEST_ACCOUNT_EMAIL, t['body_plain'].decode('utf-8'), t['body_html'].decode('utf-8'))
            #     index = index + 1

        elif args[0] == "run-test":
            test_cases = [
                [  # test cases for #0 email
                    {
                        'code': 'print (my_message.from_)',
                        'expected': TEST_ACCOUNT_EMAIL
                    },
                    {
                        'code':
                        'print("True" if "%s" == my_message.from_ else "") ' %
                        TEST_ACCOUNT_EMAIL,
                        'expected':
                        "True"
                    },
                    {
                        'code':
                        'print("True" if "test email " in my_message.subject else "") ',
                        'expected': 'True'
                    },
                ],
                [{
                    'code':
                    'print ("True" if "🤷‍♀️" in my_message.subject else "")',
                    'expected': 'True'
                }, {
                    'code':
                    'print ("True" if my_message.contains("😎") else "")',
                    'expected': 'True'
                }, {
                    'code': 'print ("*****@*****.**" in my_message.to)',
                    'expected': 'True'
                }, {
                    'code': 'print ("*****@*****.**" in my_message.cc)',
                    'expected': 'True'
                }, {
                    'code': 'print (len(my_message.cc) == 2)',
                    'expected': 'True'
                }, {
                    'code':
                    """my_message.add_flags("test")\n\tprint (my_message.has_flag("test"))""",
                    'expected': 'True'
                }, {
                    'code':
                    """my_message.remove_flags("test")\n\tprint (my_message.has_flag("test"))""",
                    'expected': 'False'
                }]
            ]

            # Run test
            try:
                folder_names = ["INBOX"]
                for msg_index in range(len(test_cases)):
                    for folder_name in folder_names:
                        # pick up recent messages
                        message = MessageSchema.objects.filter( \
                            imap_account=imapAccount, folder__name=folder_name, base_message__subject__startswith='#%d ' % msg_index).order_by("-base_message__date")

                        if not message.exists():
                            print(
                                "Unable to load the corresponding message #%d %s"
                                %
                                (msg_index, test_emails[msg_index]['subject']))
                            continue

                        message = message[0]
                        assert isinstance(message, MessageSchema)

                        mailbox = MailBox(imapAccount, imap, is_simulate=False)
                        for test_per_message_index in range(
                                len(test_cases[msg_index])):
                            imap_res = interpret_bypass_queue(mailbox, extra_info={'code': "def on_message(my_message):\n\t" + \
                                test_cases[msg_index][test_per_message_index]['code'].decode("utf-8", "replace"), 'msg-id': message.id})
                            # print(imap_res)

                            try:
                                # print(imap_res['appended_log'][message.id])
                                result = imap_res['appended_log'][
                                    message.id]['log'].rstrip("\n\r")
                                assert result == test_cases[msg_index][
                                    test_per_message_index]['expected']
                            except AssertionError:
                                print ("CASE #%d-%d %s (expected %s)" % (msg_index, test_per_message_index, \
                                    result, test_cases[msg_index][test_per_message_index]['expected']))
                                continue

                            print("SUCCESS #%d-%d %s" %
                                  (msg_index, test_per_message_index,
                                   message.base_message.subject))
            except Exception, e:
                print("failed while doing a user code run %s %s " %
                      (e, traceback.format_exc()))
            finally:
Ejemplo n.º 4
0
    try:
        res['messages'] = {}

        for folder_name in folder_names:
            messages = MessageSchema.objects.filter(
                imap_account=imapAccount,
                folder__name=folder_name).order_by("-base_message__date")[:N]

            for message_schema in messages:
                assert isinstance(message_schema, MessageSchema)
                mailbox = MailBox(imapAccount, imap, is_simulate=True)
                imap_res = interpret_bypass_queue(mailbox,
                                                  None,
                                                  extra_info={
                                                      'code': code,
                                                      'msg-id':
                                                      message_schema.id
                                                  })
                logger.debug(imap_res)

                message = Message(message_schema, imap)

                from_field = None
                if message.from_:
                    from_field = {
                        "name": message.from_.name,
                        "email": message.from_.email,
                        "organization": message.from_.organization,
                        "geolocation": message.from_.geolocation
                    }
Ejemplo n.º 5
0
def run_simulate_on_messages(user, email, folder_names, N=3, code=''):
    """This function is called to evaluate user's code on messages

        Args:
            user (Model.UserProfile)
            email (string): user's email address
            folder_name (string): name of a folder to extract messages 
            N (int): number of recent messages
            code (string): code to be simulated
    """
    res = {'status': False, 'imap_error': False, 'imap_log': ""}
    logger = logging.getLogger('youps')  # type: logging.Logger

    # this log is going to stdout but not going to the logging file
    # why are django settings not being picked up
    logger.info("user %s has requested simulation" % email)

    imapAccount = None
    imap = None

    try:
        imapAccount = ImapAccount.objects.get(email=email)
        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused
    except Exception as e:
        logger.exception("failed while logging into imap")
        res['code'] = "Fail to access your IMAP account"
        return

    try:
        res['messages'] = {}

        for folder_name in folder_names:
            messages = MessageSchema.objects.filter(
                imap_account=imapAccount,
                folder__name=folder_name).order_by("-base_message__date")[:N]

            for message_schema in messages:
                assert isinstance(message_schema, MessageSchema)
                mailbox = MailBox(imapAccount, imap, is_simulate=True)
                imap_res = interpret_bypass_queue(mailbox,
                                                  extra_info={
                                                      'code': code,
                                                      'msg-id':
                                                      message_schema.id
                                                  })
                logger.debug(imap_res)

                message = Message(message_schema, imap)

                from_field = None
                if message.from_:
                    from_field = {
                        "name": message.from_.name,
                        "email": message.from_.email,
                        "organization": message.from_.organization,
                        "geolocation": message.from_.geolocation
                    }

                to_field = [{
                    "name": tt.name,
                    "email": tt.email,
                    "organization": tt.organization,
                    "geolocation": tt.geolocation
                } for tt in message.to]

                cc_field = [{
                    "name": tt.name,
                    "email": tt.email,
                    "organization": tt.organization,
                    "geolocation": tt.geolocation
                } for tt in message.cc]

                # TODO attach activated line
                # This is to log for users
                new_msg = {
                    "timestamp":
                    str(datetime.datetime.now().strftime("%m/%d %H:%M:%S,%f")),
                    "type":
                    "new_message",
                    "folder":
                    message.folder.name,
                    "from_":
                    from_field,
                    "subject":
                    message.subject,
                    "to":
                    to_field,
                    "cc":
                    cc_field,
                    "flags":
                    [f.encode('utf8', 'replace') for f in message.flags],
                    "date":
                    str(message.date),
                    "deadline":
                    str(message.deadline),
                    "is_read":
                    message.is_read,
                    "is_deleted":
                    message.is_deleted,
                    "is_recent":
                    message.is_recent,
                    "log":
                    imap_res['appended_log'][message_schema.id]['log'],
                    "error":
                    imap_res['appended_log'][message_schema.id]['error']
                    if 'error' in imap_res['appended_log'][message_schema.id]
                    else False
                }

                res['messages'][message_schema.id] = new_msg

        res['status'] = True
    except ImapAccount.DoesNotExist:
        logger.exception("failed while doing a user code run")
        res['code'] = "Not logged into IMAP"
    except FolderSchema.DoesNotExist:
        logger.exception("failed while doing a user code run")
        logger.debug("Folder is not found, but it should exist!")
    except Exception as e:
        logger.exception("failed while doing a user code run %s %s " %
                         (e, traceback.format_exc()))
        res['code'] = msg_code['UNKNOWN_ERROR']
    finally:
        imap.logout()

    logging.debug(res)
    return res
Ejemplo n.º 6
0
def mailbot(arrived_message, address=None, host=None):
    # no public groups to list on squadbox.
    if WEBSITE == 'squadbox' or WEBSITE == 'murmur':
        logging.debug("Ignored message to all@%s, no public groups to list" %
                      HOST)
        return

    else:
        logger.info("Email to mailbot@%s" % HOST)

        name, addr = parseaddr(arrived_message['from'].lower())
        site = None
        # restart the db connection
        django.db.close_connection()

        try:
            site = Site.objects.get_current()
            addr = addr.strip()
            imapAccount = ImapAccount.objects.get(email=addr)
            logging.debug("mailbot %s" % addr)
            auth_res = authenticate(imapAccount)
            if not auth_res['status']:
                raise ValueError(
                    'Something went wrong during authentication. Log in again at %s/editor'
                    % host)

            imap = auth_res['imap']

            mailbox = MailBox(imapAccount, imap)

            # Get the original message
            original_message_schema = MessageSchema.objects.filter(
                imap_account=imapAccount,
                message_id=arrived_message["In-Reply-To"])
            if original_message_schema.exists():
                original_message_schema = original_message_schema[0]

                imap.select_folder(original_message_schema.folder.name)
                original_message = Message(original_message_schema, imap)
            else:
                # in case YoUPS didn't register to DB yet, save the message to DB immediately
                mail_found_at = ""
                original_message_id = -1
                for folder in mailbox._list_selectable_folders():
                    imap.select_folder(folder.name)
                    original_message_id = imap.search([
                        "HEADER", "Message-ID", arrived_message["In-Reply-To"]
                    ])

                    # original_message

                    if original_message_id:
                        mail_found_at = folder
                        break

                if not mail_found_at:
                    raise ValueError(
                        "Email does not exist. The message is deleted or YoUPS can't detect the message."
                    )
                else:
                    # Save this message immediately. so it can be ran when it is registered to the database
                    try:
                        logger.critical("%s %s" %
                                        (imapAccount.email, mail_found_at))
                        folder = mail_found_at

                        if original_message_id:
                            folder._save_new_messages(original_message_id[0],
                                                      urgent=True)

                            original_message_schema = MessageSchema.objects.filter(
                                imap_account=imapAccount,
                                message_id=arrived_message["In-Reply-To"])
                            if not original_message_schema.exists():
                                raise
                            imap.select_folder(
                                original_message_schema.folder.name)
                            original_message = Message(original_message_schema,
                                                       imap)

                    except FolderSchema.DoesNotExist, MessageSchema.DoesNotExist:
                        raise ValueError(
                            "Email does not exist. The message is deleted or YoUPS can't detect the message."
                        )

            entire_message = message_from_string(str(arrived_message))
            entire_body = get_body(entire_message)

            code_body = entire_body['plain'][:(
                -1) * len(original_message.content['text'])]
            gmail_header = "---------- Forwarded message ---------"
            if gmail_header in code_body:
                code_body = code_body.split(gmail_header)[0].strip()
            logging.debug(code_body)

            shortcuts = EmailRule.objects.filter(mode=imapAccount.current_mode,
                                                 type="shortcut")
            if not imapAccount.current_mode or not shortcuts.exists():
                body = "Your YoUPS hasn't turned on or don't have email shortcuts yet! Define your shortcuts here %s://%s" % (
                    PROTOCOL, site.domain)

                mail = MailResponse(From=WEBSITE + "@" + host,
                                    To=imapAccount.email,
                                    Subject="Re: " + original_message.subject,
                                    Body=body)
                relay.deliver(mail)

            else:

                body = {"text": "", "html": ""}
                for shortcut in shortcuts:
                    res = interpret_bypass_queue(
                        mailbox,
                        None,
                        extra_info={
                            "msg-id": original_message_schema.id,
                            "code": shortcut.code,
                            "shortcut": code_body
                        })
                    logging.debug(res)

                    for key, value in res['appended_log'].iteritems():
                        if not value['error']:
                            body[
                                "text"] = 'Your mail shortcut is successfully applied! \n'
                            body[
                                "html"] = 'Your mail shortcut is successfully applied! <br>'
                        else:
                            body["text"] = 'Something went wrong! \n'
                            body["html"] = 'Something went wrong! <br>'

                        body["text"] = body["text"] + value['log']
                        body["html"] = body["html"] + value['log']

                    logger.debug(body)

                # Go to sent folder and delete the sent function from user
                if imapAccount.is_gmail:
                    imap.select_folder('[Gmail]/Sent Mail')
                else:
                    import imapclient
                    sent = imap.find_special_folder(imapclient.SENT)
                    if sent is not None:
                        imap.select_folder(sent)
                this_message = imap.search([
                    "HEADER", "In-Reply-To", original_message_schema.message_id
                ])
                imap.delete_messages(this_message)

                new_message = MIMEMultipart('alternative')
                new_message["Subject"] = "Re: " + arrived_message["subject"]
                new_message["From"] = WEBSITE + "@" + host
                new_message["In-Reply-To"] = original_message_schema.message_id

                try:
                    new_msg = {}
                    from_field = original_message._get_from_friendly()

                    to_field = original_message._get_to_friendly()

                    cc_field = original_message._get_cc_friendly()

                    new_msg["timestamp"] = str(
                        datetime.now().strftime("%m/%d %H:%M:%S,%f"))
                    new_msg["type"] = "new_message"
                    new_msg["from_"] = from_field
                    new_msg["to"] = to_field
                    new_msg["cc"] = cc_field
                    new_msg["trigger"] = "shortcut"
                    new_msg["log"] = body["text"]
                    new_msg.update(original_message._get_meta_data_friendly())
                    log_decoded = json.loads(imapAccount.execution_log) if len(
                        imapAccount.execution_log) else {}
                    log_decoded[new_msg["timestamp"]] = new_msg

                    imapAccount.execution_log = json.dumps(log_decoded)
                    imapAccount.save()
                except Exception:
                    logger.critical("error adding logs")

                # new_message.set_payload(content.encode('utf-8'))
                if "text" in body and "html" in body:
                    body["text"] = "Your command: %s%sResult: %s" % (
                        code_body, "\n\n", body["text"])
                    body["html"] = "Your command: %s%sResult: %s" % (
                        code_body, "<br><br>", body["html"])
                    part1 = MIMEText(body["text"].encode('utf-8'), 'plain')
                    part2 = MIMEText(body["html"].encode('utf-8'), 'html')
                    new_message.attach(part1)
                    new_message.attach(part2)
                else:
                    body["text"] = "Your command:%s%sResult:%s" % (
                        code_body, "\n\n", body["text"])
                    part1 = MIMEText(body["text"].encode('utf-8'), 'plain')
                    new_message.attach(part1)

                imap.append(original_message_schema.folder.name,
                            str(new_message))
                # instead of sending email, just replace the forwarded email to arrive on the inbox quietly

        except ImapAccount.DoesNotExist:
            subject = "YoUPS shortcuts Error"
            error_msg = 'Your email %s is not registered or stopped due to an error. Write down your own email rule at %s://%s' % (
                addr, PROTOCOL, site.domain)
            mail = MailResponse(From=WEBSITE + "@" + host,
                                To=arrived_message['From'],
                                Subject=subject,
                                Body=error_msg)
            relay.deliver(mail)