Skip to content

Commit

Permalink
Merge branch 'feature/2204_discontinued_soon_merge_reverted' into dev…
Browse files Browse the repository at this point in the history
…elop
  • Loading branch information
Steven-Eardley committed Aug 7, 2023
2 parents 36fbd5c + 6a87482 commit cd8bf6d
Show file tree
Hide file tree
Showing 22 changed files with 422 additions and 11 deletions.
5 changes: 5 additions & 0 deletions cms/data/notifications.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,8 @@ update_request:publisher:rejected:notify:
short:
Your update request was rejected

journal:assed:discontinuing_soon:notify:
long: |
Journal "{title}" (id: {id}) will discontinue in {days} days.
short:
Journal discontinuing
15 changes: 15 additions & 0 deletions doajtest/testbook/public_site/ToC.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
suite: Public Site
testset: ToC
tests:
- title: Test Correctly Displayed Discontinued Date
context:
role: anonymous
steps:
- step: To prepare to do this test make sure there are 3 journals publically available in DOAJ
one with discontinued date in the past
one with discontinued date in the future
one with discontinued date today
- step: Search for every journal from the list above
results:
- On the ToC of the journal with discontinued date in the past or today - the discontinued date is displayed
- On the ToC of the journal with discontinued date in the future - the discontinued date is not displayed
4 changes: 2 additions & 2 deletions doajtest/unit/api_tests/test_apiv3_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ def test_03_applications(self):
for i in range(5):
a = models.Suggestion()
a.set_owner("owner")
a.set_created(dates.format(dates.after(now, i)))
a.set_created(dates.format(dates.seconds_after(now, i)))
bj = a.bibjson()
bj.title = "Test Suggestion {x}".format(x=i)
bj.add_identifier(bj.P_ISSN, "{x}000-0000".format(x=i))
Expand All @@ -256,7 +256,7 @@ def test_03_applications(self):
for i in range(5):
a = models.Suggestion()
a.set_owner("stranger")
a.set_created(dates.format(dates.after(now, i + 5)))
a.set_created(dates.format(dates.seconds_after(now, i + 5)))
bj = a.bibjson()
bj.title = "Test Suggestion {x}".format(x=i)
bj.add_identifier(bj.P_ISSN, "{x}000-0000".format(x=i))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from portality import models
from portality import constants
from portality.bll import exceptions
from doajtest.helpers import DoajTestCase
from doajtest.fixtures import JournalFixtureFactory, ApplicationFixtureFactory
from portality.events.consumers.journal_discontinuing_soon_notify import JournalDiscontinuingSoonNotify
from doajtest.fixtures import BackgroundFixtureFactory
import time

# Mock required to make application lookup work
@classmethod
def pull_application(cls, id):
app = models.Application(**ApplicationFixtureFactory.make_application_source())
return app

@classmethod
def pull_by_key(cls, key, value):
ed = models.EditorGroup()
acc = models.Account()
acc.set_id('testuser')
acc.set_email("[email protected]")
acc.save(blocking=True)
ed.set_maned(acc.id)
ed.save(blocking=True)

return ed

class TestJournalDiscontinuingSoonNotify(DoajTestCase):
def setUp(self):
super(TestJournalDiscontinuingSoonNotify, self).setUp()
self.pull_application = models.Application.pull
models.Application.pull = pull_application
self.pull_by_key = models.EditorGroup.pull_by_key
models.EditorGroup.pull_by_key = pull_by_key

def tearDown(self):
super(TestJournalDiscontinuingSoonNotify, self).tearDown()
models.Application.pull = self.pull_application
models.EditorGroup.pull_by_key = self.pull_by_key

def test_consumes(self):

event = models.Event("test:event", context={"data" : {"1234"}})
assert not JournalDiscontinuingSoonNotify.consumes(event)

event = models.Event("test:event", context={"data": {}})
assert not JournalDiscontinuingSoonNotify.consumes(event)

event = models.Event(constants.EVENT_JOURNAL_DISCONTINUING_SOON)
assert not JournalDiscontinuingSoonNotify.consumes(event)

