def send_confirmation_email(email: str, server_url: str) -> bool:
    """
    Sends email containing the link which users use to set up their accounts.

    :param email the email address which the user registered with
    :param server_url the address of the flask application
    :returns boolean true if the email was sent succesfully, false otherwise.
    """
    uri = generate_uri(email)
    message_body = f"""
Hello,

Please confirm your account by going to:

http://{server_url}/signup?t={uri}&e={email}

Yours,

The UCC Netsoc SysAdmin Team
"""
    if not config.FLASK_CONFIG['debug']:
        response = mail_helper.send_mail(
            "*****@*****.**",
            email,
            "Account Registration",
            message_body,
        )
    else:
        response = type("Response", (object, ), {
            "status_code": 200,
            "token": uri
        })
    return response
Beispiel #2
0
def send_sudo_request_email(username: str, user_email: str) -> object:
    """
    Sends an email notifying SysAdmins that a user has requested an account on feynman.

    :param username the server username of the user who made the request.
    :param user_email the email address of that user to contact them for vetting.
    """
    message_body = \
        f"""
Hi {username},

Thank you for making a request for an account with sudo privileges on feynman.netsoc.co.

We will be in touch shortly.

Best,

The UCC Netsoc SysAdmin Team.

PS: Please "Reply All" to the emails so that you get a quicker response.

"""
    return mail_helper.send_mail(
        config.NETSOC_ADMIN_EMAIL_ADDRESS,
        config.NETSOC_EMAIL_ADDRESS,
        "[Netsoc Help] Sudo request on Feynman for " + username,
        message_body,
        [user_email] + config.SYSADMIN_EMAILS,
    )
Beispiel #3
0
def send_help_email(username: str, user_email: str, subject: str, message: str) -> object:
    """
    Sends an email to the netsoc email address containing the help data,
    CC'ing all the SysAdmins and the user requesting help.
    This enables us to reply to the email directly instead of copypasting the
    from address and disconnecting history.

    :param username the user requesting help
    :param user_email the user's email address
    :param subject the subject of the user's help requests
    :param message the user's actual message
    """
    message_body = f"""
From: {username}\n
Email: {user_email}

{message}

PS: Please "Reply All" to the emails so that you get a quicker response."""
    if not config.FLASK_CONFIG['debug']:
        response = mail_helper.send_mail(
            config.NETSOC_ADMIN_EMAIL_ADDRESS,
            config.NETSOC_EMAIL_ADDRESS,
            "[Netsoc Help] " + subject,
            message_body,
            [user_email] + config.SYSADMIN_EMAILS,
        )
    else:
        response = type("Response", (object,), {"status_code": 200})
    return response
def send_details_email(email: str, user: str, password: str,
                       mysql_pass: str) -> bool:
    """
    Sends an email once a user has registered succesfully confirming
    the details they have signed up with.

    :param email the email address which this email is being sent
    :param user the username which you log into the servers with
    :param password the password which you log into the servers with
    :returns True if the email has been sent succesfully, False otherwise
    """

    message_body = f"""
Hello,

Thank you for registering with UCC Netsoc! Your server log-in details are as follows:

username: {user}
password: {password}

We also provide MySQL free of charge.
You can access it with any MySQL client at mysql.netsoc.co with the following details:

username: {user}
password: {mysql_pass}

You can change your MySQL password at https://admin.netsoc.co/tools/mysql.

If you need any help, please contact [email protected], or via the help section on https://admin.netsoc.co/help.

To log in, run:
    ssh {user}@leela.netsoc.co
and enter your password when prompted.
If you are using Windows, go to http://www.putty.org/ and download the SSH client.

Please change your password when you first log-in to something you'll remember!
You can change your server password at https://admin.netsoc.co/tools/account.

Yours,

The UCC Netsoc SysAdmin Team

P.S. We are always changing and improving our services, with new features and services being added all the time.
Follow us on social media or join our discord at https://discord.gg/qPUmuYw to keep up to date with our latest updates!
    """
    if not config.FLASK_CONFIG['debug']:
        response = mail_helper.send_mail(
            "*****@*****.**",
            email,
            "Account Registration",
            message_body,
        )
    else:
        response = type("Response", (object, ), {"status_code": 200})
    return str(response.status_code).startswith("20")
