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

Support for the Research Organization Registry (ROR) #4483

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8a8d7c7
First draft of data model #3168
joemull Jul 26, 2024
06ad0a9
Build ROR importer #3168
joemull Dec 4, 2024
1d63f73
Updates to data model #3168
joemull Dec 6, 2024
2ecfe7a
Create standard buttons #3168
joemull Dec 6, 2024
2a963aa
UI for core affiliation management #3168
joemull Dec 6, 2024
aef0bb3
Deprecate several more old account templates #4380
joemull Dec 6, 2024
67096e8
chore #3168 Clean up old prints in testing
joemull Dec 9, 2024
e7b1c05
Work through regressions #3168
joemull Dec 9, 2024
84c720c
Avoid Django ListView paginator bug
joemull Dec 13, 2024
de6d106
Display primary affiliation; add primary if first #3168
joemull Dec 13, 2024
c2576aa
feat #3168 Add affiliation inline to admin pages
joemull Jan 20, 2025
ed69d4c
feat #3168 Migrations for existing data
joemull Jan 20, 2025
77fa89b
feat #3168 Avoid bug that caused duplicate locations to be created
joemull Jan 22, 2025
40b1a0c
feat #3168 Add country and location to data migration
joemull Jan 22, 2025
bf7407a
feat #3168 Override get_or_create to handle old affiliation fields
joemull Jan 22, 2025
aac820c
feat #3168 Utility for matching legacy organizations
joemull Jan 24, 2025
a9d19a5
feat #3168 Improve importing process
joemull Jan 24, 2025
4f0730f
feat #3168 Fix a bug where a bool might be unset
joemull Jan 24, 2025
93b05fc
feat #3168 Fix a bug with a URL name
joemull Jan 24, 2025
4272462
feat #3168 Display start and end dates on affiliations
joemull Jan 24, 2025
56f41e1
feat #3168 Use function-based views for CRUD interface
joemull Jan 24, 2025
7fac40a
feat #3168 Fix logic that manages affiliations
joemull Jan 27, 2025
069c497
Clean up submission test data
joemull Jan 27, 2025
5dbbf18
feat #3168 Adjustments from manual testing
joemull Jan 27, 2025
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
89 changes: 86 additions & 3 deletions src/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ class SettingAdmin(admin.ModelAdmin):
class AccountAdmin(UserAdmin):
"""Displays Account objects in the Django admin interface."""
list_display = ('id', 'email', 'orcid', 'first_name', 'middle_name',
'last_name', 'institution', '_roles_in', 'last_login')
'last_name', '_roles_in', 'last_login')
list_display_links = ('id', 'email')
list_filter = ('accountrole__journal',
'repositoryrole__repository__short_name',
'is_active', 'is_staff', 'is_admin', 'is_superuser',
'last_login')
search_fields = ('id', 'username', 'email', 'first_name', 'middle_name',
'last_name', 'orcid', 'institution',
'last_name', 'orcid',
'biography', 'signature')

