qrurls/admin.py
author Tero Marttila <terom@fixme.fi>
Wed, 21 Aug 2013 01:17:44 +0300
changeset 50 b8a8269d7214
parent 49 7c0dcf6603f5
child 51 6f35a169ef01
permissions -rw-r--r--
Fixup publish_scheduling() return
import datetime
import urllib

from django import http, shortcuts, forms
from django.conf import settings, urls
from django.contrib import admin
from django.core.urlresolvers import reverse
from django.utils import timezone, formats
import django.utils.html
import django.forms.models

from qrurls.models import URL, URLItem, URLImage

class URLItemFormset (django.forms.models.BaseInlineFormSet) :
    """
        Uses the existing URLItems for the URLFeed to determine the initial publishing
        times for new items.
    """

    def __init__ (self, *args, **kwargs) :
        urlfeed = kwargs.get('instance')
        extra = kwargs.get('extra', 5)

        publishing_date, publishing_time = URLAdmin.publish_scheduling(urlfeed)
    
        kwargs.update(initial=[
                dict(published=publish) for publish in URLAdmin.publishing_schedule(
                    publishing_date, publishing_time, count=extra)
        ])
        super(URLItemFormset, self).__init__(*args, **kwargs)

class URLItemInline (admin.TabularInline) :
    """
        Inline set of URLItems for an URLFeed.
    """

    model = URLItem
    formset = URLItemFormset

