12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160 |
- # -*- coding: utf-8 -*-
- """
- (c) 2014-2018 - Copyright Red Hat Inc
- Authors:
- Pierre-Yves Chibon <pingou@pingoured.fr>
- pagure notifications.
- """
- from __future__ import print_function, unicode_literals, absolute_import
- # pylint: disable=too-many-branches
- # pylint: disable=too-many-arguments
- import datetime
- import hashlib
- import json
- import logging
- import os
- import re
- import smtplib
- import time
- import six
- import ssl
- from email.header import Header
- from email.mime.text import MIMEText
- from six.moves.urllib_parse import urljoin
- import blinker
- import flask
- import pagure.lib.query
- import pagure.lib.tasks_services
- from pagure.config import config as pagure_config
- _log = logging.getLogger(__name__)
- REPLY_MSG = "To reply, visit the link below"
- if pagure_config["EVENTSOURCE_SOURCE"]:
- REPLY_MSG += " or just reply to this email"
- def fedmsg_publish(*args, **kwargs): # pragma: no cover
- """ Try to publish a message on the fedmsg bus. """
- if not pagure_config.get("FEDMSG_NOTIFICATIONS", True):
- return
- _log.warning(
- "fedmsg support is being deprecated in favor of fedora-messaging "
- "you likely want to stop relying on it as it will disapear in the "
- "future, most likely in the 6.0 release"
- )
- # We catch Exception if we want :-p
- # pylint: disable=broad-except
- # Ignore message about fedmsg import
- # pylint: disable=import-error
- kwargs["modname"] = "pagure"
- kwargs["cert_prefix"] = "pagure"
- kwargs["active"] = True
- try:
- import fedmsg
- fedmsg.publish(*args, **kwargs)
- except Exception:
- _log.exception("Error sending fedmsg")
- def fedora_messaging_publish(topic, message): # pragma: no cover
- """ Try to publish a message on AMQP using fedora-messaging. """
- if not pagure_config.get("FEDORA_MESSAGING_NOTIFICATIONS", False):
- return
- try:
- import fedora_messaging.api
- import fedora_messaging.exceptions
- msg = fedora_messaging.api.Message(
- topic="pagure.{}".format(topic), body=message
- )
- fedora_messaging.api.publish(msg)
- except fedora_messaging.exceptions.PublishReturned as e:
- _log.warning(
- "Fedora Messaging broker rejected message %s: %s", msg.id, e
- )
- except fedora_messaging.exceptions.ConnectionException as e:
- _log.warning("Error sending message %s: %s", msg.id, e)
- except Exception:
- _log.exception("Error sending fedora-messaging message")
- stomp_conn = None
- def stomp_publish(topic, message):
- """ Try to publish a message on a Stomp-compliant message bus. """
- if not pagure_config.get("STOMP_NOTIFICATIONS", False):
- return
- # We catch Exception if we want :-p
- # pylint: disable=broad-except
- # Ignore message about stomp import
- # pylint: disable=import-error
- try:
- import stomp
- global stomp_conn
- if not stomp_conn or not stomp_conn.is_connected():
- stomp_conn = stomp.Connection12(pagure_config["STOMP_BROKERS"])
- if pagure_config.get("STOMP_SSL"):
- stomp_conn.set_ssl(
- pagure_config["STOMP_BROKERS"],
- key_file=pagure_config.get("STOMP_KEY_FILE"),
- cert_file=pagure_config.get("STOMP_CERT_FILE"),
- password=pagure_config.get("STOMP_CREDS_PASSWORD"),
- )
- from stomp import PrintingListener
- stomp_conn.set_listener("", PrintingListener())
- stomp_conn.start()
- stomp_conn.connect(wait=True)
- hierarchy = pagure_config["STOMP_HIERARCHY"]
- stomp_conn.send(
- destination=hierarchy + topic, body=json.dumps(message)
- )
- except Exception:
- _log.exception("Error sending stomp message")
- def blinker_publish(topic, message):
- _log.info("Sending blinker signal to: pagure - topic: %s", topic)
- ready = blinker.signal("pagure")
- ready.send("pagure", topic=topic, message=message)
- def mqtt_publish(topic, message):
- """ Try to publish a message on a MQTT message bus. """
- if not pagure_config.get("MQTT_NOTIFICATIONS", False):
- return
- mqtt_host = pagure_config.get("MQTT_HOST")
- mqtt_port = pagure_config.get("MQTT_PORT")
- mqtt_username = pagure_config.get("MQTT_USERNAME")
- mqtt_pass = pagure_config.get("MQTT_PASSWORD")
- mqtt_ca_certs = pagure_config.get("MQTT_CA_CERTS")
- mqtt_certfile = pagure_config.get("MQTT_CERTFILE")
- mqtt_keyfile = pagure_config.get("MQTT_KEYFILE")
- mqtt_cert_reqs = pagure_config.get("MQTT_CERT_REQS", ssl.CERT_REQUIRED)
- mqtt_tls_version = pagure_config.get(
- "MQTT_TLS_VERSION", ssl.PROTOCOL_TLSv1_2
- )
- mqtt_ciphers = pagure_config.get("MQTT_CIPHERS")
- mqtt_topic_prefix = pagure_config.get("MQTT_TOPIC_PREFIX") or None
- if mqtt_topic_prefix:
- topic = "/".join([mqtt_topic_prefix.rstrip("/"), topic])
- # We catch Exception if we want :-p
- # pylint: disable=broad-except
- # Ignore message about mqtt import
- # pylint: disable=import-error
- try:
- import paho.mqtt.client as mqtt
- client = mqtt.Client(os.uname()[1])
- client.tls_set(
- ca_certs=mqtt_ca_certs,
- certfile=mqtt_certfile,
- keyfile=mqtt_keyfile,
- cert_reqs=mqtt_cert_reqs,
- tls_version=mqtt_tls_version,
- ciphers=mqtt_ciphers,
- )
- if mqtt_username and mqtt_pass:
- client.username_pw_set(mqtt_username, mqtt_pass)
- client.connect(mqtt_host, mqtt_port)
- client.publish(topic, json.dumps(message))
- client.disconnect()
- except Exception:
- _log.exception("Error sending mqtt message")
- def log(project, topic, msg, webhook=True):
- """ This is the place where we send notifications to user about actions
- occuring in pagure.
- """
- # Send fedmsg notification (if fedmsg is there and set-up)
- if not project or (
- project.settings.get("fedmsg_notifications", True)
- and not project.private
- ):
- fedmsg_publish(topic, msg)
- fedora_messaging_publish(topic, msg)
- # Send stomp notification (if stomp is there and set-up)
- if not project or (
- project.settings.get("stomp_notifications", True)
- and not project.private
- ):
- stomp_publish(topic, msg)
- # Send mqtt notification (if mqtt is there and set-up)
- if not project or (
- project.settings.get("mqtt_notifications", True)
- and not project.private
- ):
- mqtt_publish(topic, msg)
- # Send blink notification to any 3rd party plugins, if there are any
- blinker_publish(topic, msg)
- if webhook and project and not project.private:
- pagure.lib.tasks_services.webhook_notification.delay(
- topic=topic,
- msg=msg,
- namespace=project.namespace,
- name=project.name,
- user=project.user.username if project.is_fork else None,
- )
- def _add_mentioned_users(emails, comment):
- """ Check the comment to see if an user is mentioned in it and if
- so add this user to the list of people to notify.
- """
- mentio_re = r"@(\w+)"
- for username in re.findall(mentio_re, comment):
- user = pagure.lib.query.search_user(flask.g.session, username=username)
- if user:
- emails.add(user.default_email)
- return emails
- def _clean_emails(emails, user):
- """ Remove the email of the user doing the action if it is in the list.
- This avoids receiving emails about action you do.
- """
- # Remove the user doing the action from the list of person to email
- # unless they actively asked for it
- if (
- user
- and user.emails
- and not user.settings.get("cc_me_to_my_actions", False)
- ):
- for email in user.emails:
- if email.email in emails:
- emails.remove(email.email)
- return emails
- def _get_emails_for_obj(obj):
- """ Return the list of emails to send notification to when notifying
- about the specified issue or pull-request.
- """
- emails = set()
- # Add project creator/owner
- if obj.project.user.default_email:
- emails.add(obj.project.user.default_email)
- # Add committers is object is private, otherwise all contributors
- if obj.isa in ["issue", "pull-request"] and obj.private:
- for user in obj.project.committers:
- if user.default_email:
- emails.add(user.default_email)
- else:
- for user in obj.project.users:
- if user.default_email:
- emails.add(user.default_email)
- # Add people in groups with any access to the project:
- for group in obj.project.groups:
- if group.creator.default_email:
- emails.add(group.creator.default_email)
- for user in group.users:
- if user.default_email:
- emails.add(user.default_email)
- # Add people that commented on the issue/PR
- if obj.isa in ["issue", "pull-request"]:
- for comment in obj.comments:
- if comment.user.default_email:
- emails.add(comment.user.default_email)
- # Add the person that opened the issue/PR
- if obj.user.default_email:
- emails.add(obj.user.default_email)
- # Add the person assigned to the issue/PR
- if obj.isa in ["issue", "pull-request"]:
- if obj.assignee and obj.assignee.default_email:
- emails.add(obj.assignee.default_email)
- # Add public notifications to lists/users set project-wide
- if obj.isa == "issue" and not obj.private:
- for notifs in obj.project.notifications.get("issues", []):
- emails.add(notifs)
- elif obj.isa == "pull-request":
- for notifs in obj.project.notifications.get("requests", []):
- emails.add(notifs)
- # Add the person watching this project, if it's a public issue or a
- # pull-request
- if (obj.isa == "issue" and not obj.private) or obj.isa == "pull-request":
- for watcher in obj.project.watchers:
- if watcher.watch_issues:
- emails.add(watcher.user.default_email)
- else:
- # If there is a watch entry and it is false, it means the user
- # explicitly requested to not watch the issue
- if watcher.user.default_email in emails:
- emails.remove(watcher.user.default_email)
- # Add/Remove people who explicitly asked to be added/removed
- if obj.isa in ["issue", "pull-request"]:
- for watcher in obj.watchers:
- if not watcher.watch and watcher.user.default_email in emails:
- emails.remove(watcher.user.default_email)
- elif watcher.watch:
- emails.add(watcher.user.default_email)
- # Drop the email used by pagure when sending
- emails = _clean_emails(
- emails,
- pagure_config.get(
- pagure_config.get("FROM_EMAIL", "pagure@fedoraproject.org")
- ),
- )
- return emails
- def _get_emails_for_commit_notification(project):
- emails = set()
- for watcher in project.watchers:
- if watcher.watch_commits:
- emails.add(watcher.user.default_email)
- # Drop the email used by pagure when sending
- emails = _clean_emails(
- emails,
- pagure_config.get(
- pagure_config.get("FROM_EMAIL", "pagure@fedoraproject.org")
- ),
- )
- return emails
- def _build_url(*args):
- """ Build a URL from a given list of arguments. """
- items = []
- for idx, arg in enumerate(args):
- arg = "%s" % arg
- if arg.startswith("/"):
- arg = arg[1:]
- if arg.endswith("/") and not idx + 1 == len(args):
- arg = arg[:-1]
- items.append(arg)
- return "/".join(items)
- def _fullname_to_url(fullname):
- """ For forked projects, fullname is 'forks/user/...' but URL is
- 'fork/user/...'. This is why we can't have nice things.
- """
- if fullname.startswith("forks/"):
- fullname = fullname.replace("forks", "fork", 1)
- return fullname
- def send_email(
- text,
- subject,
- to_mail,
- mail_id=None,
- in_reply_to=None,
- project_name=None,
- user_from=None,
- reporter=None,
- assignee=None,
- ): # pragma: no cover
- """ Send an email with the specified information.
- :arg text: the content of the email to send
- :type text: unicode
- :arg subject: the subject of the email
- :arg to_mail: a string representing a list of recipient separated by a
- comma
- :kwarg mail_id: if defined, the header `mail-id` is set with this value
- :kwarg in_reply_to: if defined, the header `In-Reply-To` is set with
- this value
- :kwarg project_name: if defined, the name of the project
- """
- if not to_mail:
- return
- from_email = pagure_config.get("FROM_EMAIL", "pagure@fedoraproject.org")
- if isinstance(from_email, bytes):
- from_email = from_email.decode("utf-8")
- if user_from:
- header = Header(user_from, "utf-8")
- from_email = "%s <%s>" % (header.encode(), from_email)
- if project_name is not None:
- subject_tag = project_name
- else:
- subject_tag = "Pagure"
- if mail_id:
- mail_id = mail_id + "@%s" % pagure_config["DOMAIN_EMAIL_NOTIFICATIONS"]
- if in_reply_to:
- in_reply_to = (
- in_reply_to + "@%s" % pagure_config["DOMAIN_EMAIL_NOTIFICATIONS"]
- )
- smtp = None
- for mailto in to_mail.split(","):
- try:
- pagure.lib.query.allowed_emailaddress(mailto)
- except pagure.exceptions.PagureException:
- continue
- msg = MIMEText(text.encode("utf-8"), "plain", "utf-8")
- msg["Subject"] = Header("[%s] %s" % (subject_tag, subject), "utf-8")
- msg["From"] = from_email
- if mail_id:
- msg["mail-id"] = mail_id
- msg["Message-Id"] = "<%s>" % mail_id
- if in_reply_to:
- msg["In-Reply-To"] = "<%s>" % in_reply_to
- msg["X-Auto-Response-Suppress"] = "All"
- msg["X-pagure"] = pagure_config["APP_URL"]
- if project_name is not None:
- msg["X-pagure-project"] = project_name
- msg["List-ID"] = project_name
- msg["List-Archive"] = _build_url(
- pagure_config["APP_URL"], _fullname_to_url(project_name)
- )
- if reporter is not None:
- msg["X-pagure-reporter"] = reporter
- if assignee is not None:
- msg["X-pagure-assignee"] = assignee
- # Send the message via our own SMTP server, but don't include the
- # envelope header.
- msg["To"] = mailto
- salt = pagure_config.get("SALT_EMAIL")
- if salt and not isinstance(salt, bytes):
- salt = salt.encode("utf-8")
- if mail_id and pagure_config["EVENTSOURCE_SOURCE"]:
- key = (
- b"<"
- + mail_id.encode("utf-8")
- + b">"
- + salt
- + mailto.encode("utf-8")
- )
- if isinstance(key, six.text_type):
- key = key.encode("utf-8")
- mhash = hashlib.sha512(key)
- msg["Reply-To"] = "reply+%s@%s" % (
- mhash.hexdigest(),
- pagure_config["DOMAIN_EMAIL_NOTIFICATIONS"],
- )
- msg["Mail-Followup-To"] = msg["Reply-To"]
- if not pagure_config.get("EMAIL_SEND", True):
- _log.debug("******EMAIL******")
- _log.debug("From: %s", from_email)
- _log.debug("To: %s", to_mail)
- _log.debug("Subject: %s", subject)
- _log.debug("in_reply_to: %s", in_reply_to)
- _log.debug("mail_id: %s", mail_id)
- _log.debug("Contents:")
- _log.debug("%s" % text)
- _log.debug("*****************")
- _log.debug(msg.as_string())
- _log.debug("*****/EMAIL******")
- continue
- try:
- if smtp is None:
- if pagure_config["SMTP_SSL"]:
- smtp = smtplib.SMTP_SSL(
- pagure_config["SMTP_SERVER"],
- pagure_config["SMTP_PORT"],
- )
- else:
- smtp = smtplib.SMTP(
- pagure_config["SMTP_SERVER"],
- pagure_config["SMTP_PORT"],
- )
- if (
- pagure_config["SMTP_USERNAME"]
- and pagure_config["SMTP_PASSWORD"]
- ):
- smtp.login(
- pagure_config["SMTP_USERNAME"],
- pagure_config["SMTP_PASSWORD"],
- )
- smtp.sendmail(from_email, [mailto], msg.as_string())
- except smtplib.SMTPException as err:
- _log.exception(err)
- if smtp:
- smtp.quit()
- return msg
- def notify_new_comment(comment, user=None):
- """ Notify the people following an issue that a new comment was added
- to the issue.
- """
- text = """
- %s added a new comment to an issue you are following:
- ``
- %s
- ``
- %s
- %s
- """ % (
- comment.user.user,
- comment.comment,
- REPLY_MSG,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(comment.issue.project.fullname),
- "issue",
- comment.issue.id,
- ),
- )
- mail_to = _get_emails_for_obj(comment.issue)
- if comment.user and comment.user.default_email:
- mail_to.add(comment.user.default_email)
- mail_to = _add_mentioned_users(mail_to, comment.comment)
- mail_to = _clean_emails(mail_to, user)
- assignee = comment.issue.assignee.user if comment.issue.assignee else None
- send_email(
- text,
- "Issue #%s: %s" % (comment.issue.id, comment.issue.title),
- ",".join(mail_to),
- mail_id=comment.mail_id,
- in_reply_to=comment.issue.mail_id,
- project_name=comment.issue.project.fullname,
- user_from=comment.user.fullname or comment.user.user,
- reporter=comment.issue.user.user,
- assignee=assignee,
- )
- def notify_new_issue(issue, user=None):
- """ Notify the people following a project that a new issue was added
- to it.
- """
- text = """
- %s reported a new issue against the project: `%s` that you are following:
- ``
- %s
- ``
- %s
- %s
- """ % (
- issue.user.user,
- issue.project.name,
- issue.content,
- REPLY_MSG,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(issue.project.fullname),
- "issue",
- issue.id,
- ),
- )
- mail_to = _get_emails_for_obj(issue)
- mail_to = _add_mentioned_users(mail_to, issue.content)
- mail_to = _clean_emails(mail_to, user)
- assignee = issue.assignee.user if issue.assignee else None
- send_email(
- text,
- "Issue #%s: %s" % (issue.id, issue.title),
- ",".join(mail_to),
- mail_id=issue.mail_id,
- project_name=issue.project.fullname,
- user_from=issue.user.fullname or issue.user.user,
- reporter=issue.user.user,
- assignee=assignee,
- )
- def notify_assigned_issue(issue, new_assignee, user):
- """ Notify the people following an issue that the assignee changed.
- """
- action = "reset"
- if new_assignee:
- action = "assigned to `%s`" % new_assignee.user
- text = """
- The issue: `%s` of project: `%s` has been %s by %s.
- %s
- """ % (
- issue.title,
- issue.project.name,
- action,
- user.username,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(issue.project.fullname),
- "issue",
- issue.id,
- ),
- )
- mail_to = _get_emails_for_obj(issue)
- if new_assignee and new_assignee.default_email:
- mail_to.add(new_assignee.default_email)
- mail_to = _clean_emails(mail_to, user)
- uid = time.mktime(datetime.datetime.now().timetuple())
- assignee = issue.assignee.user if issue.assignee else None
- send_email(
- text,
- "Issue #%s: %s" % (issue.id, issue.title),
- ",".join(mail_to),
- mail_id="%s/assigned/%s" % (issue.mail_id, uid),
- in_reply_to=issue.mail_id,
- project_name=issue.project.fullname,
- user_from=user.fullname or user.user,
- reporter=issue.user.user,
- assignee=assignee,
- )
- def notify_status_change_issue(issue, user):
- """ Notify the people following a project that an issue changed status.
- """
- status = issue.status
- if status.lower() != "open" and issue.close_status:
- status = "%s as %s" % (status, issue.close_status)
- text = """
- The status of the issue: `%s` of project: `%s` has been updated to: %s by %s.
- %s
- """ % (
- issue.title,
- issue.project.fullname,
- status,
- user.username,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(issue.project.fullname),
- "issue",
- issue.id,
- ),
- )
- mail_to = _get_emails_for_obj(issue)
- uid = time.mktime(datetime.datetime.now().timetuple())
- assignee = issue.assignee.user if issue.assignee else None
- send_email(
- text,
- "Issue #%s: %s" % (issue.id, issue.title),
- ",".join(mail_to),
- mail_id="%s/close/%s" % (issue.mail_id, uid),
- in_reply_to=issue.mail_id,
- project_name=issue.project.fullname,
- user_from=user.fullname or user.user,
- reporter=issue.user.user,
- assignee=assignee,
- )
- def notify_meta_change_issue(issue, user, msg):
- """ Notify that a custom field changed
- """
- text = """
- `%s` updated issue.
- %s
- %s
- """ % (
- user.username,
- msg,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(issue.project.fullname),
- "issue",
- issue.id,
- ),
- )
- mail_to = _get_emails_for_obj(issue)
- uid = time.mktime(datetime.datetime.now().timetuple())
- assignee = issue.assignee.user if issue.assignee else None
- send_email(
- text,
- "Issue #%s: %s" % (issue.id, issue.title),
- ",".join(mail_to),
- mail_id="%s/close/%s" % (issue.mail_id, uid),
- in_reply_to=issue.mail_id,
- project_name=issue.project.fullname,
- user_from=user.fullname or user.user,
- reporter=issue.user.user,
- assignee=assignee,
- )
- def notify_assigned_request(request, new_assignee, user):
- """ Notify the people following a pull-request that the assignee changed.
- """
- action = "reset"
- if new_assignee:
- action = "assigned to `%s`" % new_assignee.user
- text = """
- The pull-request: `%s` of project: `%s` has been %s by %s.
- %s
- """ % (
- request.title,
- request.project.name,
- action,
- user.username,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(request.project.fullname),
- "pull-request",
- request.id,
- ),
- )
- mail_to = _get_emails_for_obj(request)
- if new_assignee and new_assignee.default_email:
- mail_to.add(new_assignee.default_email)
- mail_to = _clean_emails(mail_to, user)
- uid = time.mktime(datetime.datetime.now().timetuple())
- assignee = request.assignee.user if request.assignee else None
- send_email(
- text,
- "PR #%s: %s" % (request.id, request.title),
- ",".join(mail_to),
- mail_id="%s/assigned/%s" % (request.mail_id, uid),
- in_reply_to=request.mail_id,
- project_name=request.project.fullname,
- user_from=user.fullname or user.user,
- reporter=request.user.user,
- assignee=assignee,
- )
- def notify_new_pull_request(request):
- """ Notify the people following a project that a new pull-request was
- added to it.
- """
- text = """
- %s opened a new pull-request against the project: `%s` that you are following:
- ``
- %s
- ``
- %s
- %s
- """ % (
- request.user.user,
- request.project.name,
- request.title,
- REPLY_MSG,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(request.project.fullname),
- "pull-request",
- request.id,
- ),
- )
- mail_to = _get_emails_for_obj(request)
- assignee = request.assignee.user if request.assignee else None
- send_email(
- text,
- "PR #%s: %s" % (request.id, request.title),
- ",".join(mail_to),
- mail_id=request.mail_id,
- project_name=request.project.fullname,
- user_from=request.user.fullname or request.user.user,
- reporter=request.user.user,
- assignee=assignee,
- )
- def notify_merge_pull_request(request, user):
- """ Notify the people following a project that a pull-request was merged
- in it.
- """
- text = """
- %s merged a pull-request against the project: `%s` that you are following.
- Merged pull-request:
- ``
- %s
- ``
- %s
- """ % (
- user.username,
- request.project.name,
- request.title,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(request.project.fullname),
- "pull-request",
- request.id,
- ),
- )
- mail_to = _get_emails_for_obj(request)
- uid = time.mktime(datetime.datetime.now().timetuple())
- assignee = request.assignee.user if request.assignee else None
- send_email(
- text,
- "PR #%s: %s" % (request.id, request.title),
- ",".join(mail_to),
- mail_id="%s/close/%s" % (request.mail_id, uid),
- in_reply_to=request.mail_id,
- project_name=request.project.fullname,
- user_from=user.fullname or user.user,
- reporter=request.user.user,
- assignee=assignee,
- )
- def notify_reopen_pull_request(request, user):
- """ Notify the people following a project that a closed pull-request
- has been reopened.
- """
- text = """
- %s reopened a pull-request against the project: `%s` that you are following.
- Reopened pull-request:
- ``
- %s
- ``
- %s
- """ % (
- user.username,
- request.project.name,
- request.title,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(request.project.fullname),
- "pull-request",
- request.id,
- ),
- )
- mail_to = _get_emails_for_obj(request)
- uid = time.mktime(datetime.datetime.now().timetuple())
- assignee = request.assignee.user if request.assignee else None
- send_email(
- text,
- "PR #%s: %s" % (request.id, request.title),
- ",".join(mail_to),
- mail_id="%s/close/%s" % (request.mail_id, uid),
- in_reply_to=request.mail_id,
- project_name=request.project.fullname,
- user_from=user.fullname or user.user,
- reporter=request.user.user,
- assignee=assignee,
- )
- def notify_closed_pull_request(request, user):
- """ Notify the people following a project that a pull-request was
- closed in it.
- """
- text = """
- %s closed without merging a pull-request against the project: `%s` that you
- are following.
- Closed pull-request:
- ``
- %s
- ``
- %s
- """ % (
- user.username,
- request.project.name,
- request.title,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(request.project.fullname),
- "pull-request",
- request.id,
- ),
- )
- mail_to = _get_emails_for_obj(request)
- uid = time.mktime(datetime.datetime.now().timetuple())
- assignee = request.assignee.user if request.assignee else None
- send_email(
- text,
- "PR #%s: %s" % (request.id, request.title),
- ",".join(mail_to),
- mail_id="%s/close/%s" % (request.mail_id, uid),
- in_reply_to=request.mail_id,
- project_name=request.project.fullname,
- user_from=user.fullname or user.user,
- reporter=request.user.user,
- assignee=assignee,
- )
- def notify_pull_request_comment(comment, user):
- """ Notify the people following a pull-request that a new comment was
- added to it.
- """
- text = """
- %s commented on the pull-request: `%s` that you are following:
- ``
- %s
- ``
- %s
- %s
- """ % (
- comment.user.user,
- comment.pull_request.title,
- comment.comment,
- REPLY_MSG,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(comment.pull_request.project.fullname),
- "pull-request",
- comment.pull_request.id,
- ),
- )
- mail_to = _get_emails_for_obj(comment.pull_request)
- mail_to = _add_mentioned_users(mail_to, comment.comment)
- mail_to = _clean_emails(mail_to, user)
- assignee = (
- comment.pull_request.assignee.user
- if comment.pull_request.assignee
- else None
- )
- send_email(
- text,
- "PR #%s: %s" % (comment.pull_request.id, comment.pull_request.title),
- ",".join(mail_to),
- mail_id=comment.mail_id,
- in_reply_to=comment.pull_request.mail_id,
- project_name=comment.pull_request.project.fullname,
- user_from=comment.user.fullname or comment.user.user,
- reporter=comment.pull_request.user.user,
- assignee=assignee,
- )
- def notify_pull_request_flag(flag, user):
- """ Notify the people following a pull-request that a new flag was
- added to it.
- """
- text = """
- %s flagged the pull-request `%s` as %s: %s
- %s
- """ % (
- flag.username,
- flag.pull_request.title,
- flag.status,
- flag.comment,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(flag.pull_request.project.fullname),
- "pull-request",
- flag.pull_request.id,
- ),
- )
- mail_to = _get_emails_for_obj(flag.pull_request)
- assignee = (
- flag.pull_request.assignee.user if flag.pull_request.assignee else None
- )
- send_email(
- text,
- "PR #%s - %s: %s" % (flag.pull_request.id, flag.username, flag.status),
- ",".join(mail_to),
- mail_id=flag.mail_id,
- in_reply_to=flag.pull_request.mail_id,
- project_name=flag.pull_request.project.fullname,
- user_from=flag.username,
- reporter=flag.pull_request.user.user,
- assignee=assignee,
- )
- def notify_new_email(email, user):
- """ Ask the user to confirm to the email belong to them.
- """
- root_url = pagure_config.get("APP_URL", flask.request.url_root)
- url = urljoin(
- root_url or flask.request.url_root,
- flask.url_for("ui_ns.confirm_email", token=email.token),
- )
- text = """Dear %(username)s,
- You have registered a new email on pagure at %(root_url)s.
- To finish your validate this registration, please click on the following
- link or copy/paste it in your browser, this link will remain valid only 2 days:
- %(url)s
- The email will not be activated until you finish this step.
- Sincerely,
- Your pagure admin.
- """ % (
- {"username": user.username, "url": url, "root_url": root_url}
- )
- send_email(
- text,
- "Confirm new email",
- email.email,
- user_from=user.fullname or user.user,
- )
- def notify_new_commits(abspath, project, branch, commits):
- """ Notify the people following a project's commits that new commits have
- been added.
- """
- # string note: abspath, project and branch can only contain ASCII
- # by policy (pagure and/or gitolite)
- commits_info = []
- for commit in commits:
- commits_info.append(
- {
- "commit": commit,
- "author": pagure.lib.git.get_author(commit, abspath),
- "subject": pagure.lib.git.get_commit_subject(commit, abspath),
- }
- )
- # make sure this is unicode
- commits_string = "\n".join(
- "{0} {1} {2}".format(
- commit_info["commit"],
- commit_info["author"],
- commit_info["subject"],
- )
- for commit_info in commits_info
- )
- commit_url = _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(project.fullname),
- "commits",
- branch,
- )
- email_body = """
- The following commits were pushed to the repo %s on branch
- %s, which you are following:
- %s
- To view more about the commits, visit:
- %s
- """ % (
- project.fullname,
- branch,
- commits_string,
- commit_url,
- )
- mail_to = _get_emails_for_commit_notification(project)
- send_email(
- email_body,
- 'New Commits To "{0}" ({1})'.format(project.fullname, branch),
- ",".join(mail_to),
- project_name=project.fullname,
- )
- def notify_commit_flag(flag, user):
- """ Notify the people following a project that a new flag was added
- to one of its commit.
- """
- text = """
- %s flagged the commit `%s` as %s: %s
- %s
- """ % (
- flag.username,
- flag.commit_hash,
- flag.status,
- flag.comment,
- _build_url(
- pagure_config["APP_URL"],
- _fullname_to_url(flag.project.fullname),
- "c",
- flag.commit_hash,
- ),
- )
- mail_to = _get_emails_for_obj(flag)
- send_email(
- text,
- "Commit #%s - %s: %s" % (flag.commit_hash, flag.username, flag.status),
- ",".join(mail_to),
- mail_id=flag.mail_id,
- in_reply_to=flag.project.mail_id,
- project_name=flag.project.fullname,
- user_from=flag.username,
- )
|