Coverage for cookbook/admin.py: 85%

233 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2023-12-29 00:47 +0100

1from django.conf import settings 

2from django.contrib import admin 

3from django.contrib.auth.admin import UserAdmin 

4from django.contrib.auth.models import Group, User 

5from django.contrib.postgres.search import SearchVector 

6from django.utils import translation 

7from django_scopes import scopes_disabled 

8from treebeard.admin import TreeAdmin 

9from treebeard.forms import movenodeform_factory 

10 

11from cookbook.managers import DICTIONARY 

12 

13from .models import (BookmarkletImport, Comment, CookLog, Food, ImportLog, Ingredient, InviteLink, 

14 Keyword, MealPlan, MealType, NutritionInformation, Property, PropertyType, 

15 Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink, 

16 ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage, 

17 Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, 

18 TelegramBot, Unit, UnitConversion, UserFile, UserPreference, UserSpace, 

19 ViewLog) 

20 

21 

22class CustomUserAdmin(UserAdmin): 

23 def has_add_permission(self, request, obj=None): 

24 return False 

25 

26 

27admin.site.unregister(User) 

28admin.site.register(User, CustomUserAdmin) 

29 

30admin.site.unregister(Group) 

31 

32 

33@admin.action(description='Delete all data from a space') 

34def delete_space_action(modeladmin, request, queryset): 

35 for space in queryset: 

36 space.safe_delete() 

37 

38 

39class SpaceAdmin(admin.ModelAdmin): 

40 list_display = ('name', 'created_by', 'max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing') 

41 search_fields = ('name', 'created_by__username') 

42 autocomplete_fields = ('created_by',) 

43 filter_horizontal = ('food_inherit',) 

44 list_filter = ('max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing') 

45 date_hierarchy = 'created_at' 

46 actions = [delete_space_action] 

47 

48 

49admin.site.register(Space, SpaceAdmin) 

50 

51 

52class UserSpaceAdmin(admin.ModelAdmin): 

53 list_display = ('user', 'space',) 

54 search_fields = ('user__username', 'space__name',) 

55 filter_horizontal = ('groups',) 

56 autocomplete_fields = ('user', 'space',) 

57 

58 

59admin.site.register(UserSpace, UserSpaceAdmin) 

60 

61 

62class UserPreferenceAdmin(admin.ModelAdmin): 

63 list_display = ('name', 'theme', 'nav_color', 'default_page') 

64 search_fields = ('user__username',) 

65 list_filter = ('theme', 'nav_color', 'default_page',) 

66 date_hierarchy = 'created_at' 

67 filter_horizontal = ('plan_share', 'shopping_share',) 

68 

69 @staticmethod 

70 def name(obj): 

71 return obj.user.get_user_display_name() 

72 

73 

74admin.site.register(UserPreference, UserPreferenceAdmin) 

75 

76 

77class SearchPreferenceAdmin(admin.ModelAdmin): 

78 list_display = ('name', 'search', 'trigram_threshold', ) 

79 search_fields = ('user__username',) 

80 list_filter = ('search',) 

81 

82 @staticmethod 

83 def name(obj): 

84 return obj.user.get_user_display_name() 

85 

86 

87admin.site.register(SearchPreference, SearchPreferenceAdmin) 

88 

89 

90class StorageAdmin(admin.ModelAdmin): 

91 list_display = ('name', 'method') 

92 search_fields = ('name',) 

93 

94 

95admin.site.register(Storage, StorageAdmin) 

96 

97 

98class SyncAdmin(admin.ModelAdmin): 

99 list_display = ('storage', 'path', 'active', 'last_checked') 

100 search_fields = ('storage__name', 'path') 

101 

102 

103admin.site.register(Sync, SyncAdmin) 

104 

105 

106class SupermarketCategoryInline(admin.TabularInline): 

107 model = SupermarketCategoryRelation 

108 

109 

110class SupermarketAdmin(admin.ModelAdmin): 

111 list_display = ('name', 'space',) 

112 inlines = (SupermarketCategoryInline,) 

113 

114 

115class SupermarketCategoryAdmin(admin.ModelAdmin): 

116 list_display = ('name', 'space',) 

117 

118 

119admin.site.register(Supermarket, SupermarketAdmin) 

120admin.site.register(SupermarketCategory, SupermarketCategoryAdmin) 

121 

122 

123class SyncLogAdmin(admin.ModelAdmin): 

124 list_display = ('sync', 'status', 'msg', 'created_at') 

125 

126 

127admin.site.register(SyncLog, SyncLogAdmin) 

128 

129 

130@admin.action(description='Temporarily ENABLE sorting on Foods and Keywords.') 

131def enable_tree_sorting(modeladmin, request, queryset): 

132 Food.node_order_by = ['name'] 

133 Keyword.node_order_by = ['name'] 

134 with scopes_disabled(): 

135 Food.fix_tree(fix_paths=True) 

136 Keyword.fix_tree(fix_paths=True) 

137 

138 

139@admin.action(description='Temporarily DISABLE sorting on Foods and Keywords.') 

140def disable_tree_sorting(modeladmin, request, queryset): 

