Coverage for src / mesh / admin.py: 92%
104 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-05-04 12:41 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-05-04 12:41 +0000
1from django.contrib import admin
2from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
3from django.forms import BaseForm
4from django.http import HttpRequest
5from django.utils.translation import gettext_lazy as _
7from mesh.models.orm.base_models import BaseChangeTrackingModel
8from mesh.models.orm.editorial_models import (
9 EditorialDecision,
10 EditorialDecisionFile,
11 EditorSectionRight,
12 EditorSubmissionRight,
13)
14from mesh.models.orm.file_models import BaseFileWrapperModel
15from mesh.models.orm.journal_models import JournalSection
16from mesh.models.orm.review_models import Review, ReviewAdditionalFile
17from mesh.models.orm.submission_models import (
18 Submission,
19 SubmissionAdditionalFile,
20 SubmissionAuthor,
21 SubmissionLog,
22 SubmissionMainFile,
23 SubmissionVersion,
24)
25from mesh.models.orm.suggestion_model import Suggestion
26from mesh.models.orm.user_models import SuggestedReviewer, User, UserToken
29def get_file_wrapper_inline(
30 model_class: type[BaseFileWrapperModel],
31 name_plural: str = "Files",
32 extra_fields: list[str] = [],
33 read_only_fields: list[str] = [],
34) -> type[admin.TabularInline]:
35 """
36 Returns a `TalubarInline` to display related `BaseFileWrapperModel` instances.
37 """
39 class FileWrapperInlineAdmin(admin.TabularInline):
40 model = model_class
41 extra = 0
42 verbose_name_plural = name_plural
43 fields = ["file", "name", *extra_fields]
44 readonly_fields = read_only_fields
46 return FileWrapperInlineAdmin
49class BaseUserChangeTrackingAdmin(admin.ModelAdmin):
50 """
51 Base admin model for models inheriting from BaseChangeTrackingModel.
52 Attach the request to the object to be saved.
53 """
55 readonly_fields: list[str] = [
56 "date_created",
57 "created_by",
58 "date_last_modified",
59 "last_modified_by",
60 ]
62 def save_model(
63 self,
64 request: HttpRequest,
65 obj: BaseChangeTrackingModel,
66 form: BaseForm,
67 change: bool,
68 ) -> None:
69 obj._user = request.user
70 # change = whether the object is being created or updated
71 if change and not form.has_changed():
72 obj.do_not_update = True
74 super().save_model(request, obj, form, change)
77class UserTokenInline(admin.StackedInline):
78 model = UserToken
79 fk_name = "user"
80 can_delete = False
81 fields = ["key", "date_refreshed", "date_created"]
82 readonly_fields = ["date_created"]
85@admin.register(User)
86class UserAdmin(DjangoUserAdmin):
87 """Define admin model for our custom User model having no email field."""
89 inlines = (UserTokenInline,)
90 fieldsets = (
91 (None, {"fields": ("email", "password")}),
92 (_("Personal info"), {"fields": ("first_name", "last_name")}),
93 (_("For staff"), {"fields": ["current_role", "journal_manager"]}),
94 (
95 _("Permissions"),
96 {
97 "fields": (
98 "is_active",
99 "is_staff",
100 "is_superuser",
101 "groups",
102 "user_permissions",
103 )
104 },
105 ),
106 (_("Important dates"), {"fields": ("last_login", "date_joined")}),
107 )
108 add_fieldsets = (
109 (
110 None,
111 {
112 "classes": ("wide",),
113 "fields": (
114 "email",
115 "password1",
116 "password2",
117 "first_name",
118 "last_name",
119 ),
120 },
121 ),
122 )
123 list_display = (
124 "email",
125 "first_name",
126 "last_name",
127 "current_role",
128 "is_staff",
129 "is_superuser",
130 "journal_manager",
131 )
132 search_fields = ("email", "first_name", "last_name")
133 ordering = ("email",)
134 readonly_fields = ["current_role", "last_login", "date_joined"]
137@admin.register(SubmissionLog)
138class ModelLogAdmin(BaseUserChangeTrackingAdmin):
139 list_display = [field.name for field in SubmissionLog._meta.get_fields()]
142@admin.register(JournalSection)
143class JournalSectionAdmin(BaseUserChangeTrackingAdmin):
144 fieldsets = (
145 (None, {"fields": ["name", "parent"]}),
146 (_("Object metadata"), {"fields": ["date_created", "created_by"]}),
147 )
148 list_display = ["name", "parent", "date_created", "created_by"]
151class EditorSubmissionRightInline(admin.TabularInline):
152 extra = 0
153 verbose_name_plural = _("Assigned Editors")
154 model = EditorSubmissionRight
157@admin.register(Submission)
158class SubmissionAdmin(BaseUserChangeTrackingAdmin):
159 inlines = (EditorSubmissionRightInline,)
160 fieldsets = (
161 (
162 _("Metadata"),
163 {"fields": ["created_by", "journal_section", "state", "date_created"]},
164 ),
165 (_("Submission data"), {"fields": ["name", "abstract"]}),
166 )
167 readonly_fields = ["name", "abstract"]
168 list_display = ["created_by", "date_created", "journal_section", "name", "state"]
170 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
171 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
174@admin.register(SubmissionVersion)
175class SubmissionVersionAdmin(BaseUserChangeTrackingAdmin):
176 inlines = (
177 get_file_wrapper_inline(SubmissionMainFile),
178 get_file_wrapper_inline(SubmissionAdditionalFile),
179 )
180 fieldsets = [
181 (
182 _("Submission version"),
183 {"fields": ["submission", "number", "submitted", "date_submitted"]},
184 )
185 ]
186 readonly_fields = ["submission", "number", "submitted", "date_submitted"]
187 list_display = [
188 "submission",
189 "number",
190 "date_created",
191 "submitted",
192 "date_submitted",
193 ]
195 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
196 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
199@admin.register(SubmissionAuthor)
200class SubmissionAuthorAdmin(BaseUserChangeTrackingAdmin):
201 fieldsets = [
202 (
203 None,
204 {
205 "fields": [
206 "first_name",
207 "last_name",
208 "email",
209 "corresponding",
210 "date_created",
211 "created_by",
212 ]
213 },
214 )
215 ]
216 list_display = [
217 "first_name",
218 "last_name",
219 "email",
220 "corresponding",
221 "date_created",
222 "created_by",
223 ]
226@admin.register(EditorSectionRight)
227class EditorSectionRightAdmin(BaseUserChangeTrackingAdmin):
228 fieldsets = [(None, {"fields": ["user", "journal_section", "date_created", "created_by"]})]
229 list_display = ["user", "journal_section", "date_created", "created_by"]
232@admin.register(EditorSubmissionRight)
233class EditorSubmissionRightAdmin(BaseUserChangeTrackingAdmin):
234 fieldsets = [(None, {"fields": ["user", "submission", "date_created", "created_by"]})]
235 list_display = ["user", "submission", "date_created", "created_by"]
238@admin.register(Review)
239class ReviewAdmin(BaseUserChangeTrackingAdmin):
240 inlines = (get_file_wrapper_inline(ReviewAdditionalFile, extra_fields=["author_access"]),)
241 fieldsets = [
242 (
243 None,
244 {
245 "fields": [
246 "version",
247 "reviewer",
248 "state",
249 "date_response_due",
250 "date_review_due",
251 "request_email",
252 "accepted",
253 "date_accepted",
254 "accept_comment",
255 "recommendation",
256 "comment",
257 "date_created",
258 "created_by",
259 ]
260 },
261 )
262 ]
263 list_display = [
264 "reviewer",
265 "date_response_due",
266 "accepted",
267 "date_review_due",
268 "recommendation",
269 "date_created",
270 "created_by",
271 ]
273 readonly_fields = ["version", "accepted", "date_accepted"]
275 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
276 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
279@admin.register(EditorialDecision)
280class EditorialDecisionAdmin(BaseUserChangeTrackingAdmin):
281 inlines = (get_file_wrapper_inline(EditorialDecisionFile),)
282 fieldsets = [
283 (
284 None,
285 {
286 "fields": [
287 "version",
288 "value",
289 "date_created",
290 "created_by",
291 "comment",
292 "last_modified_by",
293 "date_last_modified",
294 ]
295 },
296 )
297 ]
299 list_display = ["version", "value", "date_created", "created_by", "comment"]
300 readonly_fields = ["version"]
302 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
303 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
306@admin.register(SuggestedReviewer)
307class SuggestedReviewerAdmin(admin.ModelAdmin):
308 list_display = ["first_name", "last_name", "email"]
311@admin.register(Suggestion)
312class SuggestionAdmin(admin.ModelAdmin):
313 list_display = ["submission", "suggested_reviewer", "suggested_user", "suggest_to_avoid"]