Ejemplo n.º 1
0
    def setUp(self):
        self.c = Client()
        self.journal = logic.journal()
        an_hour_ago = utils.utcnow() - timedelta(hours=1)
        many_hours_ago = an_hour_ago - timedelta(hours=999)
        fmt = utils.ymdhms
        self.article_data_list = [
            {'title': 'foo',
             'status': 'vor',
             'version': 1,
             'doi': "10.7554/eLife.00001",
             'journal': self.journal,
             'pub-date': fmt(an_hour_ago),
             },

            {'title': 'bar',
             'status': 'vor',
             'version': 1,
             'doi': "10.7554/eLife.00002",
             'journal': self.journal,
             'pub-date': fmt(many_hours_ago),
             },

            {'title': 'baz',
             'version': 1,
             'status': 'poa', # **
             'doi': "10.7554/eLife.00003",
             'journal': self.journal,
             'pub-date': fmt(an_hour_ago),
             }
        ]
        [logic.add_or_update_article(**article_data) for article_data in self.article_data_list]
Ejemplo n.º 2
0
    def setUp(self):
        self.c = Client()
        an_hour_ago = utils.utcnow() - timedelta(hours=1)
        many_hours_ago = an_hour_ago - timedelta(hours=999)
        fmt = utils.ymdhms
        self.article_data_list = [
            {'title': 'foo',
             'status': 'vor',
             'version': 1,
             'doi': "10.7554/eLife.00001",
             'pub-date': fmt(an_hour_ago),
             },

            {'title': 'bar',
             'status': 'vor',
             'version': 1,
             'doi': "10.7554/eLife.00002",
             'pub-date': fmt(many_hours_ago),
             },

            {'title': 'baz',
             'version': 1,
             'status': 'poa', # **
             'doi': "10.7554/eLife.00003",
             'pub-date': fmt(an_hour_ago),
             }
        ]
        [self.add_or_update_article(**article_data) for article_data in self.article_data_list]
Ejemplo n.º 3
0
def add(art, event, value=None, datetime_event=None):
    utils.ensure(art, "need art")
    datetime_event = datetime_event or utils.utcnow()
    struct = {
        'event': event,
        'value': str(value),
        'datetime_event': datetime_event
    }
    create = update = True
    ae, created, updated = \
        create_or_update(models.ArticleEvent, struct, ['article', 'event', 'datetime_event'], create, update, article=art)
    return ae
Ejemplo n.º 4
0
 def test_ingest_from_cli(self):
     "ingest script requires the --ingest flag and a source of data"
     args = [self.nom, '--ingest', '--id', self.msid, '--version', self.version, self.ajson_fixture1]
     errcode, stdout = self.call_command(*args)
     self.assertEqual(errcode, 0)
     # article has been ingested
     self.assertEqual(models.ArticleVersion.objects.count(), 1)
     # message returned is json encoded with all the right keys and values
     result = json.loads(stdout.getvalue())
     self.assertTrue(utils.has_all_keys(result, ['status', 'id', 'datetime']))
     self.assertEqual(result['status'], 'ingested')
     # the date and time is roughly the same as right now, ignoring microseconds
     expected_datetime = utils.ymdhms(utils.utcnow())
     self.assertEqual(result['datetime'][:20], expected_datetime[:20])
     self.assertEqual(result['datetime'][-6:], expected_datetime[-6:])
Ejemplo n.º 5
0
 def test_ingest_from_cli(self):
     "ingest script requires the --ingest flag and a source of data"
     args = [
         self.nom, '--ingest', '--id', self.msid, '--version', self.version,
         self.ajson_fixture1
     ]
     errcode, stdout = self.call_command(*args)
     self.assertEqual(errcode, 0)
     # article has been ingested
     self.assertEqual(models.ArticleVersion.objects.count(), 1)
     # message returned is json encoded with all the right keys and values
     result = json.loads(stdout)
     self.assertTrue(
         utils.has_all_keys(result, ['status', 'id', 'datetime']))
     self.assertEqual(result['status'], 'ingested')
     # the date and time is roughly the same as right now, ignoring microseconds
     expected_datetime = utils.utcnow()
     actual_datetime = utils.todt(result['datetime'])
     delta = expected_datetime - actual_datetime
     threshold = 2  # seconds
     self.assertTrue(delta.seconds <= threshold)
Ejemplo n.º 6
0
 def test_utcnow(self):
     "utcnow returns a UTC datetime"
     # TODO: this test could be improved
     now = utils.utcnow()
     self.assertEqual(now.tzinfo, pytz.utc)
