Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 296 lines (261 sloc) 15.09 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
from datetime import datetime

from django import forms
from django.contrib import admin, messages
from django.db.models import ForeignKey
from django.conf import settings
from django.http import HttpResponseRedirect, HttpResponse

from widgetry.tabs.placeholderadmin import ModelAdminWithTabsAndCMSPlaceholder

from arkestra_utilities.widgets.wym_editor import WYMEditor
from arkestra_utilities import admin_tabs_extension
from arkestra_utilities.mixins import SupplyRequestMixin, AutocompleteMixin, InputURLMixin, fieldsets

from links.admin import ExternalLinkForm, get_or_create_external_link
from links.admin import ObjectLinkInline

from models import NewsArticle, NewsSource, Event, EventType

class NewsAndEventsForm(InputURLMixin):
    # a shared form for news and events
    class Meta:
        widgets = {'summary': forms.Textarea(
              attrs={'cols':80, 'rows':2,},
            ),
        }
    
    def clean(self):
        # create the short_title automatically if necessary
        if not self.cleaned_data["short_title"] and self.cleaned_data.get("title"):
            if len(self.cleaned_data["title"]) > 70:
                raise forms.ValidationError("Please provide a short (less than 70 characters) version of the Title for the Short title field.")
            else:
                self.cleaned_data["short_title"] = self.cleaned_data["title"]
                
        # check ExternalLink-related issues
        self.cleaned_data["external_url"] = get_or_create_external_link(self.request,
            self.cleaned_data.get("input_url", None), # a manually entered url
            self.cleaned_data.get("external_url", None), # a url chosen with autocomplete
            self.cleaned_data.get("title"), # link title
            self.cleaned_data.get("summary"), # link description
            )

        # misc checks
        if not self.cleaned_data["external_url"]:
            if not self.cleaned_data["hosted_by"]:
                raise forms.ValidationError("A Host is required except for items on external websites - please provide either a Host or an External URL")
            # must have body or url in order to be published
            if not self.instance and self.instance.body.cmsplugin_set.all():
            # if not self.cleaned_data["body"]:
                message = u"This will not be published until either an external URL or Plugin has been added. Perhaps you ought to do that now."
                messages.add_message(self.request, messages.WARNING, message)


class NewsAndEventsAdmin(SupplyRequestMixin, AutocompleteMixin, ModelAdminWithTabsAndCMSPlaceholder):
    exclude = ('content', 'url')
    search_fields = ['title',]
    list_display = ('short_title', 'date', 'hosted_by',)
    list_editable = ('hosted_by',)
    related_search_fields = ['hosted_by', 'external_url',]
    prepopulated_fields = {
        'slug': ('title',)
            }
        
    def _media(self):
        return super(AutocompleteMixin, self).media + super(ModelAdminWithTabsAndCMSPlaceholder, self).media
    media = property(_media)



class NewsArticleForm(NewsAndEventsForm):
    class Meta(NewsAndEventsForm.Meta):
        model = NewsArticle
        
    def clean(self):
        super(NewsArticleForm, self).clean()
        
        # sticky_until value must be greater than (later) than date
        date = datetime.date(self.cleaned_data['date'])
        self.cleaned_data['sticky_until'] = self.cleaned_data.get('sticky_until', date)
        # if importance = 0, it's not sticky

        self.cleaned_data['sticky_until'] = self.cleaned_data['sticky_until'] or datetime.date(self.cleaned_data['date'])
        if self.cleaned_data['importance'] == 0:
            self.cleaned_data['sticky_until'] = None
        elif self.cleaned_data['sticky_until'] < datetime.date(self.cleaned_data['date']):
            self.cleaned_data['sticky_until'] = datetime.date(self.cleaned_data['date'])
        return self.cleaned_data


class NewsArticleAdmin(NewsAndEventsAdmin):
    # some general settings
    form = NewsArticleForm
    list_filter = ('date',)
    read_only_fields = ('sticky_until')
    filter_horizontal = (
        'please_contact',
        'publish_to',
        )
        
    fieldset_stickiness = ('How this item should behave in lists', {'fields': ('sticky_until', 'is_sticky_everywhere',)})
    tabs = (
            ('Basic', {'fieldsets': (fieldsets["basic"], fieldsets["host"], fieldsets["image"]),}),
            ('Date & significance', {'fieldsets': (fieldsets["date"], fieldsets["importance"], fieldset_stickiness)}),
            ('Body', {'fieldsets': (fieldsets["body"],)}),
            ('Where to Publish', {'fieldsets': (fieldsets["where_to_publish"],)}),
            ('Related people', {'fieldsets': (fieldsets["people"],)}),
            ('Links', {'inlines': (ObjectLinkInline,),}),
            ('Advanced Options', {'fieldsets': (fieldsets["url"], fieldsets["slug"],)}),
        )

