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

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

Avoid BeakerException? error.

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