Skip to content

Commit 9324a15

Browse files
committed
add embargo report to admin
1 parent c9dc568 commit 9324a15

6 files changed

Lines changed: 238 additions & 9 deletions

File tree

admin/nodes/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
re_path(r'^flagged_spam$', views.NodeFlaggedSpamList.as_view(), name='flagged-spam'),
99
re_path(r'^known_spam$', views.NodeKnownSpamList.as_view(), name='known-spam'),
1010
re_path(r'^known_ham$', views.NodeKnownHamList.as_view(), name='known-ham'),
11+
re_path(r'^embargo_report/$', views.EmbargoReportView.as_view(), name='embargo-report'),
1112
re_path(r'^doi_backlog_list/$', views.DoiBacklogListView.as_view(), name='doi-backlog-list'),
1213
re_path(r'^approval_backlog_list/$', views.ApprovalBacklogListView.as_view(), name='approval-backlog-list'),
1314
re_path(r'^confirm_approve_backlog_list/$', views.ConfirmApproveBacklogView.as_view(), name='confirm-approve-backlog-list'),

admin/nodes/views.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
View,
1717
FormView,
1818
ListView,
19+
TemplateView
1920
)
21+
from django.core.paginator import Paginator, InvalidPage
2022

2123
from admin.base.forms import GuidForm
2224
from admin.base.utils import change_embargo_date
@@ -39,6 +41,7 @@
3941
SpamStatus,
4042
TrashedFile
4143
)
44+
from osf.models.sanctions import Embargo
4245
from osf.models.admin_log_entry import (
4346
update_admin_log,
4447
NODE_REMOVED,
@@ -474,6 +477,54 @@ def get_context_data(self, **kwargs):
474477
}
475478

476479

480+
class EmbargoReportView(PermissionRequiredMixin, TemplateView):
481+
"""Report view for inspecting current and overdue embargoed registrations.
482+
483+
Shows:
484+
- pending embargoes that should have been activated
485+
- active embargoes that are past their end date
486+
- upcoming active embargoes
487+
"""
488+
template_name = 'nodes/embargo_report.html'
489+
permission_required = 'osf.view_registration'
490+
raise_exception = True
491+
492+
def get_context_data(self, **kwargs):
493+
context = super().get_context_data(**kwargs)
494+
pending_embargoes = Embargo.objects.pending_embargoes().select_related('initiated_by')
495+
active_embargoes = Embargo.objects.active_embargoes().select_related('initiated_by')
496+
497+
pending_overdue_embargoes = [
498+
embargo for embargo in pending_embargoes
499+
if embargo.should_be_embargoed
500+
]
501+
502+
overdue_embargoes = [
503+
embargo for embargo in active_embargoes
504+
if embargo.should_be_completed
505+
]
506+
507+
upcoming_queryset = active_embargoes.filter(
508+
end_date__gte=timezone.now(),
509+
).order_by('end_date')
510+
511+
page_number = self.request.GET.get('page') or 1
512+
paginator = Paginator(upcoming_queryset, 10)
513+
try:
514+
upcoming_page = paginator.page(page_number)
515+
except InvalidPage:
516+
upcoming_page = paginator.page(1)
517+
518+
context.update({
519+
'now': timezone.now(),
520+
'pending_overdue_embargoes': pending_overdue_embargoes,
521+
'overdue_embargoes': overdue_embargoes,
522+
'upcoming_embargoes': upcoming_page.object_list,
523+
'upcoming_page': upcoming_page,
524+
})
525+
return context
526+
527+
477528
class ConfirmApproveBacklogView(RegistrationListView):
478529
template_name = 'nodes/registration_approval_list.html'
479530
permission_required = 'osf.view_registrationapproval'