class URLAdmin (admin.ModelAdmin) :
    @classmethod
    def publish_scheduling (cls, urlfeed) :
        """Calculate initial URLItem.published values for feed, or defaults."""
        # hack to get at the URLFeed to determine our initial values..
        if urlfeed and isinstance(urlfeed, URL) :
            # starting from the following day
            return (
                    urlfeed.last_item().published.date() + datetime.timedelta(days=1),
                    urlfeed.publishing_time,
            )
        else:
            # no data...
            return datetime.date.today(), datetime.time()
       
    @classmethod
    def publishing_schedule (cls, publishing_date, publishing_time, count) :
        """Yield URLItem.published values."""
        for days in xrange(0, count) :
            yield datetime.datetime.combine(
                    publishing_date + datetime.timedelta(days=days),
                    publishing_time
            )

    def timezone (self, obj) :
        now = timezone.localtime(obj.now())
        tz = now.tzinfo
        td = now.tzinfo.utcoffset(now)

        if td :
            minutes, seconds = divmod(td.total_seconds(), 60)
            hours, minutes = divmod(minutes, 60)
            offset = "(UTC%+03d:%02d)" % (hours, minutes)
        else :
            offset = ""

        return u"%s %s" % (tz, offset)

    def qrcode_url (self, obj) :
        warn = None

        if obj.shorturl.upper() != obj.shorturl :
            warn = "Shorturl should be UPPERCASE for most compact QR code"

        return '<a href="{url}">{url}</a>{warn}'.format(
                url     = django.utils.html.escape(obj.qrcode_url()),
                warn    = '<p class="errornote">{warn}</p>'.format(warn=warn) if warn else '',
        )
    qrcode_url.allow_tags = True

    def qrcode_img (self, obj) :
        return '<img src="{img}" />'.format(
                img=django.utils.html.escape(obj.qrcode_img()),
        )
    qrcode_img.allow_tags = True
    
    # XXX: a whole bunch of ugly datetime-formatting for display...
    def active (self, obj) :
        item = obj.active_item()
        if item :
            return "%s %s" % (formats.localize(timezone.localtime(item.published)), item)
        else :
            return ""

    def now (self, obj) :
        return formats.localize(timezone.localtime(obj.now()))

    def upcoming (self, obj) :
        item = obj.upcoming_item()
        if item :
            return "%s %s" % (formats.localize(timezone.localtime(item.published)), item)
        else :
            return ""

    readonly_fields = (
        'timezone',
        'qrcode_url',
        'qrcode_img',
        'active_item',
        'upcoming_item',
        'active',
        'now',
        'upcoming',
    )
    list_display = (
        'get_absolute_url',
        'active_item',
        'upcoming_item',
    )
    fieldsets = (
        (None, {
            'fields': (
                'shorturl', 
                'publishing_time', 
                'timezone',
            ),
        }),
        ("QRCode", {
            'fields': ('qrcode_url', 'qrcode_img'),
        }),
        ("Item publishing overview", {
            'fields': (
                'active',
                'now',
                'upcoming',
            ),
        }),
    )
    inlines = (URLItemInline, )

    ## Import
    class ImportForm (forms.Form) :
        shorturl = forms.ModelChoiceField(URL.objects)
        publishing_date = forms.DateField(widget=admin.widgets.AdminDateWidget)
        publishing_time = forms.TimeField(widget=admin.widgets.AdminTimeWidget)
        image = forms.ImageField()

    def import_images_handler (self, url_feed, data) :
        """Custom for backend for mass-importing images into a feed."""
        
        images = [data['image']]
        publishing = self.publishing_schedule(data['publishing_date'], data['publishing_time'], len(images))

        for image, publish in zip(images, publishing) :
            # XXX: move title default elsewhere
            url_image = URLImage(image=image, title=image.name)
            url_image.save()

            url_item = URLItem(shorturl=url_feed, published=publish, image=url_image)
            url_item.save()

        return http.HttpResponseRedirect(reverse('admin:qrurls_url_change', args=(url_feed.id, )))

    def import_images (self, request, shorturl_id) :
        """Custom form frontend for mass-importing images into a feed."""
        url_feed = URL.objects.get(id=int(shorturl_id))
        
        if request.method == 'POST' :
            form = self.ImportForm(request.POST, request.FILES)

            if form.is_valid() :
                return self.import_images_handler(url_feed, form.cleaned_data)
        else :
            publishing_date, publishing_time = self.publish_scheduling(url_feed)

            form = self.ImportForm(initial=dict(
                shorturl        = url_feed.id,
                publishing_date = publishing_date,
                publishing_time = publishing_time,
            ))
        
        return shortcuts.render(request, 'admin/qrurls_import_images.html', dict(
            current_app     = self.admin_site.name,

            media           = self.media + form.media,
            form_url        = reverse('admin:qrurls_import_images', kwargs=dict(shorturl_id=url_feed.id)),
            form            = form,
        ))

    def get_urls (self) :
        return urls.patterns('',
            urls.url(r'^(?P<shorturl_id>\d+)/import$', self.admin_site.admin_view(self.import_images),
                name='qrurls_import_images'),
        ) + super(URLAdmin, self).get_urls()

    def import_images_action (self, request, queryset) :
        url_feed, = [url_feed for url_feed in queryset]
        return http.HttpResponseRedirect(
                reverse('admin:qrurls_import_images', kwargs=dict(shorturl_id=url_feed.id)) # ) + '?' + urllib.urlencode(qs, doseq=True)
        )
    import_images_action.short_description = "Import images for selected feeds"
    
    actions = [import_images_action]

class URLItemAdmin (admin.ModelAdmin) :
    list_display = (
        'shorturl', 'published_state', 'get_absolute_url', 'image', 'published',
    )
    readonly_fields = ('published_state', 'published')
    fieldsets = (
        ("Publishing", {
            'fields': ('shorturl', 'published', ),
        }),
        ("Target", {
            'fields': ('url', 'image'),
        }),
    )

class URLImageAdmin (admin.ModelAdmin) :
    list_display = (
        'title',
        'uploaded',
    )
    # hide the "uploaded" field
    fields = (
        'image',
        'title',
    )
    readonly_fields = (
        'uploaded',
    )
    
    inlines = (URLItemInline, )

admin.site.register(URL, URLAdmin)
admin.site.register(URLItem, URLItemAdmin)
admin.site.register(URLImage, URLImageAdmin)