event = models.Event(constants.EVENT_JOURNAL_DISCONTINUING_SOON, context = {"journal": {"1234"}, "discontinue_date": "2002-22-02"})
assert JournalDiscontinuingSoonNotify.consumes(event)

def test_consume_success(self):
self._make_and_push_test_context("/")

source = BackgroundFixtureFactory.example()
bj = models.BackgroundJob(**source)
# bj.save(blocking=True)

acc = models.Account()
acc.set_id('testuser')
acc.set_email("[email protected]")
acc.add_role('admin')
acc.save(blocking=True)

source = JournalFixtureFactory.make_journal_source()
journal = models.Journal(**source)
journal.save(blocking=True)

event = models.Event(constants.BACKGROUND_JOB_FINISHED, context={"job" : bj.data, "journal" : journal.id})
JournalDiscontinuingSoonNotify.consume(event)

time.sleep(2)
ns = models.Notification.all()
assert len(ns) == 1

n = ns[0]
assert n.who == acc.id
assert n.created_by == JournalDiscontinuingSoonNotify.ID
assert n.classification == constants.NOTIFICATION_CLASSIFICATION_STATUS
assert n.long is not None
assert n.short is not None
assert n.action is not None
assert not n.is_seen()
77 changes: 77 additions & 0 deletions doajtest/unit/test_task_discontinued_soon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import unittest
import datetime

from doajtest.helpers import DoajTestCase

from portality.core import app
from portality import models
from portality.tasks import find_discontinued_soon
from portality.ui.messages import Messages
from doajtest.fixtures import JournalFixtureFactory

DELTA = app.config.get('DISCONTINUED_DATE_DELTA',1)

class TestDiscontinuedSoon(DoajTestCase):

def _date_to_found(self):
return (datetime.datetime.today() + datetime.timedelta(days=DELTA)).strftime('%Y-%m-%d')

def _date_too_late(self):
return (datetime.datetime.today() + datetime.timedelta(days=DELTA+1)).strftime('%Y-%m-%d')

def test_discontinued_soon_found(self):

# Both these should be found
journal_discontinued_to_found_1 = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True))
journal_discontinued_to_found_1.set_id("1")
jbib = journal_discontinued_to_found_1.bibjson()
jbib.title = "Discontinued Tomorrow 1"
jbib.discontinued_date = self._date_to_found()
journal_discontinued_to_found_1.save(blocking=True)

journal_discontinued_to_found_2 = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True))
journal_discontinued_to_found_2.set_id("2")
jbib = journal_discontinued_to_found_2.bibjson()
jbib.title = "Discontinued Tomorrow 2"
jbib.discontinued_date = self._date_to_found()
journal_discontinued_to_found_2.save(blocking=True)

# that shouldn't be found
journal_discontinued_too_late = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True))
journal_discontinued_too_late.set_id("3")
jbib = journal_discontinued_too_late.bibjson()
jbib.title = "Discontinued In 2 days"
jbib.discontinued_date = self._date_too_late()
journal_discontinued_too_late.save(blocking=True)

job = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask.prepare("system")
task = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask(job)
task.run()

assert len(job.audit) == 2
assert job.audit[0]["message"] == Messages.DISCONTINUED_JOURNAL_FOUND_LOG.format(id="1")
assert job.audit[1]["message"] == Messages.DISCONTINUED_JOURNAL_FOUND_LOG.format(id="2")

def test_discontinued_soon_not_found(self):

# None of these should be found - this one discontinues in 2 days
journal_discontinued_too_late = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True))
journal_discontinued_too_late.set_id("1")
jbib = journal_discontinued_too_late.bibjson()
jbib.title = "Discontinued In 2 days"
jbib.discontinued_date = self._date_too_late()
journal_discontinued_too_late.save(blocking=True)

# this one is not in doaj
journal_not_in_doaj = models.Journal(**JournalFixtureFactory.make_journal_source(in_doaj=False))
journal_not_in_doaj.set_id("2")
jbib = journal_not_in_doaj.bibjson()
jbib.discontinued_date = self._date_to_found()
journal_not_in_doaj.save(blocking=True)

job = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask.prepare("system")
task = find_discontinued_soon.FindDiscontinuedSoonBackgroundTask(job)
task.run()

assert len(job.audit) == 1
assert job.audit[0]["message"] == Messages.NO_DISCONTINUED_JOURNALS_FOUND_LOG
4 changes: 4 additions & 0 deletions portality/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ def form_diff_table_subject_expand(val):

return ", ".join(results)

@app.template_filter("is_in_the_past")
def is_in_the_past(dttm):
return dates.is_before(dttm, dates.today())


#######################################################

Expand Down
4 changes: 3 additions & 1 deletion portality/bll/services/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from portality.events.consumers.journal_editor_group_assigned_notify import JournalEditorGroupAssignedNotify
from portality.events.consumers.application_publisher_inprogress_notify import ApplicationPublisherInprogressNotify
from portality.events.consumers.update_request_publisher_rejected_notify import UpdateRequestPublisherRejectedNotify
from portality.events.consumers.journal_discontinuing_soon_notify import JournalDiscontinuingSoonNotify


class EventsService(object):
Expand All @@ -44,7 +45,8 @@ class EventsService(object):
JournalEditorGroupAssignedNotify,
UpdateRequestPublisherAcceptedNotify,
UpdateRequestPublisherAssignedNotify,
UpdateRequestPublisherRejectedNotify
UpdateRequestPublisherRejectedNotify,
JournalDiscontinuingSoonNotify
]

def __init__(self):
Expand Down
2 changes: 2 additions & 0 deletions portality/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@
EVENT_APPLICATION_EDITOR_GROUP_ASSIGNED = "application:editor_group:assigned"
EVENT_JOURNAL_ASSED_ASSIGNED = "journal:assed:assigned"
EVENT_JOURNAL_EDITOR_GROUP_ASSIGNED = "journal:editor_group:assigned"
EVENT_JOURNAL_DISCONTINUING_SOON = "journal:discontinuing_soon"

NOTIFICATION_CLASSIFICATION_STATUS = "alert"
NOTIFICATION_CLASSIFICATION_STATUS_CHANGE = "status_change"
NOTIFICATION_CLASSIFICATION_ASSIGN = "assign"
NOTIFICATION_CLASSIFICATION_CREATE = "create"
Expand Down
55 changes: 55 additions & 0 deletions portality/events/consumers/journal_discontinuing_soon_notify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ~~JournalDiscontinuingSoonNotify:Consumer~~
import json
import urllib.parse

from portality.util import url_for
from portality.events.consumer import EventConsumer
from portality.core import app
from portality import constants
from portality import models
from portality.bll import DOAJ, exceptions
from portality.lib import edges
from portality import dao

class JournalDiscontinuingSoonNotify(EventConsumer):
ID = "journal:assed:discontinuing_soon:notify"

@classmethod
def consumes(cls, event):
return event.id == constants.EVENT_JOURNAL_DISCONTINUING_SOON and \
event.context.get("journal") is not None and \
event.context.get("discontinue_date") is not None

@classmethod
def consume(cls, event):
journal_id = event.context.get("journal")
discontinued_date = event.context.get("discontinue_date")

journal = models.Journal.pull(journal_id)
if journal is None:
return

if not journal.editor_group:
return

eg = models.EditorGroup.pull_by_key("name", journal.editor_group)
managing_editor = eg.maned
if not managing_editor:
return

# ~~-> Notifications:Service ~~
svc = DOAJ.notificationsService()

notification = models.Notification()
notification.who = managing_editor
notification.created_by = cls.ID
notification.classification = constants.NOTIFICATION_CLASSIFICATION_STATUS
notification.long = svc.long_notification(cls.ID).format(
days=app.config.get('DISCONTINUED_DATE_DELTA',0),
title=journal.bibjson().title,
id=journal.id
)
notification.short = svc.short_notification(cls.ID)
notification.action = url_for("admin.journal_page", journal_id=journal.id)

svc.notify(notification)
26 changes: 24 additions & 2 deletions portality/lib/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,27 @@ def before_now(seconds: int) -> datetime:
return before(now(), seconds)


