Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added support for the CRediT Taxonomy for contributors #4512

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8d8d740
Initial work on CRediT
MartinPaulEve Nov 21, 2024
ec37b88
Templates to display CRediT
MartinPaulEve Nov 25, 2024
53a813f
More work on CRediT interface
MartinPaulEve Nov 25, 2024
ea47914
Fix duplicate ID
MartinPaulEve Nov 25, 2024
9589493
Layout
MartinPaulEve Nov 25, 2024
51205f3
Add CRediT to review metadata page
MartinPaulEve Nov 25, 2024
e2ab527
Add CRediT to review metadata page using frozen data
MartinPaulEve Nov 25, 2024
ea01600
Fix CREDIT_ROLE_CHOICES
MartinPaulEve Nov 25, 2024
071c30a
Add CRediT info link
MartinPaulEve Nov 26, 2024
fbd1a19
Add edit CRediT to edit metadata page
MartinPaulEve Nov 26, 2024
81358e2
Handle blank entry for add_credit
MartinPaulEve Nov 26, 2024
d9c5730
Add logic
MartinPaulEve Dec 3, 2024
1a4020d
Add logic to add, remove, and view CRediT records
MartinPaulEve Dec 3, 2024
084e0b0
Undo migrations
MartinPaulEve Dec 4, 2024
debcdee
Migrations
MartinPaulEve Dec 4, 2024
764cb8c
Revert templates/admin and submission/views.py to master
MartinPaulEve Dec 6, 2024
de81dc5
fix: change indentation to only run CRediT update when force_update i…
MartinPaulEve Dec 9, 2024
26cad02
fix: long lines
MartinPaulEve Dec 9, 2024
2bae120
fix: long lines of python
MartinPaulEve Dec 9, 2024
1522142
fix: add CRediT URLs
MartinPaulEve Dec 13, 2024
b484cca
fix: replace emoji with font-awesome
MartinPaulEve Dec 13, 2024
fa4f26d
fix: hide CRediT sections if not used
MartinPaulEve Dec 13, 2024
879ae54
feat: add CRediT to JATS
MartinPaulEve Dec 13, 2024
4687842
fix: DRY for credit roles and credit roles with URLs
MartinPaulEve Dec 13, 2024
1a83e9f
fix: add comments
MartinPaulEve Dec 13, 2024
ccc9d3b
Add flag to toggle CRediT
MartinPaulEve Dec 18, 2024
2b7e64d
Add option to toggle credit
MartinPaulEve Dec 18, 2024
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: 1 addition & 1 deletion src/core/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ def get_settings_to_edit(display_group, journal, user):
'use_ga_four', 'display_login_page_notice', 'login_page_notice',
'display_register_page_notice', 'register_page_notice',
'support_email', 'support_contact_message_for_staff',
'from_address', 'replyto_address',
'from_address', 'replyto_address', "use_credit"
]

group_of_settings = process_setting_list(journal_settings, 'general', journal)
Expand Down
51 changes: 50 additions & 1 deletion src/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from review import models as review_models
from copyediting import models as copyediting_models
from submission import models as submission_models
from submission.models import CreditRecord
from utils.logger import get_logger
from utils import logic as utils_logic
from utils.forms import plain_text_validator
Expand Down Expand Up @@ -565,6 +566,14 @@ def snapshot_self(self, article, force_update=True):
setattr(frozen_author, k, v)
frozen_author.save()

# now update the CRediT records
credit_records = CreditRecord.objects.filter(article=article,
author=self)

for credit_record in credit_records:
credit_record.frozen_author = frozen_author
credit_record.save()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an indentation problem here. This code is inline with line 564, outside the if, meaning the else on 576 will be a syntax error. It needs to be indented so that it is part of the if clause started on 564, right?

I think this will also need to remove roles from the frozen author that have been removed on the author, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so I wasn't sure what force_update meant in "if frozen_author and force_update", and assumed it was a unique case, but that we would always want to save the credit_records when we freeze an article. Is that not right?

Copy link
Member

@joemull joemull Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree it's a good idea to update credit records in this spot, it just needs to be inside the first if clause / indented four spaces.

WRT to force_update, it is defined on snapshot_authors if you search for it (granted, it should be defined on snapshot_self). It is "Whether or not to update existing records". So this if block is supposed to run when there are existing frozen authors and when they need to be updated, which is a lot of the time, like in the pre-publication stage, IIRC.

With the current indentation, you are changing the code below from if / else to for / else, which is not what we want, because the else will always run. We only want lines 577 etc. to run if the conditions on line 564 are not met.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Martin has now fixed the indentation and syntax bugs here.

But I still think this needs to remove past CRediT roles from the FrozenAuthor during a forced update. As mentioned on 5 Dec above: "I think this will also need to remove roles from the frozen author that have been removed on the author, right?"

Currently I do not think the interface would invite users to edit credit roles on the author after submission, but still it makes sense to keep the function straightforward and idempotent because it may be a bug for other places that create these records. Think about importers, plugins, etc.

else:
try:
order_object = article.articleauthororder_set.get(author=self)
Expand All @@ -576,12 +585,52 @@ def snapshot_self(self, article, force_update=True):
defaults={'order': order_integer}
)

