Coverage for website/promotion/admin.py: 46.75%

67 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2025-08-14 10:31 +0000

1"""Registers admin interfaces for the models defined in this module.""" 

2 

3from django.contrib import admin 

4from django.contrib.admin import ModelAdmin 

5from django.db import models 

6from django.db.models.functions import Lower 

7 

8from events.services import is_organiser 

9from promotion.forms import PromotionRequestForm 

10 

11from .models import PromotionChannel, PromotionRequest 

12 

13 

14class CaseInsensitiveFilter(admin.FieldListFilter): 

15 def __init__(self, field, request, params, model, model_admin, field_path): 

16 self.lookup_kwarg = f"{field_path}__iexact" 

17 self.lookup_kwarg2 = f"{field_path}__isnull" 

18 self.lookup_val = params.get(self.lookup_kwarg) 

19 self.lookup_val2 = params.get(self.lookup_kwarg2) 

20 super().__init__(field, request, params, model, model_admin, field_path) 

21 self.empty_value_display = model_admin.get_empty_value_display() 

22 queryset = model_admin.get_queryset(request) 

23 lookup_choices = ( 

24 queryset.annotate(lowered=Lower(field.name)) 

25 .order_by(field.name) 

26 .distinct() 

27 .values_list(field.name, flat=True) 

28 ) 

29 self.lookup_choices = set( 

30 map(lambda x: x.lower() if x is not None else x, lookup_choices) 

31 ) 

32 

33 def get_facet_counts(self, pk_attname, filtered_qs): 

34 return { 

35 f"{i}__c": models.Count( 

36 pk_attname, 

37 filter=models.Q( 

38 (self.lookup_kwarg, value) 

39 if value is not None 

40 else (self.lookup_kwarg2, True) 

41 ), 

42 ) 

43 for i, value in enumerate(self.lookup_choices) 

44 } 

45 

46 def choices(self, changelist): 

47 add_facets = changelist.add_facets 

48 facet_counts = self.get_facet_queryset(changelist) 

49 yield { 

50 "selected": self.lookup_val is None, 

51 "query_string": changelist.get_query_string( 

52 remove=[self.lookup_kwarg, self.lookup_kwarg2] 

53 ), 

54 "display": "All", 

55 } 

56 include_none = False 

57 empty_title = self.empty_value_display 

58 for key, val in enumerate(self.lookup_choices): 

59 if add_facets: 

60 count = facet_counts[f"{key}__c"] 

61 if val is None: 

62 include_none = True 

63 empty_title = f"{empty_title} ({count})" if add_facets else empty_title 

64 continue 

65 yield { 

66 "selected": self.lookup_val is not None and val in self.lookup_val, 

67 "query_string": changelist.get_query_string({self.lookup_kwarg: val}), 

68 "display": f"{val} ({count})" if add_facets else val, 

69 } 

70 if include_none: 

71 yield { 

72 "selected": self.lookup_val2 is True, 

73 "query_string": changelist.get_query_string( 

74 {self.lookup_kwarg2: "True"}, remove=[self.lookup_kwarg] 

75 ), 

76 "display": empty_title, 

77 } 

78 

79 def expected_parameters(self): 

80 return [self.lookup_kwarg, self.lookup_kwarg2] 

81 

82 

83@admin.register(PromotionRequest) 

84class PromotionRequestAdmin(admin.ModelAdmin): 

85 """This manages the admin interface for the model items.""" 

86 

87 list_display = ("event", "publish_date", "channel", "assigned_to", "status") 

88 list_filter = ( 

89 "publish_date", 

90 ("assigned_to", CaseInsensitiveFilter), 

91 "status", 

92 ) 

93 date_hierarchy = "publish_date" 

94 form = PromotionRequestForm 

95 actions = ["mark_not_started", "mark_started", "mark_finished", "mark_published"] 

96 

97 def has_change_permission(self, request, obj=None): 

98 if obj is not None and obj.event and is_organiser(request.member, obj.event): 98 ↛ 99line 98 didn't jump to line 99 because the condition on line 98 was never true

99 return True 

100 return super().has_change_permission(request, obj) 

101 

102 def mark_not_started(self, request, queryset): 

103 """Change the status of the event to published.""" 

104 self._change_published(queryset, PromotionRequest.NOT_STARTED) 

105 

106 mark_not_started.short_description = "Mark requests as not started" 

107 

108 def mark_started(self, request, queryset): 

109 """Change the status of the event to published.""" 

110 self._change_published(queryset, PromotionRequest.STARTED) 

111 

112 mark_started.short_description = "Mark requests as started" 

113 

114 def mark_finished(self, request, queryset): 

115 """Change the status of the event to published.""" 

116 self._change_published(queryset, PromotionRequest.FINISHED) 

117 

118 mark_finished.short_description = "Mark requests as finished" 

119 

120 def mark_published(self, request, queryset): 

121 """Change the status of the event to published.""" 

122 self._change_published(queryset, PromotionRequest.PUBLISHED) 

123 

124 mark_published.short_description = "Mark requests as published" 

125 

126 @staticmethod 

127 def _change_published(queryset, status): 

128 queryset.update(status=status) 

129 

130 

131@admin.register(PromotionChannel) 

132class PromotionChannelAdmin(ModelAdmin): 

133 list_display = ("name", "publisher_reminder_email")