class EventForm(NewsAndEventsForm):
    class Meta(NewsAndEventsForm.Meta):
        model = Event

    def clean(self):
        # 1. obtain missing information from parent
        parent = self.cleaned_data['parent']
        if parent:
            print "admin.clean thinks this has a parent:", parent
            # the many-to-many fields can be inherited
            m2m_fields = ['publish_to', ] #organisers ,'enquiries', 'registration_enquiries',
            for field_name in m2m_fields:
                print "checking parent field_content"
                self.cleaned_data[field_name] = self.cleaned_data[field_name] or list(getattr(parent,field_name).all())
            # other fields
            attribute_list = ['building', 'precise_location', 'hosted_by', 'access_note']
            for field_name in attribute_list:
                print "checking which attributes to inherit:", field_name
                self.cleaned_data[field_name] = self.cleaned_data[field_name] or getattr(parent,field_name)
            # if parent is single day event, and this one has no date set, inherit the parent's
            if not self.cleaned_data["start_date"]:
                if parent.single_day_event:
                    self.cleaned_data["start_date"] = self.cleaned_data["end_date"] = parent.start_date
                    self.cleaned_data["single_day_event"] = True
                    message = u"You didn't say, but I am guessing that this is a single-day event on " + unicode(self.cleaned_data["start_date"]) + u"."
                    messages.add_message(self.request, messages.INFO, message)
                else:
                    raise forms.ValidationError(u"I'm terribly sorry, I can't work out when this event is supposed to start. You'll have to enter that information yourself.")

        # 2. go and do the checks in the parent class
        super(EventForm, self).clean()
        
        # 3. check dates
        if self.cleaned_data["start_date"]:
            if self.cleaned_data["series"]:
                raise forms.ValidationError("An event with a start date can't also be a series of events. Please correct this.")
            elif self.cleaned_data["end_date"] == self.cleaned_data["start_date"]:
                self.cleaned_data["single_day_event"] = True
            elif not self.cleaned_data["end_date"]:
                self.cleaned_data["single_day_event"] = True
                message = u"You didn't enter an end date, so I have assumed this is a single-day event"
                messages.add_message(self.request, messages.INFO, message)
            elif not self.cleaned_data["single_day_event"]:
                if self.cleaned_data["end_date"] < self.cleaned_data["start_date"]:
                    raise forms.ValidationError('This event appears to end before it starts, which is very silly. Please correct the dates.')
                if not self.cleaned_data["start_time"] and self.cleaned_data["end_time"]:
                    self.cleaned_data["end_time"] = None
                    message = u"You didn't enter a start time, so I deleted the end time. I hope that's OK."
                    messages.add_message(self.request, messages.WARNING, message)
            
            if self.cleaned_data["single_day_event"]:
                self.cleaned_data["end_date"] = self.cleaned_data["start_date"]
                if not self.cleaned_data["start_time"]:
                    message = u"You have a lovely smile."
                    messages.add_message(self.request, messages.INFO, message)
                    self.cleaned_data["end_time"] = None
                elif self.cleaned_data["end_time"] and self.cleaned_data["end_time"] < self.cleaned_data["start_time"]:
                    raise forms.ValidationError('This event appears to end before it starts, which is very silly. Please correct the times.')
                                  
            self.cleaned_data['jumps_queue_on'] = self.cleaned_data['jumps_queue_on'] or self.cleaned_data['start_date']
            if self.cleaned_data['importance'] == 0:
                self.cleaned_data['jumps_queue_on'] = None
            elif self.cleaned_data['jumps_queue_on'] > self.cleaned_data['start_date']:
                self.cleaned_data['jumps_queue_on'] = self.cleaned_data['start_date']

        # an event without a start date can be assumed to be a series of events
        else:
            self.cleaned_data["series"] = True
            message = u"You didn't enter a start date, so I will assume this is a series of events."
            messages.add_message(self.request, messages.INFO, message)
            self.cleaned_data['start_date'] = self.cleaned_data['end_date'] = self.cleaned_data['start_time'] = self.cleaned_data['end_time'] = None
            self.cleaned_data['single_day_event'] = False
            self.cleaned_data['jumps_queue_on'] = None
            self.cleaned_data['importance'] = 0
        return self.cleaned_data

    '''
def clean_enquiries(self):
data = self.cleaned_data['enquiries']
parent = self.cleaned_data['parent']
print "cleaning enquiries: %s (%s) parent: %s (%s)" % (data,type(data), parent, type(parent))
if not data and parent:
print " getting defaultdata from parent"
data = list(parent.enquiries.all())
return data
'''

