Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions admin/nodes/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from django import forms


class AddSystemTagForm(forms.Form):
system_tag_to_add = forms.CharField(label='system_tag_to_add', min_length=1, max_length=1024, required=True)


class RegistrationDateForm(forms.Form):
registered_date = forms.DateTimeField(
widget=forms.DateTimeInput(attrs={'class': 'form-control'}),
Expand Down
5 changes: 5 additions & 0 deletions admin/nodes/templatetags/node_extras.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,8 @@ def get_spam_status(resource):
return mark_safe('<span class="label label-danger">Spam</span>')
elif resource.spam_status == SpamStatus.HAM:
return mark_safe('<span class="label label-success">Ham</span>')


@register.filter
def get_class_name(resource):
return resource.__class__.__name__.lower()
2 changes: 2 additions & 0 deletions admin/nodes/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,7 @@
re_path(r'^(?P<guid>[a-z0-9]+)/update_moderation_state/$', views.NodeUpdateModerationStateView.as_view(), name='node-update-mod-state'),
re_path(r'^(?P<guid>[a-z0-9]+)/resync_datacite/$', views.NodeResyncDataCiteView.as_view(), name='resync-datacite'),
re_path(r'^(?P<guid>[a-z0-9]+)/revert/$', views.NodeRevertToDraft.as_view(), name='revert-to-draft'),
re_path(r'^(?P<guid>[a-z0-9]+)/system_tags/add/$', views.NodeAddSystemTag.as_view(), name='add-system-tag'),
re_path(r'^(?P<guid>[a-z0-9]+)/system_tags/(?P<tag_id>[a-z0-9]+)/remove/$', views.NodeRemoveSystemTag.as_view(), name='remove-system-tag'),
re_path(r'^(?P<guid>[a-z0-9]+)/update_permissions/$', views.NodeUpdatePermissionsView.as_view(), name='update-permissions'),
]
31 changes: 30 additions & 1 deletion admin/nodes/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from admin.base.views import GuidView
from admin.base.forms import GuidForm
from admin.notifications.views import detect_duplicate_notifications, delete_selected_notifications
from admin.nodes.forms import RegistrationDateForm
from admin.nodes.forms import AddSystemTagForm, RegistrationDateForm

from api.share.utils import update_share
from api.caching.tasks import update_storage_usage_cache
Expand Down Expand Up @@ -921,3 +921,32 @@ def post(self, request, *args, **kwargs):
registration = self.get_object()
registration.to_draft()
return redirect(self.get_success_url())


class NodeAddSystemTag(NodeMixin, FormView):
""" Allows authorized users to add system tags to a node.
"""
permission_required = 'osf.change_node'
raise_exception = True
form_class = AddSystemTagForm

def form_valid(self, form):
resource = self.get_object()
system_tag_to_add = form.cleaned_data['system_tag_to_add']
resource.add_system_tag(system_tag_to_add)
resource.save()

return super().form_valid(form)


class NodeRemoveSystemTag(NodeMixin, View):
""" Allows authorized users to remove system tags from a node.
"""
permission_required = 'osf.change_node'
raise_exception = True

