예제 #1
0
    def test_article_publish_v2_forced(self):
        "an unpublished v2 article can be successfully published again, if forced"
        # ingest and publish the v1
        _, _, av = ajson_ingestor.ingest(self.ajson)
        ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # modify and ingest+publish a v2
        self.ajson['article']['version'] = 2
        _, _, av2 = ajson_ingestor.ingest_publish(self.ajson)
        av2 = self.freshen(av2)
        self.assertTrue(av2.published())

        # the v2 should have been published normally.
        self.assertEqual(utils.ymd(datetime.now()), utils.ymd(av2.datetime_published))

        # give the article-json a 'versionDate' - this won't ordinarily happen until further down the line
        # but lets embed this logic while it's still fresh in everybody's heads.

        # modify the versionDate of the v2 and ingest+publish again
        yesterday = datetime.now() - timedelta(days=1)
        self.ajson['article']['versionDate'] = yesterday
        _, _, av2v2 = ajson_ingestor.ingest_publish(self.ajson, force=True)
        av2v2 = self.freshen(av2v2)
        self.assertEqual(utils.ymd(yesterday), utils.ymd(av2v2.datetime_published))
예제 #2
0
    def test_article_publish_v2_forced2(self):
        "a PUBLISHED v2 article can be successfully published (again), if forced"
        av = ajson_ingestor.ingest(self.ajson)
        ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # modify and ingest+publish a v2
        self.ajson['article']['version'] = 2
        # there is a versionDate here, but because we're not forcing it, it doesn't get looked for
        # lax is the distributor of non-v1 pub dates. this may find their way into xml later, but
        # they will always come from lax.
        av2 = ajson_ingestor.ingest_publish(self.ajson)
        av2 = self.freshen(av2)
        self.assertTrue(av2.published())
        self.assertEqual(utils.ymd(datetime.now()),
                         utils.ymd(av2.datetime_published))

        # don't set a versionDate, just force a publish
        # we expect the v2.datetime_publish to remain unchanged
        del self.ajson['article'][
            'versionDate']  # remember, this was copied from a v1 that had a versionDate!
        av2v2 = ajson_ingestor.ingest_publish(self.ajson, force=True)
        av2v2 = self.freshen(av2v2)

        self.assertEqual(av2.datetime_published, av2v2.datetime_published)
예제 #3
0
    def test_article_publish_v2_forced(self):
        "an unpublished v2 article can be successfully published again, if forced"
        # ingest and publish the v1
        av = ajson_ingestor.ingest(self.ajson)
        ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # modify and ingest+publish a v2
        self.ajson['article']['version'] = 2
        av2 = ajson_ingestor.ingest_publish(self.ajson)
        av2 = self.freshen(av2)
        self.assertTrue(av2.published())

        # the v2 should have been published normally.
        self.assertEqual(utils.ymd(datetime.now()),
                         utils.ymd(av2.datetime_published))

        # give the article-json a 'versionDate' - this won't ordinarily happen until further down the line
        # but lets embed this logic while it's still fresh in everybody's heads.

        # modify the versionDate of the v2 and ingest+publish again
        yesterday = datetime.now() - timedelta(days=1)
        self.ajson['article']['versionDate'] = yesterday
        av2v2 = ajson_ingestor.ingest_publish(self.ajson, force=True)
        av2v2 = self.freshen(av2v2)
        self.assertEqual(utils.ymd(yesterday),
                         utils.ymd(av2v2.datetime_published))
예제 #4
0
    def test_out_of_sequence_publish_fails(self):
        "attempting to ingest an article with a version greater than another *published* version fails"
        # ingest and publish a v1
        _, _, av = ajson_ingestor.ingest(self.ajson) # v1
        ajson_ingestor.publish(self.msid, self.version)

        # now attempt to ingest a v3
        self.ajson['article']['version'] = 3
        self.assertRaises(StateError, ajson_ingestor.ingest, self.ajson)

        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)
        av = self.freshen(av)
        self.assertEqual(av.version, 1) # assert the version hasn't changed
예제 #5
0
    def test_out_of_sequence_publish_fails(self):
        "attempting to ingest an article with a version greater than another *published* version fails"
        # ingest and publish a v1
        av = ajson_ingestor.ingest(self.ajson)  # v1
        ajson_ingestor.publish(self.msid, self.version)

        # now attempt to ingest a v3
        self.ajson['article']['version'] = 3
        self.assertRaises(StateError, ajson_ingestor.ingest, self.ajson)

        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)
        av = self.freshen(av)
        self.assertEqual(av.version, 1)  # assert the version hasn't changed
