diff --git a/.elasticbeanstalk/config.yml b/.elasticbeanstalk/config.yml
index 2d7244ba0..c4d6b6a63 100644
--- a/.elasticbeanstalk/config.yml
+++ b/.elasticbeanstalk/config.yml
@@ -4,7 +4,8 @@ branch-defaults:
develop:
environment: isiscb-develop
global:
- application_name: IsisCB
+ application_name: IsisCB Staging Python 3
+ #application_name: IsisCB Celery Staging Python 3 (non worker)
default_ec2_keyname: isiscb-eb
default_platform: 64bit Amazon Linux 2015.03 v2.0.1 running Python 2.7
default_region: us-west-2
diff --git a/isiscb/curation/forms.py b/isiscb/curation/forms.py
index 458ee77cd..13636ed4c 100644
--- a/isiscb/curation/forms.py
+++ b/isiscb/curation/forms.py
@@ -234,6 +234,36 @@ class Meta(object):
model = AuthorityValue
fields = ['value']
+class CitationValueForm(forms.ModelForm):
+ value = forms.CharField(label="Citation ID", widget=forms.TextInput(attrs={'data-type':'citation_id'}))
+ citation_name = forms.CharField(label='Name of stored citation', widget=forms.TextInput(attrs={'readonly': True}))
+
+ def __init__(self, *args, **kwargs):
+ super(CitationValueForm, self).__init__(*args, **kwargs)
+ instance = kwargs.get('instance')
+
+ if instance and not self.is_bound:
+ self.fields['value'].initial = instance.pk
+ self.fields['citation_name'].initial = instance.value.title_for_display
+
+ def clean_value(self):
+ value = self.cleaned_data['value']
+
+ try:
+ value = Citation.objects.get(id=value)
+ except:
+ raise forms.ValidationError('Citation record does not exist.')
+
+ return value
+
+ def save(self, *args, **kwargs):
+ self.instance.value = self.cleaned_data.get('value')
+ super(CitationValueForm, self).save(*args, **kwargs)
+
+ class Meta(object):
+ model = CitationValue
+ fields = ['value']
+
class PartDetailsForm(forms.ModelForm):
extent_note = forms.CharField(widget=forms.widgets.Textarea({'rows': '1'}), required=False)
diff --git a/isiscb/curation/templates/curation/authority_attribute_changeview.html b/isiscb/curation/templates/curation/authority_attribute_changeview.html
index 8c62ad946..8c4a628ad 100644
--- a/isiscb/curation/templates/curation/authority_attribute_changeview.html
+++ b/isiscb/curation/templates/curation/authority_attribute_changeview.html
@@ -122,6 +122,7 @@
{{ attribute_form.value_freeform|addcss:"form-control" }}
+
@@ -170,7 +171,7 @@
var value = $(this).val();
var container = $('#value_form_container');
container.empty();
- var form = $('#form_for_' + value).clone();
+ var form = $('#form_for_' + value).clone(withDataAndEvents=true);
container.append(form);
// update help text
@@ -205,6 +206,19 @@
$("#geocode-attr-warning").modal('hide');
$("#attributeForm").submit();
})
+
+ $("[data-type='citation_id']").change(function() {
+ $.ajax({
+ url: "{% url 'curation:api_citation' %}" + "?id=" + $("[data-type='citation_id']").val(),
+ success: function(data) {
+ $("#ajax_errors").text("")
+ $("#id_value-citation_name").val(data['title'])
+ },
+ error: function(data) {
+ $("#ajax_errors").html('
Citation with provided id could not be found.')
+ }
+ });
+ });
});
@@ -265,7 +279,7 @@
Are you sure?
You are about to delete an attribute of type
. Deletion cannot be undone!
{% if attribute.type_controlled.name == country_code_attribute %}
-
+
This attribute is a country code. You might need to reindex related citations to make sure your changes are reflected on the public site.
{% endif %}
diff --git a/isiscb/curation/urls.py b/isiscb/curation/urls.py
index 28a6b9d28..d35f9ee8c 100644
--- a/isiscb/curation/urls.py
+++ b/isiscb/curation/urls.py
@@ -49,6 +49,8 @@
re_path(r'^citation/(?P
[A-Z0-9]+)/$', views.citation, name='curate_citation'),
re_path(r'^authority/(?P[A-Z0-9]+)/$', views.authority, name='curate_authority'),
+ re_path(r'^api/citation$', views.get_citation_by_id, name='api_citation'),
+
re_path(r'^timelines$', bulk_change_csv_views.timeline_tasks, name='timeline_tasks'),
re_path(r'^timelines/(?P[A-Z0-9]+)/delete$', bulk_change_csv_views.timeline_delete, name='delete_timeline'),
diff --git a/isiscb/curation/view_helpers.py b/isiscb/curation/view_helpers.py
index e1c1a57f1..e03863809 100644
--- a/isiscb/curation/view_helpers.py
+++ b/isiscb/curation/view_helpers.py
@@ -13,6 +13,8 @@ def _create_attribute_value_forms():
value_forms[at.id] = ISODateValueForm
elif value_class is AuthorityValue:
value_forms[at.id] = AuthorityValueForm
+ elif value_class is CitationValue:
+ value_forms[at.id] = CitationValueForm
else:
value_forms[at.id] = modelform_factory(value_class,
exclude=('attribute', 'child_class'))
diff --git a/isiscb/curation/views.py b/isiscb/curation/views.py
index 25fbaf7ad..889763f72 100644
--- a/isiscb/curation/views.py
+++ b/isiscb/curation/views.py
@@ -2136,6 +2136,19 @@ def search_users(request):
} for u in queryset[:20]]
return JsonResponse(results, safe=False)
+@user_passes_test(lambda u: u.is_superuser or u.is_staff)
+def get_citation_by_id(request):
+ id = request.GET.get('id', None)
+ if not id:
+ return JsonResponse({'citation': None})
+
+ citation = Citation.objects.filter(id=id).first()
+ if not citation:
+ return JsonResponse({}, status=404)
+ return JsonResponse({
+ 'id': citation.id,
+ 'title': citation.title_for_display,
+ })
@user_passes_test(lambda u: u.is_superuser or u.is_staff)
def quick_and_dirty_citation_search(request):
@@ -2293,7 +2306,7 @@ def _get_filtered_queryset(request, object_type='CITATION'):
if 'collection_only' in filter_params:
filter_params.pop('collection_only')
filter_params_raw = filter_params.urlencode()#.encode('utf-8')
- if object_type is 'CITATION':
+ if object_type == 'CITATION':
_qs = operations.filter_queryset(request.user, Citation.objects.all())
queryset = CitationFilter(filter_params, queryset=_qs)
else:
diff --git a/isiscb/isiscb/local_postgresql_settings.py b/isiscb/isiscb/local_postgresql_settings.py
index 7d3fd6f43..8aa1af697 100644
--- a/isiscb/isiscb/local_postgresql_settings.py
+++ b/isiscb/isiscb/local_postgresql_settings.py
@@ -327,6 +327,7 @@
TIMELINE_PUBLICATION_DATE_ATTRIBUTE = os.environ.get('TIMELINE_PUBLICATION_DATE_ATTRIBUTE', "PublicationDate")
RECORD_SUBTYPE_ATTRIBUTE = os.environ.get('RECORD_SUBTYPE_ATTRIBUTE', "RecordSubType")
ACCESSED_ATTRIBUTE_NAME = os.environ.get('ACCESSED_ATTRIBUTE_NAME', "LastAccessedDate")
+BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME = os.environ.get('BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME', "BibliographicEssay")
DOI_LINKED_DATA_NAME = os.environ.get('DOI_LINKED_DATA_NAME', "DOI")
ISBN_LINKED_DATA_NAME = os.environ.get('ISBN_LINKED_DATA_NAME', "ISBN")
diff --git a/isiscb/isiscb/production_settings.py b/isiscb/isiscb/production_settings.py
index fb2f5f92c..1542c10b7 100644
--- a/isiscb/isiscb/production_settings.py
+++ b/isiscb/isiscb/production_settings.py
@@ -412,6 +412,7 @@
TIMELINE_PUBLICATION_DATE_ATTRIBUTE = os.environ.get('TIMELINE_PUBLICATION_DATE_ATTRIBUTE', "PublicationDate")
RECORD_SUBTYPE_ATTRIBUTE = os.environ.get('RECORD_SUBTYPE_ATTRIBUTE', "RecordSubType")
ACCESSED_ATTRIBUTE_NAME = os.environ.get('ACCESSED_ATTRIBUTE_NAME', "LastAccessedDate")
+BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME = os.environ.get('BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME', "BibliographicEssay")
COUNTRY_CODE_ATTRIBUTE = os.environ.get('COUNTRY_CODE_ATTRIBUTE', "CountryCode")
diff --git a/isiscb/isiscb/test_settings.py b/isiscb/isiscb/test_settings.py
index 6b8b442d1..2f65e30ed 100644
--- a/isiscb/isiscb/test_settings.py
+++ b/isiscb/isiscb/test_settings.py
@@ -321,6 +321,7 @@
TIMELINE_PUBLICATION_DATE_ATTRIBUTE = os.environ.get('TIMELINE_PUBLICATION_DATE_ATTRIBUTE', "PublicationDate")
RECORD_SUBTYPE_ATTRIBUTE = os.environ.get('RECORD_SUBTYPE_ATTRIBUTE', "RecordSubType")
ACCESSED_ATTRIBUTE_NAME = os.environ.get('ACCESSED_ATTRIBUTE_NAME', "LastAccessedDate")
+BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME = os.environ.get('BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME', "BibliographicEssay")
DOI_LINKED_DATA_NAME = os.environ.get('DOI_LINKED_DATA_NAME', "DOI")
ISBN_LINKED_DATA_NAME = os.environ.get('ISBN_LINKED_DATA_NAME', "ISBN")
diff --git a/isiscb/isisdata/migrations/0095_auto_20210826_0119.py b/isiscb/isisdata/migrations/0095_auto_20210826_0119.py
new file mode 100644
index 000000000..1208938d3
--- /dev/null
+++ b/isiscb/isisdata/migrations/0095_auto_20210826_0119.py
@@ -0,0 +1,32 @@
+# Generated by Django 3.0.7 on 2021-08-26 01:19
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contenttypes', '0002_remove_content_type_name'),
+ ('isisdata', '0094_auto_20210717_1853'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='attributetype',
+ name='value_content_type',
+ field=models.ForeignKey(limit_choices_to=models.Q(('model', 'textvalue'), ('model', 'charvalue'), ('model', 'intvalue'), ('model', 'datetimevalue'), ('model', 'datevalue'), ('model', 'floatvalue'), ('model', 'locationvalue'), ('model', 'isodatevalue'), ('model', 'isodaterangevalue'), ('model', 'authorityvalue'), ('model', 'citationvalue'), _connector='OR'), on_delete=django.db.models.deletion.CASCADE, related_name='attribute_value', to='contenttypes.ContentType'),
+ ),
+ migrations.CreateModel(
+ name='CitationValue',
+ fields=[
+ ('value_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='isisdata.Value')),
+ ('name', models.TextField(blank=True, null=True)),
+ ('value', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='isisdata.Citation')),
+ ],
+ options={
+ 'verbose_name': 'citation',
+ },
+ bases=('isisdata.value',),
+ ),
+ ]
diff --git a/isiscb/isisdata/models.py b/isiscb/isisdata/models.py
index e14f202ea..6f1a27139 100644
--- a/isiscb/isisdata/models.py
+++ b/isiscb/isisdata/models.py
@@ -43,7 +43,8 @@
VALUETYPES = Q(model='textvalue') | Q(model='charvalue') | Q(model='intvalue') \
| Q(model='datetimevalue') | Q(model='datevalue') \
| Q(model='floatvalue') | Q(model='locationvalue') \
- | Q(model='isodatevalue') | Q(model='isodaterangevalue') | Q(model='authorityvalue')
+ | Q(model='isodatevalue') | Q(model='isodaterangevalue') \
+ | Q(model='authorityvalue') | Q(model='citationvalue')
class Value(models.Model):
@@ -533,6 +534,34 @@ def __str__(self):
class Meta(object):
verbose_name = 'location'
+class CitationValue(Value):
+ """
+ A citation value. Points to an instance of :class:`.Citation`\.
+ """
+ # CHECK: Had to add on_delete so chose cascade -> JD: since we don't delete Authorities at the moment, this is probably fine
+ value = models.ForeignKey('Citation', on_delete=models.CASCADE)
+ name = models.TextField(blank=True, null=True)
+
+ def __unicode__(self):
+ return str(self.value)
+
+ def __str__(self):
+ return str(self.value)
+
+ class Meta(object):
+ verbose_name = 'citation'
+
+ @staticmethod
+ def convert(value):
+ if type(value) is Citation:
+ return value
+
+ try:
+ return Citation.objects.get(pk=value)
+ except ValueError:
+ raise ValidationError('Must be the id of an existing citation.')
+
+
class AuthorityValue(Value):
"""
An authority value. Points to an instance of :class:`.Authority`\.
diff --git a/isiscb/isisdata/templates/isisdata/authority_fragments/fragment_authority_info_box.html b/isiscb/isisdata/templates/isisdata/authority_fragments/fragment_authority_info_box.html
index 935c4d4b7..dad6f910e 100644
--- a/isiscb/isisdata/templates/isisdata/authority_fragments/fragment_authority_info_box.html
+++ b/isiscb/isisdata/templates/isisdata/authority_fragments/fragment_authority_info_box.html
@@ -2,6 +2,7 @@
{% load static %}
{% load search_filters %}
{% load authority_filters %}
+{% load citation_filters %}
{% load facet_filters %}
@@ -131,8 +132,24 @@ {{ authority.name }}
{% endif %}
+ {% with authority|get_bibliographic_essays as bib_essays %}
+ {% if bib_essays %}
+ {% for bib_essay in bib_essays %}
+
+ There is a bibliographic essay on this topic: "{{bib_essay.value.cvalue.title_for_display}}" by {{bib_essay.value.cvalue|get_authors|join_authors:""}}
+
+ {% if bib_essay.value.cvalue|get_urls %}
+ {% for url in bib_essay.value.cvalue|get_urls %}
+
Link: {{ url.resource_name }}
+ {% endfor %}
+ {% endif %}
+
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+
{% for attribute in authority.attributes.all %}
- {% if attribute|is_attribute_visible %}
+ {% if attribute|is_attribute_visible and not attribute|is_bibliographic_essay %}
{{ attribute.type_controlled.display_name }}: {% if attribute.value_freeform %}{{ attribute.value_freeform }}{% else %}{{ attribute.value.display }}{% endif %}
{% endif %}
{% endfor %}
diff --git a/isiscb/isisdata/templatetags/authority_filters.py b/isiscb/isisdata/templatetags/authority_filters.py
index cafed3b6f..9694573bc 100644
--- a/isiscb/isisdata/templatetags/authority_filters.py
+++ b/isiscb/isisdata/templatetags/authority_filters.py
@@ -15,3 +15,15 @@ def is_attribute_visible(attribute):
return False
return attribute.public
+
+@register.filter
+def is_bibliographic_essay(attribute):
+ return attribute.type_controlled.name==settings.BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME
+
+@register.filter
+def get_bibliographic_essays(authority):
+ return authority.attributes.filter(type_controlled__name=settings.BIBLIOGRAPHIC_ESSAY_ATTRIBUTE_NAME)
+
+@register.filter
+def get_urls(citation):
+ return citation.linkeddata_entries.filter(type_controlled__name=settings.URL_LINKED_DATA_NAME)
diff --git a/isiscb/isisdata/templatetags/citation_filters.py b/isiscb/isisdata/templatetags/citation_filters.py
index 4c6a92748..6f400707d 100644
--- a/isiscb/isisdata/templatetags/citation_filters.py
+++ b/isiscb/isisdata/templatetags/citation_filters.py
@@ -46,6 +46,12 @@ def get_editors(citation):
return citation.acrelation_set.filter(type_controlled__in=['ED'])
return citation
+@register.filter
+def get_authors(citation):
+ if citation:
+ return citation.acrelation_set.filter(type_controlled__in=['AU'], citation__public=True, public=True).order_by('data_display_order')
+ return citation
+
@register.filter
def join_names_with_postfix(name_list, postfix):
diff --git a/requirements.txt b/requirements.txt
index c3a0c059c..e58aeb6ff 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,14 +1,14 @@
amqp==2.5.2
-asgiref==3.2.7
+#asgiref==3.2.7
attrs==19.3.0
-awsebcli==3.18.2
+awsebcli==3.20.2
backports.ssl-match-hostname==3.7.0.1
bcrypt==3.1.7
billiard==3.6.3.0
bleach==3.1.4
blessed==1.17.4
-boto3==1.12.36
-botocore==1.15.36
+boto3==1.18.35
+botocore==1.21.36
cached-property==1.5.1
cachetools==4.0.0
celery==4.4.2
@@ -21,14 +21,14 @@ colorclass==2.2.0
confusable-homoglyphs==3.2.0
cryptography==2.9
defusedxml==0.6.0
-Django==3.0.7
+Django==3.1.12
django-allauth==0.41.0
django-autocomplete-light==3.5.1
django-braces==1.14.0
django-celery-results==1.2.1
django-cors-headers==3.2.1
django-extensions==2.2.9
-django-filter==2.2.0
+django-filter==2.4.0
django-guardian==2.2.0
django-haystack==3.0b1
django-ipware==2.1.0
@@ -76,7 +76,7 @@ paramiko==2.7.1
pathspec==0.5.9
pbr==5.4.4
pefile==2019.4.18
-Pillow==8.0
+Pillow==8.3.2
pip-upgrader==1.4.15
protobuf==3.11.3
psycopg2-binary==2.8.6
@@ -96,12 +96,12 @@ PyYAML==5.3.1
rdflib==4.2.2
redis==3.4.1
regex==2020.4.4
-requests==2.20.1
+#requests==2.20.1
requests-oauthlib==1.3.0
rsa==4.0
rules==2.2
-s3transfer==0.3.3
-semantic-version==2.5.0
+#s3transfer==0.3.3
+#semantic-version==2.5.0
six==1.11.0
smart-open==1.10.0
social-auth-app-django==3.1.0
@@ -112,7 +112,7 @@ termcolor==1.1.0
terminaltables==3.1.0
texttable==1.6.2
Unidecode==1.1.1
-urllib3==1.24.3
+urllib3==1.26.6
vine==1.3.0
wcwidth==0.1.9
webencodings==0.5.1