terom@27: import datetime terom@49: import urllib terom@27: terom@49: from django import http, shortcuts, forms terom@49: from django.conf import settings, urls terom@2: from django.contrib import admin terom@49: from django.core.urlresolvers import reverse terom@47: from django.utils import timezone, formats terom@27: import django.utils.html terom@27: import django.forms.models terom@27: terom@30: from qrurls.models import URL, URLItem, URLImage terom@27: terom@54: """ terom@54: Private backend UI, using django-admin. terom@54: """ terom@54: terom@27: class URLItemFormset (django.forms.models.BaseInlineFormSet) : terom@47: """ terom@47: Uses the existing URLItems for the URLFeed to determine the initial publishing terom@47: times for new items. terom@47: """ terom@47: terom@27: def __init__ (self, *args, **kwargs) : terom@27: urlfeed = kwargs.get('instance') terom@49: extra = kwargs.get('extra', 5) terom@27: terom@49: publishing_date, publishing_time = URLAdmin.publish_scheduling(urlfeed) terom@49: terom@27: kwargs.update(initial=[ terom@49: dict(published=publish) for publish in URLAdmin.publishing_schedule( terom@49: publishing_date, publishing_time, count=extra) terom@27: ]) terom@27: super(URLItemFormset, self).__init__(*args, **kwargs) terom@2: terom@3: class URLItemInline (admin.TabularInline) : terom@47: """ terom@47: Inline set of URLItems for an URLFeed. terom@47: """ terom@47: terom@3: model = URLItem terom@27: formset = URLItemFormset terom@3: terom@2: class URLAdmin (admin.ModelAdmin) : terom@49: @classmethod terom@49: def publish_scheduling (cls, urlfeed) : terom@49: """Calculate initial URLItem.published values for feed, or defaults.""" terom@49: # hack to get at the URLFeed to determine our initial values.. terom@49: if urlfeed and isinstance(urlfeed, URL) : terom@49: # starting from the following day terom@49: return ( terom@49: urlfeed.last_item().published.date() + datetime.timedelta(days=1), terom@49: urlfeed.publishing_time, terom@49: ) terom@49: else: terom@49: # no data... terom@50: return datetime.date.today(), datetime.time() terom@49: terom@49: @classmethod terom@49: def publishing_schedule (cls, publishing_date, publishing_time, count) : terom@49: """Yield URLItem.published values.""" terom@49: for days in xrange(0, count) : terom@49: yield datetime.datetime.combine( terom@49: publishing_date + datetime.timedelta(days=days), terom@49: publishing_time terom@49: ) terom@49: terom@47: def timezone (self, obj) : terom@47: now = timezone.localtime(obj.now()) terom@47: tz = now.tzinfo terom@47: td = now.tzinfo.utcoffset(now) terom@47: terom@47: if td : terom@47: minutes, seconds = divmod(td.total_seconds(), 60) terom@47: hours, minutes = divmod(minutes, 60) terom@47: offset = "(UTC%+03d:%02d)" % (hours, minutes) terom@47: else : terom@47: offset = "" terom@47: terom@47: return u"%s %s" % (tz, offset) terom@47: terom@22: def qrcode_url (self, obj) : terom@22: warn = None terom@22: terom@22: if obj.shorturl.upper() != obj.shorturl : terom@22: warn = "Shorturl should be UPPERCASE for most compact QR code" terom@22: terom@22: return '{url}{warn}'.format( terom@22: url = django.utils.html.escape(obj.qrcode_url()), terom@22: warn = '

{warn}

