66from django .contrib .auth .decorators import login_required
77
88from ietf .doc .models import Document , NewRevisionDocEvent , DocEvent
9- from ietf .doc .utils import can_request_review_of_doc , can_manage_review_requests_for_team
109from ietf .ietfauth .utils import is_authorized_in_doc_stream , user_is_person
11- from ietf .review .models import ReviewRequest , ReviewRequestStateName
12- from ietf .review .utils import active_review_teams
10+ from ietf .name .models import ReviewRequestStateName
11+ from ietf .group .models import Role
12+ from ietf .review .models import ReviewRequest
13+ from ietf .review .utils import active_review_teams , assign_review_request_to_reviewer
14+ from ietf .review .utils import can_request_review_of_doc , can_manage_review_requests_for_team
1315from ietf .utils .fields import DatepickerDateField
1416
1517class RequestReviewForm (forms .ModelForm ):
@@ -89,7 +91,6 @@ def request_review(request, name):
8991 time = review_req .time ,
9092 )
9193
92- # FIXME: if I'm a reviewer, auto-assign to myself?
9394 return redirect ('doc_view' , name = doc .name )
9495
9596 else :
@@ -104,21 +105,25 @@ def review_request(request, name, request_id):
104105 doc = get_object_or_404 (Document , name = name )
105106 review_req = get_object_or_404 (ReviewRequest , pk = request_id )
106107
107- is_reviewer = review_req .reviewer and user_is_person (request .user , review_req .reviewer .role . person )
108+ is_reviewer = review_req .reviewer and user_is_person (request .user , review_req .reviewer .person )
108109 can_manage_req = can_manage_review_requests_for_team (request .user , review_req .team )
109110
110111 can_withdraw_request = (review_req .state_id in ["requested" , "accepted" ]
111112 and is_authorized_in_doc_stream (request .user , doc ))
112113
113- can_reject_request_assignment = (review_req .state_id in ["requested" , "accepted" ]
114- and review_req .reviewer_id is not None
115- and (is_reviewer or can_manage_req ))
114+ can_assign_reviewer = (review_req .state_id in ["requested" , "accepted" ]
115+ and is_authorized_in_doc_stream (request .user , doc ))
116+
117+ can_reject_reviewer_assignment = (review_req .state_id in ["requested" , "accepted" ]
118+ and review_req .reviewer_id is not None
119+ and (is_reviewer or can_manage_req ))
116120
117121 return render (request , 'doc/review/review_request.html' , {
118122 'doc' : doc ,
119123 'review_req' : review_req ,
120124 'can_withdraw_request' : can_withdraw_request ,
121- 'can_reject_request_assignment' : can_reject_request_assignment ,
125+ 'can_reject_reviewer_assignment' : can_reject_reviewer_assignment ,
126+ 'can_assign_reviewer' : can_assign_reviewer ,
122127 })
123128
124129def withdraw_request (request , name , request_id ):
@@ -150,52 +155,96 @@ def withdraw_request(request, name, request_id):
150155 'review_req' : review_req ,
151156 })
152157
153- class RejectRequestAssignmentForm (forms .Form ):
158+ class PersonEmailLabeledRoleModelChoiceField (forms .ModelChoiceField ):
159+ def __init__ (self , * args , ** kwargs ):
160+ if not "queryset" in kwargs :
161+ kwargs ["queryset" ] = Role .objects .select_related ("person" , "email" )
162+ super (PersonEmailLabeledRoleModelChoiceField , self ).__init__ (* args , ** kwargs )
163+
164+ def label_from_instance (self , role ):
165+ return u"{} <{}>" .format (role .person .name , role .email .address )
166+
167+ class AssignReviewerForm (forms .Form ):
168+ reviewer = PersonEmailLabeledRoleModelChoiceField (widget = forms .RadioSelect , empty_label = "(None)" , required = False )
169+
170+ def __init__ (self , review_req , * args , ** kwargs ):
171+ super (AssignReviewerForm , self ).__init__ (* args , ** kwargs )
172+ f = self .fields ["reviewer" ]
173+ f .queryset = f .queryset .filter (name = "reviewer" , group = review_req .team )
174+ if review_req .reviewer :
175+ f .initial = review_req .reviewer_id
176+
177+ def assign_reviewer (request , name , request_id ):
178+ doc = get_object_or_404 (Document , name = name )
179+ review_req = get_object_or_404 (ReviewRequest , pk = request_id , state__in = ["requested" , "accepted" ])
180+
181+ can_manage_req = can_manage_review_requests_for_team (request .user , review_req .team )
182+
183+ if not can_manage_req :
184+ return HttpResponseForbidden ("You do not have permission to perform this action" )
185+
186+ if request .method == "POST" and request .POST .get ("action" ) == "assign" :
187+ form = AssignReviewerForm (review_req , request .POST )
188+ if form .is_valid ():
189+ reviewer = form .cleaned_data ["reviewer" ]
190+ assign_review_request_to_reviewer (review_req , reviewer , request .user .person )
191+
192+ return redirect (review_request , name = review_req .doc .name , request_id = review_req .pk )
193+ else :
194+ form = AssignReviewerForm (review_req )
195+
196+ return render (request , 'doc/review/assign_reviewer.html' , {
197+ 'doc' : doc ,
198+ 'review_req' : review_req ,
199+ 'form' : form ,
200+ })
201+
202+ class RejectReviewerAssignmentForm (forms .Form ):
154203 message_to_secretary = forms .CharField (widget = forms .Textarea , required = False , help_text = "Optional explanation of rejection, will be emailed to team secretary" )
155204
156- def reject_request_assignment (request , name , request_id ):
205+ def reject_reviewer_assignment (request , name , request_id ):
157206 doc = get_object_or_404 (Document , name = name )
158207 review_req = get_object_or_404 (ReviewRequest , pk = request_id , state__in = ["requested" , "accepted" ])
159208
160209 if not review_req .reviewer :
161210 return redirect (review_request , name = review_req .doc .name , request_id = review_req .pk )
162211
163- is_reviewer = user_is_person (request .user , review_req .reviewer .role . person )
212+ is_reviewer = user_is_person (request .user , review_req .reviewer .person )
164213 can_manage_req = can_manage_review_requests_for_team (request .user , review_req .team )
165214
166215 if not (is_reviewer or can_manage_req ):
167216 return HttpResponseForbidden ("You do not have permission to perform this action" )
168217
169218 if request .method == "POST" and request .POST .get ("action" ) == "reject" :
170- # reject the old request
171- prev_state = review_req .state
219+ # reject the request
172220 review_req .state = ReviewRequestStateName .objects .get (slug = "rejected" )
173221 review_req .save ()
174222
175- # assignment of reviewer is currently considered minutia, so
176- # not reported in the log
177- if prev_state .slug == "accepted" :
178- DocEvent .objects .create (
179- type = "changed_review_request" ,
180- doc = doc ,
181- by = request .user .person ,
182- desc = "Request for {} review by {} is unassigned" .format (review_req .type .name , review_req .team .acronym .upper ()),
183- )
184-
185- # make a new, open review request
186- ReviewRequest .objects .create (
223+ DocEvent .objects .create (
224+ type = "changed_review_request" ,
225+ doc = review_req .doc ,
226+ by = request .user .person ,
227+ desc = "Assignment of request for {} review by {} to {} was rejected" .format (
228+ review_req .type .name ,
229+ review_req .team .acronym .upper (),
230+ review_req .reviewer .person ,
231+ ),
232+ )
233+
234+ # make a new unassigned review request
235+ new_review_req = ReviewRequest .objects .create (
187236 time = review_req .time ,
188237 type = review_req .type ,
189238 doc = review_req .doc ,
190239 team = review_req .team ,
191240 deadline = review_req .deadline ,
192241 requested_rev = review_req .requested_rev ,
193- state = prev_state ,
242+ state = ReviewRequestStateName . objects . get ( slug = "requested" ) ,
194243 )
195244
196- return redirect (review_request , name = review_req .doc .name , request_id = review_req .pk )
245+ return redirect (review_request , name = new_review_req .doc .name , request_id = new_review_req .pk )
197246
198- return render (request , 'doc/review/reject_request_assignment .html' , {
247+ return render (request , 'doc/review/reject_reviewer_assignment .html' , {
199248 'doc' : doc ,
200249 'review_req' : review_req ,
201250 })
0 commit comments