def send_forgot_email(email: str, server_url: str) -> bool:
    """
    Sends email containing the user's username and the link which users use to
    generate a new password

    :param email the email address which the user registered with
    :param server_url the address of the flask application
    :returns boolean true if the email was sent succesfully, false otherwise.
    """

    conn = pymysql.connect(**config.MYSQL_DETAILS)
    user = ""
    with conn.cursor() as c:
        sql = "SELECT uid FROM users WHERE email=%s;"
        c.execute(sql, (email, ))
        user = c.fetchone()[0]

    uri = generate_uri(email)
    message_body = f"""
Hello,

Your server log-in is as follows:

username: {user}

If you wish to reset your password then click the link below.

http://{server_url}/resetpassword?t={uri}&e={email}&u={user}

Yours,

The UCC Netsoc SysAdmin Team
"""
    if not config.FLASK_CONFIG['debug']:
        response = mail_helper.send_mail(
            "*****@*****.**",
            email,
            "Account Details",
            message_body,
        )
    else:
        response = type("Response", (object, ), {
            "status_code": 200,
            "token": uri,
            "user": user
        })
    return response
Beispiel #6
0
def process_comment_event(event):
    if event.note[
            'noteable_type'] != 'MergeRequest' or event.author_id == cfg.gl_bot_uid:
        return

    mr = wine_gl.mergerequests.get(event.note['noteable_id'])
    note = mr.notes.get(event.target_id)
    print(note)

    # Find discussion object
    discussion_id = None
    if event.target_type == 'Note':
        # Not part of a discussion, just find the root email for the MR
        discussion_id = 0
    if event.target_type == 'DiscussionNote':
        # Find the discussion, by finding which discussion contains the note
        for discussion in mr.discussions.list(all=True):
            for discussion_note in discussion.attributes['notes']:
                print(discussion_note)
                if discussion_note['id'] == note.id:
                    discussion_id = discussion.id
                    break
            if discussion_id is not None: break
    if event.target_type == 'DiffNote':
        discussion_id = note.position['start_sha']
    assert discussion_id is not None

    discussion_entry = db_helper.Discussion(mr.id, discussion_id)
    mail_thread = db_helper.lookup_mail_thread(discussion_entry)
    mr_thread = db_helper.lookup_mail_thread(db_helper.Discussion(mr.id, 0))
    child = mail_thread is not None

    comment_body = note.body
    if not child and event.target_type == 'DiffNote':
        comment_body = '> `TODO: put diff information here`\n\n' + comment_body

    sent_msg_id = mail_helper.send_mail(
        'Gitlab Merge-Request Comment',
        comment_body,
        in_reply_to=mail_thread if child else mr_thread)
    if child:
        db_helper.add_child(mail_thread, sent_msg_id)
    else:
        db_helper.link_discussion_to_mail(discussion_entry, sent_msg_id)
def send_reset_email(email: str, user: str, password: str) -> bool:
    """
    Sends an email once a user has reset their password

    :param email the email address which this email is being sent
    :param user the username which you log into the servers with
    :param password the password which you log into the servers with
    :returns True if the email has been sent succesfully, False otherwise
    """

    message_body = f"""
Hello,

Your password has been reset! Your new server log-in details are as follows:

username: {user}
password: {password}

To log in, run:
    ssh {user}@leela.netsoc.co
and enter your password when prompted.
If you are using Windows, go to http://www.putty.org/ and download the SSH client.

Please change your password when you first log-in to something you'll remember!
You can change your server password at https://admin.netsoc.co/tools/account.

Yours,

The UCC Netsoc SysAdmin Team
    """
    if not config.FLASK_CONFIG['debug']:
        response = mail_helper.send_mail(
            "*****@*****.**",
            email,
            "Password Reset",
            message_body,
        )
    else:
        response = type("Response", (object, ), {"status_code": 200})
    return str(response.status_code).startswith("20")