141 Food.node_order_by = [] 

142 Keyword.node_order_by = [] 

143 

144 

145@admin.action(description='Fix problems and sort tree by name') 

146def sort_tree(modeladmin, request, queryset): 

147 orginal_value = modeladmin.model.node_order_by[:] 

148 modeladmin.model.node_order_by = ['name'] 

149 with scopes_disabled(): 

150 modeladmin.model.fix_tree(fix_paths=True) 

151 modeladmin.model.node_order_by = orginal_value 

152 

153 

154class KeywordAdmin(TreeAdmin): 

155 form = movenodeform_factory(Keyword) 

156 ordering = ('space', 'path',) 

157 search_fields = ('name',) 

158 actions = [sort_tree, enable_tree_sorting, disable_tree_sorting] 

159 

160 

161admin.site.register(Keyword, KeywordAdmin) 

162 

163 

164@admin.action(description='Delete Steps not part of a Recipe.') 

165def delete_unattached_steps(modeladmin, request, queryset): 

166 with scopes_disabled(): 

167 Step.objects.filter(recipe=None).delete() 

168 

169 

170class StepAdmin(admin.ModelAdmin): 

171 list_display = ('recipe_and_name', 'order', 'space') 

172 ordering = ('recipe__name', 'name', 'space', ) 

173 search_fields = ('name', 'recipe__name') 

174 actions = [delete_unattached_steps] 

175 

176 @staticmethod 

177 @admin.display(description="Name") 

178 def recipe_and_name(obj): 

179 if not obj.recipe_set.exists(): 

180 return f"Orphaned Step{'':s if not obj.name else f': {obj.name}'}" 

181 return f"{obj.recipe_set.first().name}: {obj.name}" if obj.name else obj.recipe_set.first().name 

182 

183 

184admin.site.register(Step, StepAdmin) 

185 

186 

187@admin.action(description='Rebuild index for selected recipes') 

188def rebuild_index(modeladmin, request, queryset): 

189 language = DICTIONARY.get(translation.get_language(), 'simple') 

190 with scopes_disabled(): 

191 Recipe.objects.all().update( 

192 name_search_vector=SearchVector('name__unaccent', weight='A', config=language), 

193 desc_search_vector=SearchVector('description__unaccent', weight='B', config=language) 

194 ) 

195 Step.objects.all().update(search_vector=SearchVector('instruction__unaccent', weight='B', config=language)) 

196 

197 

198class RecipeAdmin(admin.ModelAdmin): 

199 list_display = ('name', 'internal', 'created_by', 'storage', 'space') 

200 search_fields = ('name', 'created_by__username') 

201 ordering = ('name', 'created_by__username', ) 

202 list_filter = ('internal',) 

203 date_hierarchy = 'created_at' 

204 

205 @staticmethod 

206 def created_by(obj): 

207 return obj.created_by.get_user_display_name() 

208 

209 if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql': 

210 actions = [rebuild_index] 

211 

212 

213admin.site.register(Recipe, RecipeAdmin) 

214 

215 

216class UnitAdmin(admin.ModelAdmin): 

217 list_display = ('name', 'space') 

218 ordering = ('name', 'space', ) 

219 search_fields = ('name',) 

220 

221 

222admin.site.register(Unit, UnitAdmin) 

223 

224 

225# admin.site.register(FoodInheritField) 

226 

227 

228class FoodAdmin(TreeAdmin): 

229 form = movenodeform_factory(Keyword) 

230 ordering = ('space', 'path',) 

231 search_fields = ('name',) 

232 actions = [sort_tree, enable_tree_sorting, disable_tree_sorting] 

233 

234 

235admin.site.register(Food, FoodAdmin) 

236 

237 

238class UnitConversionAdmin(admin.ModelAdmin): 

239 list_display = ('base_amount', 'base_unit', 'food', 'converted_amount', 'converted_unit') 

240 search_fields = ('food__name', 'unit__name') 

241 

242 

243admin.site.register(UnitConversion, UnitConversionAdmin) 

244 

245 

246@admin.action(description='Delete Ingredients not part of a Recipe.') 

247def delete_unattached_ingredients(modeladmin, request, queryset): 

248 with scopes_disabled(): 

249 Ingredient.objects.filter(step__recipe=None).delete() 

250 

251 

252class IngredientAdmin(admin.ModelAdmin): 

253 list_display = ('recipe_name', 'amount', 'unit', 'food', 'space') 

254 search_fields = ('food__name', 'unit__name', 'step__recipe__name') 

255 actions = [delete_unattached_ingredients] 

256 

257 @staticmethod 

258 @admin.display(description="Recipe") 

259 def recipe_name(obj): 

260 recipes = obj.step_set.first().recipe_set.all() if obj.step_set.exists() else None 

261 return recipes.first().name if recipes else 'Orphaned Ingredient' 

262 

263 

264admin.site.register(Ingredient, IngredientAdmin) 

265 

266 

267class CommentAdmin(admin.ModelAdmin): 

268 list_display = ('recipe', 'name', 'created_at') 

269 search_fields = ('text', 'created_by__username') 

270 date_hierarchy = 'created_at' 

271 