예제 #6
0
    def test_article_publish_v1(self):
        "an unpublished v1 article can be successfully published"
        av = ajson_ingestor.ingest(self.ajson)
        self.assertEqual(models.Journal.objects.count(), 1)
        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)
        self.assertFalse(av.published())

        # publish
        av = ajson_ingestor.publish(self.msid, self.version)

        # aaand just make sure we still have the expected number of objects
        self.assertEqual(models.Journal.objects.count(), 1)
        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)

        self.assertTrue(av.published())
        self.assertTrue(isinstance(av.datetime_published, datetime))

        # the pubdate of an unpublished v1 article is the same as that found in the
        # given json.
        av = self.freshen(av)
        expected_pubdate = utils.ymd(
            utils.todt(self.ajson['article']['published']))
        self.assertEqual(expected_pubdate, utils.ymd(av.datetime_published))
예제 #7
0
    def test_article_publish_fails_if_already_published(self):
        "a published article CANNOT be published again"
        _, _, av = ajson_ingestor.ingest(self.ajson)
        av = ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # publish again
        self.assertRaises(StateError, ajson_ingestor.publish, self.msid, self.version)
예제 #8
0
 def test_publish_dry_run(self):
     "specifying a dry run does not commit changes to database"
     _, _, saved_av = ajson_ingestor.ingest(self.ajson) # do an actual ingest first
     unsaved_av = ajson_ingestor.publish(self.msid, self.version, dry_run=True)
     self.assertEqual(models.ArticleVersion.objects.count(), 1)
     # ensure the article version stored has no published date
     models.ArticleVersion.objects.get(pk=saved_av.pk, datetime_published=None)
     # and that the object returned *does* have a datetime published
     self.assertTrue(unsaved_av.published())
예제 #9
0
    def test_article_publish_fails_if_already_published(self):
        "a published article CANNOT be published again"
        av = ajson_ingestor.ingest(self.ajson)
        av = ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # publish again
        self.assertRaises(StateError, ajson_ingestor.publish, self.msid,
                          self.version)
예제 #10
0
    def test_article_publish_succeeds_for_published_article_if_forced(self):
        "publication of an already published article can occur only if forced"
        _, _, av = ajson_ingestor.ingest(self.ajson)
        av = ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        expected_pubdate = utils.ymd(utils.todt(self.ajson['article']['published']))
        self.assertEqual(expected_pubdate, utils.ymd(av.datetime_published))

        # publish again, no changes to pubdate expected
        av = ajson_ingestor.publish(self.msid, self.version, force=True)
        av = self.freshen(av)
        self.assertEqual(expected_pubdate, utils.ymd(av.datetime_published))

        # ingest new pubdate, force publication
        new_pubdate = utils.todt('2016-01-01')
        self.ajson['article']['published'] = new_pubdate
        ajson_ingestor.ingest_publish(self.ajson, force=True)
        av = self.freshen(av)
        self.assertEqual(utils.ymd(new_pubdate), utils.ymd(av.datetime_published))
예제 #11
0
    def test_article_publish_v2(self):
        "an unpublished v2 article can be successfully published"
        _, _, av = ajson_ingestor.ingest(self.ajson)
        self.assertEqual(models.Journal.objects.count(), 1)
        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)
        self.assertFalse(av.published())

        ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # modify to a v2 and publish
        self.ajson['article']['version'] = 2
        _, _, av2 = ajson_ingestor.ingest_publish(self.ajson)

        av2 = self.freshen(av2)
        self.assertEqual(models.ArticleVersion.objects.count(), 2)
        self.assertTrue(av2.published())
        self.assertEqual(utils.ymd(datetime.now()), utils.ymd(av2.datetime_published))
예제 #12
0
    def test_article_publish_v2(self):
        "an unpublished v2 article can be successfully published"
        av = ajson_ingestor.ingest(self.ajson)
        self.assertEqual(models.Journal.objects.count(), 1)
        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)
        self.assertFalse(av.published())

        ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # modify to a v2 and publish
        self.ajson['article']['version'] = 2
        av2 = ajson_ingestor.ingest_publish(self.ajson)

        av2 = self.freshen(av2)
        self.assertEqual(models.ArticleVersion.objects.count(), 2)
        self.assertTrue(av2.published())
        self.assertEqual(utils.ymd(datetime.now()),
                         utils.ymd(av2.datetime_published))