admin/templates/base.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
<li><a href="{% url 'nodes:ia-backlog-list' %}"><i class='fa fa-link'></i> <span>IA Backlog</span></a></li>
170170
<li><a href="{% url 'nodes:doi-backlog-list' %}"><i class='fa fa-link'></i> <span>DOI Backlog</span></a></li>
171171
<li><a href="{% url 'nodes:approval-backlog-list' %}"><i class='fa fa-link'></i> <span>Approval Backlog</span></a></li>
172+
<li><a href="{% url 'nodes:embargo-report' %}"><i class='fa fa-link'></i> <span>Embargo Report</span></a></li>
172173
</ul>
173174
</div>
174175
{% endif %}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
{% extends "base.html" %}
2+
{% load node_extras %}
3+
4+
{% block content %}
5+
<div class="page-header">
6+
<h1>Embargo Report</h1>
7+
</div>
8+
9+
<h2>Upcoming Active Embargoes</h2>
10+
<table class="table table-striped table-bordered table-hover">
11+
<thead>
12+
<tr>
13+
<th>Registration</th>
14+
<th>Embargo ID</th>
15+
<th>State</th>
16+
<th>Embargo Start</th>
17+
<th>Embargo End</th>
18+
<th>Initiated By</th>
19+
</tr>
20+
</thead>
21+
{% include "util/pagination.html" with items=upcoming_page status='' pagin=False order='' %}
22+
<tbody>
23+
{% for embargo in upcoming_embargoes %}
24+
{% with registration=embargo.registrations.first %}
25+
{% if registration %}
26+
<tr>
27+
<td>
28+
<a href="{{ registration | reverse_node }}">
29+
{{ registration.title | truncatechars:30 }}
30+
</a>
31+
</td>
32+
<td>{{ embargo.id }}</td>
33+
<td>{{ embargo.state }}</td>
34+
<td>{{ embargo.initiation_date|date:"F j, Y P" }}</td>
35+
<td>{{ embargo.end_date|date:"F j, Y P" }}</td>
36+
<td>
37+
{% if embargo.initiated_by %}
38+
<a href="{{ embargo.initiated_by | reverse_user }}">
39+
{{ embargo.initiated_by.fullname }}
40+
</a>
41+
{% else %}
42+
&mdash;
43+
{% endif %}
44+
</td>
45+
</tr>
46+
{% endif %}
47+
{% endwith %}
48+
{% empty %}
49+
<tr>
50+
<td colspan="6">No active embargoes found.</td>
51+
</tr>
52+
{% endfor %}
53+
</tbody>
54+
</table>
55+
56+
<h2>Pending Embargoes Past Pending Window</h2>
57+
<p>These embargoes are still awaiting approval but have passed the automatic activation window.</p>
58+
<table class="table table-striped table-bordered table-hover">
59+
<thead>
60+
<tr>
61+
<th>Registration</th>
62+
<th>Embargo ID</th>
63+
<th>State</th>
64+
<th>Embargo Initiation</th>
65+
<th>Embargo End</th>
66+
<th>Initiated By</th>
67+
</tr>
68+
</thead>
69+
<tbody>
70+
{% for embargo in pending_overdue_embargoes %}
71+
{% with registration=embargo.registrations.first %}
72+
{% if registration %}
73+
<tr>
74+
<td>
75+
<a href="{{ registration | reverse_node }}">
76+
{{ registration.title | truncatechars:30 }}
77+
</a>
78+
</td>
79+
<td>{{ embargo.id }}</td>
80+
<td>{{ embargo.state }}</td>
81+
<td>{{ embargo.initiation_date|date:"F j, Y P" }}</td>
82+
<td>{{ embargo.end_date|date:"F j, Y P" }}</td>
83+
<td>
84+
{% if embargo.initiated_by %}
85+
<a href="{{ embargo.initiated_by | reverse_user }}">
86+
{{ embargo.initiated_by.fullname }}
87+
</a>
88+
{% else %}
89+
&mdash;
90+
{% endif %}
91+
</td>
92+
</tr>
93+
{% endif %}
94+
{% endwith %}
95+
{% empty %}
96+
<tr>
97+
<td colspan="6">No pending embargoes past the pending window.</td>
98+
</tr>
99+
{% endfor %}
100+
</tbody>
101+
</table>
102+
103+
<h2>Active Embargoes Past Pending Window</h2>
104+
<p>These embargoes have an end date in the past but the embargo is still marked as active.</p>
105+
<table class="table table-striped table-bordered table-hover">
106+
<thead>
107+
<tr>
108+
<th>Registration</th>
109+
<th>Embargo ID</th>
110+
<th>State</th>
111+
<th>Embargo End</th>
112+
<th>Is Registration Public?</th>
113+
<th>Initiated By</th>
114+
</tr>
115+
</thead>
116+
<tbody>
117+
{% for embargo in overdue_embargoes %}
118+
{% with registration=embargo.registrations.first %}
119+
{% if registration %}
120+
<tr>
121+
<td>
122+
<a href="{{ registration | reverse_node }}">
123+
{{ registration.title | truncatechars:30 }}
124+
</a>
125+
</td>
126+
<td>{{ embargo.id }}</td>
127+
<td>{{ embargo.state }}</td>
128+
<td>{{ embargo.end_date|date:"F j, Y P" }}</td>
129+
<td>
130+
{% if registration.is_public %}
131+
Yes
132+
{% else %}
133+
No
134+
{% endif %}
135+
</td>
136+
<td>
137+
{% if embargo.initiated_by %}
138+
<a href="{{ embargo.initiated_by | reverse_user }}">
139+
{{ embargo.initiated_by.fullname }}
140+
</a>
141+
{% else %}
142+
&mdash;
143+
{% endif %}
144+
</td>
145+
</tr>
146+
{% endif %}
147+
{% endwith %}
148+
{% empty %}
149+
<tr>
150+
<td colspan="6">No overdue active embargoes found.</td>
151+
</tr>
152+
{% endfor %}
153+
</tbody>
154+
</table>
155+
156+
{% endblock %}
157+

