def request_args(request, **overrides): opts = {} opts.update(settings.API_OPTS) opts.update(overrides) def ispositiveint(v): ensure(isint(v) and int(v) > 0, "expecting positive integer, got: %s" % v) return int(v) def inrange(minpp, maxpp): def fn(v): ensure(v >= minpp and v <= maxpp, "value must be between %s and %s" % (minpp, maxpp)) return v return fn def asc_or_desc(val): v = val.strip().upper() ensure(v in ['ASC', 'DESC'], "expecting either 'asc' or 'desc' for 'order' parameter, got: %s" % val) return v desc = { 'page': [p('page', opts['page_num']), ispositiveint], 'per_page': [p('per-page', opts['per_page']), ispositiveint, inrange(opts['min_per_page'], opts['max_per_page'])], 'order': [p('order', opts['order_direction']), str, asc_or_desc] } return render_item(desc, request.GET)
def et(struct): return { 'type': 'external-article', 'articleTitle': p(struct, 'article.title'), 'journal': p(struct, 'journal.name'), 'authorLine': p(struct, 'article.authorLine'), 'uri': 'https://doi.org/%s' % p(struct, 'article.doi'), }
def et(struct): return OrderedDict([ ('type', 'external-article'), ('articleTitle', p(struct, 'article.title')), ('journal', p(struct, 'journal.name')), ('authorLine', p(struct, 'article.authorLine')), ('uri', 'https://doi.org/%s' % p(struct, 'article.doi')), ])
def request_args(request, **overrides): opts = {} opts.update(settings.API_OPTS) opts.update(overrides) def ispositiveint(param): def wrap(v): ensure( isint(v) and int(v) > 0, "expecting positive integer for %r parameter" % param) return int(v) return wrap def inrange(minpp, maxpp): def fn(v): ensure( v >= minpp and v <= maxpp, "value must be between %s and %s for 'per-page' parameter" % (minpp, maxpp)) return v return fn def asc_or_desc(val): v = val.strip().upper()[:4] ensure(v in ['ASC', 'DESC'], "expecting either 'asc' or 'desc' for 'order' parameter") return v desc = { 'page': [p('page', opts['page_num']), ispositiveint('page')], 'per_page': [ p('per-page', opts['per_page']), ispositiveint('per-page'), inrange(opts['min_per_page'], opts['max_per_page']) ], 'order': [p('order', opts['order_direction']), str, asc_or_desc] } return render_item(desc, request.GET)
def request_args(request, **overrides): opts = {} opts.update(settings.API_OPTS) opts.update(overrides) def ispositiveint(v): ensure( isint(v) and int(v) > 0, "expecting positive integer, got: %s" % v) return int(v) def inrange(minpp, maxpp): def fn(v): ensure(v >= minpp and v <= maxpp, "value must be between %s and %s" % (minpp, maxpp)) return v return fn def isin(lst): def fn(val): ensure(val in lst, "value is not in %r" % (lst, )) return val return fn desc = { 'page': [p('page', opts['page_num']), ispositiveint], 'per_page': [ p('per-page', opts['per_page']), ispositiveint, inrange(opts['min_per_page'], opts['max_per_page']) ], 'order': [ p('order', opts['order_direction']), uppercase, isin(['ASC', 'DESC']) ], 'period': [p('by', 'day'), lowercase, isin(['day', 'month'])], } return render_item(desc, request.GET)
SCHEMA_PATH = join(PROJECT_DIR, 'schema/api-raml/dist') SCHEMA_IDX = { 'poa': join(SCHEMA_PATH, 'model/article-poa.v1.json'), 'vor': join(SCHEMA_PATH, 'model/article-vor.v1.json'), 'history': join(SCHEMA_PATH, 'model/article-history.v1.json'), 'list': join(SCHEMA_PATH, 'model/article-list.v1.json') } API_PATH = join(SCHEMA_PATH, 'api.raml') def _load_api_raml(path): # load the api.raml file, ignoring any "!include" commands yaml.add_multi_constructor('', lambda *args: '[disabled]') return yaml.load(open(path, 'r'))['traits']['paged']['queryParameters'] API_OPTS = render_item({ 'per_page': [p('per-page.default'), int], 'min_per_page': [p('per-page.minimum'), int], 'max_per_page': [p('per-page.maximum'), int], 'page_num': [p('page.default'), int], 'order_direction': [p('order.default')], }, _load_api_raml(API_PATH)) # KONG gateway options KONG_AUTH_HEADER = 'KONG-Authenticated' INTERNAL_NETWORK = '10.0.2.0/24' #
# ignores any events missing a 'datetime' key # WARN: if 'datetime' is present but is empty, it *will be given a datetime of now()* ae_list = utils.lfilter(lambda struct: 'datetime_event' in struct, ae_list) return [add(article, **struct) for struct in ae_list] # # # INGEST_EVENTS = [ # why the list with a single value here? et3.render expects a pipeline of transformations { 'event': [models.DATE_XML_RECEIVED], 'datetime_event': [p('-history.received', render.EXCLUDE_ME)] }, { 'event': [models.DATE_XML_ACCEPTED], 'datetime_event': [p('-history.accepted', render.EXCLUDE_ME)] }, { 'event': [models.DATETIME_ACTION_INGEST], 'datetime_event': [None], 'value': [p('forced?'), lambda v: "forced=%s" % v] }, ] PUBLISH_EVENTS = [ { 'event': [models.DATETIME_ACTION_PUBLISH],
from et3 import render from et3.extract import path as p from django.db import IntegrityError from functools import partial from jsonschema import ValidationError LOG = logging.getLogger(__name__) class StateError(RuntimeError): pass # make the article-json lax compatible # receives a list of article-json ARTICLE = { 'manuscript_id': [p('id'), int], 'volume': [p('volume')], 'type': [p('type')], 'doi': [p('id'), utils.msid2doi], # remove when apiv1 is turned off #'ejp_type': [p('type'), models.EJP_TYPE_REV_SLUG_IDX.get] } ARTICLE_VERSION = { 'title': [p('title')], 'version': [p('version')], 'status': [p('status')], # only v1 article-json has a published date. v2 article-json does not 'datetime_published': [p('published', None), utils.todt], } def atomic(fn):
from django.conf import settings LOG = logging.getLogger(__name__) # make the article-json lax compatible # receives a list of article-json def exclude_if_empty(val): if not val: return render.EXCLUDE_ME return val ARTICLE = { 'manuscript_id': [p('id'), int], 'volume': [p('volume')], 'type': [p('type')], 'doi': [p('id'), utils.msid2doi], # remove when apiv1 is turned off 'date_received': [p('-history.received', None), utils.todt, exclude_if_empty], 'date_accepted': [p('-history.accepted', None), utils.todt, exclude_if_empty], #'ejp_type': [p('type'), models.EJP_TYPE_REV_SLUG_IDX.get] } ARTICLE_VERSION = { 'title': [p('title')], 'version': [p('version')], 'status': [p('status')], # only v1 article-json has a published date. v2 article-json does not
'metric': join(SCHEMA_PATH, 'model/metric.v1.json'), } API_PATH = join(SCHEMA_PATH, 'api.raml') def _load_api_raml(path): # load the api.raml file, ignoring any "!include" commands yaml.add_multi_constructor('', lambda *args: '[disabled]') return yaml.load( open(path, 'r'), Loader=yaml.FullLoader)['traits']['paged']['queryParameters'] API_OPTS = render_item( { 'per_page': [p('per-page.default'), int], 'min_per_page': [p('per-page.minimum'), int], 'max_per_page': [p('per-page.maximum'), int], 'page_num': [p('page.default'), int], 'order_direction': [p('order.default')], }, _load_api_raml(API_PATH)) LOG_FILE = join(PROJECT_DIR, 'elife-metrics.log') if ENV != DEV: LOG_FILE = join('/var/log/', 'elife-metrics.log') DEBUG_LOG_FILE = join(PROJECT_DIR, 'debugme.log') # whereever our log files are, ensure they are writable before we do anything else. def writable(path):
from django.db import IntegrityError from functools import partial from jsonschema import ValidationError LOG = logging.getLogger(__name__) class StateError(RuntimeError): pass # make the article-json lax compatible # receives a list of article-json ARTICLE = { "manuscript_id": [p("id"), int], "volume": [p("volume")], "type": [p("type")], "doi": [p("id"), utils.msid2doi], # remove when apiv1 is turned off #'ejp_type': [p('type'), models.EJP_TYPE_REV_SLUG_IDX.get] } ARTICLE_VERSION = { "title": [p("title")], "version": [p("version")], "status": [p("status")], # only v1 article-json has a published date. v2 article-json does not "datetime_published": [p("published", None), utils.todt], }
types = { 'RA': 'Research article', 'AV': 'Short report', 'RR': 'Research advance', 'SR': 'Registered report', 'TR': 'Tools and resources', 'RE': 'Research exchange', # deprecated in favour of SC 'SC': 'Scientific Correspondence', 'RS': 'Replication study', 'RC': 'Research communication', } assert mstype in types.keys(), "unknown paper type %r" % mstype return mstype DESCRIPTION = OrderedDict([ ('manuscript_id', [p('ms'), int, str]), # yes, str->int->str, I know. ('ejp_type', [p('type'), paper_type]), ('date_initial_qc', [p('initial_qc_dt', None), todt]), ('date_initial_decision', [p('initial_decision_dt', None), todt]), ('initial_decision', [p('initial_decision', None), tfield]), ('date_full_qc', [p('full_qc_dt', None), todt]), ('date_full_decision', [p('full_decision_dt', None), todt]), ('decision', [p('full_decision', None), tfield]), ('date_rev1_qc', [p('rev1_qc_dt', None), todt]), ('date_rev1_decision', [p('rev1_decision_dt', None), todt]), ('rev1_decision', [p('rev1_decision', None), tfield]),