Commit | Line | Data |
---|---|---|
6ef8ead4 | 1 | # -*- encoding: utf-8 -*- |
29e2a8fd | 2 | import operator |
116db1fd | 3 | |
da048859 | 4 | from auf.django.references import models as ref |
31249cf3 | 5 | from django import forms |
264a3210 | 6 | from django.core.urlresolvers import reverse as url |
6ef8ead4 | 7 | from django.contrib import admin |
6d885e0c | 8 | from django.contrib.auth.admin import UserAdmin |
9 | from django.contrib.auth.models import User | |
da048859 EMS |
10 | from django.db.models import Q |
11 | from django.db.models.query import QuerySet | |
e3c3296e | 12 | from django.http import HttpResponseRedirect |
116db1fd | 13 | |
da048859 EMS |
14 | from auf_savoirs_en_partage.savoirs.globals import META |
15 | from auf_savoirs_en_partage.savoirs.models import \ | |
31249cf3 EMS |
16 | SourceActualite, Actualite, ActualiteVoir, \ |
17 | Evenement, EvenementVoir, Record, RecordEdit, \ | |
18 | RecordCategorie, ListSet, HarvestLog, Profile, PageStatique | |
81fe476e | 19 | |
31249cf3 EMS |
20 | |
21 | class ListSetListFilter(admin.RelatedFieldListFilter): | |
6a6986bc | 22 | """ |
31249cf3 EMS |
23 | Filtre custom automatiquement lié à un field nommé 'listsets'. Il a pour |
24 | but de s'afficher lorsqu'un server a déjà été présélectionné. Dans ce | |
25 | cas, il affiche une liste qui contient les listsets de ce server. | |
6a6986bc | 26 | """ |
31249cf3 EMS |
27 | def __init__(self, field, request, params, model, model_admin, field_path): |
28 | super(ListSetListFilter, self).__init__( | |
29 | field, request, params, model, model_admin, field_path | |
30 | ) | |
6a6986bc | 31 | self.server_name = request.GET.get('server', None) |
32 | ||
33 | def has_output(self): | |
34 | return self.server_name is not None | |
35 | ||
23b5b3d5 | 36 | |
da048859 EMS |
37 | class AllRegionsListFilter(admin.SimpleListFilter): |
38 | """ | |
39 | Filtre qui offre aussi les régions inactives dans ses choix. | |
40 | """ | |
41 | title = u'région' | |
42 | parameter_name = 'regions' | |
43 | ||
44 | def lookups(self, request, model_admin): | |
45 | return [(r.id, r.nom) for r in ref.Region.avec_inactifs.all()] | |
46 | ||
47 | def queryset(self, request, queryset): | |
48 | return queryset.filter(regions=self.value()) | |
49 | ||
50 | ||
5212238e EMS |
51 | class RecordAdminQuerySet(QuerySet): |
52 | ||
53 | def filter(self, *args, **kwargs): | |
54 | """Gère des filtres supplémentaires pour l'admin. | |
31249cf3 | 55 | |
5212238e EMS |
56 | C'est la seule façon que j'ai trouvée de contourner les mécanismes |
57 | de recherche de l'admin.""" | |
58 | search = kwargs.pop('admin_search', None) | |
59 | search_titre = kwargs.pop('admin_search_titre', None) | |
60 | search_sujet = kwargs.pop('admin_search_sujet', None) | |
61 | search_description = kwargs.pop('admin_search_description', None) | |
62 | search_auteur = kwargs.pop('admin_search_auteur', None) | |
63 | ||
64 | if search: | |
65 | qs = self | |
31249cf3 EMS |
66 | search_all = not (search_titre or search_description or |
67 | search_sujet or search_auteur) | |
5212238e EMS |
68 | fields = [] |
69 | if search_titre or search_all: | |
70 | fields += ['title', 'alt_title'] | |
71 | if search_description or search_all: | |
72 | fields += ['description', 'abstract'] | |
73 | if search_sujet or search_all: | |
74 | fields += ['subject'] | |
75 | if search_auteur or search_all: | |
76 | fields += ['creator', 'contributor'] | |
77 | ||
78 | for bit in search.split(): | |
31249cf3 EMS |
79 | or_queries = [Q(**{field + '__icontains': bit}) |
80 | for field in fields] | |
5212238e EMS |
81 | qs = qs.filter(reduce(operator.or_, or_queries)) |
82 | ||
83 | if args or kwargs: | |
84 | qs = super(RecordAdminQuerySet, qs).filter(*args, **kwargs) | |
85 | return qs | |
86 | else: | |
87 | return super(RecordAdminQuerySet, self).filter(*args, **kwargs) | |
23b5b3d5 | 88 | |
31249cf3 EMS |
89 | |
90 | class RecordAdmin(admin.ModelAdmin): | |
91 | fields = ('server', 'title', 'creator', 'description', 'modified', | |
a5f76eb4 | 92 | 'identifier', 'uri', 'source', 'contributor', 'publisher', |
656b9c0f | 93 | 'type', 'format', 'language', 'categorie', 'disciplines', |
31249cf3 EMS |
94 | 'thematiques', 'pays', 'regions', 'validated') |
95 | ||
96 | list_filter = ( | |
97 | 'validated', 'server', ('listsets', ListSetListFilter), 'pays', | |
da048859 | 98 | AllRegionsListFilter, 'disciplines', 'thematiques', 'categorie' |
31249cf3 EMS |
99 | ) |
100 | list_display = ( | |
101 | 'title', 'subject', 'uri_display', 'creator', 'categorie', | |
102 | 'est_complet', 'validated' | |
103 | ) | |
18dbd2cf EMS |
104 | list_editable = ('validated',) |
105 | list_per_page = 25 | |
106 | ||
31249cf3 EMS |
107 | actions = ('assigner_pays', 'assigner_regions', 'assigner_disciplines', |
108 | 'assigner_thematiques', 'assigner_categorie') | |
da9020f3 | 109 | |
23b5b3d5 | 110 | def __init__(self, *args, **kwargs): |
31249cf3 EMS |
111 | """ |
112 | Surcharge l'initialisation pour définir les champs de recherche | |
113 | dynamiquement, et les champs en lecture seule uniquement. | |
114 | """ | |
23b5b3d5 | 115 | self.readonly_fields = META.keys() |
d972b61d | 116 | self.readonly_fields.append('listsets') |
31249cf3 | 117 | super(RecordAdmin, self).__init__(*args, **kwargs) |
6d885e0c | 118 | |
1719bf4e | 119 | def queryset(self, request): |
5212238e | 120 | return RecordAdminQuerySet(Record) |
77b0fac0 EMS |
121 | |
122 | # Présentation de l'information | |
31249cf3 | 123 | |
6d885e0c | 124 | def est_complet(self, obj): |
6d885e0c | 125 | v = obj.est_complet() |
89f07b48 | 126 | return '<img src="/static/admin/img/icon-%s.gif" alt="%d"/>' % ( |
31249cf3 EMS |
127 | ('no', 'yes')[v], v |
128 | ) | |
6d885e0c | 129 | est_complet.allow_tags = True |
18dbd2cf | 130 | est_complet.short_description = u'complet' |
31249cf3 | 131 | |
18dbd2cf | 132 | def uri_display(self, obj): |
da9020f3 | 133 | return "<a target='_blank' href='%s'>%s</a>" % (obj.uri, obj.uri) |
18dbd2cf EMS |
134 | uri_display.allow_tags = True |
135 | uri_display.short_description = u'lien' | |
da9020f3 | 136 | |
18dbd2cf | 137 | def description_display(self, obj): |
23b5b3d5 | 138 | max = 140 |
31249cf3 | 139 | if obj.description is not None and len(obj.description) > max: |
23b5b3d5 | 140 | return "%s..." % obj.description[:max] |
141 | else: | |
142 | return obj.description | |
18dbd2cf | 143 | description_display.short_description = u'description' |
da9020f3 | 144 | |
18dbd2cf | 145 | # Actions |
2be148fe | 146 | |
e3c3296e | 147 | def assigner_pays(self, request, queryset): |
b07400fb PP |
148 | selected = queryset.values_list('id', flat=True) |
149 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
150 | return HttpResponseRedirect( |
151 | "/admin/assigner_%s?ids=%s" % ('pays', selected) | |
152 | ) | |
18dbd2cf | 153 | assigner_pays.short_description = u'Assigner des pays' |
e3c3296e | 154 | |
155 | def assigner_regions(self, request, queryset): | |
b07400fb PP |
156 | selected = queryset.values_list('id', flat=True) |
157 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
158 | return HttpResponseRedirect(url( |
159 | 'assigner_regions', | |
160 | kwargs={'app_name': 'savoirs', 'model_name': 'record'} | |
161 | ) + '?ids=' + selected) | |
264a3210 | 162 | assigner_regions.short_description = u'Assigner des régions' |
e3c3296e | 163 | |
164 | def assigner_thematiques(self, request, queryset): | |
b07400fb PP |
165 | selected = queryset.values_list('id', flat=True) |
166 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
167 | return HttpResponseRedirect( |
168 | "/admin/assigner_%s?ids=%s" % ('thematiques', selected) | |
169 | ) | |
18dbd2cf | 170 | assigner_thematiques.short_description = u'Assigner des thématiques' |
e3c3296e | 171 | |
172 | def assigner_disciplines(self, request, queryset): | |
b07400fb PP |
173 | selected = queryset.values_list('id', flat=True) |
174 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
175 | return HttpResponseRedirect(url( |
176 | 'assigner_disciplines', | |
177 | kwargs={'app_name': 'savoirs', 'model_name': 'record'} | |
178 | ) + '?ids=' + selected) | |
264a3210 | 179 | assigner_disciplines.short_description = u'Assigner des disciplines' |
116db1fd | 180 | |
656b9c0f | 181 | def assigner_categorie(self, request, queryset): |
b07400fb PP |
182 | selected = queryset.values_list('id', flat=True) |
183 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
184 | return HttpResponseRedirect( |
185 | "/admin/assigner_%s?ids=%s" % ('categorie', selected) | |
186 | ) | |
656b9c0f PP |
187 | assigner_categorie.short_description = u'Assigner une catégorie' |
188 | ||
da9020f3 | 189 | admin.site.register(Record, RecordAdmin) |
190 | ||
927764f9 | 191 | |
31249cf3 EMS |
192 | class RecordEditAdmin(RecordAdmin): |
193 | list_editable = () | |
4bf80bb5 | 194 | change_list_template = "admin/savoirs/record/change_list.html" |
927764f9 PP |
195 | |
196 | def __init__(self, model, admin_site): | |
197 | super(RecordEditAdmin, self).__init__(model, admin_site) | |
16176279 | 198 | self.readonly_fields = () |
927764f9 PP |
199 | |
200 | def get_actions(self, request): | |
201 | actions = super(RecordEditAdmin, self).get_actions(request) | |
927764f9 | 202 | del actions['assigner_pays'] |
16176279 PP |
203 | del actions['assigner_regions'] |
204 | del actions['assigner_disciplines'] | |
927764f9 | 205 | del actions['assigner_thematiques'] |
31249cf3 | 206 | del actions['assigner_categorie'] |
927764f9 PP |
207 | |
208 | return actions | |
209 | ||
927764f9 PP |
210 | admin.site.register(RecordEdit, RecordEditAdmin) |
211 | ||
212 | ||
31249cf3 EMS |
213 | class ListSetAdmin(admin.ModelAdmin): |
214 | fields = ('spec', 'name', 'server', 'validated') | |
d972b61d | 215 | list_display = fields |
31249cf3 | 216 | readonly_fields = ('spec', 'name', 'server') |
d972b61d | 217 | list_filter = ('server',) |
218 | ||
219 | admin.site.register(ListSet, ListSetAdmin) | |
220 | ||
31249cf3 EMS |
221 | |
222 | class HarvestLogAdmin(admin.ModelAdmin): | |
223 | fields = ('context', 'name', 'added', 'updated', 'processed', 'record') | |
224 | list_display = fields + ('date',) | |
225 | admin_order_fields = ('date',) | |
226 | search_fields = ( | |
227 | 'context', 'name', 'added', 'updated', 'processed', 'record__title' | |
228 | ) | |
23b5b3d5 | 229 | readonly_fields = fields |
230 | list_filter = ('context',) | |
231 | ||
232 | admin.site.register(HarvestLog, HarvestLogAdmin) | |
6d885e0c | 233 | |
31249cf3 | 234 | |
6d885e0c | 235 | class ProfileInline(admin.TabularInline): |
236 | model = Profile | |
237 | fk_name = 'user' | |
238 | max_num = 1 | |
239 | ||
31249cf3 | 240 | |
6d885e0c | 241 | class UserProfileAdmin(UserAdmin): |
31249cf3 | 242 | inlines = (ProfileInline,) |
6d885e0c | 243 | |
244 | admin.site.unregister(User) | |
245 | admin.site.register(User, UserProfileAdmin) | |
246 | ||
31249cf3 | 247 | |
f554ef70 | 248 | class ActualiteAdmin(admin.ModelAdmin): |
da048859 | 249 | list_filter = ('visible', 'disciplines', AllRegionsListFilter) |
ccbc4363 | 250 | list_display = ('titre', 'source', 'date', 'visible') |
31249cf3 | 251 | list_editable = ('visible',) |
befea523 | 252 | search_fields = ('titre', 'texte') |
31249cf3 EMS |
253 | actions = ( |
254 | 'rendre_visible', 'rendre_invisible', 'assigner_regions', | |
255 | 'assigner_disciplines' | |
256 | ) | |
f554ef70 | 257 | |
1719bf4e | 258 | def queryset(self, request): |
29e2a8fd | 259 | return Actualite.all_objects.get_query_set() |
1719bf4e | 260 | |
f554ef70 | 261 | # actions |
262 | def rendre_visible(self, request, queryset): | |
b07400fb PP |
263 | selected = queryset.values_list('id', flat=True) |
264 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
265 | return HttpResponseRedirect( |
266 | "/admin/confirmation/%s/%s?ids=%s" % | |
267 | ('actualite', 'visible', selected) | |
268 | ) | |
f554ef70 | 269 | |
270 | def rendre_invisible(self, request, queryset): | |
b07400fb PP |
271 | selected = queryset.values_list('id', flat=True) |
272 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
273 | return HttpResponseRedirect( |
274 | "/admin/confirmation/%s/%s?ids=%s" % | |
275 | ('actualite', 'invisible', selected) | |
276 | ) | |
f554ef70 | 277 | |
264a3210 | 278 | def assigner_regions(self, request, queryset): |
b07400fb PP |
279 | selected = queryset.values_list('id', flat=True) |
280 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
281 | return HttpResponseRedirect(url( |
282 | 'assigner_regions', | |
283 | kwargs={'app_name': 'savoirs', 'model_name': 'actualite'} | |
284 | ) + '?ids=' + selected) | |
264a3210 EMS |
285 | assigner_regions.short_description = u'Assigner des régions' |
286 | ||
287 | def assigner_disciplines(self, request, queryset): | |
b07400fb PP |
288 | selected = queryset.values_list('id', flat=True) |
289 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
290 | return HttpResponseRedirect(url( |
291 | 'assigner_disciplines', | |
292 | kwargs={'app_name': 'savoirs', 'model_name': 'actualite'} | |
293 | ) + '?ids=' + selected) | |
264a3210 EMS |
294 | assigner_disciplines.short_description = u'Assigner des disciplines' |
295 | ||
f554ef70 | 296 | admin.site.register(Actualite, ActualiteAdmin) |
b7a741ad | 297 | |
31249cf3 | 298 | |
81fe476e PP |
299 | class ActualiteVoirAdmin(ActualiteAdmin): |
300 | ||
301 | actions = None | |
31249cf3 EMS |
302 | list_editable = () |
303 | fields = ( | |
304 | 'titre', 'texte', 'url', 'date', 'visible', 'ancienid', 'source', | |
305 | 'disciplines', 'regions' | |
306 | ) | |
81fe476e PP |
307 | |
308 | def __init__(self, model, admin_site): | |
309 | super(ActualiteVoirAdmin, self).__init__(model, admin_site) | |
81fe476e PP |
310 | self.readonly_fields = self.fields |
311 | ||
312 | ||
313 | admin.site.register(ActualiteVoir, ActualiteVoirAdmin) | |
314 | ||
31249cf3 | 315 | |
db2999fa | 316 | class SourceActualiteAdmin(admin.ModelAdmin): |
31249cf3 EMS |
317 | actions = ('update_sources',) |
318 | list_display = ('nom', 'url', 'type') | |
319 | list_filter = ('type',) | |
db2999fa EMS |
320 | |
321 | def update_sources(self, request, queryset): | |
322 | for source in queryset: | |
323 | source.update() | |
324 | update_sources.short_description = u'Mettre à jour les fils sélectionnés' | |
325 | ||
326 | admin.site.register(SourceActualite, SourceActualiteAdmin) | |
b7a741ad | 327 | |
31249cf3 | 328 | |
73309469 | 329 | class EvenementAdminForm(forms.ModelForm): |
86983865 | 330 | mots_cles = forms.CharField(label='Mots-clés', required=False) |
86983865 | 331 | |
73309469 | 332 | class Meta: |
333 | model = Evenement | |
334 | ||
335 | def clean(self,): | |
336 | cleaned_data = self.cleaned_data | |
337 | debut = cleaned_data.get("debut") | |
338 | fin = cleaned_data.get("fin") | |
7495bc13 | 339 | if debut and fin and debut > fin: |
31249cf3 EMS |
340 | raise forms.ValidationError( |
341 | "La date de fin ne doit pas être antérieure à la date de début" | |
342 | ) | |
73309469 | 343 | return cleaned_data |
344 | ||
31249cf3 | 345 | |
b7a741ad | 346 | class EvenementAdmin(admin.ModelAdmin): |
73309469 | 347 | form = EvenementAdminForm |
31249cf3 | 348 | list_filter = ( |
da048859 | 349 | 'approuve', AllRegionsListFilter, 'discipline', 'discipline_secondaire' |
31249cf3 | 350 | ) |
731ef7ab | 351 | list_display = ('titre', 'debut', 'fin', 'ville', 'pays', 'approuve') |
31249cf3 EMS |
352 | fields = ('titre', 'discipline', 'discipline_secondaire', 'mots_cles', |
353 | 'type', 'adresse', 'ville', 'pays', 'fuseau', 'debut', 'fin', | |
354 | 'piece_jointe', 'regions', 'description', 'prenom', 'nom', | |
355 | 'courriel', 'url', 'approuve') | |
befea523 | 356 | search_fields = ('titre', 'description') |
31249cf3 | 357 | actions = ('assigner_regions', 'assigner_disciplines') |
264a3210 | 358 | |
1719bf4e | 359 | def queryset(self, request): |
29e2a8fd | 360 | return Evenement.all_objects.get_query_set() |
1719bf4e | 361 | |
264a3210 | 362 | def assigner_regions(self, request, queryset): |
b07400fb PP |
363 | selected = queryset.values_list('id', flat=True) |
364 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
365 | return HttpResponseRedirect(url( |
366 | 'assigner_regions', | |
367 | kwargs={'app_name': 'savoirs', 'model_name': 'evenement'} | |
368 | ) + '?ids=' + selected) | |
264a3210 EMS |
369 | assigner_regions.short_description = u'Assigner des régions' |
370 | ||
371 | def assigner_disciplines(self, request, queryset): | |
b07400fb PP |
372 | selected = queryset.values_list('id', flat=True) |
373 | selected = ",".join("%s" % val for val in selected) | |
31249cf3 EMS |
374 | return HttpResponseRedirect(url( |
375 | 'assigner_disciplines', | |
376 | kwargs={'app_name': 'savoirs', 'model_name': 'evenement'} | |
377 | ) + '?ids=' + selected) | |
264a3210 | 378 | assigner_disciplines.short_description = u'Assigner des disciplines' |
b7a741ad | 379 | |
380 | admin.site.register(Evenement, EvenementAdmin) | |
381 | ||
31249cf3 | 382 | |
81fe476e PP |
383 | class EvenementVoirAdmin(EvenementAdmin): |
384 | ||
385 | actions = None | |
31249cf3 | 386 | list_editable = () |
81fe476e PP |
387 | |
388 | def __init__(self, model, admin_site): | |
389 | super(EvenementVoirAdmin, self).__init__(model, admin_site) | |
81fe476e PP |
390 | self.readonly_fields = self.fields |
391 | ||
81fe476e PP |
392 | admin.site.register(EvenementVoir, EvenementVoirAdmin) |
393 | ||
31249cf3 | 394 | |
f09bc1c6 | 395 | class PageStatiqueAdmin(admin.ModelAdmin): |
31249cf3 EMS |
396 | list_display = ('titre', 'id') |
397 | list_display_links = ('titre', 'id') | |
b7a741ad | 398 | |
f09bc1c6 | 399 | class Media: |
31249cf3 | 400 | js = ('js/tiny_mce/tiny_mce.js', 'js/tiny_mce_textareas.js') |
f09bc1c6 EMS |
401 | |
402 | admin.site.register(PageStatique, PageStatiqueAdmin) | |
b7a741ad | 403 | |
656b9c0f PP |
404 | |
405 | admin.site.register(RecordCategorie) |