osf/models/sanctions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,17 @@ def _email_template_context(self, user, node, is_authorizer=False, urls=None):
456456
return {}
457457

458458

459+
class EmbargoManager(models.Manager):
460+
461+
def pending_embargoes(self):
462+
"""Embargoes that are still awaiting admin approval."""
463+
return self.filter(state=self.model.UNAPPROVED)
464+
465+
def active_embargoes(self):
466+
"""Embargoes that have been approved and are currently in effect."""
467+
return self.filter(state=self.model.APPROVED)
468+
469+
459470
class Embargo(SanctionCallbackMixin, EmailApprovableSanction):
460471
"""Embargo object for registrations waiting to go public."""
461472
SANCTION_TYPE = SanctionTypes.EMBARGO
@@ -472,6 +483,8 @@ class Embargo(SanctionCallbackMixin, EmailApprovableSanction):
472483
initiated_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.CASCADE)
473484
for_existing_registration = models.BooleanField(default=False)
474485

486+
objects = EmbargoManager()
487+
475488
@property
476489
def is_completed(self):
477490
return self.state == self.COMPLETED
@@ -497,6 +510,17 @@ def embargo_end_date(self):
497510
def pending_registration(self):
498511
return not self.for_existing_registration and self.is_pending_approval
499512

513+
@property
514+
def should_be_embargoed(self):
515+
return (
516+
(timezone.now() - self.initiation_date) >= osf_settings.EMBARGO_PENDING_TIME
517+
and not self.is_deleted
518+
)
519+
520+
@property
521+
def should_be_completed(self):
522+
return self.end_date and self.end_date < timezone.now() and not self.is_deleted
523+
500524
def _get_registration(self):
501525
return self.registrations.first()
502526

scripts/embargo_registrations.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828

2929

3030
def main(dry_run=True):
31-
pending_embargoes = Embargo.objects.filter(state=Embargo.UNAPPROVED)
31+
pending_embargoes = Embargo.objects.pending_embargoes()
3232
for embargo in pending_embargoes:
33-
if should_be_embargoed(embargo):
33+
if embargo.should_be_embargoed:
3434
if dry_run:
3535
logger.warning('Dry run mode')
3636
try:
@@ -77,9 +77,9 @@ def main(dry_run=True):
7777

7878
transaction.savepoint_rollback(sid)
7979

80-
active_embargoes = Embargo.objects.filter(state=Embargo.APPROVED)
80+
active_embargoes = Embargo.objects.active_embargoes()
8181
for embargo in active_embargoes:
82-
if embargo.end_date < timezone.now() and not embargo.is_deleted:
82+
if embargo.should_be_completed:
8383
if dry_run:
8484
logger.warning('Dry run mode')
8585
parent_registration = Registration.objects.get(embargo=embargo)
@@ -117,11 +117,6 @@ def main(dry_run=True):
117117
transaction.savepoint_rollback(sid)
118118

119119

120-
def should_be_embargoed(embargo):
121-
"""Returns true if embargo was initiated more than 48 hours prior."""
122-
return (timezone.now() - embargo.initiation_date) >= settings.EMBARGO_PENDING_TIME and not embargo.is_deleted
123-
124-
125120
@celery_app.task(name='scripts.embargo_registrations')
126121
def run_main(dry_run=True):
127122
if not dry_run:

0 commit comments

Comments
 (0)