예제 #13
0
    def test_article_publish_succeeds_for_published_article_if_forced(self):
        "publication of an already published article can occur only if forced"
        av = ajson_ingestor.ingest(self.ajson)
        av = ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        expected_pubdate = utils.ymd(
            utils.todt(self.ajson['article']['published']))
        self.assertEqual(expected_pubdate, utils.ymd(av.datetime_published))

        # publish again, no changes to pubdate expected
        av = ajson_ingestor.publish(self.msid, self.version, force=True)
        av = self.freshen(av)
        self.assertEqual(expected_pubdate, utils.ymd(av.datetime_published))

        # ingest new pubdate, force publication
        new_pubdate = utils.todt('2016-01-01')
        self.ajson['article']['published'] = new_pubdate
        ajson_ingestor.ingest_publish(self.ajson, force=True)
        av = self.freshen(av)
        self.assertEqual(utils.ymd(new_pubdate),
                         utils.ymd(av.datetime_published))
예제 #14
0
 def test_publish_dry_run(self):
     "specifying a dry run does not commit changes to database"
     saved_av = ajson_ingestor.ingest(
         self.ajson)  # do an actual ingest first
     unsaved_av = ajson_ingestor.publish(self.msid,
                                         self.version,
                                         dry_run=True)
     self.assertEqual(models.ArticleVersion.objects.count(), 1)
     # ensure the article version stored has no published date
     models.ArticleVersion.objects.get(pk=saved_av.pk,
                                       datetime_published=None)
     # and that the object returned *does* have a datetime published
     self.assertTrue(unsaved_av.published())
예제 #15
0
파일: ingest.py 프로젝트: elifesciences/lax
def handle_single(print_queue, action, infile, msid, version, force, dry_run):
    data = None

    log_context = {"msid": msid, "version": version}

    LOG.info("attempting to %s article %s", action, msid, extra=log_context)

    # read and check the article-json given, if necessary
    try:
        if action in [INGEST, BOTH]:
            raw_data = infile.read()
            log_context["data"] = str(raw_data[:25]) + "... (truncated)" if raw_data else ""
            data = json.loads(raw_data)
            # vagary of the CLI interface: article id and version are required
            # these may not match the data given
            data_version = data["article"].get("version")
            if not data_version == version:
                raise StateError(
                    "version in the data (%s) does not match version passed to script (%s)" % (data_version, version)
                )
            data_msid = int(data["article"]["id"])
            if not data_msid == msid:
                raise StateError(
                    "manuscript-id in the data (%s) does not match id passed to script (%s)" % (data_msid, msid)
                )

    except StateError as err:
        error(print_queue, INVALID, err.message, log_context)

    except ValueError as err:
        msg = "could not decode the json you gave me: %r for data: %r" % (err.message, raw_data)
        error(print_queue, INVALID, msg, log_context)

    choices = {
        # all these return a models.ArticleVersion object
        INGEST: lambda msid, ver, force, data, dry: ajson_ingestor.ingest(data, force, dry_run=dry)[-1],
        PUBLISH: lambda msid, ver, force, data, dry: ajson_ingestor.publish(msid, ver, force, dry_run=dry),
        BOTH: lambda msid, ver, force, data, dry: ajson_ingestor.ingest_publish(data, force, dry_run=dry)[-1],
    }

    try:
        av = choices[action](msid, version, force, data, dry_run)
        success(print_queue, action, av, log_context, dry_run)

    except StateError as err:
        error(print_queue, INVALID, "failed to call action %r: %s" % (action, err.message), log_context)

    except Exception as err:
        msg = "unhandled exception attempting to %r article: %s" % (action, err)
        LOG.exception(msg, extra=log_context)
        error(print_queue, ERROR, msg, log_context)
예제 #16
0
    def test_article_publish_v2_forced2(self):
        "a PUBLISHED v2 article can be successfully published (again), if forced"
        _, _, av = ajson_ingestor.ingest(self.ajson)
        ajson_ingestor.publish(self.msid, self.version)
        av = self.freshen(av)
        self.assertTrue(av.published())

        # modify and ingest+publish a v2
        self.ajson['article']['version'] = 2
        # there is a versionDate here, but because we're not forcing it, it doesn't get looked for
        # lax is the distributor of non-v1 pub dates. this may find their way into xml later, but
        # they will always come from lax.
        _, _, av2 = ajson_ingestor.ingest_publish(self.ajson)
        av2 = self.freshen(av2)
        self.assertTrue(av2.published())
        self.assertEqual(utils.ymd(datetime.now()), utils.ymd(av2.datetime_published))

        # don't set a versionDate, just force a publish
        # we expect the v2.datetime_publish to remain unchanged
        del self.ajson['article']['versionDate'] # remember, this was copied from a v1 that had a versionDate!
        _, _, av2v2 = ajson_ingestor.ingest_publish(self.ajson, force=True)
        av2v2 = self.freshen(av2v2)

        self.assertEqual(av2.datetime_published, av2v2.datetime_published)