Beispiel #8
0
def process_mr_event(event, mr):
    print(mr.author)
    if (
            event.action_name == 'opened' or event.action_name == 'pushed to'
    ) and not mr.author['id'] == cfg.gl_bot_uid and not mr.work_in_progress:
        # Forward merge request as patchset to mailing list when it is created or updated
        print('updating ML')
        # Lookup the merge request to get info about how to send it to the ML
        primary_discussion = db_helper.Discussion(mr.id, 0)
        msg_id = db_helper.lookup_mail_thread(primary_discussion)
        version = None
        if msg_id is None:
            # This means we haven't already sent a version of this MR to the mailing list, so we send the header and setup the row
            # TODO: if the MR only has one patch, batch up the MR description w/ the commit description and use that as the header/prologue
            msg_id = mail_helper.send_mail(
                mr.title,
                mr.description + '\n\nMerge-Request Link: ' + mr.web_url)
            db_helper.link_discussion_to_mail(primary_discussion, msg_id)
            db_helper.make_version_entry(mr.id)
            version = 1
        else:
            version = db_helper.get_mr_version(mr.id) + 1
            db_helper.set_mr_version(mr.id, version)
        patch_prefix = 'PATCH v' + str(version) if version != 1 else 'PATCH'

        # If this is an opening event, and the MR has been updated since, we have problems
        top_hash = event.push_data[
            'commit_to'] if event.action_name == 'pushed to' else find_mr_initial_hash(
                mr)

        # Add a branch referencing the top commit to ensure we can access this version
        source_project = gl.projects.get(mr.source_project_id)
        source_project.branches.create({
            'branch': 'temporary_scraper_branch',
            'ref': top_hash
        })
        # Add the project as a remote
        wine_git.remote('add', 'mr_source', source_project.http_url_to_repo)
        wine_git.fetch('mr_source')

        # Format patches for submission
        wine_git.format_patch('origin..' + top_hash,
                              subject_prefix=patch_prefix)

        # Remove the remote
        wine_git.remote('remove', 'mr_source')

        # Remove the branch
        source_project.branches.delete('temporary_scraper_branch')

        #send them
        #TODO: if a patch was deleted, we won't end up sending anything, maybe send a notification about the deletions instead?
        for file_path in sorted(cfg.local_wine_git_path.iterdir()):
            if file_path.name.endswith('.patch'):
                # Create the discussion and the thread, then link them

                with file_path.open() as patch_file:
                    contents = patch_file.read()

                search = re.search(r'^From (?P<commithash>\w*)', contents)
                assert search is not None
                commit_hash = search.group('commithash')
                assert commit_hash is not None

                if db_helper.remember_commit_hash(mr, commit_hash):
                    # We have already sent this patch, skip it
                    continue

                patch_discussion = mr.discussions.create(
                    {'body': 'Discussion on commit ' + commit_hash})

                search = re.search(r'(?m)^Subject: (?P<subject>.*)$', contents)
                assert search is not None
                patch_subject = search.group('subject')
                assert patch_subject is not None
                patch_msg_id = mail_helper.send_mail(patch_subject,
                                                     contents.split('\n\n',
                                                                    1)[1],
                                                     in_reply_to=msg_id)

                db_helper.link_discussion_to_mail(
                    db_helper.Discussion(mr.id, patch_discussion.id),
                    patch_msg_id)
        # Clean Up
        wine_git.reset('origin/master', hard=True)
        wine_git.clean(force=True)
        return

    if mr.author['id'] == cfg.gl_bot_uid:
        # Turn MR events into emails sent back to the submitter
        print('TODO')
