##// END OF EJS Templates
pull requests: prevent adding DEFAULT user as reviewer...
Søren Løvborg -
r5841:1658beb2 default
parent child Browse files
Show More
@@ -1,213 +1,223 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.model.pull_request
16 16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 pull request model for Kallithea
19 19
20 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Jun 6, 2012
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28 import logging
29 29 import datetime
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 from kallithea.model.meta import Session
34 34 from kallithea.lib import helpers as h
35 35 from kallithea.lib.exceptions import UserInvalidException
36 36 from kallithea.model import BaseModel
37 37 from kallithea.model.db import PullRequest, PullRequestReviewers, Notification, \
38 ChangesetStatus
38 ChangesetStatus, User
39 39 from kallithea.model.notification import NotificationModel
40 40 from kallithea.lib.utils2 import extract_mentioned_users, safe_unicode
41 41
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 class PullRequestModel(BaseModel):
47 47
48 48 cls = PullRequest
49 49
50 50 def __get_pull_request(self, pull_request):
51 51 return self._get_instance(PullRequest, pull_request)
52 52
53 53 def get_pullrequest_cnt_for_user(self, user):
54 54 return PullRequest.query() \
55 55 .join(PullRequestReviewers) \
56 56 .filter(PullRequestReviewers.user_id == user) \
57 57 .filter(PullRequest.status != PullRequest.STATUS_CLOSED) \
58 58 .count()
59 59
60 60 def get_all(self, repo_name, from_=False, closed=False):
61 61 """Get all PRs for repo.
62 62 Default is all PRs to the repo, PRs from the repo if from_.
63 63 Closed PRs are only included if closed is true."""
64 64 repo = self._get_repo(repo_name)
65 65 q = PullRequest.query()
66 66 if from_:
67 67 q = q.filter(PullRequest.org_repo == repo)
68 68 else:
69 69 q = q.filter(PullRequest.other_repo == repo)
70 70 if not closed:
71 71 q = q.filter(PullRequest.status != PullRequest.STATUS_CLOSED)
72 72 return q.order_by(PullRequest.created_on.desc()).all()
73 73
74 def _get_valid_reviewers(self, seq):
75 """ Generate User objects from a sequence of user IDs, usernames or
76 User objects. Raises UserInvalidException if the DEFAULT user is
77 specified, or if a given ID or username does not match any user.
78 """
79 for user_spec in seq:
80 user = self._get_user(user_spec)
81 if user is None or user.username == User.DEFAULT_USER:
82 raise UserInvalidException(user_spec)
83 yield user
84
74 85 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
75 86 revisions, reviewers, title, description=None):
76 87 from kallithea.model.changeset_status import ChangesetStatusModel
77 88
78 89 created_by_user = self._get_user(created_by)
79 90 org_repo = self._get_repo(org_repo)
80 91 other_repo = self._get_repo(other_repo)
81 92
82 93 new = PullRequest()
83 94 new.org_repo = org_repo
84 95 new.org_ref = org_ref
85 96 new.other_repo = other_repo
86 97 new.other_ref = other_ref
87 98 new.revisions = revisions
88 99 new.title = title
89 100 new.description = description
90 101 new.owner = created_by_user
91 102 Session().add(new)
92 103 Session().flush()
93 104
94 105 #reset state to under-review
95 106 from kallithea.model.comment import ChangesetCommentsModel
96 107 comment = ChangesetCommentsModel().create(
97 108 text=u'',
98 109 repo=org_repo,
99 110 user=new.owner,
100 111 pull_request=new,
101 112 send_email=False,
102 113 status_change=ChangesetStatus.STATUS_UNDER_REVIEW,
103 114 )
104 115 ChangesetStatusModel().set_status(
105 116 org_repo,
106 117 ChangesetStatus.STATUS_UNDER_REVIEW,
107 118 new.owner,
108 119 comment,
109 120 pull_request=new
110 121 )
111 122
123 reviewers = set(self._get_valid_reviewers(reviewers))
112 124 mention_recipients = extract_mentioned_users(new.description)
113 125 self.__add_reviewers(created_by_user, new, reviewers, mention_recipients)
114 126
115 127 return new
116 128
117 def __add_reviewers(self, user, pr, reviewers, mention_recipients=None):
129 def __add_reviewers(self, user, pr, reviewers, mention_recipients):
130 # reviewers and mention_recipients should be sets of User objects.
118 131 #members
119 for member in set(reviewers):
120 _usr = self._get_user(member)
121 if _usr is None:
122 raise UserInvalidException(member)
123 reviewer = PullRequestReviewers(_usr, pr)
132 for reviewer in reviewers:
133 reviewer = PullRequestReviewers(reviewer, pr)
124 134 Session().add(reviewer)
125 135
126 136 revision_data = [(x.raw_id, x.message)
127 137 for x in map(pr.org_repo.get_changeset, pr.revisions)]
128 138
129 139 #notification to reviewers
130 140 pr_url = pr.url(canonical=True)
131 141 threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name,
132 142 pr.pull_request_id,
133 143 h.canonical_hostname())]
134 144 subject = safe_unicode(
135 145 h.link_to(
136 146 _('%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s') % \
137 147 {'user': user.username,
138 148 'pr_title': pr.title,
139 149 'pr_nice_id': pr.nice_id()},
140 150 pr_url)
141 151 )
142 152 body = pr.description
143 153 _org_ref_type, org_ref_name, _org_rev = pr.org_ref.split(':')
144 154 email_kwargs = {
145 155 'pr_title': pr.title,
146 156 'pr_user_created': user.full_name_and_username,
147 157 'pr_repo_url': h.canonical_url('summary_home', repo_name=pr.other_repo.repo_name),
148 158 'pr_url': pr_url,
149 159 'pr_revisions': revision_data,
150 160 'repo_name': pr.other_repo.repo_name,
151 161 'org_repo_name': pr.org_repo.repo_name,
152 162 'pr_nice_id': pr.nice_id(),
153 163 'ref': org_ref_name,
154 164 'pr_username': user.username,
155 165 'threading': threading,
156 166 'is_mention': False,
157 167 }
158 168 if reviewers:
159 169 NotificationModel().create(created_by=user, subject=subject, body=body,
160 170 recipients=reviewers,
161 171 type_=Notification.TYPE_PULL_REQUEST,
162 172 email_kwargs=email_kwargs)
163 173
164 174 if mention_recipients:
165 175 mention_recipients.difference_update(reviewers)
166 176 if mention_recipients:
167 177 email_kwargs['is_mention'] = True
168 178 subject = _('[Mention]') + ' ' + subject
169 179 NotificationModel().create(created_by=user, subject=subject, body=body,
170 180 recipients=mention_recipients,
171 181 type_=Notification.TYPE_PULL_REQUEST,
172 182 email_kwargs=email_kwargs)
173 183
174 184 def mention_from_description(self, user, pr, old_description=''):
175 185 mention_recipients = (extract_mentioned_users(pr.description) -
176 186 extract_mentioned_users(old_description))
177 187
178 188 log.debug("Mentioning %s", mention_recipients)
179 self.__add_reviewers(user, pr, [], mention_recipients)
189 self.__add_reviewers(user, pr, set(), mention_recipients)
180 190
181 191 def update_reviewers(self, user, pull_request, reviewers_ids):
182 192 reviewers_ids = set(reviewers_ids)
183 193 pull_request = self.__get_pull_request(pull_request)
184 194 current_reviewers = PullRequestReviewers.query() \
185 195 .filter(PullRequestReviewers.pull_request==
186 196 pull_request) \
187 197 .all()
188 198 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
189 199
190 200 to_add = reviewers_ids.difference(current_reviewers_ids)
191 201 to_remove = current_reviewers_ids.difference(reviewers_ids)
192 202
193 203 log.debug("Adding %s reviewers", to_add)
194 self.__add_reviewers(user, pull_request, to_add)
204 self.__add_reviewers(user, pull_request, set(self._get_valid_reviewers(to_add)), set())
195 205
196 206 log.debug("Removing %s reviewers", to_remove)
197 207 for uid in to_remove:
198 208 reviewer = PullRequestReviewers.query() \
199 209 .filter(PullRequestReviewers.user_id==uid,
200 210 PullRequestReviewers.pull_request==pull_request) \
201 211 .scalar()
202 212 if reviewer:
203 213 Session().delete(reviewer)
204 214
205 215 def delete(self, pull_request):
206 216 pull_request = self.__get_pull_request(pull_request)
207 217 Session().delete(pull_request)
208 218
209 219 def close_pull_request(self, pull_request):
210 220 pull_request = self.__get_pull_request(pull_request)
211 221 pull_request.status = PullRequest.STATUS_CLOSED
212 222 pull_request.updated_on = datetime.datetime.now()
213 223 Session().add(pull_request)
General Comments 0
You need to be logged in to leave comments. Login now