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

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 _ 

6 

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 

27 

28 

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 """ 

38 

39 if read_only_fields is None: 

40 read_only_fields = [] 

41 if extra_fields is None: 

42 extra_fields = [] 

43 

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 

50 

51 return FileWrapperInlineAdmin 

52 

53 

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 """ 

59 

60 readonly_fields: list[str] = [ 

61 "date_created", 

62 "created_by", 

63 "date_last_modified", 

64 "last_modified_by", 

65 ] 

66 

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 

78 

79 super().save_model(request, obj, form, change) 

80 

81 

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"] 

88 

89 

90@admin.register(User) 

91class UserAdmin(DjangoUserAdmin): 

92 """Define admin model for our custom User model having no email field.""" 

93 

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"] 

140 

141 

142@admin.register(SubmissionLog) 

143class ModelLogAdmin(BaseUserChangeTrackingAdmin): 

144 list_display = [field.name for field in SubmissionLog._meta.get_fields()] 

145 

146 

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"] 

154 

155 

156class EditorSubmissionRightInline(admin.TabularInline): 

157 extra = 0 

158 verbose_name_plural = _("Assigned Editors") 

159 model = EditorSubmissionRight 

160 

161 

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"] 

174 

175 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]: 

176 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields)) 

177 

178 

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 ] 

199 

200 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]: 

201 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields)) 

202 

203 

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 ] 

229 

230 

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"] 

235 

236 

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"] 

241 

242 

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 ] 

277 

278 readonly_fields = ["version", "accepted", "date_accepted"] 

279 

280 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]: 

281 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields)) 

282 

283 

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 ] 

303 

304 list_display = ["version", "value", "date_created", "created_by", "comment"] 

305 readonly_fields = ["version"] 

306 

307 def get_readonly_fields(self, request: HttpRequest, obj) -> set[str]: 

308 return set(list(BaseUserChangeTrackingAdmin.readonly_fields) + list(self.readonly_fields)) 

309 

310 

311@admin.register(SuggestedReviewer) 

312class SuggestedReviewerAdmin(admin.ModelAdmin): 

313 list_display = ["first_name", "last_name", "email"] 

314 

315 

316@admin.register(Suggestion) 

317class SuggestionAdmin(admin.ModelAdmin): 

318 list_display = ["submission", "suggested_reviewer", "suggested_user", "suggest_to_avoid"]