1 # -*- encoding: utf-8 -*-
5 from django
.core
.urlresolvers
import reverse
as url
6 from django
.db
import models
7 from django
.db
.models
import Q
8 from django
.db
.models
.query
import QuerySet
9 from django
.contrib
import admin
10 from django
.contrib
.auth
.admin
import UserAdmin
11 from django
.contrib
.auth
.models
import User
12 from django
.contrib
.admin
.filterspecs
import RelatedFilterSpec
, FilterSpec
13 from django
.utils
.safestring
import mark_safe
14 from django
.utils
.translation
import ugettext
as _
15 from django
.utils
.encoding
import smart_unicode
, iri_to_uri
16 from django
.http
import HttpResponseRedirect
18 from models
import SourceActualite
, Actualite
, Discipline
, Evenement
, \
19 Record
, ListSet
, HarvestLog
, Profile
, PageStatique
20 from savoirs
.globals import META
22 class ListSetFilterSpec(RelatedFilterSpec
):
24 Filtre custom automatiquement lié à un field nommé 'listsets'. Il a pour but de s'afficher
25 lorsqu'un server a déjà été présélectionné. Dans ce cas, il affiche une liste qui contient les
26 listsets de ce server.
28 def __init__(self
, f
, request
, params
, model
, model_admin
):
29 super(ListSetFilterSpec
, self
).__init__(f
, request
, params
, model
, model_admin
)
30 self
.server_name
= request
.GET
.get('server', None)
33 return self
.server_name
is not None
35 FilterSpec
.filter_specs
.insert(0, (lambda f
: f
.name
== 'listsets', ListSetFilterSpec
))
37 # Ces deux classes permettent d'implémenter la possibilité d'avoir un champs readonly_fields
38 # dans l.administration.
39 # Ce champs est devenu natif à partir de la version 1.2
40 # http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields
41 from django
import forms
42 class ReadOnlyWidget(forms
.Widget
):
43 def __init__(self
, original_value
, display_value
):
44 self
.original_value
= original_value
45 self
.display_value
= display_value
47 super(ReadOnlyWidget
, self
).__init__()
49 def render(self
, name
, value
, attrs
=None):
50 if self
.display_value
is not None:
51 output
= self
.display_value
53 output
= unicode(self
.original_value
)
57 output
= ", ".join([ls
.name
for ls
in self
.original_value
.get_query_set()])
61 is_url
= re
.match('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', output
)
63 output
= "<a target='_blank' href='%s'>%s</a>" % (output
, output
)
65 return mark_safe(output
)
67 def value_from_datadict(self
, data
, files
, name
):
68 return self
.original_value
70 class ReadOnlyAdminFields(object):
71 def get_form(self
, request
, obj
=None):
72 form
= super(ReadOnlyAdminFields
, self
).get_form(request
, obj
)
74 if hasattr(self
, 'readonly_fields'):
75 for field_name
in self
.readonly_fields
:
76 if field_name
in form
.base_fields
:
78 if hasattr(obj
, 'get_%s_display' % field_name
):
79 display_value
= getattr(obj
, 'get_%s_display' % field_name
)()
83 form
.base_fields
[field_name
].widget
= ReadOnlyWidget(getattr(obj
, field_name
, ''), display_value
)
84 form
.base_fields
[field_name
].required
= False
87 class RecordAdminQuerySet(QuerySet
):
89 def filter(self
, *args
, **kwargs
):
90 """Gère des filtres supplémentaires pour l'admin.
92 C'est la seule façon que j'ai trouvée de contourner les mécanismes
93 de recherche de l'admin."""
94 search
= kwargs
.pop('admin_search', None)
95 search_titre
= kwargs
.pop('admin_search_titre', None)
96 search_sujet
= kwargs
.pop('admin_search_sujet', None)
97 search_description
= kwargs
.pop('admin_search_description', None)
98 search_auteur
= kwargs
.pop('admin_search_auteur', None)
102 search_all
= not (search_titre
or search_description
or search_sujet
or search_auteur
)
104 if search_titre
or search_all
:
105 fields
+= ['title', 'alt_title']
106 if search_description
or search_all
:
107 fields
+= ['description', 'abstract']
108 if search_sujet
or search_all
:
109 fields
+= ['subject']
110 if search_auteur
or search_all
:
111 fields
+= ['creator', 'contributor']
113 for bit
in search
.split():
114 or_queries
= [Q(**{field
+ '__icontains': bit
}) for field
in fields
]
115 qs
= qs
.filter(reduce(operator
.or_
, or_queries
))
118 qs
= super(RecordAdminQuerySet
, qs
).filter(*args
, **kwargs
)
121 return super(RecordAdminQuerySet
, self
).filter(*args
, **kwargs
)
123 class RecordAdmin(ReadOnlyAdminFields
, admin
.ModelAdmin
):
124 fields
= ['server', 'title', 'creator', 'description', 'modified',
125 'identifier', 'uri', 'source', 'contributor', 'publisher',
126 'type', 'format', 'language', 'disciplines', 'thematiques',
127 'pays', 'regions', 'validated']
131 list_filter
= ('validated', 'server', 'listsets', 'pays', 'regions',
132 'disciplines', 'thematiques')
133 list_display
= ('title', 'subject', 'uri_display', 'creator',
134 'est_complet', 'validated',)
135 list_editable
= ('validated',)
138 actions
= ['assigner_pays', 'assigner_regions', 'assigner_disciplines',
139 'assigner_thematiques']
141 def __init__(self
, *args
, **kwargs
):
142 """Surcharge l'initialisation pour définir les champs de recherche dynamiquement,
143 et les champs en lecture seule uniquement."""
144 self
.readonly_fields
= META
.keys()
145 self
.readonly_fields
.append('listsets')
146 super(RecordAdmin
, self
).__init__(*args
, **kwargs
)
148 def queryset(self
, request
):
149 return RecordAdminQuerySet(Record
)
151 # Présentation de l'information
153 def est_complet(self
, obj
):
154 v
= obj
.est_complet()
155 return '<img src="/admin_media/img/admin/icon-%s.gif" alt="%d"/>' % (('no','yes')[v
], v
)
156 est_complet
.allow_tags
= True
157 est_complet
.short_description
= u
'complet'
159 def uri_display(self
, obj
):
160 return "<a target='_blank' href='%s'>%s</a>" % (obj
.uri
, obj
.uri
)
161 uri_display
.allow_tags
= True
162 uri_display
.short_description
= u
'lien'
164 def description_display(self
, obj
):
166 if obj
.description
is not None and len(obj
.description
) > max:
167 return "%s..." % obj
.description
[:max]
169 return obj
.description
170 description_display
.short_description
= u
'description'
174 def assigner_pays(self
, request
, queryset
):
175 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
176 return HttpResponseRedirect("/admin/assigner_%s?ids=%s" % ('pays', ",".join(selected
)))
177 assigner_pays
.short_description
= u
'Assigner des pays'
179 def assigner_regions(self
, request
, queryset
):
180 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
181 return HttpResponseRedirect(url('assigner_regions', kwargs
=dict(app_name
='savoirs', model_name
='record')) + '?ids=' + ','.join(selected
))
182 assigner_regions
.short_description
= u
'Assigner des régions'
184 def assigner_thematiques(self
, request
, queryset
):
185 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
186 return HttpResponseRedirect("/admin/assigner_%s?ids=%s" % ('thematiques', ",".join(selected
)))
187 assigner_thematiques
.short_description
= u
'Assigner des thématiques'
189 def assigner_disciplines(self
, request
, queryset
):
190 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
191 return HttpResponseRedirect(url('assigner_disciplines', kwargs
=dict(app_name
='savoirs', model_name
='record')) + '?ids=' + ','.join(selected
))
192 assigner_disciplines
.short_description
= u
'Assigner des disciplines'
194 admin
.site
.register(Record
, RecordAdmin
)
196 class ListSetAdmin(ReadOnlyAdminFields
, admin
.ModelAdmin
):
197 fields
= ['spec', 'name', 'server', 'validated' ]
198 list_display
= fields
199 readonly_fields
= ['spec', 'name', 'server',]
200 list_filter
= ('server',)
202 admin
.site
.register(ListSet
, ListSetAdmin
)
204 class HarvestLogAdmin(ReadOnlyAdminFields
, admin
.ModelAdmin
):
205 fields
= ['context', 'name', 'added', 'updated', 'processed', 'record']
206 list_display
= fields
+ ['date']
207 admin_order_fields
= ['date']
208 search_fields
= fields
209 readonly_fields
= fields
210 list_filter
= ('context',)
212 admin
.site
.register(HarvestLog
, HarvestLogAdmin
)
214 class ProfileInline(admin
.TabularInline
):
219 class UserProfileAdmin(UserAdmin
):
220 inlines
= [ProfileInline
, ]
222 admin
.site
.unregister(User
)
223 admin
.site
.register(User
, UserProfileAdmin
)
225 class ActualiteAdmin(admin
.ModelAdmin
):
226 list_filter
= ('visible', 'disciplines', 'regions')
227 list_display
= ('titre', 'source', 'date', 'visible')
228 list_editable
= ['visible']
229 actions
= ['rendre_visible', 'rendre_invisible', 'assigner_regions', 'assigner_disciplines']
231 def queryset(self
, request
):
232 return Actualite
.all_objects
.get_query_set()
235 def rendre_visible(self
, request
, queryset
):
236 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
237 return HttpResponseRedirect("/admin/confirmation/%s/%s?ids=%s" % ('actualite', 'visible', ",".join(selected
)))
239 def rendre_invisible(self
, request
, queryset
):
240 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
241 return HttpResponseRedirect("/admin/confirmation/%s/%s?ids=%s" % ('actualite', 'invisible', ",".join(selected
)))
243 def assigner_regions(self
, request
, queryset
):
244 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
245 return HttpResponseRedirect(url('assigner_regions', kwargs
=dict(app_name
='savoirs', model_name
='actualite')) + '?ids=' + ','.join(selected
))
246 assigner_regions
.short_description
= u
'Assigner des régions'
248 def assigner_disciplines(self
, request
, queryset
):
249 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
250 return HttpResponseRedirect(url('assigner_disciplines', kwargs
=dict(app_name
='savoirs', model_name
='actualite')) + '?ids=' + ','.join(selected
))
251 assigner_disciplines
.short_description
= u
'Assigner des disciplines'
253 admin
.site
.register(Actualite
, ActualiteAdmin
)
255 class SourceActualiteAdmin(admin
.ModelAdmin
):
256 actions
= ['update_sources']
257 list_display
= ['nom', 'url', 'type']
258 list_filter
= ['type']
260 def update_sources(self
, request
, queryset
):
261 for source
in queryset
:
263 update_sources
.short_description
= u
'Mettre à jour les fils sélectionnés'
265 admin
.site
.register(SourceActualite
, SourceActualiteAdmin
)
267 class EvenementAdminForm(forms
.ModelForm
):
268 mots_cles
= forms
.CharField(label
='Mots-clés', required
=False)
274 cleaned_data
= self
.cleaned_data
275 debut
= cleaned_data
.get("debut")
276 fin
= cleaned_data
.get("fin")
277 if debut
and fin
and debut
> fin
:
278 raise forms
.ValidationError("La date de fin ne doit pas être antérieure à la date de début")
281 class EvenementAdmin(admin
.ModelAdmin
):
282 form
= EvenementAdminForm
283 list_filter
= ('approuve', 'regions', 'discipline', 'discipline_secondaire')
284 list_display
= ('titre', 'debut', 'fin', 'ville', 'pays', 'approuve')
285 fields
= ['titre', 'discipline', 'discipline_secondaire', 'mots_cles',
286 'type', 'adresse', 'ville', 'pays', 'fuseau', 'debut', 'fin', 'piece_jointe', 'regions',
287 'description', 'prenom', 'nom', 'courriel', 'url', 'approuve']
288 actions
= ['assigner_regions', 'assigner_disciplines']
290 def queryset(self
, request
):
291 return Evenement
.all_objects
.get_query_set()
293 def assigner_regions(self
, request
, queryset
):
294 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
295 return HttpResponseRedirect(url('assigner_regions', kwargs
=dict(app_name
='savoirs', model_name
='evenement')) + '?ids=' + ','.join(selected
))
296 assigner_regions
.short_description
= u
'Assigner des régions'
298 def assigner_disciplines(self
, request
, queryset
):
299 selected
= request
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
300 return HttpResponseRedirect(url('assigner_disciplines', kwargs
=dict(app_name
='savoirs', model_name
='evenement')) + '?ids=' + ','.join(selected
))
301 assigner_disciplines
.short_description
= u
'Assigner des disciplines'
303 admin
.site
.register(Evenement
, EvenementAdmin
)
305 class PageStatiqueAdmin(admin
.ModelAdmin
):
306 list_display
= ['titre', 'id']
307 list_display_links
= ['titre', 'id']
310 js
= ['js/tiny_mce/tiny_mce.js', 'js/tiny_mce_textareas.js']
312 admin
.site
.register(PageStatique
, PageStatiqueAdmin
)