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

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] = [], 

33 read_only_fields: list[str] = [], 

34) -> type[admin.TabularInline]: 

35 """ 

36 Returns a `TalubarInline` to display related `BaseFileWrapperModel` instances. 

37 """ 

38 

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 

45 

46 return FileWrapperInlineAdmin 

47 

48 

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

54 

55 readonly_fields: list[str] = [ 

56 "date_created", 

57 "created_by", 

58 "date_last_modified", 

59 "last_modified_by", 

60 ] 

61 

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 

73 

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

75 

76 

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

83 

84 

85@admin.register(User) 

86class UserAdmin(DjangoUserAdmin): 

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

88 

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

135 

136 

137@admin.register(SubmissionLog) 

138class ModelLogAdmin(BaseUserChangeTrackingAdmin): 

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

140 

141 

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

149 

150 

151class EditorSubmissionRightInline(admin.TabularInline): 

152 extra = 0 

153 verbose_name_plural = _("Assigned Editors") 

154 model = EditorSubmissionRight 

155 

156 

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

169 

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

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

172 

173 

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 ] 

194 

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

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

197 

198 

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 ] 

224 

225 

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

230 

231 

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

236 

237 

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 ] 

272 

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

274 

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

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

277 

278 

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 ] 

298 

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

300 readonly_fields = ["version"] 

301 

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

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

304 

305 

306@admin.register(SuggestedReviewer) 

307class SuggestedReviewerAdmin(admin.ModelAdmin): 

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

309 

310 

311@admin.register(Suggestion) 

312class SuggestionAdmin(admin.ModelAdmin): 

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