class YourReservations(ResourceBaseForm, YourReservationsData): permission = "seantis.reservation.SubmitReservation" grok.name('your-reservations') grok.require(permission) context_buttons = ('finish', ) grok.context(Interface) css_class = 'seantis-reservation-form' template = grok.PageTemplateFile('templates/your_reservations.pt') @button.buttonAndHandler(_(u'Submit Reservations'), name="finish") def finish(self, data): def on_success(): self.request.response.redirect(self.context.absolute_url()) self.flash(_(u'Reservations Successfully Submitted')) utils.handle_action(self.confirm_reservations, success=on_success) @button.buttonAndHandler(_(u'Reserve More'), name="proceed") def proceed(self, data): # Don't do anything, reservations stay in the session. self.request.response.redirect(self.context.absolute_url()) def update(self): if 'remove' in self.request and utils.is_uuid(self.request['remove']): self.remove_reservation(self.request['remove']) self.request.response.redirect(self.context.absolute_url()) super(YourReservations, self).update()
def hint(self): if not (self.reservation or self.approved_reservations()): return _(u'No such reservation') return _( u'Do you really want to revoke the following reservations?' )
def isValidThreshold(Allocation): thresholds = [ Allocation.available_threshold, Allocation.partly_available_threshold, ] if thresholds[0] == thresholds[1]: raise Invalid( _(u'Thresholds must have differing values') ) if not (thresholds[0] > thresholds[1]): raise Invalid( _( u'The available threshold must have a larger value than ' u'the partly available threshold' ) ) for threshold in thresholds: if not (0 <= threshold and threshold <= 100): raise Invalid( _( u'Thresholds must have values between 0 and 100' ) )
def links(self, frame=None): # global links if not frame: baseurl = self.context.absolute_url() return [(_(u'Add timeframe'), baseurl + '/++add++seantis.reservation.timeframe')] # frame specific links links = [] action_tool = getToolByName(frame, 'portal_actions') actions = action_tool.listFilteredActionsFor(frame)['workflow'] for action in actions: if action['visible'] and action['available']: action['title'] = utils.translate_workflow( self.context, self.request, action['title'] ) links.append((action['title'], action['url'])) baseurl = frame.absolute_url() links.append((_(u'Edit'), baseurl + '/edit')) links.append((_(u'Delete'), baseurl + '/delete_confirmation')) return links
class ReservationApprovalForm(ReservationDecisionForm): permission = 'seantis.reservation.ApproveReservations' grok.name('approve-reservation') grok.require(permission) context_buttons = ('approve', ) label = _(u'Approve reservation') @property def hint(self): if not self.pending_reservations(): return _(u'No such reservation') return _(u'Do you really want to approve the following reservations?') @button.buttonAndHandler(_(u'Approve')) @extract_action_data def approve(self, data): def approve(): self.scheduler.approve_reservation(data['reservation']) self.flash(_(u'Reservation confirmed')) utils.handle_action(action=approve, success=self.redirect_to_context) @button.buttonAndHandler(_(u'Cancel')) def cancel(self, action): self.redirect_to_context()
class ReservationDenialForm(ReservationDecisionForm): permission = 'seantis.reservation.ApproveReservations' grok.name('deny-reservation') grok.require(permission) destructive_buttons = ('deny', ) label = _(u'Deny reservation') @property def hint(self): if not self.pending_reservations(): return _(u'No such reservation') return _(u'Do you really want to deny the following reservations?') @button.buttonAndHandler(_(u'Deny')) @extract_action_data def deny(self, data): def deny(): self.scheduler.deny_reservation(data['reservation']) self.flash(_(u'Reservation denied')) utils.handle_action(action=deny, success=self.redirect_to_context) @button.buttonAndHandler(_(u'Cancel')) def cancel(self, action): self.redirect_to_context()
def human_date(date): # timezones are currently naive and implicity the one used by # the users - we don't have international reservations yet now = utils.utcnow() this_morning = datetime( now.year, now.month, now.day ).replace(tzinfo=now.tzinfo) time = utils.localize_date(date, time_only=True) if date >= this_morning: return _(u'Today, at ${time}', mapping={'time': time}) days = (now.date() - date.date()).days if days <= 1: return _(u'Yesterday, at ${time}', mapping={ 'time': time }) else: return _(u'${days} days ago, at ${time}', mapping={ 'days': days, 'time': time })
class ISelectionReservation(Interface): """ A reservation of a selected number of allocations. """ # hidden ids = schema.TextLine( title=_(u'Ids'), required=False ) start_time = schema.Time( title=_(u'Start'), required=False ) end_time = schema.Time( title=_(u'End'), required=False ) quota = schema.Int( title=_(u'Number of Reservations'), required=False, default=1 ) email = Email( title=_(u'Email'), required=True )
class IExportSelection(Interface): """ Configuration for all exports. """ export = schema.Choice( title=_(u'Export'), source=export_choices, required=True, default=sources[0].id, ) format = schema.Choice( title=_(u'Format'), source=format_choices, required=True, default=extensions.keys()[0] ) year = schema.Choice( title=_(u"Year"), source=year_choices, required=True, default=u'all' ) month = schema.Choice( title=_(u"Month"), source=month_choices, required=True, default=u'all' )
def add_reservation(start, end, reservation): day = start.day used_days[day] = True end += timedelta(microseconds=1) start, end = start.strftime("%H:%M"), end.strftime("%H:%M") context = resources[utils.string_uuid(reservation.resource)] if reservation.status == u"approved": rightside_urls = [(_(u"Delete"), reservation_urls.revoke_all_url(reservation.token, context))] elif reservation.status == u"pending": rightside_urls = [ (_(u"Approve"), reservation_urls.approve_all_url(reservation.token, context)), (_(u"Deny"), reservation_urls.deny_all_url(reservation.token, context)), ] else: raise NotImplementedError reservation_lists = report[day][utils.string_uuid(reservation.resource)] reservation_lists[reservation.status].append( dict( start=start, end=end, email=reservation.email, data=reservation.data, timespans=json_timespans(start, end), rightside_urls=rightside_urls, token=reservation.token, quota=utils.get_reservation_quota_statement(reservation.quota), resource=context, ) )
class ISeantisReservationSettings(Interface): throttle_minutes = schema.Int( title=_(u"Reservation Throttling"), description=_( u'The number of minutes a user needs to wait between ' u'reservations, use 0 if no throttling should occur. ' u'Users with the \'Unthrottled Reservations\' permission ' u'are excempt from this rule (Reservation-Managers by default).')) send_email_to_managers = schema.Bool( title=_(u"Email Notifications for Managers"), description=_(u'Send emails about newly made reservations to ' u'the first reservation managers found in the path.')) send_approval_email_to_managers = schema.Bool( title=_(u"Approval Email Notifications for Managers"), description=_(u'Send emails about new pending reservations to ' u'the first reservation managers found in the path.')) send_email_to_reservees = schema.Bool( title=_(u"Email Notifications for Reservees"), description=_( u'Send emails about made, approved and denied reservations ' u'to the user that made the reservation.')) pre_reservation_script = schema.Text( title=_(u"Pre-Reservation Script"), description=_( u'Run custom validation code for reservations. This is for ' u'advanced users only and may disable the reservations process. ' u'For documentation study the source code at Github.'), required=False, constraint=valid_expression)
class GroupReservationForm(ReservationForm, AllocationGroupView, SessionFormdataMixin, YourReservationsData): permission = 'seantis.reservation.SubmitReservation' grok.name('reserve-group') grok.require(permission) context_buttons = ('reserve', ) standalone_buttons = ('cancel', ) fields = field.Fields(IGroupReservation) label = _(u'Recurrance reservation') template = ViewPageTemplateFile('templates/reserve_group.pt') ignore_requirements = True autoGroups = True enable_form_tabbing = True default_fieldset_label = _(u'General Information') @property def hidden_fields(self): hidden = ['group'] try: allocation = self.group and self.scheduler.allocations_by_group( self.group).first() if allocation.quota_limit == 1: hidden.append('quota') except DirtyReadOnlySession: pass return hidden def defaults(self, **kwargs): return self.your_reservation_defaults(dict(group=self.group, quota=1)) @button.buttonAndHandler(_(u'Reserve')) @extract_action_data def reserve(self, data): approve_manually = self.scheduler.allocations_by_group(data['group']) \ .first().approve_manually def reserve(): self.run_reserve(data=data, approve_manually=approve_manually, group=data['group'], quota=data['quota']) utils.handle_action(action=reserve, success=self.redirect_to_your_reservations) @button.buttonAndHandler(_(u'Cancel')) def cancel(self, action): self.redirect_to_context()
def validate(self, data): try: start, end = utils.get_date_range(data["day"], data["start_time"], data["end_time"]) if not self.allocation(data["id"]).contains(start, end): utils.form_error(_(u"Reservation out of bounds")) return start, end except (NoResultFound, TypeError): utils.form_error(_(u"Invalid reservation request"))
class IGroupReservation(Interface): """ A reservation of an allocation group. """ group = schema.Text(title=_(u'Recurrence'), required=False) quota = schema.Int(title=_(u'Reservation Quota'), required=False, default=1) email = EmailField(title=_(u'Email'), required=True)
def validate(self, data): try: start, end = utils.get_date_range(data['day'], data['start_time'], data['end_time']) if not self.allocation(data['id']).contains(start, end): utils.form_error(_(u'Reservation out of bounds')) return start, end except (NoResultFound, TypeError): utils.form_error(_(u'Invalid reservation request'))
class ExportSelection(BaseForm, form.ResourceParameterView): permission = 'seantis.reservation.ViewReservations' grok.require(permission) grok.context(Interface) grok.name('reservation-exports') label = _(u'Reservation Export') fields = field.Fields(IExportSelection) ignoreContext = True enable_unload_protection = False @property def action(self): return u'{base}/reservation-exports?uuid={uuids}'.format( base=self.context.absolute_url(), uuids='&uuid='.join(self.uuids) ) def build_export_url(self, data): if not self.uuids: utils.form_error(_(u"Missing 'uuid' parameter")) url_template = ( u'{base}/reservation-export.{format}?source={export}&uuid={uuids}' u'&year={year}&month={month}' ) data['base'] = self.context.absolute_url() data['uuids'] = '&uuid='.join(self.uuids) return url_template.format(**data) def updateActions(self): super(ExportSelection, self).updateActions() self.actions['export'].addClass('allowMultiSubmit') self.actions['export'].addClass('context') def update(self): self.fields['export'].field = copy(self.fields['export'].field) self.fields['export'].field.description = get_sources_description( self.request ) super(ExportSelection, self).update() @button.buttonAndHandler(_(u'Export')) @extract_action_data def export(self, data): self.request.response.redirect(self.build_export_url(data)) @button.buttonAndHandler(_(u'Cancel')) @extract_action_data def cancel(self, data): self.request.response.redirect(self.context.absolute_url())
class IReservation(Interface): """ A reservation of an allocation (may be pending or approved). """ id = schema.Int(title=_(u'Id'), default=-1, required=False) day = schema.Date(title=_(u'Day'), required=False) start_time = schema.Time(title=_(u'Start'), required=False) end_time = schema.Time(title=_(u'End'), required=False) quota = schema.Int(title=_(u'Reservation Quota'), required=False, default=1) email = EmailField(title=_(u'Email'), required=True) description = schema.TextLine( title=_(u'Description'), description=_('Visible on the calendar'), required=False, ) recurrence = schema.Text( title=_(u'Recurrence'), required=False, )
class ISearchAndReserveForm(model.Schema): """ Search form for search & reserve view. """ form.mode(timeframes='hidden') timeframes = schema.Text(title=_(u'Timeframes'), default=u'', required=False) recurrence_start = schema.Date(title=_(u"Start date"), required=True) recurrence_end = schema.Date(title=_(u"End date"), required=True) whole_day = schema.Bool(title=_(u"Whole day"), required=False, default=False) start_time = schema.Time(title=_(u"Start time"), required=False) end_time = schema.Time(title=_(u"End time"), required=False) form.widget(days=CheckBoxFieldWidget) days = schema.List(title=_(u"Days"), value_type=schema.Choice(vocabulary=weekdays), required=False) minspots = schema.Int(title=_(u"Spots"), required=False) available_only = schema.Bool(title=_(u"Available only"), required=False, default=True)
class AllocationRemoveForm(AllocationForm, AllocationGroupView): permission = 'cmf.ModifyPortalContent' grok.name('remove-allocation') grok.require(permission) destructive_buttons = ('delete', ) fields = field.Fields(IAllocation).select('id', 'group') + \ field.Fields(schema.Int(__name__='recurrence_id', required=False)) template = ViewPageTemplateFile('templates/remove_allocation.pt') label = _(u'Remove allocations') hidden_fields = ['id', 'group', 'recurrence_id'] ignore_requirements = True @button.buttonAndHandler(_(u'Delete')) @extract_action_data def delete(self, data): nof_params = len( list( itertools.ifilter(None, ( data['id'], data['group'], data['recurrence_id'], )))) assert nof_params == 1, "Exactly one of id, group or recurrence_id" scheduler = self.scheduler def delete(): scheduler.remove_allocation(id=data['id'], group=data['group'], recurrence_id=data['recurrence_id']) self.flash(_(u'Allocation removed')) utils.handle_action(action=delete, success=self.redirect_to_context) @button.buttonAndHandler(_(u'Cancel')) def cancel(self, action): self.redirect_to_context() def defaults(self): id, group, recurrence_id = self.id, self.group, self.recurrence_id result = dict(id=None, recurrence_id=None, group=None) if recurrence_id: result['recurrence_id'] = recurrence_id elif group: result['group'] = group elif id: result['id'] = id return result
def validate(self, data): try: start, end = utils.get_date_range( data['day'], data['start_time'], data['end_time'] ) if not self.allocation(data['id']).contains(start, end): utils.form_error(_(u'Reservation out of bounds')) return start, end except (NoResultFound, TypeError): utils.form_error(_(u'Invalid reservation request'))
class AllocationRemoveForm(AllocationForm, AllocationGroupView): permission = 'cmf.ModifyPortalContent' grok.name('remove-allocation') grok.require(permission) destructive_buttons = ('delete', ) standalone_buttons = ('cancel', ) fields = field.Fields(IAllocation).select('id', 'group') template = ViewPageTemplateFile('templates/remove_allocation.pt') label = _(u'Delete allocations') hidden_fields = ['id', 'group'] ignore_requirements = True @property def allocation_groups(self): if not self.group: return [] return self.group.split(',') @button.buttonAndHandler(_(u'Delete')) @extract_action_data def remove(self, data): assert bool(data['id']) != bool(data['group']), \ "Either id or group, not both" scheduler = self.scheduler groups = self.allocation_groups def remove(): scheduler.remove_allocation(id=data['id'], groups=groups) if data['id']: self.flash(_(u'Allocation deleted')) else: self.flash(_(u'Allocations deleted')) utils.handle_action(action=remove, success=self.redirect_to_context) @button.buttonAndHandler(_(u'Cancel')) def cancel(self, action): self.redirect_to_context() def defaults(self): if self.group: return dict(group=self.group, id=None) else: return dict(id=self.id, group=None)
def isValidFirstLastHour(Resource): in_valid_range = lambda h: 0 <= h and h <= 24 first_hour, last_hour = Resource.first_hour, Resource.last_hour if not in_valid_range(first_hour): raise Invalid(_(u'Invalid first hour')) if not in_valid_range(last_hour): raise Invalid(_(u'Invalid last hour')) if last_hour <= first_hour: raise Invalid(_(u'First hour must be smaller than last hour'))
class ITimeframe(form.Schema): """ A timespan which is either visible or hidden. """ title = schema.TextLine(title=_(u'Name')) start = schema.Date(title=_(u'Start')) end = schema.Date(title=_(u'End')) @invariant def isValidDateRange(Timeframe): if Timeframe.start > Timeframe.end: raise Invalid(_(u'End date before start date'))
def uncommitted_reservations(self): count = self.uncommitted_reservations_count if not count: return u'' if count == 1: return _( u'There is one reservation being entered for this resource.') return _( u'There are ${nb} reservations being entered for this resource.', mapping={'nb': self.uncommitted_reservations_count})
def uncommitted_reservations(self): count = self.uncommitted_reservations_count if not count: return u"" if count == 1: return _(u"There is one reservation being entered for this resource.") return _( u"There are ${nb} reservations being entered for this resource.", mapping={"nb": self.uncommitted_reservations_count}, )
def isValidFirstLastHour(Resource): in_valid_range = lambda h: 0 <= h and h <= 24 first_hour, last_hour = Resource.first_hour, Resource.last_hour if not in_valid_range(first_hour): raise Invalid(_(u'Invalid first hour')) if not in_valid_range(last_hour): raise Invalid(_(u'Invalid last hour')) if last_hour <= first_hour: raise Invalid( _(u'First hour must be smaller than last hour') )
class ReservationRevocationForm(ReservationTargetForm, ReservationListView, ReservationUrls): permission = 'seantis.reservation.ApproveReservations' grok.name('revoke-reservation') grok.require(permission) grok.layer(ISeantisReservationSpecific) destructive_buttons = ('revoke', ) standalone_buttons = ('cancel', ) fields = field.Fields(IRevokeReservation) template = ViewPageTemplateFile('templates/revoke_reservation.pt') label = _(u'Revoke reservation') show_links = False @property def hint(self): if not self.has_reservations: return _(u'No such reservation') return _(u'Do you really want to revoke the following reservations?') @property def has_reservations(self): return self.approved_reservations() and True or False @button.buttonAndHandler(_(u'Revoke')) @extract_action_data def revoke(self, data): # might happen if the user submits twice if not self.has_reservations: return def revoke(): self.scheduler.revoke_reservation(token=data['token'], reason=data['reason'], id=data.get('id'), send_email=data['send_email']) self.flash(_(u'Reservation revoked')) utils.handle_action(action=revoke, success=self.redirect_to_context) @button.buttonAndHandler(_(u'Cancel')) def cancel(self, action): self.redirect_to_context()
def run_reserve( self, data, approve_manually, dates=None, group=None, quota=1, rrule=None, description=None ): assert dates or group assert not (dates and group) email = self.email(data) session_id = self.session_id() additional_data = self.additional_data(data, add_manager_defaults=True) # only store forms defined in the formsets list additional_data = dict( ( form, additional_data[form] ) for form in self.context.formsets if form in additional_data ) if dates: for start, end in utils.pairs(dates): run_pre_reserve_script( self.context, start, end, additional_data ) else: run_pre_reserve_script(self.context, None, None, additional_data) def run(): if dates: return self.scheduler.reserve( email, dates, data=additional_data, session_id=session_id, quota=quota, rrule=rrule, description=description ) else: return self.scheduler.reserve( email, group=group, data=additional_data, session_id=session_id, quota=quota, description=description ) token = throttled(run, 'reserve')() if approve_manually: self.flash(_(u'Added to waitinglist')) else: self.scheduler.approve_reservation(token) self.flash(_(u'Reservation successful'))
class IReservationTargetForm(Interface): """ Describes a form with a hidden reservation-token and an optional reservation-id field. """ token = schema.Text( title=_(u'Token'), required=False ) id = schema.Text( title=_(u'Id'), required=False, default=None )
def uncommitted_reservations(self): count = self.uncommitted_reservations_count if not count: return u'' if count == 1: return _( u'There is one reservation being entered for this resource.' ) return _( u'There are ${nb} reservations being entered for this resource.', mapping={'nb': self.uncommitted_reservations_count} )
def validate_templates(email): # go through the *_content attributes content_attributes = ( (k, v) for k, v in IEmailTemplate._v_attrs.items() if k.endswith('_content') ) # gather all the %(xxx)s tags form_tags = re.compile(r'%\(([a-z_]+)\)') # try to fill those with dummy variables for key, attr in content_attributes: tags = form_tags.findall(attr.getDoc()) test_data = zip(tags, (str(i) for i in range(0, len(tags)))) try: getattr(email, key) % dict(test_data) # if anything fails, it would also in the email sending process # which is the last thing we want to fail except KeyError as e: raise Invalid( _( u"Invalid template variable '${name}' in '${field}'", mapping={ 'name': e.message, 'field': attr.title } ) )
def validate_email(value): try: if value: checkEmailAddress(value) except EmailAddressInvalid: raise Invalid(_(u'Invalid email address')) return True
def links(self, template=None): # global links if not template: baseurl = self.context.absolute_url() return [(_(u'Add email template'), baseurl + '/++add++seantis.reservation.emailtemplate')] # template specific links links = [] baseurl = template.absolute_url() links.append((_(u'Edit'), baseurl + '/edit')) links.append((_(u'Delete'), baseurl + '/delete_confirmation')) return links
def isValidOption(Allocation): if Allocation.recurrence: if Allocation.partly_available and not Allocation.separately: raise Invalid(_( u'Partly available allocations can only be reserved ' u'separately' ))
def save(): if self.reservation.email != data['email']: self.scheduler.change_email(self.token, data['email']) self.scheduler.change_reservation_data(self.token, self.additional_data) self.flash(_(u'Formdata updated'))
def validate_template(context, request, data): if context.portal_type == 'seantis.reservation.emailtemplate': folder = context.aq_inner.aq_parent else: folder = context templates = utils.portal_type_in_context( folder, portal_type='seantis.reservation.emailtemplate') duplicate = False for template in templates: if template.id == context.id: continue if template.getObject().title == context.title: duplicate = True break if duplicate: msg = utils.translate( context, request, _(u"There's already an Email template in the same folder for the " u"same language")) utils.form_error(msg)
def isValidRange(Allocation): start, end = utils.get_date_range(Allocation.day, Allocation.start_time, Allocation.end_time) if not Allocation.whole_day and abs((end - start).seconds // 60) < 5: raise Invalid(_(u'The allocation must be at least 5 minutes long'))
class IRevokeReservation(IReservationIdForm): """ For the reservation revocation form. """ send_email = schema.Bool( title=_(u"Send Email"), description=_( u"Send an email to the reservee informing him of the revocation"), default=True) reason = schema.Text( title=_(u'Reason'), description=_( u"Optional reason for the revocation. Sent to the reservee. " u"e.g. 'Your reservation has to be cancelled because the lecturer " u"is ill'."), required=False)
def isValidOption(Allocation): if Allocation.recurring: if Allocation.partly_available and not Allocation.separately: raise Invalid(_( u'Partly available allocations can only be reserved ' u'separately' ))
def validate_template(context, request, data): if context.portal_type == 'seantis.reservation.emailtemplate': folder = context.aq_inner.aq_parent else: folder = context templates = utils.portal_type_in_context( folder, portal_type='seantis.reservation.emailtemplate' ) duplicate = False for template in templates: if template.id == context.id: continue if template.getObject().title == context.title: duplicate = True break if duplicate: msg = utils.translate( context, request, _(u"There's already an Email template in the same folder for the " u"same language") ) utils.form_error(msg)
def change(): start = datetime.combine(self.reservation.start.date(), data["start_time"]) end = datetime.combine(self.reservation.end.date(), data["end_time"]) changed = self.scheduler.change_reservation_time( token=data["token"], id=data["id"], new_start=start, new_end=end, send_email=data["send_email"], reason=data["reason"], ) if changed: self.flash(_(u"Reservation changed.")) else: self.flash(_(u"There was nothing to change."))
def as_human_readable_string(value): if isinstance(value, six.string_types): return value if isinstance(value, datetime): # don't use strftime here because users may end up entering year '3' # strftime does not suppport years before 1900, which is just lame # in this case we just use the German locale for now.. if value.year < 1900: return '%02d.%02d.%04d %02d:%02d' % ( value.day, value.month, value.year, value.hour, value.minute ) else: return localize_date(value, long_format=True) if isinstance(value, date): if value.year < 1900: return '%02d.%02d.%04d' % ( value.day, value.month, value.year ) else: dt = datetime(value.year, value.month, value.day) return localize_date(dt, long_format=False) if isinstance(value, RichTextValue): return value.output if value is True: return _(u'Yes') if value is False: return _(u'No') if value is None: return u'' if isinstance(value, (list, tuple)): return ', '.join(as_human_readable_string(v) for v in value) return value
def isValidRange(Allocation): start, end = utils.get_date_range( Allocation.day, Allocation.start_time, Allocation.end_time ) if not Allocation.whole_day and abs((end - start).seconds // 60) < 5: raise Invalid(_(u'The allocation must be at least 5 minutes long'))
def edit(): scheduler.move_allocation(*args) # ensure that the allocation is not accessed again by the defaults, # this prevents a DirtyReadOnlySession error self.allocation_stale = True self.flash(_(u'Allocation saved'))
def links(self, template=None): # global links if not template: baseurl = self.context.absolute_url() return [( _(u'Add email template'), baseurl + '/++add++seantis.reservation.emailtemplate' )] # template specific links links = [] baseurl = template.absolute_url() links.append((_(u'Edit'), baseurl + '/edit')) links.append((_(u'Delete'), baseurl + '/delete_confirmation')) return links
def update(self, *args, **kwargs): super(SeantisReservationSettingsPanelForm, self).update( *args, **kwargs ) if self.request.get('form.actions.remove_orphans'): count = self.remove_orphan_records() utils.flash( self.context, _(u'${count} Orphan Records Removed', mapping={'count': count}) )
def save(): self.scheduler.update_reservation( self.reservation, start, end, data.get('email'), data.get('description'), self.additional_data, ) self.flash(_(u'Formdata updated'))
def validate_timeframe(context, request, data): overlap = overlapping_timeframe(context, data['start'], data['end']) if overlap: msg = utils.translate( context, request, _( u"Timeframe overlaps with '${overlap}' in the current folder", mapping={'overlap': overlap.title} )) utils.form_error(msg)
def title(self): return _( u'Monthly Report for ${month} ${year}', mapping={ 'month': utils.month_name( self.context, self.request, self.month ), 'year': self.year } )
def additionalSchemata(self): return [ ( 'default', _(u'Settings'), field.Fields(IResourceAllocationDefaults).select( 'quota', 'reservation_quota_limit', 'approve_manually' ) ) ]
def daterange_label(self): since, until = self.daterange if until.date() == utils.utcnow().date(): return ' - '.join(( utils.localize_date(since, long_format=False), self.translate(_(u'Today')) )) return ' - '.join(( utils.localize_date(since, long_format=False), utils.localize_date(until, long_format=False) ))
def allocate(): self.scheduler.allocate( dates, raster=data['raster'], quota=data['quota'], partly_available=data['partly_available'], grouped=data['recurring'] and not data['separately'], approve_manually=data['approve_manually'], quota_limit=data['reservation_quota_limit'], whole_day=data['whole_day'] ) self.flash(_(u'Allocation added'))
def events(self): resource = self.context scheduler = resource.scheduler() translate = utils.translator(self.context, self.request) is_exposed = exposure.for_allocations([resource]) # get an event for each exposed allocation events = [] for alloc in scheduler.allocations_in_range(*self.range): if not is_exposed(alloc): continue start = alloc.display_start(settings.timezone()) end = alloc.display_end(settings.timezone()) # get the urls urls = self.urls(alloc) # calculate the availability for title and class availability, title, klass = utils.event_availability( resource, self.request, scheduler, alloc ) if alloc.partly_available: partitions = alloc.availability_partitions() else: # if the allocation is not partly available there can only # be one partition meant to be shown as empty unless the # availability is zero partitions = [(100, availability == 0.0)] event_header = alloc.whole_day and translate(_(u'Whole Day')) events.append(dict( title=title, start=start.isoformat(), end=end.isoformat(), className=klass, url=urls.default, menu=urls.menu, menuorder=urls.order, allocation=alloc.id, partitions=partitions, group=alloc.group, allDay=False, moveurl=urls.move, header=event_header )) return events
def run_reserve( self, data, approve_manually, start=None, end=None, group=None, quota=1 ): assert (start and end) or group assert not (start and end and group) email = self.email(data) additional_data = self.additional_data(data, add_manager_defaults=True) session_id = self.session_id() # only store forms defined in the formsets list additional_data = dict( ( form, additional_data[form] ) for form in self.context.formsets if form in additional_data ) run_pre_reserve_script(self.context, start, end, additional_data) def run(): if start and end: return self.scheduler.reserve( email, (start, end), data=additional_data, session_id=session_id, quota=quota ) else: return self.scheduler.reserve( email, group=group, data=additional_data, session_id=session_id, quota=quota ) token = throttled(run, 'reserve')() if approve_manually: self.flash(_(u'Added to waitinglist')) else: self.scheduler.approve_reservation(token) self.flash(_(u'Reservation successful'))
def build_export_url(self, data): if not self.uuids: utils.form_error(_(u"Missing 'uuid' parameter")) url_template = ( u'{base}/reservation-export.{format}?source={export}&uuid={uuids}' u'&year={year}&month={month}' ) data['base'] = self.context.absolute_url() data['uuids'] = '&uuid='.join(self.uuids) return url_template.format(**data)