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
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, )
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
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")
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)
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]' # 密送