|
47 | 47 | REINDEX_SHARE, |
48 | 48 | REINDEX_ELASTIC, |
49 | 49 | ) |
50 | | -from osf.utils.permissions import ADMIN |
| 50 | +from osf.utils.permissions import ADMIN, API_CONTRIBUTOR_PERMISSIONS |
51 | 51 |
|
52 | 52 | from scripts.approve_registrations import approve_past_pendings |
53 | 53 |
|
@@ -110,12 +110,17 @@ def get_context_data(self, **kwargs): |
110 | 110 | 'SPAM_STATUS': SpamStatus, |
111 | 111 | 'STORAGE_LIMITS': settings.StorageLimits, |
112 | 112 | 'node': node, |
| 113 | + # to edit contributors we should have guid as django prohibits _id usage as it starts with an underscore |
| 114 | + 'annotated_contributors': node.contributor_set.prefetch_related('user__guids').annotate(guid=F('user__guids___id')), |
113 | 115 | 'children': children, |
| 116 | + 'permissions': API_CONTRIBUTOR_PERMISSIONS, |
| 117 | + 'has_update_permission': node.is_admin_contributor(self.request.user), |
114 | 118 | 'duplicates': detailed_duplicates |
115 | 119 | }) |
116 | 120 |
|
117 | 121 | return context |
118 | 122 |
|
| 123 | + |
119 | 124 | class NodeRemoveNotificationView(View): |
120 | 125 | def post(self, request, *args, **kwargs): |
121 | 126 | selected_ids = request.POST.getlist('selected_notifications') |
@@ -197,6 +202,75 @@ def add_contributor_removed_log(self, node, user): |
197 | 202 | ).save() |
198 | 203 |
|
199 | 204 |
|
| 205 | +class NodeUpdatePermissionsView(NodeMixin, View): |
| 206 | + permission_required = ('osf.view_node', 'osf.change_node') |
| 207 | + raise_exception = True |
| 208 | + redirect_view = NodeRemoveContributorView |
| 209 | + |
| 210 | + def post(self, request, *args, **kwargs): |
| 211 | + data = dict(request.POST) |
| 212 | + contributor_id_to_remove = data.get('remove-user') |
| 213 | + resource = self.get_object() |
| 214 | + |
| 215 | + if contributor_id_to_remove: |
| 216 | + contributor_id = contributor_id_to_remove[0] |
| 217 | + # html renders form into form incorrectly, |
| 218 | + # so this view handles contributors deletion and permissions update |
| 219 | + return self.redirect_view( |
| 220 | + request=request, |
| 221 | + kwargs={'guid': resource.guid, 'user_id': contributor_id} |
| 222 | + ).post(request, user_id=contributor_id) |
| 223 | + |
| 224 | + new_emails_to_add = data.get('new-emails', []) |
| 225 | + new_permissions_to_add = data.get('new-permissions', []) |
| 226 | + |
| 227 | + new_permission_indexes_to_remove = [] |
| 228 | + for email, permission in zip(new_emails_to_add, new_permissions_to_add): |
| 229 | + contributor_user = OSFUser.objects.filter(emails__address=email.lower()).first() |
| 230 | + if not contributor_user: |
| 231 | + new_permission_indexes_to_remove.append(new_emails_to_add.index(email)) |
| 232 | + messages.error(self.request, f'Email {email} is not registered in OSF.') |
| 233 | + continue |
| 234 | + elif resource.is_contributor(contributor_user): |
| 235 | + new_permission_indexes_to_remove.append(new_emails_to_add.index(email)) |
| 236 | + messages.error(self.request, f'User with email {email} is already a contributor.') |
| 237 | + continue |
| 238 | + |
| 239 | + resource.add_contributor_registered_or_not( |
| 240 | + auth=request, |
| 241 | + user_id=contributor_user._id, |
| 242 | + permissions=permission, |
| 243 | + save=True |
| 244 | + ) |
| 245 | + messages.success(self.request, f'User with email {email} was successfully added.') |
| 246 | + |
| 247 | + # should remove permissions of invalid emails because |
| 248 | + # admin can make all existing contributors non admins |
| 249 | + # and enter an invalid email with the only admin permission |
| 250 | + for permission_index in new_permission_indexes_to_remove: |
| 251 | + new_permissions_to_add.pop(permission_index) |
| 252 | + |
| 253 | + updated_permissions = data.get('updated-permissions', []) |
| 254 | + all_permissions = updated_permissions + new_permissions_to_add |
| 255 | + has_admin = list(filter(lambda permission: ADMIN in permission, all_permissions)) |
| 256 | + if not has_admin: |
| 257 | + messages.error(self.request, 'Must be at least one admin on this node.') |
| 258 | + return redirect(self.get_success_url()) |
| 259 | + |
| 260 | + for contributor_permission in updated_permissions: |
| 261 | + guid, permission = contributor_permission.split('-') |
| 262 | + user = OSFUser.load(guid) |
| 263 | + resource.update_contributor( |
| 264 | + user, |
| 265 | + permission, |
| 266 | + resource.get_visible(user), |
| 267 | + request, |
| 268 | + save=True |
| 269 | + ) |
| 270 | + |
| 271 | + return redirect(self.get_success_url()) |
| 272 | + |
| 273 | + |
200 | 274 | class NodeDeleteView(NodeMixin, View): |
201 | 275 | """ Allows authorized users to mark nodes as deleted. |
202 | 276 | """ |
|
0 commit comments