def _rss_feed(self, repos, public=True): if public: link = h.canonical_url('public_journal_atom') desc = '%s %s %s' % (c.site_name, _('Public Journal'), 'rss feed') else: link = h.canonical_url('journal_atom') desc = '%s %s %s' % (c.site_name, _('Journal'), 'rss feed') return self._feed(repos, feeds.RssFeed, link, desc)
def __add_reviewers(self, pr, reviewers, mention_recipients=None): #members for member in set(reviewers): _usr = self._get_user(member) reviewer = PullRequestReviewers(_usr, pr) Session().add(reviewer) revision_data = [(x.raw_id, x.message) for x in map(pr.org_repo.get_changeset, pr.revisions)] #notification to reviewers pr_url = pr.url(canonical=True) threading = [h.canonical_url('pullrequest_show', repo_name=pr.other_repo.repo_name, pull_request_id=pr.pull_request_id)] subject = safe_unicode( h.link_to( _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \ {'user': pr.author.username, 'pr_title': pr.title, 'pr_id': pr.pull_request_id}, pr_url) ) body = pr.description _org_ref_type, org_ref_name, _org_rev = pr.org_ref.split(':') email_kwargs = { 'pr_title': pr.title, 'pr_user_created': h.person(pr.author), 'pr_repo_url': h.canonical_url('summary_home', repo_name=pr.other_repo.repo_name), 'pr_url': pr_url, 'pr_revisions': revision_data, 'repo_name': pr.other_repo.repo_name, 'pr_id': pr.pull_request_id, 'ref': org_ref_name, 'pr_username': pr.author.username, 'threading': threading, 'is_mention': False, } if reviewers: NotificationModel().create(created_by=pr.author, subject=subject, body=body, recipients=reviewers, type_=Notification.TYPE_PULL_REQUEST, email_kwargs=email_kwargs) if mention_recipients: mention_recipients.discard(None) mention_recipients.difference_update(reviewers) if mention_recipients: email_kwargs['is_mention'] = True subject = _('[Mention]') + ' ' + subject NotificationModel().create(created_by=pr.author, subject=subject, body=body, recipients=mention_recipients, type_=Notification.TYPE_PULL_REQUEST, email_kwargs=email_kwargs)
def __get_desc(self, cs): desc_msg = [(_('%s committed on %s') % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>'] #branches, tags, bookmarks if cs.branch: desc_msg.append('branch: %s<br/>' % cs.branch) if h.is_hg(c.db_repo_scm_instance): for book in cs.bookmarks: desc_msg.append('bookmark: %s<br/>' % book) for tag in cs.tags: desc_msg.append('tag: %s<br/>' % tag) diff_processor, changes = self.__changes(cs) # rev link _url = h.canonical_url('changeset_home', repo_name=c.db_repo.repo_name, revision=cs.raw_id) desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8])) desc_msg.append('<pre>') desc_msg.append(h.urlify_text(cs.message)) desc_msg.append('\n') desc_msg.extend(changes) if self.include_diff: desc_msg.append('\n\n') desc_msg.append(diff_processor.as_raw()) desc_msg.append('</pre>') return map(safe_unicode, desc_msg)
def create_registration(self, form_data): from kallithea.model.notification import NotificationModel import kallithea.lib.helpers as h form_data['admin'] = False form_data['extern_type'] = User.DEFAULT_AUTH_TYPE form_data['extern_name'] = '' new_user = self.create(form_data) # notification to admins subject = _('New user registration') body = ( 'New user registration\n' '---------------------\n' '- Username: {user.username}\n' '- Full Name: {user.full_name}\n' '- Email: {user.email}\n' ).format(user=new_user) edit_url = h.canonical_url('edit_user', id=new_user.user_id) email_kwargs = { 'registered_user_url': edit_url, 'new_username': new_user.username, 'new_email': new_user.email, 'new_full_name': new_user.full_name} NotificationModel().create(created_by=new_user, subject=subject, body=body, recipients=None, type_=NotificationModel.TYPE_REGISTRATION, email_kwargs=email_kwargs)
def __get_desc(self, cs): desc_msg = [(_('%s committed on %s') % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>'] #branches, tags, bookmarks if cs.branch: desc_msg.append('branch: %s<br/>' % cs.branch) if h.is_hg(c.db_repo_scm_instance): for book in cs.bookmarks: desc_msg.append('bookmark: %s<br/>' % book) for tag in cs.tags: desc_msg.append('tag: %s<br/>' % tag) diff_processor, changes = self.__changes(cs) # rev link _url = h.canonical_url('changeset_home', repo_name=c.db_repo.repo_name, revision=cs.raw_id) desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8])) desc_msg.append('<pre>') desc_msg.append(h.urlify_text(cs.message)) desc_msg.append('\n') desc_msg.extend(changes) if self.include_diff: desc_msg.append('\n\n') desc_msg.append(diff_processor.as_raw()) desc_msg.append('</pre>') return map(safe_unicode, desc_msg)
def create_registration(self, form_data): from kallithea.model.notification import NotificationModel import kallithea.lib.helpers as h form_data['admin'] = False form_data['extern_name'] = EXTERN_TYPE_INTERNAL form_data['extern_type'] = EXTERN_TYPE_INTERNAL new_user = self.create(form_data) self.sa.add(new_user) self.sa.flush() # notification to admins subject = _('New user registration') body = ('New user registration\n' '---------------------\n' '- Username: %s\n' '- Full Name: %s\n' '- Email: %s\n') body = body % (new_user.username, new_user.full_name, new_user.email) edit_url = h.canonical_url('edit_user', id=new_user.user_id) email_kwargs = {'registered_user_url': edit_url, 'new_username': new_user.username} NotificationModel().create(created_by=new_user, subject=subject, body=body, recipients=None, type_=Notification.TYPE_REGISTRATION, email_kwargs=email_kwargs)
def create_registration(self, form_data): from kallithea.model.notification import NotificationModel import kallithea.lib.helpers as h form_data['admin'] = False form_data['extern_type'] = User.DEFAULT_AUTH_TYPE form_data['extern_name'] = '' new_user = self.create(form_data) # notification to admins subject = _('New user registration') body = ( u'New user registration\n' '---------------------\n' '- Username: {user.username}\n' '- Full Name: {user.full_name}\n' '- Email: {user.email}\n' ).format(user=new_user) edit_url = h.canonical_url('edit_user', id=new_user.user_id) email_kwargs = { 'registered_user_url': edit_url, 'new_username': new_user.username, 'new_email': new_user.email, 'new_full_name': new_user.full_name} NotificationModel().create(created_by=new_user, subject=subject, body=body, recipients=None, type_=Notification.TYPE_REGISTRATION, email_kwargs=email_kwargs)
def reset_password_link(self, data): from kallithea.lib.celerylib import tasks, run_task from kallithea.model.notification import EmailNotificationModel import kallithea.lib.helpers as h user_email = data['email'] user = User.get_by_email(user_email) if user: log.debug('password reset user found %s' % user) link = h.canonical_url('reset_password_confirmation', key=user.api_key) reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET body = EmailNotificationModel().get_email_tmpl(reg_type, 'txt', user=user.short_contact, reset_url=link) html_body = EmailNotificationModel().get_email_tmpl(reg_type, 'html', user=user.short_contact, reset_url=link) log.debug('sending email') run_task(tasks.send_email, [user_email], _("Password reset link"), body, html_body) log.info('send new password mail to %s' % user_email) else: log.debug("password reset email %s not found" % user_email) return True
def _atom_feed(self, repos, public=True): journal = self._get_journal_data(repos) if public: _link = h.canonical_url('public_journal_atom') _desc = '%s %s %s' % (c.site_name, _('public journal'), 'atom feed') else: _link = h.canonical_url('journal_atom') _desc = '%s %s %s' % (c.site_name, _('journal'), 'atom feed') feed = Atom1Feed(title=_desc, link=_link, description=_desc, language=self.language, ttl=self.ttl) for entry in journal[:self.feed_nr]: user = entry.user if user is None: #fix deleted users user = AttributeDict({ 'short_contact': entry.username, 'email': '', 'full_contact': '' }) action, action_extra, ico = h.action_parser(entry, feed=True) title = "%s - %s %s" % (user.short_contact, action(), entry.repository.repo_name) desc = action_extra() _url = None if entry.repository is not None: _url = h.canonical_url('changelog_home', repo_name=entry.repository.repo_name) feed.add_item(title=title, pubdate=entry.action_date, link=_url or h.canonical_url(''), author_email=user.email, author_name=user.full_contact, description=desc) response.content_type = feed.mime_type return feed.writeString('utf-8')
def _get_feed_from_cache(key, kind): feed = Rss201rev2Feed( title=self.title % repo_name, link=h.canonical_url('summary_home', repo_name=repo_name), description=self.description % repo_name, language=self.language, ttl=self.ttl ) for cs in reversed(list(c.db_repo_scm_instance[-self.feed_nr:])): feed.add_item(title=self._get_title(cs), link=h.canonical_url('changeset_home', repo_name=repo_name, revision=cs.raw_id), author_name=cs.author, description=''.join(self.__get_desc(cs)), pubdate=cs.date, ) response.content_type = feed.mime_type return feed.writeString('utf-8')
def _rss_feed(self, repos, public=True): journal = self._get_journal_data(repos) if public: _link = h.canonical_url('public_journal_atom') _desc = '%s %s %s' % (c.site_name, _('Public Journal'), 'rss feed') else: _link = h.canonical_url('journal_atom') _desc = '%s %s %s' % (c.site_name, _('Journal'), 'rss feed') feed = Rss201rev2Feed(title=_desc, link=_link, description=_desc, language=language, ttl=ttl) for entry in journal[:feed_nr]: user = entry.user if user is None: #fix deleted users user = AttributeDict({'short_contact': entry.username, 'email': '', 'full_contact': ''}) action, action_extra, ico = h.action_parser(entry, feed=True) title = "%s - %s %s" % (user.short_contact, action(), entry.repository.repo_name) desc = action_extra() _url = None if entry.repository is not None: _url = h.canonical_url('changelog_home', repo_name=entry.repository.repo_name) feed.add_item(title=title, pubdate=entry.action_date, link=_url or h.canonical_url(''), author_email=user.email, author_name=user.full_contact, description=desc) response.content_type = feed.mime_type return feed.writeString('utf-8')
def _get_feed_from_cache(key, kind): feed = Rss201rev2Feed( title=_('%s %s feed') % (c.site_name, repo_name), link=h.canonical_url('summary_home', repo_name=repo_name), description=_('Changes on %s repository') % repo_name, language=language, ttl=ttl ) rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20)) for cs in reversed(list(c.db_repo_scm_instance[-rss_items_per_page:])): feed.add_item(title=self._get_title(cs), link=h.canonical_url('changeset_home', repo_name=repo_name, revision=cs.raw_id), author_name=cs.author, description=''.join(self.__get_desc(cs)), pubdate=cs.date, ) response.content_type = feed.mime_type return feed.writeString('utf-8')
def _get_feed_from_cache(key, kind): feed = Rss201rev2Feed(title=self.title % repo_name, link=h.canonical_url('summary_home', repo_name=repo_name), description=self.description % repo_name, language=self.language, ttl=self.ttl) for cs in reversed(list(c.db_repo_scm_instance[-self.feed_nr:])): feed.add_item( title=self._get_title(cs), link=h.canonical_url('changeset_home', repo_name=repo_name, revision=cs.raw_id), author_name=cs.author, description=''.join(self.__get_desc(cs)), pubdate=cs.date, ) response.content_type = feed.mime_type return feed.writeString('utf-8')
def _get_feed_from_cache(key, kind): feed = Rss201rev2Feed( title=_('%s %s feed') % (c.site_name, repo_name), link=h.canonical_url('summary_home', repo_name=repo_name), description=_('Changes on %s repository') % repo_name, language=language, ttl=ttl) rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20)) for cs in reversed( list(c.db_repo_scm_instance[-rss_items_per_page:])): feed.add_item( title=self._get_title(cs), link=h.canonical_url('changeset_home', repo_name=repo_name, revision=cs.raw_id), author_name=cs.author, description=''.join(self.__get_desc(cs)), pubdate=cs.date, ) response.content_type = feed.mime_type return feed.writeString('utf-8')
def _feed(self, repos, feeder, link, desc): response.content_type = feeder.content_type journal = self._get_journal_data(repos) header = dict( title=desc, link=link, description=desc, ) entries=[] for entry in journal[:feed_nr]: user = entry.user if user is None: # fix deleted users user = AttributeDict({'short_contact': entry.username, 'email': '', 'full_contact': ''}) action, action_extra, ico = h.action_parser(entry, feed=True) title = "%s - %s %s" % (user.short_contact, action(), entry.repository.repo_name) _url = None if entry.repository is not None: _url = h.canonical_url('changelog_home', repo_name=entry.repository.repo_name) entries.append(dict( title=title, pubdate=entry.action_date, link=_url or h.canonical_url(''), author_email=user.email, author_name=user.full_name_or_username, description=action_extra(), )) return feeder.render(header, entries)
def _get_notification_data(self, repo, comment, user, comment_text, line_no=None, revision=None, pull_request=None, status_change=None, closing_pr=False): """ Get notification data :param comment_text: :param line: :returns: tuple (subj,body,recipients,notification_type,email_kwargs) """ # make notification body = comment_text # text of the comment line = '' if line_no: line = _('on line %s') % line_no #changeset if revision: notification_type = Notification.TYPE_CHANGESET_COMMENT cs = repo.scm_instance.get_changeset(revision) desc = "%s" % (cs.short_id) threading = [ '%s-rev-%s@%s' % (repo.repo_name, revision, h.canonical_hostname()) ] if line_no: # TODO: url to file _and_ line number threading.append('%s-rev-%s-line-%s@%s' % (repo.repo_name, revision, line_no, h.canonical_hostname())) comment_url = h.canonical_url('changeset_home', repo_name=repo.repo_name, revision=revision, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re changeset: %(desc)s %(line)s' % \ {'desc': desc, 'line': line}, comment_url) ) # get the current participants of this changeset recipients = ChangesetComment.get_users(revision=revision) # add changeset author if it's in kallithea system cs_author = User.get_from_cs_author(cs.author) if not cs_author: #use repo owner if we cannot extract the author correctly cs_author = repo.user recipients += [cs_author] email_kwargs = { 'status_change': status_change, 'cs_comment_user': h.person(user, 'username_and_name'), 'cs_target_repo': h.canonical_url('summary_home', repo_name=repo.repo_name), 'cs_comment_url': comment_url, 'raw_id': revision, 'message': cs.message, 'repo_name': repo.repo_name, 'short_id': h.short_id(revision), 'branch': cs.branch, 'comment_username': user.username, 'threading': threading, } #pull request elif pull_request: notification_type = Notification.TYPE_PULL_REQUEST_COMMENT desc = comment.pull_request.title _org_ref_type, org_ref_name, _org_rev = comment.pull_request.org_ref.split( ':') threading = [ '%s-pr-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, h.canonical_hostname()) ] if line_no: # TODO: url to file _and_ line number threading.append('%s-pr-%s-line-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, line_no, h.canonical_hostname())) comment_url = pull_request.url(canonical=True, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re pull request #%(pr_id)s: %(desc)s %(line)s' % \ {'desc': desc, 'pr_id': comment.pull_request.pull_request_id, 'line': line}, comment_url) ) # get the current participants of this pull request recipients = ChangesetComment.get_users( pull_request_id=pull_request.pull_request_id) # add pull request author recipients += [pull_request.author] # add the reviewers to notification recipients += [x.user for x in pull_request.reviewers] #set some variables for email notification email_kwargs = { 'pr_title': pull_request.title, 'pr_id': pull_request.pull_request_id, 'status_change': status_change, 'closing_pr': closing_pr, 'pr_comment_url': comment_url, 'pr_comment_user': h.person(user, 'username_and_name'), 'pr_target_repo': h.canonical_url('summary_home', repo_name=pull_request.other_repo.repo_name), 'repo_name': pull_request.other_repo.repo_name, 'ref': org_ref_name, 'comment_username': user.username, 'threading': threading, } return subj, body, recipients, notification_type, email_kwargs
def _get_notification_data(self, repo, comment, user, comment_text, line_no=None, revision=None, pull_request=None, status_change=None, closing_pr=False): """ Get notification data :param comment_text: :param line: :returns: tuple (subj,body,recipients,notification_type,email_kwargs) """ # make notification body = comment_text # text of the comment line = '' if line_no: line = _('on line %s') % line_no #changeset if revision: notification_type = Notification.TYPE_CHANGESET_COMMENT cs = repo.scm_instance.get_changeset(revision) desc = "%s" % (cs.short_id) threading = ['%s-rev-%s@%s' % (repo.repo_name, revision, h.canonical_hostname())] if line_no: # TODO: url to file _and_ line number threading.append('%s-rev-%s-line-%s@%s' % (repo.repo_name, revision, line_no, h.canonical_hostname())) comment_url = h.canonical_url('changeset_home', repo_name=repo.repo_name, revision=revision, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re changeset: %(desc)s %(line)s' % \ {'desc': desc, 'line': line}, comment_url) ) # get the current participants of this changeset recipients = ChangesetComment.get_users(revision=revision) # add changeset author if it's in kallithea system cs_author = User.get_from_cs_author(cs.author) if not cs_author: #use repo owner if we cannot extract the author correctly cs_author = repo.user recipients += [cs_author] email_kwargs = { 'status_change': status_change, 'cs_comment_user': h.person(user, 'username_and_name'), 'cs_target_repo': h.canonical_url('summary_home', repo_name=repo.repo_name), 'cs_comment_url': comment_url, 'raw_id': revision, 'message': cs.message, 'repo_name': repo.repo_name, 'short_id': h.short_id(revision), 'branch': cs.branch, 'comment_username': user.username, 'threading': threading, } #pull request elif pull_request: notification_type = Notification.TYPE_PULL_REQUEST_COMMENT desc = comment.pull_request.title _org_ref_type, org_ref_name, _org_rev = comment.pull_request.org_ref.split(':') threading = ['%s-pr-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, h.canonical_hostname())] if line_no: # TODO: url to file _and_ line number threading.append('%s-pr-%s-line-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, line_no, h.canonical_hostname())) comment_url = pull_request.url(canonical=True, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re pull request #%(pr_id)s: %(desc)s %(line)s' % \ {'desc': desc, 'pr_id': comment.pull_request.pull_request_id, 'line': line}, comment_url) ) # get the current participants of this pull request recipients = ChangesetComment.get_users(pull_request_id= pull_request.pull_request_id) # add pull request author recipients += [pull_request.author] # add the reviewers to notification recipients += [x.user for x in pull_request.reviewers] #set some variables for email notification email_kwargs = { 'pr_title': pull_request.title, 'pr_id': pull_request.pull_request_id, 'status_change': status_change, 'closing_pr': closing_pr, 'pr_comment_url': comment_url, 'pr_comment_user': h.person(user, 'username_and_name'), 'pr_target_repo': h.canonical_url('summary_home', repo_name=pull_request.other_repo.repo_name), 'repo_name': pull_request.other_repo.repo_name, 'ref': org_ref_name, 'comment_username': user.username, 'threading': threading, } return subj, body, recipients, notification_type, email_kwargs
def create_update(self, old_pull_request, updaterev, title, description, reviewers_ids): org_repo = RepoModel()._get_repo(old_pull_request.org_repo.repo_name) org_ref_type, org_ref_name, org_rev = old_pull_request.org_ref.split(':') new_org_rev = self._get_ref_rev(org_repo, 'rev', updaterev) other_repo = RepoModel()._get_repo(old_pull_request.other_repo.repo_name) other_ref_type, other_ref_name, other_rev = old_pull_request.other_ref.split(':') # other_rev is ancestor #assert other_ref_type == 'branch', other_ref_type # TODO: what if not? new_other_rev = self._get_ref_rev(other_repo, other_ref_type, other_ref_name) cs_ranges, _cs_ranges_not, ancestor_rev = CompareController._get_changesets(org_repo.scm_instance.alias, other_repo.scm_instance, new_other_rev, # org and other "swapped" org_repo.scm_instance, new_org_rev) old_revisions = set(old_pull_request.revisions) revisions = [cs.raw_id for cs in cs_ranges] new_revisions = [r for r in revisions if r not in old_revisions] lost = old_revisions.difference(revisions) infos = ['This is an update of %s "%s".' % (h.canonical_url('pullrequest_show', repo_name=old_pull_request.other_repo.repo_name, pull_request_id=old_pull_request.pull_request_id), old_pull_request.title)] if lost: infos.append(_('Missing changesets since the previous pull request:')) for r in old_pull_request.revisions: if r in lost: rev_desc = org_repo.get_changeset(r).message.split('\n')[0] infos.append(' %s "%s"' % (h.short_id(r), rev_desc)) if new_revisions: infos.append(_('New changesets on %s %s since the previous pull request:') % (org_ref_type, org_ref_name)) for r in reversed(revisions): if r in new_revisions: rev_desc = org_repo.get_changeset(r).message.split('\n')[0] infos.append(' %s %s' % (h.short_id(r), h.shorter(rev_desc, 80))) if ancestor_rev == other_rev: infos.append(_("Ancestor didn't change - show diff since previous version:")) infos.append(h.canonical_url('compare_url', repo_name=org_repo.repo_name, # other_repo is always same as repo_name org_ref_type='rev', org_ref_name=h.short_id(org_rev), # use old org_rev as base other_ref_type='rev', other_ref_name=h.short_id(new_org_rev), )) # note: linear diff, merge or not doesn't matter else: infos.append(_('This pull request is based on another %s revision and there is no simple diff.') % other_ref_name) else: infos.append(_('No changes found on %s %s since previous version.') % (org_ref_type, org_ref_name)) # TODO: fail? # hack: ancestor_rev is not an other_ref but we want to show the # requested destination and have the exact ancestor new_other_ref = '%s:%s:%s' % (other_ref_type, other_ref_name, ancestor_rev) new_org_ref = '%s:%s:%s' % (org_ref_type, org_ref_name, new_org_rev) try: title, old_v = re.match(r'(.*)\(v(\d+)\)\s*$', title).groups() v = int(old_v) + 1 except (AttributeError, ValueError): v = 2 title = '%s (v%s)' % (title.strip(), v) # using a mail-like separator, insert new update info at the top of the list descriptions = description.replace('\r\n', '\n').split('\n-- \n', 1) description = descriptions[0].strip() + '\n\n-- \n' + '\n'.join(infos) if len(descriptions) > 1: description += '\n\n' + descriptions[1].strip() try: pull_request = PullRequestModel().create( self.authuser.user_id, old_pull_request.org_repo.repo_name, new_org_ref, old_pull_request.other_repo.repo_name, new_other_ref, revisions, reviewers_ids, title, description ) except UserInvalidException as u: h.flash(_('Invalid reviewer "%s" specified') % u, category='error') raise HTTPBadRequest() except Exception: h.flash(_('Error occurred while creating pull request'), category='error') log.error(traceback.format_exc()) raise HTTPFound(location=old_pull_request.url()) ChangesetCommentsModel().create( text=_('Closed, replaced by %s .') % pull_request.url(canonical=True), repo=old_pull_request.other_repo.repo_id, user=c.authuser.user_id, pull_request=old_pull_request.pull_request_id, closing_pr=True) PullRequestModel().close_pull_request(old_pull_request.pull_request_id) Session().commit() h.flash(_('Pull request update created'), category='success') raise HTTPFound(location=pull_request.url())
def _get_notification_data(self, repo, comment, author, comment_text, line_no=None, revision=None, pull_request=None, status_change=None, closing_pr=False): """ :returns: tuple (subj,body,recipients,notification_type,email_kwargs) """ # make notification body = comment_text # text of the comment line = '' if line_no: line = _('on line %s') % line_no #changeset if revision: notification_type = Notification.TYPE_CHANGESET_COMMENT cs = repo.scm_instance.get_changeset(revision) desc = cs.short_id threading = [ '%s-rev-%s@%s' % (repo.repo_name, revision, h.canonical_hostname()) ] if line_no: # TODO: url to file _and_ line number threading.append('%s-rev-%s-line-%s@%s' % (repo.repo_name, revision, line_no, h.canonical_hostname())) comment_url = h.canonical_url('changeset_home', repo_name=repo.repo_name, revision=revision, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re changeset: %(desc)s %(line)s' % \ {'desc': desc, 'line': line}, comment_url) ) # get the current participants of this changeset recipients = _list_changeset_commenters(revision) # add changeset author if it's known locally cs_author = User.get_from_cs_author(cs.author) if not cs_author: #use repo owner if we cannot extract the author correctly # FIXME: just use committer name even if not a user cs_author = repo.owner recipients.append(cs_author) email_kwargs = { 'status_change': status_change, 'cs_comment_user': author.full_name_and_username, 'cs_target_repo': h.canonical_url('summary_home', repo_name=repo.repo_name), 'cs_comment_url': comment_url, 'cs_url': h.canonical_url('changeset_home', repo_name=repo.repo_name, revision=revision), 'raw_id': revision, 'message': cs.message, 'message_short': h.shorter(cs.message, 50, firstline=True), 'cs_author': cs_author, 'repo_name': repo.repo_name, 'short_id': h.short_id(revision), 'branch': cs.branch, 'comment_username': author.username, 'threading': threading, } #pull request elif pull_request: notification_type = Notification.TYPE_PULL_REQUEST_COMMENT desc = comment.pull_request.title _org_ref_type, org_ref_name, _org_rev = comment.pull_request.org_ref.split( ':') _other_ref_type, other_ref_name, _other_rev = comment.pull_request.other_ref.split( ':') threading = [ '%s-pr-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, h.canonical_hostname()) ] if line_no: # TODO: url to file _and_ line number threading.append('%s-pr-%s-line-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, line_no, h.canonical_hostname())) comment_url = pull_request.url(canonical=True, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re pull request %(pr_nice_id)s: %(desc)s %(line)s' % \ {'desc': desc, 'pr_nice_id': comment.pull_request.nice_id(), 'line': line}, comment_url) ) # get the current participants of this pull request recipients = _list_pull_request_commenters(pull_request) recipients.append(pull_request.owner) recipients += pull_request.get_reviewer_users() #set some variables for email notification email_kwargs = { 'pr_title': pull_request.title, 'pr_title_short': h.shorter(pull_request.title, 50), 'pr_nice_id': pull_request.nice_id(), 'status_change': status_change, 'closing_pr': closing_pr, 'pr_comment_url': comment_url, 'pr_url': pull_request.url(canonical=True), 'pr_comment_user': author.full_name_and_username, 'pr_target_repo': h.canonical_url('summary_home', repo_name=pull_request.other_repo.repo_name), 'pr_target_branch': other_ref_name, 'pr_source_repo': h.canonical_url('summary_home', repo_name=pull_request.org_repo.repo_name), 'pr_source_branch': org_ref_name, 'pr_owner': pull_request.owner, 'pr_owner_username': pull_request.owner.username, 'repo_name': pull_request.other_repo.repo_name, 'comment_username': author.username, 'threading': threading, } return subj, body, recipients, notification_type, email_kwargs
def add_reviewers(self, user, pr, reviewers, mention_recipients=None): """Add reviewer and send notification to them. """ reviewers = set(reviewers) _assert_valid_reviewers(reviewers) if mention_recipients is not None: mention_recipients = set(mention_recipients) - reviewers _assert_valid_reviewers(mention_recipients) #members for reviewer in reviewers: prr = PullRequestReviewer(reviewer, pr) Session().add(prr) #notification to reviewers pr_url = pr.url(canonical=True) threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name, pr.pull_request_id, h.canonical_hostname())] subject = safe_unicode( h.link_to( _('%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s') % \ {'user': user.username, 'pr_title': pr.title, 'pr_nice_id': pr.nice_id()}, pr_url) ) body = pr.description _org_ref_type, org_ref_name, _org_rev = pr.org_ref.split(':') _other_ref_type, other_ref_name, _other_rev = pr.other_ref.split(':') revision_data = [(x.raw_id, x.message) for x in map(pr.org_repo.get_changeset, pr.revisions)] email_kwargs = { 'pr_title': pr.title, 'pr_title_short': h.shorter(pr.title, 50), 'pr_user_created': user.full_name_and_username, 'pr_repo_url': h.canonical_url('summary_home', repo_name=pr.other_repo.repo_name), 'pr_url': pr_url, 'pr_revisions': revision_data, 'repo_name': pr.other_repo.repo_name, 'org_repo_name': pr.org_repo.repo_name, 'pr_nice_id': pr.nice_id(), 'pr_target_repo': h.canonical_url('summary_home', repo_name=pr.other_repo.repo_name), 'pr_target_branch': other_ref_name, 'pr_source_repo': h.canonical_url('summary_home', repo_name=pr.org_repo.repo_name), 'pr_source_branch': org_ref_name, 'pr_owner': pr.owner, 'pr_owner_username': pr.owner.username, 'pr_username': user.username, 'threading': threading, 'is_mention': False, } if reviewers: NotificationModel().create(created_by=user, subject=subject, body=body, recipients=reviewers, type_=Notification.TYPE_PULL_REQUEST, email_kwargs=email_kwargs) if mention_recipients: email_kwargs['is_mention'] = True subject = _('[Mention]') + ' ' + subject # FIXME: this subject is wrong and unused! NotificationModel().create(created_by=user, subject=subject, body=body, recipients=mention_recipients, type_=Notification.TYPE_PULL_REQUEST, email_kwargs=email_kwargs)
def _get_notification_data(self, repo, comment, author, comment_text, line_no=None, revision=None, pull_request=None, status_change=None, closing_pr=False): """ :returns: tuple (subj,body,recipients,notification_type,email_kwargs) """ # make notification body = comment_text # text of the comment line = '' if line_no: line = _('on line %s') % line_no #changeset if revision: notification_type = Notification.TYPE_CHANGESET_COMMENT cs = repo.scm_instance.get_changeset(revision) desc = cs.short_id threading = ['%s-rev-%s@%s' % (repo.repo_name, revision, h.canonical_hostname())] if line_no: # TODO: url to file _and_ line number threading.append('%s-rev-%s-line-%s@%s' % (repo.repo_name, revision, line_no, h.canonical_hostname())) comment_url = h.canonical_url('changeset_home', repo_name=repo.repo_name, revision=revision, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re changeset: %(desc)s %(line)s' % \ {'desc': desc, 'line': line}, comment_url) ) # get the current participants of this changeset recipients = _list_changeset_commenters(revision) # add changeset author if it's known locally cs_author = User.get_from_cs_author(cs.author) if not cs_author: #use repo owner if we cannot extract the author correctly # FIXME: just use committer name even if not a user cs_author = repo.owner recipients.append(cs_author) email_kwargs = { 'status_change': status_change, 'cs_comment_user': author.full_name_and_username, 'cs_target_repo': h.canonical_url('summary_home', repo_name=repo.repo_name), 'cs_comment_url': comment_url, 'cs_url': h.canonical_url('changeset_home', repo_name=repo.repo_name, revision=revision), 'raw_id': revision, 'message': cs.message, 'message_short': h.shorter(cs.message, 50, firstline=True), 'cs_author': cs_author, 'repo_name': repo.repo_name, 'short_id': h.short_id(revision), 'branch': cs.branch, 'comment_username': author.username, 'threading': threading, } #pull request elif pull_request: notification_type = Notification.TYPE_PULL_REQUEST_COMMENT desc = comment.pull_request.title _org_ref_type, org_ref_name, _org_rev = comment.pull_request.org_ref.split(':') _other_ref_type, other_ref_name, _other_rev = comment.pull_request.other_ref.split(':') threading = ['%s-pr-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, h.canonical_hostname())] if line_no: # TODO: url to file _and_ line number threading.append('%s-pr-%s-line-%s@%s' % (pull_request.other_repo.repo_name, pull_request.pull_request_id, line_no, h.canonical_hostname())) comment_url = pull_request.url(canonical=True, anchor='comment-%s' % comment.comment_id) subj = safe_unicode( h.link_to('Re pull request %(pr_nice_id)s: %(desc)s %(line)s' % \ {'desc': desc, 'pr_nice_id': comment.pull_request.nice_id(), 'line': line}, comment_url) ) # get the current participants of this pull request recipients = _list_pull_request_commenters(pull_request) recipients.append(pull_request.owner) recipients += pull_request.get_reviewer_users() #set some variables for email notification email_kwargs = { 'pr_title': pull_request.title, 'pr_title_short': h.shorter(pull_request.title, 50), 'pr_nice_id': pull_request.nice_id(), 'status_change': status_change, 'closing_pr': closing_pr, 'pr_comment_url': comment_url, 'pr_url': pull_request.url(canonical=True), 'pr_comment_user': author.full_name_and_username, 'pr_target_repo': h.canonical_url('summary_home', repo_name=pull_request.other_repo.repo_name), 'pr_target_branch': other_ref_name, 'pr_source_repo': h.canonical_url('summary_home', repo_name=pull_request.org_repo.repo_name), 'pr_source_branch': org_ref_name, 'pr_owner': pull_request.owner, 'pr_owner_username': pull_request.owner.username, 'repo_name': pull_request.other_repo.repo_name, 'comment_username': author.username, 'threading': threading, } return subj, body, recipients, notification_type, email_kwargs
def create_update(self, old_pull_request, updaterev, title, description, reviewers_ids): org_repo = RepoModel()._get_repo(old_pull_request.org_repo.repo_name) org_ref_type, org_ref_name, org_rev = old_pull_request.org_ref.split( ':') new_org_rev = self._get_ref_rev(org_repo, 'rev', updaterev) other_repo = RepoModel()._get_repo( old_pull_request.other_repo.repo_name) other_ref_type, other_ref_name, other_rev = old_pull_request.other_ref.split( ':') # other_rev is ancestor #assert other_ref_type == 'branch', other_ref_type # TODO: what if not? new_other_rev = self._get_ref_rev(other_repo, other_ref_type, other_ref_name) cs_ranges, _cs_ranges_not, ancestor_rev = CompareController._get_changesets( org_repo.scm_instance.alias, other_repo.scm_instance, new_other_rev, # org and other "swapped" org_repo.scm_instance, new_org_rev) old_revisions = set(old_pull_request.revisions) revisions = [cs.raw_id for cs in cs_ranges] new_revisions = [r for r in revisions if r not in old_revisions] lost = old_revisions.difference(revisions) infos = [ 'This is an update of %s "%s".' % (h.canonical_url('pullrequest_show', repo_name=old_pull_request.other_repo.repo_name, pull_request_id=old_pull_request.pull_request_id), old_pull_request.title) ] if lost: infos.append( _('Missing changesets since the previous pull request:')) for r in old_pull_request.revisions: if r in lost: rev_desc = org_repo.get_changeset(r).message.split('\n')[0] infos.append(' %s "%s"' % (h.short_id(r), rev_desc)) if new_revisions: infos.append( _('New changesets on %s %s since the previous pull request:') % (org_ref_type, org_ref_name)) for r in reversed(revisions): if r in new_revisions: rev_desc = org_repo.get_changeset(r).message.split('\n')[0] infos.append(' %s %s' % (h.short_id(r), h.shorter(rev_desc, 80))) if ancestor_rev == other_rev: infos.append( _("Ancestor didn't change - show diff since previous version:" )) infos.append( h.canonical_url( 'compare_url', repo_name=org_repo. repo_name, # other_repo is always same as repo_name org_ref_type='rev', org_ref_name=h.short_id( org_rev), # use old org_rev as base other_ref_type='rev', other_ref_name=h.short_id(new_org_rev), )) # note: linear diff, merge or not doesn't matter else: infos.append( _('This pull request is based on another %s revision and there is no simple diff.' ) % other_ref_name) else: infos.append( _('No changes found on %s %s since previous version.') % (org_ref_type, org_ref_name)) # TODO: fail? # hack: ancestor_rev is not an other_ref but we want to show the # requested destination and have the exact ancestor new_other_ref = '%s:%s:%s' % (other_ref_type, other_ref_name, ancestor_rev) new_org_ref = '%s:%s:%s' % (org_ref_type, org_ref_name, new_org_rev) try: title, old_v = re.match(r'(.*)\(v(\d+)\)\s*$', title).groups() v = int(old_v) + 1 except (AttributeError, ValueError): v = 2 title = '%s (v%s)' % (title.strip(), v) # using a mail-like separator, insert new update info at the top of the list descriptions = description.replace('\r\n', '\n').split('\n-- \n', 1) description = descriptions[0].strip() + '\n\n-- \n' + '\n'.join(infos) if len(descriptions) > 1: description += '\n\n' + descriptions[1].strip() try: pull_request = PullRequestModel().create( self.authuser.user_id, old_pull_request.org_repo.repo_name, new_org_ref, old_pull_request.other_repo.repo_name, new_other_ref, revisions, reviewers_ids, title, description) except Exception: h.flash(_('Error occurred while creating pull request'), category='error') log.error(traceback.format_exc()) return redirect(old_pull_request.url()) ChangesetCommentsModel().create( text=_('Closed, replaced by %s .') % pull_request.url(canonical=True), repo=old_pull_request.other_repo.repo_id, user=c.authuser.user_id, pull_request=old_pull_request.pull_request_id, closing_pr=True) PullRequestModel().close_pull_request(old_pull_request.pull_request_id) Session().commit() h.flash(_('Pull request update created'), category='success') return redirect(pull_request.url())
def __init__(self, old_pull_request, new_org_rev, new_other_rev, title, description, owner, reviewers): self.old_pull_request = old_pull_request org_repo = old_pull_request.org_repo org_ref_type, org_ref_name, org_rev = old_pull_request.org_ref.split(':') other_repo = old_pull_request.other_repo other_ref_type, other_ref_name, other_rev = old_pull_request.other_ref.split(':') # other_rev is ancestor #assert other_ref_type == 'branch', other_ref_type # TODO: what if not? new_org_ref = '%s:%s:%s' % (org_ref_type, org_ref_name, new_org_rev) new_other_ref = '%s:%s:%s' % (other_ref_type, other_ref_name, new_other_rev) self.create_action = CreatePullRequestAction(org_repo, other_repo, new_org_ref, new_other_ref, None, None, owner, reviewers) # Generate complete title/description old_revisions = set(old_pull_request.revisions) revisions = self.create_action.revisions new_revisions = [r for r in revisions if r not in old_revisions] lost = old_revisions.difference(revisions) infos = ['This is a new iteration of %s "%s".' % (h.canonical_url('pullrequest_show', repo_name=old_pull_request.other_repo.repo_name, pull_request_id=old_pull_request.pull_request_id), old_pull_request.title)] if lost: infos.append(_('Missing changesets since the previous iteration:')) for r in old_pull_request.revisions: if r in lost: rev_desc = org_repo.get_changeset(r).message.split('\n')[0] infos.append(' %s %s' % (h.short_id(r), rev_desc)) if new_revisions: infos.append(_('New changesets on %s %s since the previous iteration:') % (org_ref_type, org_ref_name)) for r in reversed(revisions): if r in new_revisions: rev_desc = org_repo.get_changeset(r).message.split('\n')[0] infos.append(' %s %s' % (h.short_id(r), h.shorter(rev_desc, 80))) if self.create_action.other_ref == old_pull_request.other_ref: infos.append(_("Ancestor didn't change - diff since previous iteration:")) infos.append(h.canonical_url('compare_url', repo_name=org_repo.repo_name, # other_repo is always same as repo_name org_ref_type='rev', org_ref_name=h.short_id(org_rev), # use old org_rev as base other_ref_type='rev', other_ref_name=h.short_id(new_org_rev), )) # note: linear diff, merge or not doesn't matter else: infos.append(_('This iteration is based on another %s revision and there is no simple diff.') % other_ref_name) else: infos.append(_('No changes found on %s %s since previous iteration.') % (org_ref_type, org_ref_name)) # TODO: fail? try: title, old_v = re.match(r'(.*)\(v(\d+)\)\s*$', title).groups() v = int(old_v) + 1 except (AttributeError, ValueError): v = 2 self.create_action.title = '%s (v%s)' % (title.strip(), v) # using a mail-like separator, insert new iteration info in description with latest first descriptions = description.replace('\r\n', '\n').split('\n-- \n', 1) description = descriptions[0].strip() + '\n\n-- \n' + '\n'.join(infos) if len(descriptions) > 1: description += '\n\n' + descriptions[1].strip() self.create_action.description = description if not CreatePullRequestIterationAction.is_user_authorized(self.old_pull_request): raise CreatePullRequestAction.Unauthorized(_('You are not authorized to create the pull request'))