source: main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser.py @ 7078

Last change on this file since 7078 was 7070, checked in by Henrik Bettermann, 13 years ago

Add more tests and increase test coverage.

  • Property svn:keywords set to Id
File size: 11.1 KB
Line 
1## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
2## This program is free software; you can redistribute it and/or modify
3## it under the terms of the GNU General Public License as published by
4## the Free Software Foundation; either version 2 of the License, or
5## (at your option) any later version.
6##
7## This program is distributed in the hope that it will be useful,
8## but WITHOUT ANY WARRANTY; without even the implied warranty of
9## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10## GNU General Public License for more details.
11##
12## You should have received a copy of the GNU General Public License
13## along with this program; if not, write to the Free Software
14## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15##
16"""UI components for hostels and related components.
17"""
18import grok
19import sys
20from time import time
21from datetime import date, datetime
22from zope.component import createObject
23from waeup.sirp.browser import (
24    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage,
25    NullValidator)
26from waeup.sirp.browser.breadcrumbs import Breadcrumb
27from waeup.sirp.browser.resources import datepicker, datatable, tabs, toggleall
28from waeup.sirp.browser.viewlets import (
29    ManageActionButton, PrimaryNavTab, AddActionButton)
30from waeup.sirp.interfaces import IWAeUPObject, IUserAccount
31from waeup.sirp.widgets.datewidget import (
32    FriendlyDateWidget, FriendlyDateDisplayWidget,
33    FriendlyDatetimeDisplayWidget)
34from waeup.sirp.browser.pages import delSubobjects
35from waeup.sirp.authentication import get_principal_role_manager
36from waeup.sirp.hostels.container import HostelsContainer
37from waeup.sirp.hostels.vocabularies import NOT_OCCUPIED
38from waeup.sirp.hostels.hostel import Hostel
39from waeup.sirp.hostels.interfaces import (
40    IHostelsContainer, IHostel, IBed, IBedAllocateStudent)
41
42def write_log_message(view, message):
43    ob_class = view.__implemented__.__name__.replace('waeup.sirp.','')
44    view.context.loggerInfo(ob_class, message)
45    return
46
47# Save function used for save methods in manager pages
48def msave(view, **data):
49    form = view.request.form
50    changed_fields = view.applyData(view.context, **data)
51    # Turn list of lists into single list
52    if changed_fields:
53        changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
54    fields_string = ' + '.join(changed_fields)
55    view.context._p_changed = True
56    view.flash('Form has been saved.')
57    if fields_string:
58        write_log_message(view, 'saved: % s' % fields_string)
59    return
60
61class HostelsTab(PrimaryNavTab):
62    """Hostels tab in primary navigation.
63    """
64
65    grok.context(IWAeUPObject)
66    grok.order(5)
67    grok.require('waeup.viewHostels')
68    grok.template('primarynavtab')
69
70    pnav = 5
71    tab_title = u'Hostels'
72
73    @property
74    def link_target(self):
75        return self.view.application_url('hostels')
76
77class HostelsBreadcrumb(Breadcrumb):
78    """A breadcrumb for the hostels container.
79    """
80    grok.context(IHostelsContainer)
81    title = u'Hostels'
82
83class HostelBreadcrumb(Breadcrumb):
84    """A breadcrumb for the hostel container.
85    """
86    grok.context(IHostel)
87
88    def title(self):
89        return self.context.hostel_name
90
91class BedBreadcrumb(Breadcrumb):
92    """A breadcrumb for the hostel container.
93    """
94    grok.context(IBed)
95
96    def title(self):
97        co = self.context.getBedCoordinates()
98        return 'Block %s, Room %s, Bed %s' % (co[1], co[2], co[3])
99
100class HostelsContainerPage(WAeUPDisplayFormPage):
101    """The standard view for hostels containers.
102    """
103    grok.context(IHostelsContainer)
104    grok.name('index')
105    grok.require('waeup.viewHostels')
106    grok.template('containerpage')
107    label = 'Accommodation Section'
108    title = 'Hostels'
109    pnav = 5
110
111class HostelsContainerManageActionButton(ManageActionButton):
112    grok.order(1)
113    grok.context(IHostelsContainer)
114    grok.view(HostelsContainerPage)
115    grok.require('waeup.manageHostels')
116    text = 'Manage accommodation section'
117
118class HostelsContainerManagePage(WAeUPDisplayFormPage):
119    """The manage page for hostel containers.
120    """
121    grok.context(IHostelsContainer)
122    grok.name('manage')
123    grok.require('waeup.manageHostels')
124    grok.template('containermanagepage')
125    pnav = 5
126    title = 'Hostels'
127    label = 'Manage accommodation section'
128
129    # It's quite dangerous to remove entire hostels with its content (beds).
130    # Thus, this remove method should be combined with an archiving function.
131    @grok.action('Remove selected')
132    def delHostels(self, **data):
133        form = self.request.form
134        if form.has_key('val_id'):
135            deleted = []
136            child_id = form['val_id']
137            if not isinstance(child_id, list):
138                child_id = [child_id]
139            for id in child_id:
140                deleted.append(id)
141            write_log_message(self, 'deleted: % s' % ', '.join(deleted))
142        delSubobjects(self, redirect='@@manage', tab='2')
143        return
144
145    @grok.action('Add hostel', validator=NullValidator)
146    def addSubunit(self, **data):
147        self.redirect(self.url(self.context, 'addhostel'))
148        return
149
150class HostelAddFormPage(WAeUPAddFormPage):
151    """Add-form to add a hostel.
152    """
153    grok.context(IHostelsContainer)
154    grok.require('waeup.manageHostels')
155    grok.name('addhostel')
156    #grok.template('hosteladdpage')
157    form_fields = grok.AutoFields(IHostel)
158    title = 'Hostels'
159    label = 'Add hostel'
160    pnav = 5
161
162    @grok.action('Create hostel')
163    def addHostel(self, **data):
164        hostel = Hostel()
165        self.applyData(hostel, **data)
166        hostel.hostel_id = data[
167            'hostel_name'].lower().replace(' ','-').replace('_','-')
168        try:
169            self.context.addHostel(hostel)
170        except KeyError:
171            self.flash('The hostel already exists.')
172            return
173        self.flash('Hostel created.')
174        write_log_message(self, 'added: % s' % data['hostel_name'])
175        self.redirect(self.url(self.context[hostel.hostel_id], 'index'))
176        return
177
178class HostelDisplayFormPage(WAeUPDisplayFormPage):
179    """ Page to display hostel data
180    """
181    grok.context(IHostel)
182    grok.name('index')
183    grok.require('waeup.viewHostels')
184    #grok.template('hostelpage')
185    pnav = 5
186
187    @property
188    def label(self):
189        return self.context.hostel_name
190
191    @property
192    def title(self):
193        return self.context.hostel_name
194
195class HostelManageActionButton(ManageActionButton):
196    grok.order(1)
197    grok.context(IHostel)
198    grok.view(HostelDisplayFormPage)
199    grok.require('waeup.manageHostels')
200    text = 'Manage'
201    target = 'manage'
202
203class HostelManageFormPage(WAeUPEditFormPage):
204    """ View to edit hostel data
205    """
206    grok.context(IHostel)
207    grok.name('manage')
208    grok.require('waeup.manageHostels')
209    form_fields = grok.AutoFields(IHostel).omit('hostel_id')
210    grok.template('hostelmanagepage')
211    label = 'Manage hostel'
212    pnav = 5
213    taboneactions = ['Save']
214    tabtwoactions = ['Update all beds',
215        'Switch reservation of selected beds',
216        'Release selected beds']
217    not_occupied = NOT_OCCUPIED
218
219    @property
220    def title(self):
221        return self.context.hostel_name
222
223    @property
224    def students_url(self):
225        return self.url(grok.getSite(),'students')
226
227    def update(self):
228        datepicker.need() # Enable jQuery datepicker in date fields.
229        tabs.need()
230        datatable.need()
231        super(HostelManageFormPage, self).update()
232        return
233
234    @grok.action('Save')
235    def save(self, **data):
236        msave(self, **data)
237        return
238
239    @grok.action('Update all beds')
240    def updateBeds(self, **data):
241        removed, added, modified, modified_beds = self.context.updateBeds()
242        message = '%d empty beds removed, %d beds added, %d occupied beds modified (%s)' % (
243            removed, added, modified, modified_beds)
244        self.flash(message)
245        write_log_message(self, message)
246        self.redirect(self.url(self.context, '@@manage')+'#tab-2')
247        return
248
249    @grok.action('Switch reservation of selected beds')
250    def switchReservations(self, **data):
251        form = self.request.form
252        if form.has_key('val_id'):
253            child_id = form['val_id']
254        else:
255            self.flash('No item selected.')
256            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
257            return
258        if not isinstance(child_id, list):
259            child_id = [child_id]
260        switched = []
261        for bed_id in child_id:
262            try:
263                message = self.context[bed_id].switchReservation()
264                switched.append('%s (%s)' % (bed_id,message))
265            except:
266                self.flash('Could not switch %s: %s: %s' % (
267                        id, sys.exc_info()[0], sys.exc_info()[1]))
268                self.redirect(self.url(self.context, '@@manage')+'#tab-2')
269                return
270        if len(switched):
271            message = ', '.join(switched)
272            self.flash('Successfully switched beds: %s' % message)
273            write_log_message(self, 'switched: %s' % message)
274            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
275        return
276
277    @grok.action('Release selected beds')
278    def releaseBeds(self, **data):
279        form = self.request.form
280        if form.has_key('val_id'):
281            child_id = form['val_id']
282        else:
283            self.flash('No item selected.')
284            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
285            return
286        if not isinstance(child_id, list):
287            child_id = [child_id]
288        released = []
289        for bed_id in child_id:
290            message = self.context[bed_id].releaseBed()
291            if message:
292                released.append('%s (%s)' % (bed_id,message))
293        if len(released):
294            message = ', '.join(released)
295            self.flash('Successfully released beds: %s' % message)
296            write_log_message(self, 'released: %s' % message)
297            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
298        else:
299            self.flash('No allocated bed selected.')
300            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
301        return
302
303class BedManageFormPage(WAeUPEditFormPage):
304    """ View to edit bed data
305    """
306    grok.context(IBedAllocateStudent)
307    grok.name('index')
308    grok.require('waeup.manageHostels')
309    form_fields = grok.AutoFields(IBedAllocateStudent).omit(
310        'bed_id').omit('bed_number').omit('bed_type')
311    label = 'Allocate student'
312    pnav = 5
313
314    @property
315    def title(self):
316        co = self.context.getBedCoordinates()
317        return '%s, Block %s, Room %s, Bed %s' % (
318            self.context.__parent__.hostel_name, co[1], co[2], co[3])
319
320    @grok.action('Save')
321    def save(self, **data):
322        msave(self, **data)
323        self.redirect(self.url(self.context.__parent__, '@@manage')+'#tab-2')
324        return
325
326    def update(self):
327        if self.context.owner != NOT_OCCUPIED:
328            # Don't use this form for exchanging students.
329            # Beds must be released first before they can be allocated to
330            # other students.
331            self.redirect(self.url(self.context.__parent__, '@@manage')+'#tab-2')
332        return
Note: See TracBrowser for help on using the repository browser.