def create_or_update_merge_request(mr, title, author, description, patches,
                                   prologue_msg_id):
    # create the local git branch
    branch_name = None
    if mr is None:
        branch_name = 'ml-patchset-{0}'.format(time.time())
        LOCAL_REPO_GIT.checkout('HEAD', b=branch_name)
    else:
        branch_name = mr.source_branch
        LOCAL_REPO_GIT.checkout(branch_name)
        LOCAL_REPO_GIT.reset('master', hard=True)

    # apply the patches
    try:
        for patch in patches:
            LOCAL_REPO_GIT.am(str(patch.path))
    except:
        print('Failed to apply patches, discarding patchset')
        # TODO: make more robust, and send email back if it didn't apply
        if mr is not None:
            LOCAL_REPO_GIT.reset('origin/' + branch_name, hard=True)
        LOCAL_REPO_GIT.checkout('master')
        if mr is None:
            LOCAL_REPO_GIT.branch(D=branch_name)
        return
    finally:
        for patch in patches:
            patch.path.unlink()

    LOCAL_REPO_GIT.checkout('master')

    # push work to origin
    LOCAL_REPO_GIT.push('origin', branch_name, force=True)

    # create merge request
    if mr is None:
        mr = FORK_REPO.mergerequests.create({
            'source_branch':
            branch_name,
            'target_project_id':
            cfg.MAIN_REPO_ID,
            'target_branch':
            'master',
            'title':
            title
            if title is not None else 'Multi-Patch Patchset from Mailing List',
            'description':
            description
        })
        if not cfg.BIDIRECTIONAL_COMM:
            admin_mr = ADMIN_PROJECT_VIEW.mergerequests.get(mr.id)
            admin_mr.discussion_locked = True
            admin_mr.save()

        # send email to mailing list as a place to put MR comments
        if prologue_msg_id is None:
            if len(patches) == 1:
                db_helper.link_discussion_to_mail(
                    db_helper.Discussion(mr.id, 0), patches[0].msgid)
                return
            # send meta email if prologue wasn't sent
            mail_helper.send_mail(
                'Gitlab discussion thread for recent patchset by' + author,
                'Merge-Request Link: ' + mr.web_url)
        else:
            db_helper.link_discussion_to_mail(db_helper.Discussion(mr.id, 0),
                                              prologue_msg_id)
    elif prologue_msg_id and len(patches) != 1:
        extra_discussion = mr.discussions.create(
            {'body': 'Discussion on updated commits'})
        db_helper.link_discussion_to_mail(
            db_helper.Discussion(mr.id, extra_discussion.id), prologue_msg_id)

    # create a discussion for each patch
    for patch in patches:
        patch_discussion = mr.discussions.create(
            {'body': 'Discussion for {0}'.format(patch.subject)})
        # link mail thread to discussion
        db_helper.link_discussion_to_mail(
            db_helper.Discussion(mr.id, patch_discussion.id), patch.msgid)
Beispiel #10
0
receivers = '[email protected],[email protected]'
cc = '[email protected],[email protected]'  # 抄送
bcc = '[email protected],[email protected]'  # 密送
mail_subject = '我是标题'
mail_content = '我是内容<p><img src="cid:12.jpg"></p>'  # 注意插图的引用方式!且插图名称不能是中文!
attachment_names = 'itinerary.pdf'
illustrate_names = '12.jpg'
result = mail_helper.draft(receivers, mail_subject, mail_content, cc, bcc,
                           attachment_names, illustrate_names)
print(result)

# 发送一封普通邮件
receivers = '[email protected],[email protected]'
mail_subject = '我是标题'
mail_content = '我是内容'
result = mail_helper.send_mail(receivers, mail_subject, mail_content)
print(result)

# 发送一封普通邮件,同时抄送、密送
receivers = '[email protected],[email protected]'
cc = '[email protected],[email protected]'  # 抄送
bcc = '[email protected],[email protected]'  # 密送
mail_subject = '我是标题'
mail_content = '我是内容'
result = mail_helper.send_mail(receivers, mail_subject, mail_content, cc, bcc)
print(result)

# 发送一封普通邮件,同时抄送、密送,并有附件和插图
receivers = '[email protected],[email protected]'
cc = '[email protected],[email protected]'  # 抄送
bcc = '[email protected],[email protected]'  # 密送