submission_models.FrozenAuthor.objects.get_or_create(
fa, _ = submission_models.FrozenAuthor.objects.get_or_create(
author=self,
article=article,
defaults=dict(order=order_object.order, **frozen_dict)
)

# now update the CRediT records
credit_records = CreditRecord.objects.filter(article=article,
author=self)

for credit_record in credit_records:
credit_record.frozen_author = fa
credit_record.save()

def credits(self, article):
"""
Returns the CRediT records for this user on a given article
"""
return submission_models.CreditRecord.objects.filter(article=article,
author=self)

def add_credit(self, credit_role_text, article):
"""
Adds a CRediT role to the article for this user
"""
record, _ = (
submission_models.CreditRecord.objects.get_or_create(
article=article, author=self, role=credit_role_text)
)

return record

def remove_credit(self, credit_role_text, article):
"""
Removes a CRediT role from the article for this user
"""
try:
record, _ = (
submission_models.CreditRecord.objects.get(
article=article, author=self, role=credit_role_text)
)

record.delete()
except submission_models.CreditRecord.DoesNotExist:
pass

def frozen_author(self, article):
try:
return submission_models.FrozenAuthor.objects.get(
Expand Down
21 changes: 21 additions & 0 deletions src/journal/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,25 @@ def article(request, identifier_type, identifier):
file__mime_type='text/html',
)

credit_roles = {}
show_credit = False

use_credit = setting_handler.get_setting(
"general", "use_credit",
journal=request.journal
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't working yet because it needs to get the associated setting value.


if use_credit:
for frozen_author in article_object.frozen_authors():
credit_role_qs = submission_models.CreditRecord.objects.filter(
article=article_object, frozen_author=frozen_author
).order_by("role")

credit_roles[frozen_author] = credit_role_qs

if len(credit_role_qs) > 0:
show_credit = True

template = 'journal/article.html'
context = {
'article': article_object,
Expand All @@ -487,6 +506,8 @@ def article(request, identifier_type, identifier):
'identifier': identifier,
'article_content': content,
'tables_in_galley': tables_in_galley,
'credit_roles': credit_roles,
'show_credit': show_credit,
}

return render(request, template, context)
Expand Down
8 changes: 8 additions & 0 deletions src/submission/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ class ArticleLogAdmin(admin_utils.ArticleFKModelAdmin):
def _article(self, obj):
return truncatewords_html(str(obj.article), 10) if obj else ''

class CreditRecordAdmin(admin.ModelAdmin):
list_display = ('role', 'article', 'author', '_frozenauthor')
list_filter = ('article', 'author', 'role')
search_fields = ('role', 'article', 'author', '_frozenauthor')

def _frozenauthor(self, obj):
return truncatewords_html(str(obj.article), 10) if obj else ''

class LicenseAdmin(admin.ModelAdmin):
list_display = ('name', 'short_name', 'journal', 'url', '_text')
Expand Down Expand Up @@ -223,6 +230,7 @@ class ArticleAuthorOrderAdmin(admin_utils.ArticleFKModelAdmin):
(models.Keyword, KeywordAdmin),
(models.SubmissionConfiguration, SubmissionConfigAdmin),
(models.ArticleAuthorOrder, ArticleAuthorOrderAdmin),
(models.CreditRecord, CreditRecordAdmin)
]

[admin.site.register(*t) for t in admin_list]
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 4.2.16 on 2024-12-04 15:55

import core.model_utils
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('repository', '0045_historicalrepository_display_public_metrics_and_more'),
('submission', '0084_remove_article_jats_article_type_and_more'),
]

operations = [
migrations.AlterField(
model_name='article',
name='jats_article_type_override',
field=core.model_utils.DynamicChoiceField(blank=True, choices=[], default=None, help_text='The type of article as per the JATS standard. This field allows you to override the default for the section.', max_length=255, null=True),
),
migrations.AlterField(
model_name='section',
name='jats_article_type',
field=core.model_utils.DynamicChoiceField(blank=True, choices=[], help_text='The default JATS article type for articles in this section. This can be overridden on a per-article basis.', max_length=255, null=True, verbose_name='JATS default article type'),
),
migrations.CreateModel(
name='CreditRecord',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('last_modified', models.DateTimeField(auto_now=True)),
('role', models.CharField(blank=True, choices=[('Conceptualization', 'Conceptualization'), ('Data Curation', 'Data Curation'), ('Formal Analysis', 'Formal Analysis'), ('Funding Acquisition', 'Funding Acquisition'), ('Investigation', 'Investigation'), ('Methodology', 'Methodology'), ('Project Administration', 'Project Administration'), ('Resources', 'Resources'), ('Software', 'Software'), ('Supervision', 'Supervision'), ('Validation', 'Validation'), ('Visualization', 'Visualization'), ('Writing - Original Draft', 'Writing - Original Draft'), ('Writing - Review & Editing', 'Writing - Review & Editing')], max_length=100, null=True)),
('article', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='submission.article')),
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
('frozen_author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='submission.frozenauthor')),
('preprint_author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='repository.preprintauthor')),
],
options={
'verbose_name': 'CRediT record',
'verbose_name_plural': 'CRediT records',
},
),
]
Loading