fieldsets = UserAdmin.fieldsets + (
(None, {'fields': (
'name_prefix', 'middle_name', 'orcid',
'institution', 'department', 'country', 'twitter',
'twitter',
'linkedin', 'facebook', 'github', 'website', 'biography', 'enable_public_profile',
'signature', 'profile_image', 'interest', "preferred_timezone",
)}),
Expand All @@ -71,6 +71,7 @@ class AccountAdmin(UserAdmin):
raw_id_fields = ('interest',)

inlines = [
admin_utils.AffiliationInline,
admin_utils.AccountRoleInline,
admin_utils.RepositoryRoleInline,
admin_utils.EditorialGroupMemberInline,
Expand Down Expand Up @@ -398,6 +399,84 @@ class AccessRequestAdmin(admin.ModelAdmin):
date_hierarchy = ('requested')


class OrganizationAdmin(admin.ModelAdmin):
list_display = ('pk', 'ror', '_ror_display', '_custom_label',
'website', '_locations', 'ror_status')
list_display_links = ('pk', 'ror')
list_filter = ('ror_status', 'locations__country')
search_fields = ('pk', 'ror_display__value', 'custom_label__value', 'labels__value',
'aliases__value', 'acronyms__value', 'website', 'ror')
raw_id_fields = ('locations', )

def _ror_display(self, obj):
return obj.ror_display if obj and obj.ror_display else ''

def _locations(self, obj):
return '; '.join([str(l) for l in obj.locations.all()]) if obj else ''

def _custom_label(self, obj):
return obj.custom_label if obj and obj.custom_label else ''


class OrganizationNameAdmin(admin.ModelAdmin):
list_display = ('pk', 'value', 'language')
list_display_links = ('pk', 'value')
search_fields = ('pk', 'value')
raw_id_fields = ('ror_display_for', 'custom_label_for',
'label_for', 'alias_for', 'acronym_for')

def _ror_display(self, obj):
return obj.ror_display if obj and obj.ror_display else ''

def _locations(self, obj):
return '; '.join([str(l) for l in obj.locations.all()]) if obj else ''

def _custom_label(self, obj):
return obj.custom_label if obj and obj.custom_label else ''


class LocationAdmin(admin.ModelAdmin):
list_display = ('pk', 'name', 'country', 'geonames_id')
list_display_links = ('pk', 'name')
list_filter = ('country',)
search_fields = ('pk', 'name', 'country__code', 'country__name',
'geonames_id')


class AffiliationAdmin(admin.ModelAdmin):
list_display = ('pk', '_person', 'organization',
'title', 'department', 'start', 'end')
list_display_links = ('pk', '_person')
list_filter = ('start', 'end', 'organization__locations__country')
search_fields = (
'pk',
'title',
'department',
'organization__ror_display__value',
'organization__custom_label__value',
'organization__labels__value',
'organization__aliases__value',
'organization__acronyms__value',
'account__first_name',
'account__last_name',
'account__email',
'frozen_author__first_name',
'frozen_author__last_name',
'frozen_author__frozen_email',
'preprint_author__account__first_name',
'preprint_author__account__last_name',
'preprint_author__account__email',
)
raw_id_fields = ('account', 'frozen_author',
'preprint_author', 'organization')

def _person(self, obj):
if obj:
return obj.account or obj.frozen_author or obj.preprint_author
else:
return ''


admin_list = [
(models.AccountRole, AccountRoleAdmin),
(models.Account, AccountAdmin),
Expand Down Expand Up @@ -427,6 +506,10 @@ class AccessRequestAdmin(admin.ModelAdmin):
(models.Contacts, ContactsAdmin),
(models.Contact, ContactAdmin),
(models.AccessRequest, AccessRequestAdmin),
(models.Organization, OrganizationAdmin),
(models.OrganizationName, OrganizationNameAdmin),
(models.Location, LocationAdmin),
(models.Affiliation, AffiliationAdmin),
]

[admin.site.register(*t) for t in admin_list]
3 changes: 3 additions & 0 deletions src/core/forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
AccessRequestForm,
AccountRoleForm,
AdminUserForm,
AffiliationForm,
ArticleMetaImageForm,
CBVFacetForm,
ConfirmableForm,
ConfirmableIfErrorsForm,
ConfirmDeleteForm,
EditAccountForm,
EditKey,
EditorialGroupForm,
Expand All @@ -24,6 +26,7 @@
JournalSubmissionForm,
LoginForm,
NotificationForm,
OrganizationNameForm,
PasswordResetForm,
PressJournalAttrForm,
QuickUserForm,
Expand Down
34 changes: 32 additions & 2 deletions src/core/forms/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class RegistrationForm(forms.ModelForm, CaptchaForm):
class Meta:
model = models.Account
fields = ('email', 'salutation', 'first_name', 'middle_name',
'last_name', 'department', 'institution', 'country', 'orcid',)
'last_name', 'orcid',)
widgets = {'orcid': forms.HiddenInput() }

def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -532,7 +532,7 @@ def __init__(self, *args, **kwargs):
class QuickUserForm(forms.ModelForm):
class Meta:
model = models.Account
fields = ('email', 'salutation', 'first_name', 'last_name', 'institution',)
fields = ('email', 'salutation', 'first_name', 'last_name',)


class LoginForm(CaptchaForm):
Expand Down Expand Up @@ -940,3 +940,33 @@ class AccountRoleForm(forms.ModelForm):
class Meta:
model = models.AccountRole
fields = '__all__'


class OrganizationNameForm(forms.ModelForm):

class Meta:
model = models.OrganizationName
fields = ('value',)


class AffiliationForm(forms.ModelForm):

class Meta:
model = models.Affiliation
fields = '__all__'
widgets = {
'account': forms.HiddenInput,
'frozen_author': forms.HiddenInput,
'preprint_author': forms.HiddenInput,
'organization': forms.HiddenInput,
'start': HTMLDateInput,
'end': HTMLDateInput,
}


class ConfirmDeleteForm(forms.Form):
"""
A generic form for use on confirm-delete pages
where a valid form with POST data means yes, delete.
"""
pass
32 changes: 32 additions & 0 deletions src/core/include_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,38 @@
re_path(r'^manager/user/(?P<user_id>\d+)/edit/$', core_views.user_edit, name='core_user_edit'),
re_path(r'^manager/user/(?P<user_id>\d+)/history/$', core_views.user_history, name='core_user_history'),

## Affiliations
re_path(
r'^profile/organization/search/$',
core_views.OrganizationListView.as_view(),
name='core_organization_search'
),
re_path(
r'^profile/organization_name/create/$',
core_views.organization_name_create,
name='core_organization_name_create'
),
re_path(
r'^profile/organization_name/(?P<organization_name_id>\d+)/update/$',
core_views.organization_name_update,
name='core_organization_name_update'
),
re_path(
r'^profile/organization/(?P<organization_id>\d+)/affiliation/create/$',
core_views.affiliation_create,
name='core_affiliation_create'
),
re_path(
r'^profile/affiliation/(?P<affiliation_id>\d+)/update/$',
core_views.affiliation_update,
name='core_affiliation_update'
),
re_path(
r'^profile/affiliation/(?P<affiliation_id>\d+)/delete/$',
core_views.affiliation_delete,
name='core_affiliation_delete'
),

# Templates
re_path(r'^manager/templates/$', core_views.email_templates, name='core_email_templates'),

Expand Down
2 changes: 1 addition & 1 deletion src/core/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ def check_for_bad_login_attempts(request):
time = timezone.now() - timedelta(minutes=10)

attempts = models.LoginAttempt.objects.filter(user_agent=user_agent, ip_address=ip_address, timestamp__gte=time)
print(time, attempts.count())
logger.info(time, attempts.count())
ajrbyers marked this conversation as resolved.
Show resolved Hide resolved
return attempts.count()


Expand Down
Loading