Ejemplo n.º 7
0
    def test_only_most_recent_article_versions_returned(self):
        an_hour_ago = utils.utcnow() - timedelta(hours=1)
        many_hours_ago = an_hour_ago - timedelta(hours=999)
        fmt = utils.ymdhms
        article_data_list = [
            {'title': 'foo',
             'version': 1,
             'doi': "10.7554/eLife.00001",
             'pub-date': fmt(an_hour_ago),
             },


            {'title': 'bar',
             'version': 1,
             'doi': "10.7554/eLife.00002",
             'pub-date': fmt(many_hours_ago),
             },
            {'title': 'bar',
             'version': 2,
             'doi': "10.7554/eLife.00002",
             'pub-date': fmt(many_hours_ago - timedelta(hours=1)),
             'update': fmt(many_hours_ago - timedelta(hours=1)),
             },
            {'title': 'bar',
             'version': 3,
             'doi': "10.7554/eLife.00002",
             'pub-date': fmt(many_hours_ago - timedelta(hours=2)),
             'update': fmt(many_hours_ago - timedelta(hours=2)),
             },


            {'title': 'baz',
             'version': 1,
             'doi': "10.7554/eLife.00003",
             'pub-date': fmt(an_hour_ago + timedelta(minutes=5)),
             },
            {'title': 'baz',
             'version': 2,
             'doi': "10.7554/eLife.00003",
             'pub-date': fmt(an_hour_ago + timedelta(minutes=10)),
             'update': fmt(an_hour_ago + timedelta(minutes=10)),
             }

        ]
        [self.add_or_update_article(**article_data) for article_data in article_data_list]

        self.assertEqual(models.Article.objects.count(), 3)
        self.assertEqual(models.ArticleVersion.objects.count(), 6)

        total, avlist = logic.latest_article_version_list()
        self.assertEqual(total, 3)
        self.assertEqual(len(avlist), 3)

        expected_version_order = [
            ('10.7554/eLife.00003', 2), # published less than an hour ago
            ('10.7554/eLife.00001', 1), # published an hour ago
            ('10.7554/eLife.00002', 3), # published many hours ago
        ]

        for av, expected in zip(avlist, expected_version_order):
            self.assertEqual(av.article.doi, expected[0])
            self.assertEqual(av.version, expected[1])
Ejemplo n.º 8
0
def _publish(msid, version, force=False):
    """attach a `datetime_published` value to an article version. if none provided, use RIGHT NOW.
    you cannot publish an already published article version unless force==True"""
    try:
        av = models.ArticleVersion.objects.get(article__manuscript_id=msid, version=version)
        if av.published():
            if not force:
                raise StateError("refusing to publish an already published article version")

        # NOTE: we don't use any other article fragments for determining the publication date

        # except the xml->json fragment.
        raw_data = fragments.get(av, XML2JSON)

        # the json *will always* have a published date if v1 ...
        if version == 1:
            # pull that published date from the stored (but unpublished) article-json
            # and set the pub-date on the ArticleVersion object
            datetime_published = utils.todt(raw_data.get('published'))
            if not datetime_published:
                raise StateError("found 'published' value in article-json, but it's either null or unparsable as a datetime")

        else:
            # but *not* if it's > v1. in this case, we generate one.
            if av.published() and force:
                # this article version is already published and a force publish request has been sent
                if False and 'versionDate' in raw_data: # fail this case for now.
                    # FUTURE CASE: when a 'versionDate' value is present in the article-json, use that.
                    # as of 2016-10-21 version history IS NOT captured in the xml,
                    # it won't be parsed by the bot-lax-adaptor and it
                    # won't find it's way here. this is a future-case only.
                    datetime_published = utils.todt(raw_data['versionDate'])
                    if not datetime_published:
                        raise StateError("found 'versionDate' value in article-json, but it's either null or unparseable as a datetime")
                else:
                    # CURRENT CASE
                    # preserve the existing pubdate set by lax. ignore anything given in the ajson.
                    # if the pubdate for an article is to change, it must come from the xml (see above case)
                    datetime_published = av.datetime_published
            else:
                # CURRENT CASE
                # this article version hasn't been published yet. use a value of RIGHT NOW as the published date.
                datetime_published = utils.utcnow()

        av.datetime_published = datetime_published
        av.save()

        # merge the fragments we have available and make them available for serving
        # allow errors when the publish operation is being forced
        fragments.merge_if_valid(av, quiet=force)

        # notify event bus that article change has occurred
        transaction.on_commit(partial(events.notify, av.article))

        return av

    except ValidationError:
        raise StateError("refusing to publish an article '%sv%s' with invalid article-json" % (msid, version))

    except models.ArticleFragment.DoesNotExist:
        raise StateError("no 'xml->json' fragment found. being strict and failing this publish. please INGEST!")

    except models.ArticleVersion.DoesNotExist:
        # attempted to publish an article that doesn't exist ...
        raise StateError("refusing to publish an article '%sv%s' that doesn't exist" % (msid, version))
