source: main/waeup.kofa/trunk/src/waeup/kofa/hostels/browser.py @ 13352

Last change on this file since 13352 was 13346, checked in by Henrik Bettermann, 9 years ago

Remove beds_reserved attribute from hostels. Hostels do no longer
contain information about reserved bed spaces.

Use default values for list attributes. Otherwise the hostel manage page cannot be opened after import of hostels.

  • Property svn:keywords set to Id
File size: 13.4 KB
RevLine 
[7195]1## $Id: browser.py 13346 2015-10-26 08:57:30Z henrik $
2##
[6953]3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""UI components for hostels and related components.
19"""
20import grok
[6973]21import sys
[7718]22from zope.i18n import translate
23from zope.component import getUtility
[9217]24from waeup.kofa.browser.layout import (
[7819]25    KofaEditFormPage, KofaAddFormPage, KofaDisplayFormPage,
[13319]26    NullValidator, UtilityView)
[7811]27from waeup.kofa.browser.breadcrumbs import Breadcrumb
28from waeup.kofa.browser.layout import default_primary_nav_template
29from waeup.kofa.browser.pages import delSubobjects
30from waeup.kofa.browser.viewlets import (
[7257]31    ManageActionButton, PrimaryNavTab)
[7811]32from waeup.kofa.browser.layout import jsaction, action
[13177]33from waeup.kofa.interfaces import IKofaObject, IKofaUtils, DOCLINK
[7811]34from waeup.kofa.interfaces import MessageFactory as _
35from waeup.kofa.hostels.vocabularies import NOT_OCCUPIED
36from waeup.kofa.hostels.hostel import Hostel
37from waeup.kofa.hostels.interfaces import (
[9414]38    IHostelsContainer, IHostel, IBed)
[8685]39from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
[6953]40
[6956]41# Save function used for save methods in manager pages
42def msave(view, **data):
43    changed_fields = view.applyData(view.context, **data)
44    # Turn list of lists into single list
45    if changed_fields:
46        changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
47    fields_string = ' + '.join(changed_fields)
48    view.context._p_changed = True
[7718]49    view.flash(_('Form has been saved.'))
[6956]50    if fields_string:
[13166]51        view.context.writeLogMessage(view, 'saved: %s' % fields_string)
[6956]52    return
53
[6953]54class HostelsTab(PrimaryNavTab):
55    """Hostels tab in primary navigation.
56    """
57
[7819]58    grok.context(IKofaObject)
[6953]59    grok.order(5)
60    grok.require('waeup.viewHostels')
[10771]61    grok.name('hostelstab')
[7243]62    template = default_primary_nav_template
[6953]63    pnav = 5
[7674]64    tab_title = _(u'Hostels')
[6953]65
66    @property
67    def link_target(self):
68        return self.view.application_url('hostels')
69
70class HostelsBreadcrumb(Breadcrumb):
71    """A breadcrumb for the hostels container.
72    """
73    grok.context(IHostelsContainer)
[7718]74    title = _(u'Hostels')
[6953]75
76class HostelBreadcrumb(Breadcrumb):
77    """A breadcrumb for the hostel container.
78    """
79    grok.context(IHostel)
80
[6959]81    def title(self):
82        return self.context.hostel_name
83
[7068]84class BedBreadcrumb(Breadcrumb):
85    """A breadcrumb for the hostel container.
86    """
87    grok.context(IBed)
88
89    def title(self):
[9199]90        co = self.context.coordinates
[7718]91        return _('Block ${a}, Room ${b}, Bed ${c}',
92            mapping = {'a':co[1], 'b':co[2], 'c':co[3]})
[7068]93
[7819]94class HostelsContainerPage(KofaDisplayFormPage):
[6953]95    """The standard view for hostels containers.
96    """
97    grok.context(IHostelsContainer)
98    grok.name('index')
99    grok.require('waeup.viewHostels')
[6959]100    grok.template('containerpage')
[7718]101    label = _('Accommodation Section')
[6953]102    pnav = 5
[8685]103    form_fields = grok.AutoFields(IHostelsContainer)
104    form_fields[
105        'startdate'].custom_widget = FriendlyDatetimeDisplayWidget('le')
106    form_fields[
107        'enddate'].custom_widget = FriendlyDatetimeDisplayWidget('le')
[6953]108
109class HostelsContainerManageActionButton(ManageActionButton):
110    grok.order(1)
111    grok.context(IHostelsContainer)
112    grok.view(HostelsContainerPage)
113    grok.require('waeup.manageHostels')
[7718]114    text = _('Manage accommodation section')
[6953]115
[8685]116class HostelsContainerManagePage(KofaEditFormPage):
[6953]117    """The manage page for hostel containers.
118    """
119    grok.context(IHostelsContainer)
120    grok.name('manage')
121    grok.require('waeup.manageHostels')
[6959]122    grok.template('containermanagepage')
[6953]123    pnav = 5
[7718]124    label = _('Manage accommodation section')
[8685]125    form_fields = grok.AutoFields(IHostelsContainer)
126    taboneactions = [_('Save')]
[9197]127    tabtwoactions = [_('Add hostel'),
128        _('Clear all hostels'),
129        _('Remove selected')]
[13177]130    doclink = DOCLINK + '/hostels.html#accommodation-section'
[6953]131
[6959]132    # It's quite dangerous to remove entire hostels with its content (beds).
[6966]133    # Thus, this remove method should be combined with an archiving function.
[7718]134    @jsaction(_('Remove selected'))
[6959]135    def delHostels(self, **data):
136        form = self.request.form
[9701]137        if 'val_id' in form:
[6959]138            deleted = []
139            child_id = form['val_id']
[6966]140            if not isinstance(child_id, list):
141                child_id = [child_id]
[6959]142            for id in child_id:
143                deleted.append(id)
[13170]144            self.context.writeLogMessage(
145                self, 'deleted: % s' % ', '.join(deleted))
[6959]146        delSubobjects(self, redirect='@@manage', tab='2')
147        return
[6953]148
[7718]149    @action(_('Add hostel'), validator=NullValidator)
[6959]150    def addSubunit(self, **data):
151        self.redirect(self.url(self.context, 'addhostel'))
152        return
153
[11254]154    @jsaction(_('Clear all hostels'), style='danger')
[9197]155    def clearHostels(self, **data):
156        self.context.clearAllHostels()
157        self.flash(_('All hostels cleared.'))
[13166]158        self.context.writeLogMessage(self, 'all hostels cleared')
[11254]159        self.redirect(self.url(self.context, '@@manage')+'#tab2')
[9197]160        return
161
[8685]162    @action(_('Save'), style='primary')
163    def save(self, **data):
164        self.applyData(self.context, **data)
165        self.flash(_('Settings have been saved.'))
166        return
167
[13319]168class ReleaseExpiredAllocationsPage(UtilityView, grok.View):
169    """Release all expired allocated beds.
170    """
171    grok.context(IHostelsContainer)
172    grok.name('releaseexpired')
[13320]173    grok.require('waeup.manageHostels')
[13319]174
175    def update(self, n=7):
176        released = self.context.releaseExpiredAllocations(n)
177        if len(released):
178            message = ', '.join(released)
179            self.context.writeLogMessage(self, 'released: %s' % message)
180            flash_msg = _('Successfully released beds: ${a}', mapping = {'a':message})
181        else:
182            flash_msg = _('No bed released.')
183        self.flash(flash_msg, type='success')
184        self.redirect(self.url(self.context))
185        return
186
187    def render(self):
188        return
189
[7819]190class HostelAddFormPage(KofaAddFormPage):
[6953]191    """Add-form to add a hostel.
192    """
193    grok.context(IHostelsContainer)
194    grok.require('waeup.manageHostels')
195    grok.name('addhostel')
[6970]196    #grok.template('hosteladdpage')
[10683]197    form_fields = grok.AutoFields(IHostel).omit('beds_reserved', 'hostel_id')
[7718]198    label = _('Add hostel')
[6953]199    pnav = 5
[13177]200    doclink = DOCLINK + '/hostels.html#accommodation-section'
[6953]201
[7718]202    @action(_('Create hostel'))
[6953]203    def addHostel(self, **data):
[6954]204        hostel = Hostel()
205        self.applyData(hostel, **data)
[6973]206        hostel.hostel_id = data[
207            'hostel_name'].lower().replace(' ','-').replace('_','-')
[6966]208        try:
209            self.context.addHostel(hostel)
210        except KeyError:
[11254]211            self.flash(_('The hostel already exists.'), type='warning')
[6966]212            return
[7718]213        self.flash(_('Hostel created.'))
[13166]214        self.context.writeLogMessage(self, 'added: % s' % data['hostel_name'])
[6953]215        self.redirect(self.url(self.context[hostel.hostel_id], 'index'))
216        return
217
[7819]218class HostelDisplayFormPage(KofaDisplayFormPage):
[6953]219    """ Page to display hostel data
220    """
221    grok.context(IHostel)
222    grok.name('index')
223    grok.require('waeup.viewHostels')
[9534]224    grok.template('hostelpage')
225    form_fields = grok.AutoFields(IHostel).omit('beds_reserved')
[6953]226    pnav = 5
227
[6956]228    @property
229    def label(self):
230        return self.context.hostel_name
[6953]231
232class HostelManageActionButton(ManageActionButton):
233    grok.order(1)
234    grok.context(IHostel)
235    grok.view(HostelDisplayFormPage)
236    grok.require('waeup.manageHostels')
[7718]237    text = _('Manage')
[6970]238    target = 'manage'
[6953]239
[7819]240class HostelManageFormPage(KofaEditFormPage):
[6953]241    """ View to edit hostel data
242    """
243    grok.context(IHostel)
[6970]244    grok.name('manage')
[6953]245    grok.require('waeup.manageHostels')
[9534]246    form_fields = grok.AutoFields(IHostel).omit('hostel_id', 'beds_reserved')
[6970]247    grok.template('hostelmanagepage')
[7718]248    label = _('Manage hostel')
[6953]249    pnav = 5
[7718]250    taboneactions = [_('Save')]
251    tabtwoactions = [_('Update all beds'),
252        _('Switch reservation of selected beds'),
[9197]253        _('Release selected beds'),
254        _('Clear hostel')]
[6996]255    not_occupied = NOT_OCCUPIED
[13177]256    doclink = DOCLINK + '/hostels.html#browser-pages'
[6953]257
[6956]258    @property
[6996]259    def students_url(self):
260        return self.url(grok.getSite(),'students')
261
[11254]262    @action(_('Save'), style='primary')
[6953]263    def save(self, **data):
264        msave(self, **data)
265        return
[6970]266
[13346]267    @action(_('Update all beds'), style='primary',
268            warning=_('Attention: The updater removes all reservation flags of existing beds.'
269                        ' You really want to update?'))
[6970]270    def updateBeds(self, **data):
[6988]271        removed, added, modified, modified_beds = self.context.updateBeds()
272        message = '%d empty beds removed, %d beds added, %d occupied beds modified (%s)' % (
273            removed, added, modified, modified_beds)
[7718]274        flash_message = _(
275            '${a} empty beds removed, ${b} beds added, '
276            + '${c} occupied beds modified (${d})',
277            mapping = {'a':removed, 'b':added, 'c':modified, 'd':modified_beds})
278        self.flash(flash_message)
[13166]279        self.context.writeLogMessage(self, message)
[11254]280        self.redirect(self.url(self.context, '@@manage')+'#tab2')
[6970]281        return
[6973]282
[7718]283    @action(_('Switch reservation of selected beds'))
[6974]284    def switchReservations(self, **data):
[6973]285        form = self.request.form
[9701]286        if 'val_id' in form:
[6973]287            child_id = form['val_id']
288        else:
[11254]289            self.flash(_('No item selected.'), type='warning')
290            self.redirect(self.url(self.context, '@@manage')+'#tab2')
[6973]291            return
292        if not isinstance(child_id, list):
293            child_id = [child_id]
[7718]294        switched = [] # for log file
295        switched_translated = [] # for flash message
[7833]296        # Here we know that the cookie has been set
297        preferred_language = self.request.cookies.get('kofa.language')
[6973]298        for bed_id in child_id:
[7718]299            message = self.context[bed_id].switchReservation()
300            switched.append('%s (%s)' % (bed_id,message))
[7811]301            m_translated = translate(message, 'waeup.kofa',
[7718]302                target_language=preferred_language)
303            switched_translated.append('%s (%s)' % (bed_id,m_translated))
[6973]304        if len(switched):
[6988]305            message = ', '.join(switched)
[7718]306            m_translated = ', '.join(switched_translated)
307            self.flash(_('Successfully switched beds: ${a}',
308                mapping = {'a':m_translated}))
[13166]309            self.context.writeLogMessage(self, 'switched: %s' % message)
[11254]310            self.redirect(self.url(self.context, '@@manage')+'#tab2')
[6973]311        return
312
[7718]313    @action(_('Release selected beds'))
[7042]314    def releaseBeds(self, **data):
315        form = self.request.form
[9701]316        if 'val_id' in form:
[7042]317            child_id = form['val_id']
318        else:
[11254]319            self.flash(_('No item selected.'), type='warning')
320            self.redirect(self.url(self.context, '@@manage')+'#tab2')
[7042]321            return
322        if not isinstance(child_id, list):
323            child_id = [child_id]
324        released = []
325        for bed_id in child_id:
[7068]326            message = self.context[bed_id].releaseBed()
[7070]327            if message:
328                released.append('%s (%s)' % (bed_id,message))
[7042]329        if len(released):
330            message = ', '.join(released)
[7718]331            self.flash(_('Successfully released beds: ${a}',
332                mapping = {'a':message}))
[13166]333            self.context.writeLogMessage(self, 'released: %s' % message)
[11254]334            self.redirect(self.url(self.context, '@@manage')+'#tab2')
[7070]335        else:
[11254]336            self.flash(_('No allocated bed selected.'), type='warning')
337            self.redirect(self.url(self.context, '@@manage')+'#tab2')
[7042]338        return
[7068]339
[11254]340    @jsaction(_('Clear hostel'), style='danger')
[9197]341    def clearHostel(self, **data):
342        self.context.clearHostel()
343        self.flash(_('Hostel cleared.'))
[13166]344        self.context.writeLogMessage(self, 'cleared')
[11254]345        self.redirect(self.url(self.context, '@@manage')+'#tab2')
[9197]346        return
347
[7819]348class BedManageFormPage(KofaEditFormPage):
[7068]349    """ View to edit bed data
350    """
[9414]351    grok.context(IBed)
[7068]352    grok.name('index')
353    grok.require('waeup.manageHostels')
[9414]354    form_fields = grok.AutoFields(IBed).omit(
[9199]355        'bed_id', 'bed_number', 'bed_type')
[7718]356    label = _('Allocate student')
[7068]357    pnav = 5
[13177]358    doclink = DOCLINK + '/hostels.html#manage-bed'
[7068]359
[7718]360    @action(_('Save'))
[7068]361    def save(self, **data):
[9416]362        if data['owner'] == NOT_OCCUPIED:
[11254]363            self.flash(_('No valid student id.'), type='warning')
[9416]364            self.redirect(self.url(self.context))
365            return
[7068]366        msave(self, **data)
[11254]367        self.redirect(self.url(self.context.__parent__, '@@manage')+'#tab2')
[7068]368        return
369
370    def update(self):
371        if self.context.owner != NOT_OCCUPIED:
372            # Don't use this form for exchanging students.
373            # Beds must be released first before they can be allocated to
374            # other students.
[11254]375            self.redirect(self.url(self.context.__parent__, '@@manage')+'#tab2')
[7811]376        return
Note: See TracBrowser for help on using the repository browser.