Skip to content
Open
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
12 changes: 12 additions & 0 deletions src/submission/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,15 @@ def save(self, commit=True):
if commit:
affiliation.save()
return affiliation


class FrozenAuthorAccountForm(forms.ModelForm):
"""
A form to power the view that lets users link an existing
author record to an existing account record.
Not intended for use entering a new author record.
"""

class Meta:
model = models.FrozenAuthor
fields = ("author",)
23 changes: 23 additions & 0 deletions src/submission/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,3 +621,26 @@ def remove_credit_role(request, article):
},
)
return author


def get_current_authors(article, request):
authors = []
for author, credits in article.authors_and_credits().items():
# Prepare CREDiT form
credit_form = get_credit_form(request, author)

# Detected unlinked accounts
unlinked_account = None
if author.email and not author.author:
try:
unlinked_account = core_models.Account.objects.get(
email__iexact=author.email,
accountrole__role__slug="author",
)
except (
core_models.Account.DoesNotExist,
core_models.Account.MultipleObjectsReturned,
):
pass
authors.append((author, credits, credit_form, unlinked_account))
return authors
23 changes: 23 additions & 0 deletions src/submission/tests/test_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from mock import patch

from utils.testing import helpers
from submission import models as submission_models


class TestSubmitAuthorsLogic(TestCase):
Expand Down Expand Up @@ -216,3 +217,25 @@ def test_add_author_from_search_orcid_public_affiliations(self, get_orcid_detail
last_author.primary_affiliation().__str__(),
"Birkbeck",
)

def test_get_current_authors_detects_unlinked_authors(self):
self.client.force_login(self.kathleen)

# Create unlinked author record with same email as existing user
frozen_author, _created = submission_models.FrozenAuthor.objects.get_or_create(
article=self.article,
first_name="T.",
middle_name="S.",
last_name="Eliot",
frozen_email=self.eliot.email,
)
response = self.client.get(
reverse("submit_authors", kwargs={"article_id": self.article.pk}),
SERVER_NAME=self.journal_one.domain,
)
_kathleen_author_tup, eliot_author_tup = response.context["authors"]
_eliot_author, _credits, _credit_form, unlinked_account = eliot_author_tup
self.assertEqual(
unlinked_account,
self.eliot,
)
28 changes: 28 additions & 0 deletions src/submission/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,31 @@ def test_edit_author_save_author(self):
self.kathleen_author.first_name,
"K.",
)

@override_settings(URL_CONFIG="domain")
def test_link_author_to_account(self):
self.client.force_login(self.kathleen)

