diff --git a/partners/forms.py b/partners/forms.py index 18a2df7814561a220e886717e019b8b1279a8866..597203298097fd6bab5434278956ff93c80b47f9 100644 --- a/partners/forms.py +++ b/partners/forms.py @@ -135,7 +135,8 @@ class InstitutionForm(forms.ModelForm): 'acronym', 'address', 'country', - 'logo' + 'logo', + 'css_class', ) diff --git a/partners/migrations/0003_institution_css_class.py b/partners/migrations/0003_institution_css_class.py new file mode 100644 index 0000000000000000000000000000000000000000..86b396b467187655cd61d5f094d0e0d726f869e8 --- /dev/null +++ b/partners/migrations/0003_institution_css_class.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-01-11 17:03 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0002_auto_20171229_1435'), + ] + + operations = [ + migrations.AddField( + model_name='institution', + name='css_class', + field=models.CharField(blank=True, max_length=256), + ), + ] diff --git a/partners/migrations/0004_auto_20180112_1919.py b/partners/migrations/0004_auto_20180112_1919.py new file mode 100644 index 0000000000000000000000000000000000000000..2bd79a5ac6b3cee62bb4eae8ad08f00bd7630b30 --- /dev/null +++ b/partners/migrations/0004_auto_20180112_1919.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-01-12 18:19 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0003_institution_css_class'), + ] + + operations = [ + migrations.AlterField( + model_name='institution', + name='css_class', + field=models.CharField(blank=True, max_length=256, verbose_name='Additional logo CSS class'), + ), + ] diff --git a/partners/models.py b/partners/models.py index a50861dc2dd7e6077be4095491a336da5512ece6..0bd8987374d29ede28ed6f078efaf2e03f2539c7 100644 --- a/partners/models.py +++ b/partners/models.py @@ -113,6 +113,8 @@ class Institution(models.Model): kind = models.CharField(max_length=32, choices=PARTNER_KINDS) name = models.CharField(max_length=256) logo = models.ImageField(upload_to='institutions/logo/%Y/', blank=True) + css_class = models.CharField(max_length=256, blank=True, + verbose_name="Additional logo CSS class") acronym = models.CharField(max_length=16) address = models.TextField(blank=True) country = CountryField() diff --git a/partners/templates/partners/supporting_partners.html b/partners/templates/partners/supporting_partners.html index 10927c949783c45dab19b57e06500155c9d44be5..65ec345bf8684ed1818ea8830e4b57170ee8edd7 100644 --- a/partners/templates/partners/supporting_partners.html +++ b/partners/templates/partners/supporting_partners.html @@ -20,7 +20,7 @@ {% if perms.scipost.can_manage_SPB %} <div class="row"> - <div class="col-12"> + <div class="col-12"> <a href="{% url 'partners:dashboard' %}">Manage Partners</a> </div> </div> @@ -154,7 +154,7 @@ <ul class="list-unstyled mb-5"> {% for agreement in current_agreements %} <li class="media mb-2"> - <img class="d-flex mr-3" width="192" src="{% if agreement.partner.institution.logo %}{{agreement.partner.institution.logo.url}}{% endif %}" alt="Partner Logo"> + <img class="d-flex mr-3 {{ agreement.partner.institution.css_class }}" width="192" src="{% if agreement.partner.institution.logo %}{{agreement.partner.institution.logo.url}}{% endif %}" alt="Partner Logo"> <div class="media-body"> <p> <strong>{{agreement.partner.institution.name}}</strong><br> diff --git a/production/managers.py b/production/managers.py index a88a6ed1cebaa7920f658f12685436416e558460..fb0788d60275ad02710acd2a94f315f89cfc8375 100644 --- a/production/managers.py +++ b/production/managers.py @@ -3,6 +3,11 @@ from django.db import models from . import constants +class ProductionUserQuerySet(models.QuerySet): + def active(self): + return self.filter(user__isnull=False) + + class ProductionStreamQuerySet(models.QuerySet): def completed(self): return self.filter(status=constants.PRODUCTION_STREAM_COMPLETED) diff --git a/production/migrations/0003_productionuser_name.py b/production/migrations/0003_productionuser_name.py new file mode 100644 index 0000000000000000000000000000000000000000..2084c70d5b0b9e3acfa7466fa460ee64495975c3 --- /dev/null +++ b/production/migrations/0003_productionuser_name.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-01-12 18:38 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('production', '0002_auto_20171229_1435'), + ] + + operations = [ + migrations.AddField( + model_name='productionuser', + name='name', + field=models.CharField(blank=True, max_length=128), + ), + ] diff --git a/production/migrations/0004_auto_20180112_1957.py b/production/migrations/0004_auto_20180112_1957.py new file mode 100644 index 0000000000000000000000000000000000000000..cc0d0d230519822b9df903fe36ae510877441d76 --- /dev/null +++ b/production/migrations/0004_auto_20180112_1957.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2018-01-12 18:57 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('production', '0003_productionuser_name'), + ] + + operations = [ + migrations.AlterField( + model_name='productionuser', + name='user', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='production_user', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/production/models.py b/production/models.py index 12c461b7d0523b84404f1f3fef6b112779ec9eb8..54becc09e16102a0bb5115c3d14f5bfc672303e0 100644 --- a/production/models.py +++ b/production/models.py @@ -8,7 +8,8 @@ from django.utils.functional import cached_property from .constants import PRODUCTION_STREAM_STATUS, PRODUCTION_STREAM_INITIATED, PRODUCTION_EVENTS,\ EVENT_MESSAGE, EVENT_HOUR_REGISTRATION, PRODUCTION_STREAM_COMPLETED,\ PROOFS_STATUSES, PROOFS_UPLOADED -from .managers import ProductionStreamQuerySet, ProductionEventManager, ProofsQuerySet +from .managers import ProductionStreamQuerySet, ProductionEventManager, ProofsQuerySet,\ + ProductionUserQuerySet from .utils import proofs_id_to_slug from finances.models import WorkLog @@ -21,12 +22,15 @@ class ProductionUser(models.Model): to relate all production related actions to. """ user = models.OneToOneField(User, on_delete=models.PROTECT, unique=True, - related_name='production_user') + related_name='production_user', null=True) + name = models.CharField(max_length=128, blank=True) - # objects = ProductionUserQuerySet.as_manager() -- Not implemented yet + objects = ProductionUserQuerySet.as_manager() def __str__(self): - return '%s, %s' % (self.user.last_name, self.user.first_name) + if self.user: + return '%s, %s' % (self.user.last_name, self.user.first_name) + return '%s (deactivated)' % self.name class ProductionStream(models.Model): diff --git a/production/templates/production/production.html b/production/templates/production/production.html index caf432ea2b5c240ce0133606dbcd6ebb5713dd8f..8198157beb4b015e49f7dfe0da807d4fda991e46 100644 --- a/production/templates/production/production.html +++ b/production/templates/production/production.html @@ -83,7 +83,7 @@ </div> <div class="col-6"> - <div class="card center-loader" id="details"> + <div class="card center-loader bg-white" id="details"> {% if stream %} {% include 'production/partials/production_stream_card.html' %} {% else %} @@ -144,7 +144,12 @@ <h3>Current Production Team</h3> <ul> {% for officer in production_officers %} - <li>{{ officer }}</li> + <li>{{ officer }} + <form action="{% url 'production:delete_officer' officer.id %}" class="d-inline px-1" method="post"> + {% csrf_token %} + <input type="submit" class="btn btn-danger mb-1" value="Remove Officer"> + </form> + </li> {% endfor %} </ul> diff --git a/production/urls.py b/production/urls.py index e0ecebf5d00fe77d42d40e79c8533a40fdeea3d1..f1419f395e8ee04d6b8c5d307f67b715139ae25f 100644 --- a/production/urls.py +++ b/production/urls.py @@ -7,6 +7,8 @@ urlpatterns = [ url(r'^(?P<stream_id>[0-9]+)$', production_views.production, name='production'), url(r'^completed$', production_views.completed, name='completed'), url(r'^officers/new$', production_views.user_to_officer, name='user_to_officer'), + url(r'^officers/(?P<officer_id>[0-9]+)/delete$', production_views.delete_officer, + name='delete_officer'), url(r'^streams/(?P<stream_id>[0-9]+)$', production_views.stream, name='stream'), url(r'^streams/(?P<stream_id>[0-9]+)/status$', diff --git a/production/views.py b/production/views.py index f368999aa87719819176a8ef2b3a22073c402cc1..52dc38d1669f07c93c894e0c11f3de82527d05bb 100644 --- a/production/views.py +++ b/production/views.py @@ -68,10 +68,10 @@ def production(request, stream_id=None): pass if request.user.has_perm('scipost.can_view_timesheets'): - context['production_team'] = ProductionUser.objects.all() + context['production_team'] = ProductionUser.objects.active() if request.user.has_perm('scipost.can_promote_to_production_team'): - context['production_officers'] = ProductionUser.objects.all() + context['production_officers'] = ProductionUser.objects.active() context['new_officer_form'] = UserToOfficerForm() return render(request, 'production/production.html', context) @@ -146,6 +146,20 @@ def user_to_officer(request): return redirect(reverse('production:production')) +@is_production_user() +@permission_required('scipost.can_promote_user_to_production_officer') +def delete_officer(request, officer_id): + production_user = get_object_or_404(ProductionUser.objects.active(), id=officer_id) + production_user.name = '{first_name} {last_name}'.format( + first_name=production_user.user.first_name, + last_name=production_user.user.last_name) + production_user.user = None + production_user.save() + + messages.success(request, '{user} removed as Production Officer'.format(user=production_user)) + return redirect(reverse('production:production')) + + @is_production_user() @permission_required('scipost.can_take_decisions_related_to_proofs', raise_exception=True) def update_status(request, stream_id): diff --git a/scipost/static/scipost/assets/css/_homepage.scss b/scipost/static/scipost/assets/css/_homepage.scss index e3ef3e8f07570b317b56029b0c3d5dee54951f4d..52cd38d0f81fd4376799cca61a20f16df4d699dd 100644 --- a/scipost/static/scipost/assets/css/_homepage.scss +++ b/scipost/static/scipost/assets/css/_homepage.scss @@ -47,6 +47,7 @@ img { max-height: 100px !important; + height: auto !important; width: auto !important; } } diff --git a/scipost/static/scipost/assets/css/_media.scss b/scipost/static/scipost/assets/css/_media.scss new file mode 100644 index 0000000000000000000000000000000000000000..e05fa803192290376002cbdf1d3bf7bbc08624eb --- /dev/null +++ b/scipost/static/scipost/assets/css/_media.scss @@ -0,0 +1,9 @@ +.media > img.small-img { + width: 100px; + margin-left: 46px; + margin-right: 46px; + + &.mr-3 { + margin-right: 62px !important; + } +} diff --git a/scipost/static/scipost/assets/css/_navbar.scss b/scipost/static/scipost/assets/css/_navbar.scss index 4f083989c47b56b03f90f528b1144febbc7e8798..c74f30a0f50d61d9ff505251fbcd1dfa3548353d 100644 --- a/scipost/static/scipost/assets/css/_navbar.scss +++ b/scipost/static/scipost/assets/css/_navbar.scss @@ -9,6 +9,10 @@ text-decoration: underline; } + .nav-link { + color: $white; + } + .navbar-nav { flex-direction: row; overflow: scroll; diff --git a/scipost/static/scipost/assets/css/style.scss b/scipost/static/scipost/assets/css/style.scss index 5b2d4702fc9744c9f3ab74936d10a968850e6049..ddd9fc91b2ca14722ee634cfe12ee1f75cb090a8 100644 --- a/scipost/static/scipost/assets/css/style.scss +++ b/scipost/static/scipost/assets/css/style.scss @@ -26,6 +26,7 @@ @import "homepage"; @import "labels"; @import "list_group"; +@import "media"; @import "messages"; @import "modal"; @import "navbar"; diff --git a/scipost/templates/scipost/index.html b/scipost/templates/scipost/index.html index 1bcfc115cbae7805a462fd0333f4192069806cbc..fb119f746bb9f6ed95963de0b7f1d11d31360e92 100644 --- a/scipost/templates/scipost/index.html +++ b/scipost/templates/scipost/index.html @@ -194,6 +194,7 @@ <a href="//www.crossref.org" target="_blank"><img src="//assets.crossref.org/logo/crossref-logo-200.svg" width="100" alt="Crossref logo"></a> <a href="//www.doaj.org" target="_blank"><img src="{% static 'scipost/images/doaj_logo_200.jpg' %}" width="90" alt="DOAJ logo"></a> <a href="//www.clockss.org" target="_blank"><img src="{% static 'scipost/images/clockss_original_logo_boxed_ai-cropped-90.png' %}" width="80" alt="Clockss logo"></a> + <a href="//i4oc.org/" target="_blank"><img width="100" src="{% static 'scipost/images/I4OC.png' %}"></a> </div> </div> <div class="row"> @@ -204,7 +205,6 @@ <a href="//www.mpg.de/en" target="_blank"><img width="100" src="{% static 'scipost/images/Max-Planck-Gesellschaft.svg' %}"></a> <a href="//www.vsnu.nl" target="_blank"><img width="100" src="{% static 'scipost/images/logovsnu.jpg' %}"></a> <a href="//www.openaire.eu" target="_blank"><img width="100" src="{% static 'scipost/images/OpenAIRE.png' %}"></a> - <a href="//i4oc.org/" target="_blank"><img width="100" src="{% static 'scipost/images/I4OC.png' %}"></a> </div> </div> </div> diff --git a/scipost/views.py b/scipost/views.py index b915380025f27fe03f00ef51651f1920ba48b8c6..a9fe527bf5667f0f4f2368b966a3ca8c66dc58a7 100644 --- a/scipost/views.py +++ b/scipost/views.py @@ -90,7 +90,7 @@ def index(request): 'journals': Journal.objects.order_by('name'), 'publications': Publication.objects.published().order_by('-publication_date', '-paper_nr')[:3], - 'current_agreements': MembershipAgreement.objects.now_active()[:2], + 'current_agreements': MembershipAgreement.objects.now_active(), } return render(request, 'scipost/index.html', context) diff --git a/submissions/forms.py b/submissions/forms.py index 855bdd6c48042c9ec3837edcc1f31a8d95551136..ee1365c2b8033b8aca7292f66a0cee41ed5facb5 100644 --- a/submissions/forms.py +++ b/submissions/forms.py @@ -762,7 +762,6 @@ class iThenticateReportForm(forms.ModelForm): self.client = self.get_client() if not self.client: - self.add_error(None, "Failed to login to iThenticate.") return None # Document (id) is found diff --git a/submissions/plagiarism.py b/submissions/plagiarism.py index a36decb68693fcd0602c6891f392405ea2847405..ef08622621274f5cc13275c68b5ba6f715675e6c 100644 --- a/submissions/plagiarism.py +++ b/submissions/plagiarism.py @@ -88,7 +88,7 @@ class iThenticate: if response['status'] == 200: submission.add_general_event('The document has been submitted for a plagiarism check.') - return response.get('data', [{}])[0].get('uploaded') + return response.get('data', [{'uploaded': [{}]}])[0].get('uploaded')[0] return None def get_url(self, document_id):