def post(self, request, *args, **kwargs):
resource = self.get_object()
tag = resource.system_tags_objects.get(id=kwargs['tag_id'])
resource.remove_tag(tag.name, auth=request.user)
return redirect(self.get_success_url())
2 changes: 2 additions & 0 deletions admin/preprints/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@
re_path(r'^(?P<guid>\w+)/resync_crossref/$', views.PreprintResyncCrossRefView.as_view(), name='resync-crossref'),
re_path(r'^(?P<guid>\w+)/make_published/$', views.PreprintMakePublishedView.as_view(), name='make-published'),
re_path(r'^(?P<guid>\w+)/unwithdraw/$', views.PreprintUnwithdrawView.as_view(), name='unwithdraw'),
re_path(r'^(?P<guid>\w+)/system_tags/add/$', views.PreprintAddSystemTag.as_view(), name='add-system-tag'),
re_path(r'^(?P<guid>\w+)/system_tags/(?P<tag_id>[a-z0-9]+)/remove/$', views.PreprintRemoveSystemTag.as_view(), name='remove-system-tag'),
re_path(r'^(?P<guid>\w+)/update_permissions/$', views.PreprintUpdatePermissionsView.as_view(), name='update-permissions'),
]
14 changes: 13 additions & 1 deletion admin/preprints/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from admin.base.views import GuidView
from admin.base.forms import GuidForm
from admin.nodes.views import NodeRemoveContributorView, NodeUpdatePermissionsView
from admin.nodes.views import NodeRemoveContributorView, NodeAddSystemTag, NodeRemoveSystemTag, NodeUpdatePermissionsView
from admin.preprints.forms import ChangeProviderForm, MachineStateForm
from admin.base.utils import osf_staff_check

Expand Down Expand Up @@ -743,3 +743,15 @@ def post(self, request, *args, **kwargs):

preprint.save()
return redirect(self.get_success_url())


class PreprintAddSystemTag(PreprintMixin, NodeAddSystemTag):
""" Allows authorized users to add system tags to a preprint.
"""
permission_required = 'osf.change_preprint'


class PreprintRemoveSystemTag(PreprintMixin, NodeRemoveSystemTag):
""" Allows authorized users to remove system tags from a preprint.
"""
permission_required = 'osf.change_preprint'
59 changes: 59 additions & 0 deletions admin/templates/nodes/add_system_tags.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{% load node_extras %}
<tr>
<td>System tags</td>
<td>
<div style="display: flex; justify-content: start;">
{% for system_tag in resource.system_tags_objects %}
{% if resource|get_class_name == 'node' or resource|get_class_name == 'registration' %}
<form method="post" action="{% url 'nodes:remove-system-tag' guid=resource.guid tag_id=system_tag.id %}">
{% elif resource|get_class_name == 'preprint' %}
<form method="post" action="{% url 'preprints:remove-system-tag' guid=resource.guid tag_id=system_tag.id %}">
{% else %}
<form method="post" action="{% url 'users:remove-system-tag' guid=resource.guid tag_id=system_tag.id %}">
{% endif %}
<div>
{% csrf_token %}
<div class="modal-footer">
<span>{{ system_tag.name }}</span>
<input class="btn btn-danger" type="submit" value="Remove" />
</div>
</div>
</form>
{% endfor %}
</div>
<br>
<a class="btn btn-default" data-toggle="modal" data-target="#systemTagModal">
Add system tag
</a>
<div class="modal" id="systemTagModal">
<div class="modal-dialog">
<div class="modal-content">
{% if resource|get_class_name == 'node' or resource|get_class_name == 'registration' %}
<form class="well" method="post" action="{% url 'nodes:add-system-tag' guid=resource.guid %}">
{% elif resource|get_class_name == 'preprint' %}
<form class="well" method="post" action="{% url 'preprints:add-system-tag' guid=resource.guid %}">
{% else %}
<form class="well" method="post" action="{% url 'users:add-system-tag' guid=resource.guid %}">
{% endif%}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">x</button>
<h3>Add a system tag to this resource</h3>
</div>
<div class="modal-body">
{% csrf_token %}
<input placeholder="Enter system tag" name="system_tag_to_add">
</div>
<div class="modal-footer">
<input class="btn btn-danger" type="submit" value="Confirm" />
<button type="button" class="btn btn-default"
data-dismiss="modal">
Cancel
</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>