'.format(warn=warn) if warn else '', terom@22: ) terom@22: qrcode_url.allow_tags = True terom@22: terom@4: def qrcode_img (self, obj) : terom@4: return ''.format( terom@4: img=django.utils.html.escape(obj.qrcode_img()), terom@4: ) terom@4: qrcode_img.allow_tags = True terom@47: terom@47: # XXX: a whole bunch of ugly datetime-formatting for display... terom@47: def active (self, obj) : terom@47: item = obj.active_item() terom@47: if item : terom@47: return "%s %s" % (formats.localize(timezone.localtime(item.published)), item) terom@47: else : terom@47: return "" terom@47: terom@47: def now (self, obj) : terom@47: return formats.localize(timezone.localtime(obj.now())) terom@47: terom@47: def upcoming (self, obj) : terom@47: item = obj.upcoming_item() terom@47: if item : terom@47: return "%s %s" % (formats.localize(timezone.localtime(item.published)), item) terom@47: else : terom@47: return "" terom@4: terom@4: readonly_fields = ( terom@47: 'timezone', terom@4: 'qrcode_url', terom@4: 'qrcode_img', terom@7: 'active_item', terom@7: 'upcoming_item', terom@47: 'active', terom@47: 'now', terom@47: 'upcoming', terom@4: ) terom@2: list_display = ( terom@11: 'get_absolute_url', terom@8: 'active_item', terom@8: 'upcoming_item', terom@2: ) terom@4: fieldsets = ( terom@4: (None, { terom@47: 'fields': ( terom@47: 'shorturl', terom@47: 'publishing_time', terom@47: 'timezone', terom@51: 'title', terom@47: ), terom@4: }), terom@4: ("QRCode", { terom@7: 'fields': ('qrcode_url', 'qrcode_img'), terom@4: }), terom@47: ("Item publishing overview", { terom@47: 'fields': ( terom@47: 'active', terom@47: 'now', terom@47: 'upcoming', terom@47: ), terom@47: }), terom@4: ) terom@3: inlines = (URLItemInline, ) terom@2: terom@49: ## Import terom@49: class ImportForm (forms.Form) : terom@49: shorturl = forms.ModelChoiceField(URL.objects) terom@49: publishing_date = forms.DateField(widget=admin.widgets.AdminDateWidget) terom@49: publishing_time = forms.TimeField(widget=admin.widgets.AdminTimeWidget) terom@49: image = forms.ImageField() terom@49: terom@49: def import_images_handler (self, url_feed, data) : terom@49: """Custom for backend for mass-importing images into a feed.""" terom@49: terom@49: images = [data['image']] terom@49: publishing = self.publishing_schedule(data['publishing_date'], data['publishing_time'], len(images)) terom@49: terom@49: for image, publish in zip(images, publishing) : terom@49: # XXX: move title default elsewhere terom@49: url_image = URLImage(image=image, title=image.name) terom@49: url_image.save() terom@49: terom@49: url_item = URLItem(shorturl=url_feed, published=publish, image=url_image) terom@49: url_item.save() terom@49: terom@49: return http.HttpResponseRedirect(reverse('admin:qrurls_url_change', args=(url_feed.id, ))) terom@49: terom@49: def import_images (self, request, shorturl_id) : terom@49: """Custom form frontend for mass-importing images into a feed.""" terom@49: url_feed = URL.objects.get(id=int(shorturl_id)) terom@49: terom@49: if request.method == 'POST' : terom@49: form = self.ImportForm(request.POST, request.FILES) terom@49: terom@49: if form.is_valid() : terom@49: return self.import_images_handler(url_feed, form.cleaned_data) terom@49: else : terom@49: publishing_date, publishing_time = self.publish_scheduling(url_feed) terom@49: terom@49: form = self.ImportForm(initial=dict( terom@49: shorturl = url_feed.id, terom@49: publishing_date = publishing_date, terom@49: publishing_time = publishing_time, terom@49: )) terom@49: terom@49: return shortcuts.render(request, 'admin/qrurls_import_images.html', dict( terom@49: current_app = self.admin_site.name, terom@49: terom@49: media = self.media + form.media, terom@49: form_url = reverse('admin:qrurls_import_images', kwargs=dict(shorturl_id=url_feed.id)), terom@49: form = form, terom@49: )) terom@49: terom@49: def get_urls (self) : terom@49: return urls.patterns('', terom@49: urls.url(r'^(?P\d+)/import$', self.admin_site.admin_view(self.import_images), terom@49: name='qrurls_import_images'), terom@49: ) + super(URLAdmin, self).get_urls() terom@49: terom@49: def import_images_action (self, request, queryset) : terom@49: url_feed, = [url_feed for url_feed in queryset] terom@49: return http.HttpResponseRedirect( terom@49: reverse('admin:qrurls_import_images', kwargs=dict(shorturl_id=url_feed.id)) # ) + '?' + urllib.urlencode(qs, doseq=True) terom@49: ) terom@49: import_images_action.short_description = "Import images for selected feeds" terom@49: terom@49: actions = [import_images_action] terom@49: terom@2: class URLItemAdmin (admin.ModelAdmin) : terom@2: list_display = ( terom@47: 'shorturl', 'published_state', 'get_absolute_url', 'image', 'published', terom@3: ) terom@47: readonly_fields = ('published_state', 'published') terom@3: fieldsets = ( terom@3: ("Publishing", { terom@3: 'fields': ('shorturl', 'published', ), terom@3: }), terom@3: ("Target", { terom@32: 'fields': ('url', 'image'), terom@3: }), terom@2: ) terom@2: terom@30: class URLImageAdmin (admin.ModelAdmin) : terom@38: list_display = ( terom@45: 'title', terom@39: 'uploaded', terom@38: ) terom@30: # hide the "uploaded" field terom@38: fields = ( terom@38: 'image', terom@40: 'title', terom@38: ) terom@30: readonly_fields = ( terom@30: 'uploaded', terom@30: ) terom@32: terom@32: inlines = (URLItemInline, ) terom@30: terom@2: admin.site.register(URL, URLAdmin) terom@2: admin.site.register(URLItem, URLItemAdmin) terom@32: admin.site.register(URLImage, URLImageAdmin)