email = "cwexmgdydil9hbgiw99l@example.org"
# Create an unlinked author record
frozen_author, _created = models.FrozenAuthor.objects.get_or_create(
article=self.article,
frozen_email=email,
)
# Create an account with the same email
account = helpers.create_user(email, ["author"], self.journal_one)
self.client.post(
reverse(
"submission_link_author_to_account",
kwargs={
"article_id": self.article.pk,
"author_id": frozen_author.pk,
},
),
SERVER_NAME=self.journal_one.domain,
)
frozen_author.refresh_from_db()
self.assertEqual(
frozen_author.author,
account,
)
5 changes: 5 additions & 0 deletions src/submission/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
views.delete_frozen_author,
name="submission_delete_frozen_author",
),
re_path(
r"^(?P<article_id>\d+)/authors/(?P<author_id>\d+)/link_to_account/$",
views.link_author_to_account,
name="submission_link_author_to_account",
),
# Affiliations
re_path(
r"^(?P<article_id>\d+)/author/(?P<author_id>\d+)/organization/search/$",
Expand Down
54 changes: 42 additions & 12 deletions src/submission/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,7 @@ def submit_authors(request, article_id):
article.save()
return redirect(reverse("submit_files", kwargs={"article_id": article_id}))

authors = []
for author, credits in article.authors_and_credits().items():
credit_form = logic.get_credit_form(request, author)
authors.append((author, credits, credit_form))
authors = logic.get_current_authors(article, request)

template = "admin/submission/submit_authors.html"
context = {
Expand Down Expand Up @@ -374,10 +371,7 @@ def edit_current_authors(request, article_id):
elif "remove_credit" in request.POST:
last_changed_author = logic.remove_credit_role(request, article)

authors = []
for author, credits in article.authors_and_credits().items():
credit_form = logic.get_credit_form(request, author)
authors.append((author, credits, credit_form))
authors = logic.get_current_authors(article, request)

template = "admin/elements/current_authors_inner.html"
context = {
Expand Down Expand Up @@ -927,10 +921,7 @@ def edit_author_metadata(request, article_id):
author = logic.add_author_from_search(search_term, request, article)
last_changed_author = author

authors = []
for author, credits in article.authors_and_credits().items():
credit_form = logic.get_credit_form(request, author)
authors.append((author, credits, credit_form))
authors = logic.get_current_authors(article, request)

template = "admin/submission/edit/author_metadata.html"
context = {
Expand Down Expand Up @@ -1033,6 +1024,45 @@ def order_authors(request, article_id):
return HttpResponse("Thanks")


@require_POST
@user_can_edit_article
def link_author_to_account(request, article_id, author_id):
next_url = request.GET.get("next", "")

article = get_object_or_404(models.Article, pk=article_id, journal=request.journal)
author = get_object_or_404(models.FrozenAuthor, pk=author_id, article=article)
account = get_object_or_404(
core_models.Account,
email__iexact=author.email,
accountrole__role__slug="author",
)

author_account_form = forms.FrozenAuthorAccountForm(
{"author": account.pk},
instance=author,
)
if author_account_form.is_valid():
author_account_form.save()
messages.add_message(
request,
messages.SUCCESS,
"%(author_name)s (%(email)s) is now linked to a user account."
% {"author_name": author.full_name(), "email": author.email},
)

if next_url:
return redirect(next_url)
else:
return redirect(
reverse(
"submission_edit_author_metadata",
kwargs={
"article_id": article_id,
},
)
)


@editor_user_required
def fields(request, field_id=None):
"""
Expand Down
22 changes: 21 additions & 1 deletion src/templates/admin/elements/current_authors_inner.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ <h2>{% trans "Current authors" %}</h2>
</div>
<div class="columns">
<div class="list-group">
{% for author, credits, credit_form in authors %}
{% for author, credits, credit_form, unlinked_account in authors %}
{% with "author-"|concat:author.pk as section_id %}
<section
id="{{ section_id }}"
Expand All @@ -36,6 +36,26 @@ <h2>{% trans "Current authors" %}</h2>
{% if article.correspondence_author and article.correspondence_author == author.author %}
{% include "admin/submission/submit_correspondence_author.html" with article=article %}
{% endif %}
{% if unlinked_account %}
<div class="bs-callout bs-callout-info">
<p>
A user account was found that has the same email address as
this author ({{ unlinked_account.email }}), but they are not linked yet.
Would you like to link the author to the account?
</p>
<form
method="POST"
action="{% url_with_return "submission_link_author_to_account" article.pk author.pk %}">
{% csrf_token %}
<div class="button-group no-bottom-margin">
<button class="button hollow secondary">
<span class="fa fa-plus"></span>
{% trans "Link Account" %}
</button>
</div>
</form>
</div>
{% endif %}
<div class="flex gap-2 direction-column-small">
{% if authors|length > 1 %}
<div class="stat">{{ forloop.counter }}</div>
Expand Down
24 changes: 19 additions & 5 deletions src/templates/admin/submission/edit/author.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,29 @@ <h2>{% trans "Name, bio, and identifiers" %}</h2>
</div>
{% include "admin/elements/forms/field.html" with field=form.frozen_biography %}
<div class="grid auto">
{% if author.author and author.author == request.user %}
{% if author.author %}
<dl class="no-bottom-margin">
<dt><strong>Email</strong></dt>
<dd>
<div>{{ author.email|default:"No email" }}</div>
<p class="help-text no-top-margin">
If the email is incorrect, edit the
email on your user profile.
</p>
{% if author.author == request.user %}
<p class="help-text no-top-margin">
If the email is incorrect, edit the
email on your user profile.
</p>
{% else %}
<p class="help-text no-top-margin">
If the email is incorrect, edit the email on the author's
{% spaceless %}
<a
target="_blank"
href="{% url 'core_user_edit' author.author.pk %}">
<span>user account</span>
<span class="show-for-sr">(opens in new tab)</span>
</a>.
{% endspaceless %}
</p>
{% endif %}
</dd>
</dl>
{% else %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@
{% include "admin/elements/button_copy.html" with content=content label_copy=label_copy label_copied=label_copied %}
{% if authors|length > 1 %}
<p>{% blocktrans %}
After they have made their account, remove and re-add
them to the author list via the search.
After they have made their account, a button will appear
above their author record letting you link up their account.
{% endblocktrans %}</p>
{% else %}
<p>{% blocktrans %}
Expand Down
Loading