Coverage for src / mesh / admin.py: 93%
108 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-22 07:20 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-22 07:20 +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] | None = None,
33 read_only_fields: list[str] | None = None,
34) -> type[admin.TabularInline]:
35 """
36 Returns a `TalubarInline` to display related `BaseFileWrapperModel` instances.
37 """
39 if read_only_fields is None:
40 read_only_fields = []
41 if extra_fields is None:
42 extra_fields = []
44 class FileWrapperInlineAdmin(admin.TabularInline):
45 model = model_class
46 extra = 0
47 verbose_name_plural = name_plural
48 fields = ["file", "name", *extra_fields]
49 readonly_fields = read_only_fields
51 return FileWrapperInlineAdmin
54class BaseUserChangeTrackingAdmin(admin.ModelAdmin):
55 """
56 Base admin model for models inheriting from BaseChangeTrackingModel.
57 Attach the request to the object to be saved.
58 """
60 readonly_fields: list[str] = [
61 "date_created",
62 "created_by",
63 "date_last_modified",
64 "last_modified_by",
65 ]
67 def save_model(
68 self,
69 request: HttpRequest,
70 obj: BaseChangeTrackingModel,
71 form: BaseForm,
72 change: bool,
73 ) -> None:
74 obj._user = request.user
75 # change = whether the object is being created or updated
76 if change and not form.has_changed():
77 obj.do_not_update = True
79 super().save_model(request, obj, form, change)
82class UserTokenInline(admin.StackedInline):
83 model = UserToken
84 fk_name = "user"
85 can_delete = False
86 fields = ["key", "date_refreshed", "date_created"]
87 readonly_fields = ["date_created"]
90@admin.register(User)
91class UserAdmin(DjangoUserAdmin):
92 """Define admin model for our custom User model having no email field."""
94 inlines = (UserTokenInline,)
95 fieldsets = (
96 (None, {"fields": ("email", "password")}),
97 (_("Personal info"), {"fields": ("first_name", "last_name")}),
98 (_("For staff"), {"fields": ["current_role", "journal_manager"]}),
99 (
100 _("Permissions"),
101 {
102 "fields": (
103 "is_active",
104 "is_staff",
105 "is_superuser",
106 "groups",
107 "user_permissions",
108 )
109 },
110 ),
111 (_("Important dates"), {"fields": ("last_login", "date_joined")}),
112 )
113 add_fieldsets = (
114 (
115 None,
116 {
117 "classes": ("wide",),
118 "fields": (
119 "email",
120 "password1",
121 "password2",
122 "first_name",
123 "last_name",
124 ),
125 },
126 ),
127 )
128 list_display = (
129 "email",
130 "first_name",
131 "last_name",
132 "current_role",
133 "is_staff",
134 "is_superuser",
135 "journal_manager",
136 )
137 search_fields = ("email", "first_name", "last_name")
138 ordering = ("email",)
139 readonly_fields = ["current_role", "last_login", "date_joined"]
142@admin.register(SubmissionLog)
143class ModelLogAdmin(BaseUserChangeTrackingAdmin):
144 list_display = [field.name for field in SubmissionLog._meta.get_fields()]
147@admin.register(JournalSection)
148class JournalSectionAdmin(BaseUserChangeTrackingAdmin):
149 fieldsets = (
150 (None, {"fields": ["name", "parent"]}),
151 (_("Object metadata"), {"fields": ["date_created", "created_by"]}),
152 )
153 list_display = ["name", "parent", "date_created", "created_by"]
156class EditorSubmissionRightInline(admin.TabularInline):
157 extra = 0
158 verbose_name_plural = _("Assigned Editors")
159 model = EditorSubmissionRight
162@admin.register(Submission)
163class SubmissionAdmin(BaseUserChangeTrackingAdmin):
164 inlines = (EditorSubmissionRightInline,)
165 fieldsets = (
166 (
167 _("Metadata"),
168 {"fields": ["created_by", "journal_section", "state", "date_created"]},
169 ),
170 (_("Submission data"), {"fields": ["name", "abstract"]}),
171 )
172 readonly_fields = ["name", "abstract"]
173 list_display = ["created_by", "date_created", "journal_section", "name", "state"]
175 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
176 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
179@admin.register(SubmissionVersion)
180class SubmissionVersionAdmin(BaseUserChangeTrackingAdmin):
181 inlines = (
182 get_file_wrapper_inline(SubmissionMainFile),
183 get_file_wrapper_inline(SubmissionAdditionalFile),
184 )
185 fieldsets = [
186 (
187 _("Submission version"),
188 {"fields": ["submission", "number", "submitted", "date_submitted"]},
189 )
190 ]
191 readonly_fields = ["submission", "number", "submitted", "date_submitted"]
192 list_display = [
193 "submission",
194 "number",
195 "date_created",
196 "submitted",
197 "date_submitted",
198 ]
200 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
201 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
204@admin.register(SubmissionAuthor)
205class SubmissionAuthorAdmin(BaseUserChangeTrackingAdmin):
206 fieldsets = [
207 (
208 None,
209 {
210 "fields": [
211 "first_name",
212 "last_name",
213 "email",
214 "corresponding",
215 "date_created",
216 "created_by",
217 ]
218 },
219 )
220 ]
221 list_display = [
222 "first_name",
223 "last_name",
224 "email",
225 "corresponding",
226 "date_created",
227 "created_by",
228 ]
231@admin.register(EditorSectionRight)
232class EditorSectionRightAdmin(BaseUserChangeTrackingAdmin):
233 fieldsets = [(None, {"fields": ["user", "journal_section", "date_created", "created_by"]})]
234 list_display = ["user", "journal_section", "date_created", "created_by"]
237@admin.register(EditorSubmissionRight)
238class EditorSubmissionRightAdmin(BaseUserChangeTrackingAdmin):
239 fieldsets = [(None, {"fields": ["user", "submission", "date_created", "created_by"]})]
240 list_display = ["user", "submission", "date_created", "created_by"]
243@admin.register(Review)
244class ReviewAdmin(BaseUserChangeTrackingAdmin):
245 inlines = (get_file_wrapper_inline(ReviewAdditionalFile, extra_fields=["author_access"]),)
246 fieldsets = [
247 (
248 None,
249 {
250 "fields": [
251 "version",
252 "reviewer",
253 "state",
254 "date_response_due",
255 "date_review_due",
256 "request_email",
257 "accepted",
258 "date_accepted",
259 "accept_comment",
260 "recommendation",
261 "comment",
262 "date_created",
263 "created_by",
264 ]
265 },
266 )
267 ]
268 list_display = [
269 "reviewer",
270 "date_response_due",
271 "accepted",
272 "date_review_due",
273 "recommendation",
274 "date_created",
275 "created_by",
276 ]
278 readonly_fields = ["version", "accepted", "date_accepted"]
280 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
281 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
284@admin.register(EditorialDecision)
285class EditorialDecisionAdmin(BaseUserChangeTrackingAdmin):
286 inlines = (get_file_wrapper_inline(EditorialDecisionFile),)
287 fieldsets = [
288 (
289 None,
290 {
291 "fields": [
292 "version",
293 "value",
294 "date_created",
295 "created_by",
296 "comment",
297 "last_modified_by",
298 "date_last_modified",
299 ]
300 },
301 )
302 ]
304 list_display = ["version", "value", "date_created", "created_by", "comment"]
305 readonly_fields = ["version"]
307 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]:
308 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields))
311@admin.register(SuggestedReviewer)
312class SuggestedReviewerAdmin(admin.ModelAdmin):
313 list_display = ["first_name", "last_name", "email"]
316@admin.register(Suggestion)
317class SuggestionAdmin(admin.ModelAdmin):
318 list_display = ["submission", "suggested_reviewer", "suggested_user", "suggest_to_avoid"]