Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/base/settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,5 @@
DEFAULT_ES_NULL_VALUE = 'N/A'

TRAVIS_ENV = False

CITATION_STYLES_REPO_URL = 'https://github.com/CenterForOpenScience/styles/archive/88e6ed31a91e9f5a480b486029cda97b535935d4.zip'
136 changes: 136 additions & 0 deletions osf/management/commands/sync_citation_styles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import io
import logging
import os
import re
import requests
import zipfile

from django.apps import apps
from django.core.management.base import BaseCommand
from django.db import transaction
from lxml import etree
from urllib.parse import urlparse

from api.base import settings

logger = logging.getLogger(__name__)


def sync_citation_styles(dry_run=False):
Comment thread
cslzchen marked this conversation as resolved.
CitationStyle = apps.get_model('osf', 'citationstyle')
zip_data = io.BytesIO(requests.get(settings.CITATION_STYLES_REPO_URL).content)
Comment thread
cslzchen marked this conversation as resolved.
with transaction.atomic():
with zipfile.ZipFile(zip_data) as zip_file:
for file_name in [name for name in zip_file.namelist() if name.endswith('.zip') and not name.startswith('dependent')]:
root = etree.fromstring(zip_file.read(file_name))

namespace = re.search(r'\{.*\}', root.tag).group()
title = root.find('{namespace}info/{namespace}title'.format(namespace=f'{namespace}')).text
has_bibliography = 'Bluebook' in title

if not has_bibliography:
bib = root.find(f'{{{namespace}}}bibliography')
layout = bib.find(f'{{{namespace}}}layout') if bib is not None else None
has_bibliography = True
if layout is not None and len(layout.getchildren()) == 1 and 'choose' in layout.getchildren()[0].tag:
choose = layout.find(f'{{{namespace}}}choose')
else_tag = choose.find(f'{{{namespace}}}else')
if else_tag is None:
supported_types = []
match_none = False
for child in choose.getchildren():
types = child.get('type', None)
match_none = child.get('match', 'any') == 'none'
if types is not None:
types = types.split(' ')
supported_types.extend(types)
if 'webpage' in types:
break
else:
if len(supported_types) and not match_none:
# has_bibliography set to False now means that either bibliography tag is absent
# or our type (webpage) is not supported by the current version of this style.
has_bibliography = False

summary = getattr(
root.find('{namespace}info/{namespace}summary'.format(namespace=f'{namespace}')), 'text', None
)
short_title = getattr(
root.find('{namespace}info/{namespace}title-short'.format(namespace=f'{namespace}')), 'text', None
)
# Required
fields = {
'_id': os.path.splitext(os.path.basename(file_name))[0],
'title': title,
'has_bibliography': has_bibliography, 'parent_style': None,
'short_title': short_title,
'summary': summary
}

CitationStyle.objects.update_or_create(**fields)

for file_name in [name for name in zip_file.namelist() if name.endswith('.zip') and name.startswith('dependent')]:
root = etree.fromstring(zip_file.read(file_name))

namespace = re.search(r'\{.*\}', root.tag).group()
title = root.find('{namespace}info/{namespace}title'.format(namespace=f'{namespace}')).text
has_bibliography = root.find(f'{{{namespace}}}bibliography') is not None or 'Bluebook' in title

style_id = os.path.splitext(os.path.basename(file_name))[0]
links = root.findall('{namespace}info/{namespace}link'.format(namespace=f'{namespace}'))
for link in links:
if link.get('rel') == 'independent-parent':
parent_style_id = urlparse(link.get('href')).path.split('/')[-1]
parent_style = CitationStyle.objects.get(_id=parent_style_id)

if parent_style is not None:
summary = getattr(
root.find('{namespace}info/{namespace}summary'.format(namespace=f'{namespace}')),
'text', None
)
short_title = getattr(
root.find('{namespace}info/{namespace}title-short'.format(namespace=f'{namespace}')),
'text', None
)

parent_has_bibliography = parent_style.has_bibliography
fields = {
'_id': style_id,
'title': title,
'has_bibliography': parent_has_bibliography,
'parent_style': parent_style_id,
'short_title': short_title,
'summary': summary
}
CitationStyle.objects.update_or_create(**fields)
break
else:
logger.debug('Unable to load parent_style object: parent {}, dependent style {}'.format(parent_style_id, style_id))
else:
fields = {
'_id': style_id,
'title': title,
'has_bibliography': has_bibliography,
'parent_style': None
}
CitationStyle.objects.update_or_create(**fields)

if dry_run:
raise RuntimeError('This is a dry run rolling back transaction.')
Comment thread
cslzchen marked this conversation as resolved.


class Command(BaseCommand):
"""Updates citation styles to its current repo URL."""
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
'--dry',
action='store_true',
dest='dry_run',
)

def handle(self, *args, **options):
dry_run = options.get('dry_run')
sync_citation_styles(dry_run=dry_run)
5 changes: 1 addition & 4 deletions osf/migrations/0074_parse_citation_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
def get_style_files(path):
files = (os.path.join(path, x) for x in os.listdir(path))
return (f for f in files if os.path.isfile(f))