1 change: 1 addition & 0 deletions admin/templates/nodes/node.html
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ <h2>{{ node.type|cut:'osf.'|title }}: <b>{{ node.title }}</b> <a href="{{ node.a
<td>IA url</td>
<td>{{ node.ia_url }}</td>
</tr>
{% include "nodes/add_system_tags.html" with resource=node %}
{% include "nodes/contributors.html" with node=node %}
{% include "nodes/spam_status.html" with resource=node %}
{% include "nodes/draft_registrations.html" with draft_registrations=node.draft_registrations.all %}
Expand Down
1 change: 1 addition & 0 deletions admin/templates/preprints/preprint.html
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ <h2>Preprint: <b>{{ preprint.title }}</b> <a href="{{ preprint.absolute_url }}">
</ul>
</td>
</tr>
{% include "nodes/add_system_tags.html" with resource=preprint %}
{% include "preprints/contributors.html" with preprint=preprint %}
{% include "nodes/spam_status.html" with resource=preprint %}
{% include "preprints/withdraw_request.html" with preprint=preprint %}
Expand Down
35 changes: 0 additions & 35 deletions admin/templates/users/add_system_tags.html

This file was deleted.

2 changes: 1 addition & 1 deletion admin/templates/users/user.html
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ <h2>User: <b>{{ user.username }}</b> <a href="{{ user.absolute_url }}"> ({{user.
{{ user.is_staff }}
</td>
</tr>
{% include "users/add_system_tags.html" with user=user %}
{% include "nodes/add_system_tags.html" with resource=user %}
{% include "nodes/spam_status.html" with resource=user %}
<tr>
<td>Preprints</td>
Expand Down
4 changes: 0 additions & 4 deletions admin/users/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,3 @@ class UserSearchForm(forms.Form):

class MergeUserForm(forms.Form):
user_guid_to_be_merged = forms.CharField(label='user_guid_to_be_merged', min_length=5, max_length=5, required=True) # TODO: Move max to 6 when needed


class AddSystemTagForm(forms.Form):
system_tag_to_add = forms.CharField(label='system_tag_to_add', min_length=1, max_length=1024, required=True)
1 change: 1 addition & 0 deletions admin/users/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
re_path(r'^(?P<guid>[a-z0-9]+)/get_claim_urls/$', views.GetUserClaimLinks.as_view(), name='get-claim-urls'),
re_path(r'^(?P<guid>[a-z0-9]+)/two-factor/disable/$', views.User2FactorDeleteView.as_view(), name='remove2factor'),
re_path(r'^(?P<guid>[a-z0-9]+)/system_tags/add/$', views.UserAddSystemTag.as_view(), name='add-system-tag'),
re_path(r'^(?P<guid>[a-z0-9]+)/system_tags/(?P<tag_id>[a-z0-9]+)/remove/$', views.UserRemoveSystemTag.as_view(), name='remove-system-tag'),
re_path(r'^(?P<guid>[a-z0-9]+)/get_confirmation/$', views.GetUserConfirmationLink.as_view(), name='get-confirmation'),
re_path(r'^(?P<guid>[a-z0-9]+)/get_reset_password/$', views.GetPasswordResetLink.as_view(), name='get-reset-password'),
re_path(r'^(?P<guid>[a-z0-9]+)/reindex_elastic_user/$', views.UserReindexElastic.as_view(),
Expand Down
18 changes: 7 additions & 11 deletions admin/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
from admin.users.forms import (
EmailResetForm,
UserSearchForm,
MergeUserForm,
AddSystemTagForm
MergeUserForm
)
from admin.nodes.views import NodeAddSystemTag, NodeRemoveSystemTag
from admin.base.views import GuidView
from api.users.services import send_password_reset_email
from website.settings import DOMAIN
Expand Down Expand Up @@ -383,20 +383,16 @@ def post(self, request, *args, **kwargs):
return redirect(self.get_success_url())


class UserAddSystemTag(UserMixin, FormView):
class UserAddSystemTag(UserMixin, NodeAddSystemTag):
""" Allows authorized users to add system tags to a user.
"""
permission_required = 'osf.change_osfuser'
raise_exception = True
form_class = AddSystemTagForm

def form_valid(self, form):
user = self.get_object()
system_tag_to_add = form.cleaned_data['system_tag_to_add']
user.add_system_tag(system_tag_to_add)
user.save()

return super().form_valid(form)
class UserRemoveSystemTag(UserMixin, NodeRemoveSystemTag):
""" Allows authorized users to remove system tags from a user.
"""
permission_required = 'osf.change_osfuser'


class UserMergeAccounts(UserMixin, FormView):
Expand Down
25 changes: 18 additions & 7 deletions osf/models/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,13 +991,17 @@ def all_tags(self):
# Tag's default manager only returns non-system tags, so we can't use self.tags
return Tag.all_tags.filter(abstractnode_tagged=self)

@property
def system_tags_objects(self):
return self.all_tags.filter(system=True)

@property
def system_tags(self):
"""The system tags associated with this node. This currently returns a list of string
names for the tags, for compatibility with v1. Eventually, we can just return the
QuerySet.
"""
return self.all_tags.filter(system=True).values_list('name', flat=True)
return self.system_tags_objects.values_list('name', flat=True)

# Override Taggable
def add_tag_log(self, tag, auth):
Expand All @@ -1019,10 +1023,15 @@ def on_tag_added(self, tag):
def remove_tag(self, tag, auth, save=True):
if not tag:
raise InvalidTagError
elif not self.tags.filter(name=tag).exists():

tag_obj = self.tags.filter(name=tag).first() or self.all_tags.filter(name=tag).first()
if not tag_obj:
raise TagNotFoundError

if tag_obj.system:
# because system tags are hidden by default TagManager
tag_obj.delete()
else:
tag_obj = Tag.objects.get(name=tag)
self.tags.remove(tag_obj)
self.add_log(
action=NodeLog.TAG_REMOVED,
Expand All @@ -1034,10 +1043,12 @@ def remove_tag(self, tag, auth, save=True):
auth=auth,
save=False,
)
if save:
self.save()
self.update_search()
return True

if save:
self.save()

self.update_search()
return True

def remove_tags(self, tags, auth, save=True):
"""
Expand Down
25 changes: 18 additions & 7 deletions osf/models/preprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -1107,13 +1107,17 @@ def all_tags(self):
# Tag's default manager only returns non-system tags, so we can't use self.tags
return Tag.all_tags.filter(preprint_tagged=self)

@property
def system_tags_objects(self):
return self.all_tags.filter(system=True)

@property
def system_tags(self):
"""The system tags associated with this node. This currently returns a list of string
names for the tags, for compatibility with v1. Eventually, we can just return the
QuerySet.
"""
return self.all_tags.filter(system=True).values_list('name', flat=True)
return self.system_tags_objects.values_list('name', flat=True)

# Override Taggable
def add_tag_log(self, tag, auth):
Expand All @@ -1134,10 +1138,15 @@ def on_tag_added(self, tag):
def remove_tag(self, tag, auth, save=True):
if not tag:
raise InvalidTagError
elif not self.tags.filter(name=tag).exists():

tag_obj = self.tags.filter(name=tag).first() or self.all_tags.filter(name=tag).first()
if not tag_obj:
raise TagNotFoundError

if tag_obj.system:
# because system tags are hidden by default TagManager
tag_obj.delete()
else:
tag_obj = Tag.objects.get(name=tag)
self.tags.remove(tag_obj)
self.add_log(
action=PreprintLog.TAG_REMOVED,
Expand All @@ -1148,10 +1157,12 @@ def remove_tag(self, tag, auth, save=True):
auth=auth,
save=False,
)
if save:
self.save()
update_or_enqueue_on_preprint_updated(preprint_id=self._id, saved_fields=['tags'])
return True

if save:
self.save()

update_or_enqueue_on_preprint_updated(preprint_id=self._id, saved_fields=['tags'])
return True

@require_permission([WRITE])
def set_supplemental_node(self, node, auth, save=False, ignore_node_permissions=False, **kwargs):
Expand Down
Loading
Loading