Ejemplo n.º 9
0
def _publish(msid, version, force=False) -> models.ArticleVersion:
    """attach a `datetime_published` value to an article version. if none provided, use RIGHT NOW.
    you cannot publish an already published article version unless force==True"""
    try:
        av = models.ArticleVersion.objects.get(article__manuscript_id=msid,
                                               version=version)
        if av.published():
            if not force:
                raise StateError(
                    codes.ALREADY_PUBLISHED,
                    "refusing to publish an already published article version")

        # NOTE: we don't use any other article fragments for determining the publication date
        # except the xml->json fragment.
        raw_data = fragments.get(av, XML2JSON).fragment

        # the json *will always* have a published date if v1 ...
        if version == 1:
            # pull that published date from the stored (but unpublished) article-json
            # and set the pub-date on the ArticleVersion object
            datetime_published = utils.todt(raw_data.get('published'))
            if not datetime_published:
                raise StateError(
                    codes.PARSE_ERROR,
                    "found 'published' value in article-json, but it's either null or unparsable as a date+time"
                )

        else:
            # but *not* if it's > v1. in this case, we generate one.
            if av.published() and force:
                # this article version is already published and a force publish request has been sent
                if False and 'versionDate' in raw_data:  # fail this case for now.
                    # FUTURE CASE: when a 'versionDate' value is present in the article-json, use that.
                    # as of 2016-10-21 version history IS NOT captured in the xml,
                    # it won't be parsed by the bot-lax-adaptor and it
                    # won't find it's way here. this is a future-case only.
                    datetime_published = utils.todt(raw_data['versionDate'])
                    if not datetime_published:
                        raise StateError(
                            codes.PARSE_ERROR,
                            "found 'versionDate' value in article-json, but it's either null or unparseable as a datetime"
                        )
                else:
                    # CURRENT CASE
                    # preserve the existing pubdate set by lax. ignore anything given in the ajson.
                    # if the pubdate for an article is to change, it must come from the xml (see above case)
                    datetime_published = av.datetime_published
            else:
                # CURRENT CASE
                # this article version hasn't been published yet. use a value of RIGHT NOW as the published date.
                datetime_published = utils.utcnow()

        av.datetime_published = datetime_published
        av.save()

        events.ajson_publish_events(av, force)

        # merge the fragments we have available and make them available for serving.
        # allow errors when the publish operation is being forced.
        fragments.set_article_json(
            av, quiet=False if settings.VALIDATE_FAILS_FORCE else force)

        # notify event bus that article change has occurred
        transaction.on_commit(partial(aws_events.notify_all, av))

        return av

    except ValidationError as err:
        # the problem isn't that the ajson is invalid, it's that we've allowed invalid ajson into the system
        raise StateError(
            codes.INVALID,
            "refusing to publish an article '%sv%s' with invalid article-json: %s"
            % (msid, version, err), err)

    except models.ArticleFragment.DoesNotExist:
        raise StateError(
            codes.NO_RECORD,
            "no 'xml->json' fragment found. being strict and failing this publish. please INGEST!"
        )

    except models.ArticleVersion.DoesNotExist:
        # attempted to publish an article that doesn't exist ...
        raise StateError(
            codes.NO_RECORD,
            "refusing to publish an article '%sv%s' that doesn't exist" %
            (msid, version))
Ejemplo n.º 10
0
    def test_only_most_recent_article_versions_returned(self):
        an_hour_ago = utils.utcnow() - timedelta(hours=1)
        many_hours_ago = an_hour_ago - timedelta(hours=999)
        fmt = utils.ymdhms
        article_data_list = [
            {'title': 'foo',
             'version': 1,
             'doi': "10.7554/eLife.00001",
             'pub-date': fmt(an_hour_ago),
             },


            {'title': 'bar',
             'version': 1,
             'doi': "10.7554/eLife.00002",
             'pub-date': fmt(many_hours_ago),
             },
            {'title': 'bar',
             'version': 2,
             'doi': "10.7554/eLife.00002",
             'pub-date': fmt(many_hours_ago - timedelta(hours=1)),
             'update': fmt(many_hours_ago - timedelta(hours=1)),
             },
            {'title': 'bar',
             'version': 3,
             'doi': "10.7554/eLife.00002",
             'pub-date': fmt(many_hours_ago - timedelta(hours=2)),
             'update': fmt(many_hours_ago - timedelta(hours=2)),
             },


            {'title': 'baz',
             'version': 1,
             'doi': "10.7554/eLife.00003",
             'pub-date': fmt(an_hour_ago + timedelta(minutes=5)),
             },
            {'title': 'baz',
             'version': 2,
             'doi': "10.7554/eLife.00003",
             'pub-date': fmt(an_hour_ago + timedelta(minutes=10)),
             'update': fmt(an_hour_ago + timedelta(minutes=10)),
             }

        ]
        [logic.add_or_update_article(**article_data) for article_data in article_data_list]

        self.assertEqual(models.Article.objects.count(), 3)
        self.assertEqual(models.ArticleVersion.objects.count(), 6)

        avlist = logic.latest_article_versions()
        self.assertEqual(len(avlist), 3)

        expected_version_order = [
            ('10.7554/eLife.00003', 2), # published less than an hour ago
            ('10.7554/eLife.00001', 1), # published an hour ago
            ('10.7554/eLife.00002', 3), # published many hours ago
        ]

        for av, expected in zip(avlist, expected_version_order):
            self.assertEqual(av.article.doi, expected[0])
            self.assertEqual(av.version, expected[1])