def parse_citation_styles(state, schema):
# drop all styles
CitationStyle = state.get_model('osf', 'citationstyle')
Expand Down Expand Up @@ -74,6 +73,4 @@ class Migration(migrations.Migration):
('osf', '0073_citationstyle_has_bibliography'),
]

operations = [
migrations.RunPython(parse_citation_styles, revert),
Comment thread
cslzchen marked this conversation as resolved.
]
operations = []
4 changes: 1 addition & 3 deletions osf/migrations/0107_add_dependent_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,4 @@ class Migration(migrations.Migration):
('osf', '0106_citationstyle_parent_style'),
]

operations = [
migrations.RunPython(update_styles, revert),
Comment thread
cslzchen marked this conversation as resolved.
]
operations = []
26 changes: 20 additions & 6 deletions osf_tests/test_registration_bulk_upload_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@

from osf_tests.factories import SubjectFactory
from osf.models import RegistrationSchema, RegistrationProvider, NodeLicense
from osf.registrations.utils import (
BulkRegistrationUpload,
CategoryField,
ContributorField,
DuplicateHeadersError,
FileUploadNotSupportedError,
InvalidHeadersError,
LicenseField,
MAX_EXCEL_COLUMN_NUMBER,
METADATA_FIELDS,
Store,
get_excel_column_name,
)

from osf.registrations.utils import (BulkRegistrationUpload, InvalidHeadersError,
FileUploadNotSupportedError, DuplicateHeadersError,
get_excel_column_name, Store, CategoryField, LicenseField, ContributorField,
MAX_EXCEL_COLUMN_NUMBER, METADATA_FIELDS)

def write_csv(header_row, *rows):
csv_buffer = io.StringIO()
Expand All @@ -24,6 +33,7 @@ def write_csv(header_row, *rows):
csv_buffer.seek(0)
return csv_buffer


def make_row(field_values={}):
return {**{
'Title': 'Test title',
Expand All @@ -42,6 +52,7 @@ def make_row(field_values={}):
'summary': 'Test study',
}, **field_values}


def assert_parsed(actual_parsed, expected_parsed):
parsed = {**actual_parsed['metadata'], **actual_parsed['registration_responses']}
for key, value in expected_parsed.items():
Expand All @@ -54,6 +65,7 @@ def assert_parsed(actual_parsed, expected_parsed):
continue
assert_equal(actual, expected)


def assert_errors(actual_errors, expected_errors):
for error in actual_errors:
assert_true('header' in error)
Expand All @@ -65,6 +77,7 @@ def assert_errors(actual_errors, expected_errors):

assert_true(len(actual_errors), len(expected_errors.keys()))


@pytest.mark.django_db
class TestBulkUploadParserValidationErrors:

Expand All @@ -79,8 +92,9 @@ def provider_subjects(self):
@pytest.fixture()
def registration_provider(self, open_ended_schema, provider_subjects):
osf_provider = RegistrationProvider.load('osf')
osf_provider.default_license = NodeLicense.objects.get(name='No license')
osf_provider.licenses_acceptable.add(NodeLicense.objects.get(name='No license'))
node_license = NodeLicense.objects.get(name='No license')
osf_provider.default_license = node_license
osf_provider.licenses_acceptable.add(node_license)
osf_provider.schemas.add(open_ended_schema)
osf_provider.subjects.add(*provider_subjects)
osf_provider.save()
Expand Down
6 changes: 0 additions & 6 deletions tasks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,16 +467,10 @@ def remove_failures_from_testmon(ctx, db_path=None):

@task
def travis_setup(ctx):
ctx.run('npm install -g bower', echo=True)

with open('package.json', 'r') as fobj:
package_json = json.load(fobj)
ctx.run('npm install @centerforopenscience/list-of-licenses@{}'.format(package_json['dependencies']['@centerforopenscience/list-of-licenses']), echo=True)

with open('bower.json', 'r') as fobj:
bower_json = json.load(fobj)
ctx.run('bower install {}'.format(bower_json['dependencies']['styles']), echo=True)

Comment thread
cslzchen marked this conversation as resolved.
@task
def test_travis_addons(ctx, numprocesses=None, coverage=False, testmon=False):
"""
Expand Down
5 changes: 4 additions & 1 deletion tests/test_citeprocpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

from django.utils import timezone
from nose.tools import * # noqa: F403
import pytest

from api.citations.utils import render_citation
from osf.models import OSFUser
from osf_tests.factories import UserFactory, PreprintFactory
from tests.base import OsfTestCase
from osf.models import OSFUser


class Node:
_id = '2nthu'
Expand All @@ -18,6 +20,7 @@ class Node:
visible_contributors = ''


@pytest.mark.skip()
class TestCiteprocpy(OsfTestCase):
Comment thread
cslzchen marked this conversation as resolved.

def setUp(self):
Expand Down
2 changes: 1 addition & 1 deletion website/settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -2108,4 +2108,4 @@ def from_node_usage(cls, usage_bytes, private_limit=None, public_limit=None):
CAS_LOG_LEVEL = 3 # ERROR

PREPRINT_METRICS_START_DATE = datetime.datetime(2019, 1, 1)
WAFFLE_VALUES_YAML = 'osf/features.yaml'
WAFFLE_VALUES_YAML = 'osf/features.yaml'