class EventAdmin(NewsAndEventsAdmin):
    # some general settings
    form = EventForm
    filter_horizontal = (
        'please_contact',
        'publish_to',
        'registration_enquiries',
        'featuring',
        )
    ordering = ['type',]
    change_list_template = "admin/news_and_events/event/change_list.html"
    list_display = ('short_title','parent', 'start_date', 'series', 'slug',)
    list_editable = ('parent', 'start_date', 'series', 'slug',)
    search_fields = ['title',]
    list_filter = ('start_date',)
    save_as = True
    # autocomplete fields
    related_search_fields = ['hosted_by','parent','building', 'external_url']

    # the tabs
    fieldset_type = ('Type', {'fields': ('type',)},)
    fieldset_building = ('Building', {'fields': ('building',)},)
    fieldset_when = ('When', {'fields': ('series', 'single_day_event', ('start_date', 'start_time'), ('end_date', 'end_time'))})
    fieldsets_relationships = (
        ('Parent & children', {
            'fields': ('parent', 'child_list_heading',),},),
        ('When displaying the children of this item in lists', {
            'fields': ('show_titles', 'display_series_summary',),},),
        )
    fieldset_registration = ('Registration enquiries', {'fields': ('registration_enquiries',)})
    fieldset_featuring = ('Featured people', {'fields': ('featuring',)})
    fieldset_jumpiness = ('How this item should behave in lists', {'fields': ('jumps_queue_on', 'jumps_queue_everywhere')})
    tabs = (
            ('Basic', {'fieldsets': (fieldsets["basic"], fieldset_type, fieldsets["host"], fieldsets["image"])}),
            ('Date & significance', {'fieldsets':
                (
                    fieldset_when,
                    fieldsets["importance"],
                    fieldset_jumpiness,)}
                    ),
            ('Location', {'fieldsets': (fieldset_building, fieldsets["location"],)}),
            ('Parent & children', {'fieldsets': fieldsets_relationships}),
            ('Body', {'fieldsets': (fieldsets["body"],)}),
            ('Where to Publish', {'fieldsets': (fieldsets["where_to_publish"],)}),
            ('People', {'fieldsets': (fieldset_featuring, fieldsets["people"], fieldset_registration)}),
            ('Links', {'inlines': (ObjectLinkInline,),}),
            ('Advanced Options', {'fieldsets': (fieldsets["url"], fieldsets["slug"],)}),
        )

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        extra_context.update({
                'root_events': Event.objects.filter(level=0),
                'has_add_permission': request.user.has_perm('news_and_events.add_event'),
                'has_change_permission': request.user.has_perm('news_and_events.change_event'),
                'has_delete_permission': request.user.has_perm('news_and_events.delete_event'),
        })
        return super(EventAdmin, self).changelist_view(request, extra_context)
    def get_urls(self):
        from django.conf.urls.defaults import patterns, url
        urls = super(EventAdmin, self).get_urls()
        # helper for url pattern generation
        info = "%sadmin_%s_%s" % (self.admin_site.name, self.model._meta.app_label, self.model._meta.module_name)
        #pat = lambda regex, fn: url(regex, self.admin_site.admin_view(fn), name='%s_%s' % (info, fn.__name__))
        url_patterns = patterns('',
            url(r'^([0-9]+)/move-page/$', self.admin_site.admin_view(self.move_event), name='%s_%s' % (info, 'move_page') ),
            #pat(r'^([0-9]+)/move-page/$', self.move_entity),
        )
        url_patterns.extend(urls)
        return url_patterns
    def move_event(self, request, event_id, extra_context=None):
        target = request.POST.get('target', None)
        position = request.POST.get('position', None)
        if target is None or position is None:
            return HttpResponseRedirect('../../')
        try:
            event = self.model.objects.get(pk=event_id)
            target = self.model.objects.get(pk=target)
        except self.model.DoesNotExist:
            return HttpResponse("error")
        # does he haves permissions to do this...?
        if not request.user.has_perm('news_and_events.change_event'):
            return HttpResponse("Denied")
        # move page
        event.move_to(target, position)
        event.save()
        return HttpResponse("ok")

class EventTypeAdmin(admin.ModelAdmin):
    pass

class NewsSourceAdmin(admin.ModelAdmin):
    pass

admin.site.register(Event,EventAdmin)
admin.site.register(NewsSource,NewsSourceAdmin)
admin.site.register(EventType,EventTypeAdmin)
admin.site.register(NewsArticle,NewsArticleAdmin)
Something went wrong with that request. Please try again.