예제 #17
0
    def test_article_publish_v1(self):
        "an unpublished v1 article can be successfully published"
        _, _, av = ajson_ingestor.ingest(self.ajson)
        self.assertEqual(models.Journal.objects.count(), 1)
        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)
        self.assertFalse(av.published())

        # publish
        av = ajson_ingestor.publish(self.msid, self.version)

        # aaand just make sure we still have the expected number of objects
        self.assertEqual(models.Journal.objects.count(), 1)
        self.assertEqual(models.Article.objects.count(), 1)
        self.assertEqual(models.ArticleVersion.objects.count(), 1)

        self.assertTrue(av.published())
        self.assertTrue(isinstance(av.datetime_published, datetime))

        # the pubdate of an unpublished v1 article is the same as that found in the
        # given json.
        av = self.freshen(av)
        expected_pubdate = utils.ymd(utils.todt(self.ajson['article']['published']))
        self.assertEqual(expected_pubdate, utils.ymd(av.datetime_published))
예제 #18
0
def handle_single(print_queue, action, infile, msid, version, force, dry_run):
    data = None

    log_context = {'msid': msid, 'version': version}

    LOG.info('attempting to %s article %s v%s',
             action,
             msid,
             version,
             extra=log_context)

    # read and check the article-json given, if necessary
    try:
        if action not in [PUBLISH]:
            raw_data = infile.read()
            log_context['data'] = str(
                raw_data[:25]) + "... (truncated)" if raw_data else ''

            try:
                data = json.loads(raw_data)
            except ValueError as err:
                msg = "could not decode the json you gave me: %r for data: %r" % (
                    err.msg, raw_data)
                raise StateError(codes.BAD_REQUEST, msg)

            # vagary of the CLI interface: article id and version are required
            # these may not match the data given
            data_version = data['article'].get('version')
            if not data_version == version:
                raise StateError(
                    codes.BAD_REQUEST,
                    "'version' in the data (%s) does not match 'version' passed to script (%s)"
                    % (data_version, version))
            data_msid = int(data['article']['id'])
            if not data_msid == msid:
                raise StateError(
                    codes.BAD_REQUEST,
                    "'id' in the data (%s) does not match 'msid' passed to script (%s)"
                    % (data_msid, msid))

    except KeyboardInterrupt as err:
        LOG.warn("ctrl-c caught during data load")
        raise

    except StateError as err:
        error_from_err(print_queue, INVALID, err, force, dry_run, log_context)

    except BaseException as err:
        LOG.exception("unhandled exception attempting to ingest article-json",
                      extra=log_context)
        error(print_queue,
              ERROR,
              codes.UNKNOWN,
              str(err),
              force,
              dry_run,
              log_context,
              trace=ftb(err))

    choices = {
        # all these return a models.ArticleVersion object
        INGEST:
        lambda msid, ver, force, data, dry: ajson_ingestor.ingest(
            data, force, dry_run=dry),
        PUBLISH:
        lambda msid, ver, force, data, dry: ajson_ingestor.publish(
            msid, ver, force, dry_run=dry),
        INGEST_PUBLISH:
        lambda msid, ver, force, data, dry: ajson_ingestor.ingest_publish(
            data, force, dry_run=dry),
    }

    try:
        av = choices[action](msid, version, force, data, dry_run)
        success(print_queue, action, av, force, dry_run, log_context)

    except KeyboardInterrupt as err:
        LOG.warn("ctrl-c caught during ingest/publish")
        raise

    except SystemExit:
        # `success` and `error` use `exit` to indicate success or failure with their return code.
        # this is handled in the `job` function, so re-raise it here and handle it there
        raise

    except StateError as err:
        # handled error
        error_from_err(print_queue, INVALID, err, force, dry_run, log_context)

    except BaseException as err:
        # unhandled error
        msg = "unhandled exception attempting to %r article: %r" % (action,
                                                                    err)
        LOG.exception(msg, extra=log_context)
        error(print_queue,
              ERROR,
              codes.UNKNOWN,
              msg,
              force,
              dry_run,
              log_context,
              trace=ftb(err))