def after(timestamp, seconds) -> datetime:
def seconds_after(timestamp, seconds) -> datetime:
return timestamp + timedelta(seconds=seconds)


def seconds_after_now(seconds: int):
return seconds_after(datetime.utcnow(), seconds)


def days_after(timestamp, days):
return timestamp + timedelta(days=days)


def days_after_now(days: int):
return days_after(datetime.utcnow(), days)


def eta(since, sofar, total) -> str:
td = (now() - since).total_seconds()
spr = float(td) / float(sofar)
alltime = int(math.ceil(total * spr))
fin = after(since, alltime)
fin = seconds_after(since, alltime)
return format(fin)


Expand Down Expand Up @@ -163,3 +175,13 @@ def day_ranges(fro: datetime, to: datetime) -> 'list[str]':

def human_date(stamp, string_format=FMT_DATE_HUMAN) -> str:
return reformat(stamp, out_format=string_format)

def is_before(mydate, comparison=None):
if comparison is None:
comparison = datetime.utcnow()
if isinstance(mydate, str):
mydate = parse(mydate)
if isinstance(comparison, str):
comparison = parse(comparison)
return mydate < comparison

Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
app_created = application.created_timestamp
for journal in related_journals:
almu = application.last_manual_update_timestamp
almu_adjusted = dates.after(almu, 3600)
almu_adjusted = dates.seconds_after(almu, 3600)

# do a load of reporting prep
jc_ac_diff = int((journal.created_timestamp - app_created).total_seconds())
Expand Down
2 changes: 1 addition & 1 deletion portality/models/v2/journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1131,4 +1131,4 @@ def query(self):
"sort" : [
{"created_date" : {"order" : "desc"}}
]
}
}
4 changes: 4 additions & 0 deletions portality/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@
"anon_export": {"month": "*", "day": "10", "day_of_week": "*", "hour": "6", "minute": "30"},
"old_data_cleanup": {"month": "*", "day": "12", "day_of_week": "*", "hour": "6", "minute": "30"},
"monitor_bgjobs": {"month": "*", "day": "*/6", "day_of_week": "*", "hour": "10", "minute": "0"},
"find_discontinued_soon": {"month": "*", "day": "*", "day_of_week": "*", "hour": "0", "minute": "3"}
}

HUEY_TASKS = {
Expand Down Expand Up @@ -1385,3 +1386,6 @@
# Pages under maintenance

PRESERVATION_PAGE_UNDER_MAINTENANCE = False

# report journals that discontinue in ... days (eg. 1 = tomorrow)
DISCONTINUED_DATE_DELTA = 0
5 changes: 5 additions & 0 deletions portality/static/js/edges/notifications.edge.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ $.extend(true, doaj, {
seen_url: "/dashboard/notifications/{notification_id}/seen",

icons: {
alert: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path d="M224 0c-17.7 0-32 14.3-32 32V51.2C119 66 64 130.6 64 208v18.8c0 47-17.3 92.4-48.5 127.6l-7.4 8.3c-8.4 9.4-10.4 22.9-5.3 34.4S19.4 416 32 416H416c12.6 0 24-7.4 29.2-18.9s3.1-25-5.3-34.4l-7.4-8.3C401.3 319.2 384 273.9 384 226.8V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32zm45.3 493.3c12-12 18.7-28.3 18.7-45.3H224 160c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7z"/>
</svg>`,
finished: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M6 3.5a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 0-1 0v2A1.5 1.5 0 0 0 6.5 14h8a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-8A1.5 1.5 0 0 0 5 3.5v2a.5.5 0 0 0 1 0v-2z"/>
<path fill-rule="evenodd" d="M11.854 8.354a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5H1.5a.5.5 0 0 0 0 1h8.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3z"/>
Expand All @@ -34,6 +38,7 @@ $.extend(true, doaj, {
},

classifications: {
alert: "Requires attention",
finished: "Task has completed",
status_change: "Application status change",
assign: "Assigned to user"
Expand Down
Loading

0 comments on commit cd8bf6d

Please sign in to comment.