272 @staticmethod 

273 def name(obj): 

274 return obj.created_by.get_user_display_name() 

275 

276 

277admin.site.register(Comment, CommentAdmin) 

278 

279 

280class RecipeImportAdmin(admin.ModelAdmin): 

281 list_display = ('name', 'storage', 'file_path') 

282 

283 

284admin.site.register(RecipeImport, RecipeImportAdmin) 

285 

286 

287class RecipeBookAdmin(admin.ModelAdmin): 

288 list_display = ('name', 'user_name', 'space') 

289 search_fields = ('name', 'created_by__username') 

290 

291 @staticmethod 

292 def user_name(obj): 

293 return obj.created_by.get_user_display_name() 

294 

295 

296admin.site.register(RecipeBook, RecipeBookAdmin) 

297 

298 

299class RecipeBookEntryAdmin(admin.ModelAdmin): 

300 list_display = ('book', 'recipe') 

301 

302 

303admin.site.register(RecipeBookEntry, RecipeBookEntryAdmin) 

304 

305 

306class MealPlanAdmin(admin.ModelAdmin): 

307 list_display = ('user', 'recipe', 'meal_type', 'from_date', 'to_date') 

308 

309 @staticmethod 

310 def user(obj): 

311 return obj.created_by.get_user_display_name() 

312 

313 

314admin.site.register(MealPlan, MealPlanAdmin) 

315 

316 

317class MealTypeAdmin(admin.ModelAdmin): 

318 list_display = ('name', 'created_by', 'order') 

319 search_fields = ('name', 'created_by__username') 

320 

321 

322admin.site.register(MealType, MealTypeAdmin) 

323 

324 

325class ViewLogAdmin(admin.ModelAdmin): 

326 list_display = ('recipe', 'created_by', 'created_at') 

327 

328 

329admin.site.register(ViewLog, ViewLogAdmin) 

330 

331 

332class InviteLinkAdmin(admin.ModelAdmin): 

333 list_display = ( 

334 'group', 'valid_until', 'space', 

335 'created_by', 'created_at', 'used_by' 

336 ) 

337 

338 

339admin.site.register(InviteLink, InviteLinkAdmin) 

340 

341 

342class CookLogAdmin(admin.ModelAdmin): 

343 list_display = ('recipe', 'created_by', 'created_at', 'rating', 'servings') 

344 search_fields = ('recipe__name', 'space__name',) 

345 

346 

347admin.site.register(CookLog, CookLogAdmin) 

348 

349 

350class ShoppingListRecipeAdmin(admin.ModelAdmin): 

351 list_display = ('id', 'recipe', 'servings') 

352 

353 

354admin.site.register(ShoppingListRecipe, ShoppingListRecipeAdmin) 

355 

356 

357class ShoppingListEntryAdmin(admin.ModelAdmin): 

358 list_display = ('id', 'food', 'unit', 'list_recipe', 'created_by', 'created_at', 'checked') 

359 

360 

361admin.site.register(ShoppingListEntry, ShoppingListEntryAdmin) 

362 

363 

364# class ShoppingListAdmin(admin.ModelAdmin): 

365# list_display = ('id', 'created_by', 'created_at') 

366 

367 

368# admin.site.register(ShoppingList, ShoppingListAdmin) 

369 

370 

371class ShareLinkAdmin(admin.ModelAdmin): 

372 list_display = ('recipe', 'created_by', 'uuid', 'created_at',) 

373 

374 

375admin.site.register(ShareLink, ShareLinkAdmin) 

376 

377 

378class PropertyTypeAdmin(admin.ModelAdmin): 

379 search_fields = ('space',) 

380 

381 list_display = ('id', 'space', 'name', 'fdc_id') 

382 

383 

384admin.site.register(PropertyType, PropertyTypeAdmin) 

385 

386 

387class PropertyAdmin(admin.ModelAdmin): 

388 list_display = ('property_amount', 'property_type') 

389 

390 

391admin.site.register(Property, PropertyAdmin) 

392 

393 

394class NutritionInformationAdmin(admin.ModelAdmin): 

395 list_display = ('id',) 

396 

397 

398admin.site.register(NutritionInformation, NutritionInformationAdmin) 

399 

400 

401class ImportLogAdmin(admin.ModelAdmin): 

402 list_display = ('id', 'type', 'running', 'created_by', 'created_at',) 

403 

404 

405admin.site.register(ImportLog, ImportLogAdmin) 

406 

407 

408class TelegramBotAdmin(admin.ModelAdmin): 

409 list_display = ('id', 'name', 'created_by',) 

410 

411 

412admin.site.register(TelegramBot, TelegramBotAdmin) 

413 

414 

415class BookmarkletImportAdmin(admin.ModelAdmin): 

416 list_display = ('id', 'url', 'created_by', 'created_at',) 

417 

418 

419admin.site.register(BookmarkletImport, BookmarkletImportAdmin) 

420 

421 

422class UserFileAdmin(admin.ModelAdmin): 

423 list_display = ('id', 'name', 'file_size_kb', 'created_at',) 

424 

425 

426admin.site.register(UserFile, UserFileAdmin)