def defaults(self): if not self.id or self.allocation_stale: return dict() allocation = self.allocation start, end = self.start, self.end if not all((start, end)): start = allocation.display_start( timezone=settings.timezone() ) end = allocation.display_end( timezone=settings.timezone() ) return { 'id': self.id, 'start_time': start.time(), 'end_time': end.time(), 'day': start.date(), 'quota': allocation.quota, 'approve_manually': allocation.approve_manually, 'whole_day': allocation.whole_day, 'reservation_quota_limit': allocation.quota_limit }
def urls(self, allocation): """Returns the options for the js contextmenu for the given allocation as well as other links associated with the event. """ items = utils.EventUrls(self.context, self.request, exposure) start = utils.utctimestamp( allocation.display_start(settings.timezone())) end = utils.utctimestamp(allocation.display_end(settings.timezone())) items.move_url('edit-allocation', dict(id=allocation.id)) # Reservation res_add = lambda n, v, p, t: \ items.menu_add(_(u'Reservations'), n, v, p, t) if allocation.is_separate: res_add(_(u'Reserve'), 'reserve', dict(id=allocation.id, start=start, end=end), 'overlay') items.default_url('reserve', dict(id=allocation.id, start=start, end=end)) else: res_add(_(u'Reserve'), 'reserve-group', dict(group=allocation.group), 'overlay') items.default_url('reserve', dict(group=allocation.group)) res_add(_(u'Manage'), 'reservations', dict(group=allocation.group), 'inpage') # menu entries for single items entry_add = lambda n, v, p, t: \ items.menu_add(_('Entry'), n, v, p, t) entry_add(_(u'Edit'), 'edit-allocation', dict(id=allocation.id), 'overlay') entry_add(_(u'Remove'), 'remove-allocation', dict(id=allocation.id), 'overlay') if allocation.in_group: # menu entries for group items group_add = lambda n, v, p, t: \ items.menu_add(_('Recurrences'), n, v, p, t) group_add(_(u'List'), 'group', dict(name=allocation.group), 'overlay') group_add(_(u'Remove'), 'remove-allocation', dict(group=allocation.group), 'overlay') # view selections if 'agendaDay' in self.context.available_views: items.menu_add( _(u'Reservations'), _(u'Daily View'), 'view', dict(selected_view='agendaDay', specific_date=allocation.start.strftime('%Y-%m-%d')), 'window') return items
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 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 inject_missing_data(self, data, allocation=None): """ Adds the date and start-/end-time to the data if they are missing, which happens because those fields may be disabled and therefore are not transferred when submitting the form. The fields are injected into the passed dictionary, which may be the reservations defaults or the submitted form data. """ extracted, errors = self.extractData(setErrors=False) # the extracted fields may contain field values which need to be # injected so the defaults are filled - otherwise no value is updated # on the disabled field for f in ("day", "start_time", "end_time"): if extracted.get(f) is not None: data[f] = extracted[f] # if the extracted data was not of any help the id of the allocation # is our last resort. try: allocation = allocation or self.allocation(data["id"]) except DirtyReadOnlySession: return tz = settings.timezone() if data.get("day") is None: data["day"] = allocation.display_start(tz).date() if data.get("start_time") is None: data["start_time"] = allocation.display_start(tz).time() if data.get("end_time") is None: data["end_time"] = allocation.display_end(tz).time()
def inject_missing_data(self, data, allocation=None): """ Adds the date and start-/end-time to the data if they are missing, which happens because those fields may be disabled and therefore are not transferred when submitting the form. The fields are injected into the passed dictionary, which may be the reservations defaults or the submitted form data. """ extracted, errors = self.extractData(setErrors=False) # the extracted fields may contain field values which need to be # injected so the defaults are filled - otherwise no value is updated # on the disabled field for f in ('day', 'start_time', 'end_time'): if extracted.get(f) is not None: data[f] = extracted[f] # if the extracted data was not of any help the id of the allocation # is our last resort. try: allocation = allocation or self.allocation(data['id']) except DirtyReadOnlySession: return tz = settings.timezone() if data.get('day') is None: data['day'] = allocation.display_start(tz).date() if data.get('start_time') is None: data['start_time'] = allocation.display_start(tz).time() if data.get('end_time') is None: data['end_time'] = allocation.display_end(tz).time()
def scheduler(self, language=None): uuid = utils.string_uuid(self.uuid()) libres_util = getUtility(ILibresUtility) libres_util.context.set_service( 'exposure', lambda ctx: LibresExposure(exposure.for_allocations([uuid]))) return libres_util.scheduler(uuid, settings.timezone().zone)
def scheduler(self, language=None): uuid = utils.string_uuid(self.uuid()) libres_util = getUtility(ILibresUtility) libres_util.context.set_service( 'exposure', lambda ctx: LibresExposure(exposure.for_allocations([uuid])) ) return libres_util.scheduler(uuid, settings.timezone().zone)
def defaults(self): parent = super(ReservationEditTimeForm, self).defaults() if self.reservation: tz = settings.timezone() parent.update( { "start_time": self.reservation.display_start(tz).time(), "end_time": self.reservation.display_end(tz).time(), } ) return parent
def defaults(self): parent = super(ReservationEditTimeForm, self).defaults() if self.reservation: tz = settings.timezone() parent.update({ 'start_time': self.reservation.display_start(tz).time(), 'end_time': self.reservation.display_end(tz).time() }) return parent
def monthly_report(year, month, resources, reservations='*'): titles = dict() for uuid in resources.keys(): titles[uuid] = utils.get_resource_title(resources[uuid]) # timezone of the report timezone = settings.timezone() # this order is used for every day in the month ordered_uuids = [i[0] for i in sorted(titles.items(), key=lambda i: i[1])] # build the hierarchical structure of the report data report = utils.OrderedDict() last_day = 28 for d in sorted((d for d in calendar.itermonthdates(year, month))): if not d.month == month: continue day = d.day last_day = max(last_day, day) report[day] = utils.OrderedDict() for uuid in ordered_uuids: report[day][uuid] = dict() report[day][uuid][u'title'] = titles[uuid] report[day][uuid][u'approved'] = list() report[day][uuid][u'pending'] = list() report[day][uuid][u'url'] = resources[uuid].absolute_url() report[day][uuid][u'lists'] = { u'approved': _(u'Approved'), u'pending': _(u'Pending'), } # gather the reservations with as much bulk loading as possible period_start = datetime(year, month, 1, tzinfo=timezone) period_end = datetime(year, month, last_day, tzinfo=timezone) period_end += timedelta(days=1, microseconds=-1) # get a list of relevant allocations in the given period query = Session().query(Allocation) query = query.filter(period_start <= Allocation._start) query = query.filter(Allocation._start <= period_end) query = query.filter(Allocation.resource == Allocation.mirror_of) query = query.filter(Allocation.resource.in_(resources.keys())) allocations = query.all() # quit if there are no allocations at this point if not allocations: return {} # store by group as it will be needed multiple times over later groups = dict() for allocation in allocations: groups.setdefault(allocation.group, list()).append(allocation) # using the groups get the relevant reservations query = Session().query(Reservation) query = query.filter(Reservation.target.in_(groups.keys())) if reservations != '*': query = query.filter(Reservation.token.in_(reservations)) query = query.order_by(Reservation.status) reservations = query.all() @utils.memoize def json_timespans(start, end): return json.dumps([dict(start=start, end=end)]) used_days = dict([(i, False) for i in range(1, 32)]) timezone = settings.timezone() def add_reservation(start, end, reservation): day = start.day used_days[day] = True end += timedelta(microseconds=1) start = sedate.to_timezone(start, timezone=timezone) end = sedate.to_timezone(end, timezone=timezone) start = utils.localize_date(start, time_only=True) end = utils.localize_date(end, time_only=True) context = resources[utils.string_uuid(reservation.resource)] 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), id=reservation.id, token=reservation.token, quota=utils.get_reservation_quota_statement(reservation.quota), resource=context, ) ) for reservation in reservations: if reservation.target_type == u'allocation': add_reservation(reservation.start, reservation.end, reservation) else: for allocation in groups[reservation.target]: add_reservation(allocation.start, allocation.end, reservation) # remove unused days for day in report: if not used_days[day]: del report[day] return report
def build_allocations_table( self, allocations, start_time=None, end_time=None ): """ Prepares the given allocations for the found-allocations table. Only works on IResourceBase contexts. """ if not allocations: return [] scheduler = self.context.scheduler() whole_day_text = self.translate(_(u'Whole day')) def get_time_text(start, end): if utils.whole_day(start, end): return whole_day_text else: return ' - '.join(( utils.localize_date(start, time_only=True), utils.localize_date(end, time_only=True), )) prev_date = None result = [] tz = settings.timezone() for allocation in allocations: if start_time or end_time: s = start_time or allocation.display_start(tz).time() e = end_time or allocation.display_end(tz).time() s, e = allocation.limit_timespan(s, e) time_text = get_time_text(s, e) else: time_text = get_time_text( allocation.display_start(tz), allocation.display_end(tz) ) s, e = None, None availability, text, allocation_class = utils.event_availability( self.context, self.request, scheduler, allocation, s, e ) date = ', '.join(( self.translate( self.short_days[allocation.display_start(tz).weekday()] ), utils.localize_date( allocation.display_start(tz), long_format=False ) )) result.append({ 'id': allocation.id, 'group': allocation.group, 'date': date, 'time': time_text, 'class': utils.event_class(availability), 'is_first_of_date': prev_date != date, 'text': ', '.join(text.split('\n')), 'is_extra_result': getattr( allocation, 'is_extra_result', False ) }) prev_date = date return result
def monthly_report(year, month, resources, reservations='*'): titles = dict() for uuid in resources.keys(): titles[uuid] = utils.get_resource_title(resources[uuid]) # timezone of the report timezone = settings.timezone() # this order is used for every day in the month ordered_uuids = [i[0] for i in sorted(titles.items(), key=lambda i: i[1])] # build the hierarchical structure of the report data report = utils.OrderedDict() last_day = 28 for d in sorted((d for d in calendar.itermonthdates(year, month))): if not d.month == month: continue day = d.day last_day = max(last_day, day) report[day] = utils.OrderedDict() for uuid in ordered_uuids: report[day][uuid] = dict() report[day][uuid][u'title'] = titles[uuid] report[day][uuid][u'approved'] = list() report[day][uuid][u'pending'] = list() report[day][uuid][u'url'] = resources[uuid].absolute_url() report[day][uuid][u'lists'] = { u'approved': _(u'Approved'), u'pending': _(u'Pending'), } # gather the reservations with as much bulk loading as possible period_start = datetime(year, month, 1, tzinfo=timezone) period_end = datetime(year, month, last_day, tzinfo=timezone) period_end += timedelta(days=1, microseconds=-1) # get a list of relevant allocations in the given period query = Session().query(Allocation) query = query.filter(period_start <= Allocation._start) query = query.filter(Allocation._start <= period_end) query = query.filter(Allocation.resource == Allocation.mirror_of) query = query.filter(Allocation.resource.in_(resources.keys())) allocations = query.all() # quit if there are no allocations at this point if not allocations: return {} # store by group as it will be needed multiple times over later groups = dict() for allocation in allocations: groups.setdefault(allocation.group, list()).append(allocation) # using the groups get the relevant reservations query = Session().query(Reservation) query = query.filter(Reservation.target.in_(groups.keys())) if reservations != '*': query = query.filter(Reservation.token.in_(reservations)) query = query.order_by(Reservation.status) reservations = query.all() @utils.memoize def json_timespans(start, end): return json.dumps([dict(start=start, end=end)]) used_days = dict([(i, False) for i in range(1, 32)]) timezone = settings.timezone() def add_reservation(start, end, reservation): day = start.day used_days[day] = True end += timedelta(microseconds=1) start = modules.calendar.to_timezone(start, timezone=timezone) end = modules.calendar.to_timezone(end, timezone=timezone) start = utils.localize_date(start, time_only=True) end = utils.localize_date(end, time_only=True) context = resources[utils.string_uuid(reservation.resource)] 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), id=reservation.id, token=reservation.token, quota=utils.get_reservation_quota_statement(reservation.quota), resource=context, ) ) for reservation in reservations: if reservation.target_type == u'allocation': add_reservation(reservation.start, reservation.end, reservation) else: for allocation in groups[reservation.target]: add_reservation(allocation.start, allocation.end, reservation) # remove unused days for day in report: if not used_days[day]: del report[day] return report
def urls(self, allocation): """Returns the options for the js contextmenu for the given allocation as well as other links associated with the event. """ items = utils.EventUrls(self.context, self.request, exposure) start = utils.utctimestamp( allocation.display_start(settings.timezone())) end = utils.utctimestamp( allocation.display_end(settings.timezone())) items.move_url('edit-allocation', dict(id=allocation.id)) # Reservation res_add = lambda n, v, p, t: \ items.menu_add(_(u'Reservations'), n, v, p, t) if allocation.is_separate: res_add( _(u'Reserve'), 'reserve', dict(id=allocation.id, start=start, end=end), 'overlay' ) items.default_url( 'reserve', dict(id=allocation.id, start=start, end=end) ) else: res_add( _(u'Reserve'), 'reserve-group', dict(group=allocation.group), 'overlay' ) items.default_url( 'reserve', dict(group=allocation.group) ) res_add( _(u'Manage'), 'reservations', dict(group=allocation.group), 'inpage' ) # menu entries for single items entry_add = lambda n, v, p, t: \ items.menu_add(_('Entry'), n, v, p, t) entry_add( _(u'Edit'), 'edit-allocation', dict(id=allocation.id), 'overlay' ) entry_add( _(u'Remove'), 'remove-allocation', dict(id=allocation.id), 'overlay' ) if allocation.in_group: # menu entries for group items group_add = lambda n, v, p, t: \ items.menu_add(_('Recurrences'), n, v, p, t) group_add( _(u'List'), 'group', dict(name=allocation.group), 'overlay' ) group_add( _(u'Remove'), 'remove-allocation', dict(group=allocation.group), 'overlay' ) # view selections if 'agendaDay' in self.context.available_views: items.menu_add( _(u'Reservations'), _(u'Daily View'), 'view', dict( selected_view='agendaDay', specific_date=allocation.start.strftime('%Y-%m-%d') ), 'window' ) return items
def build_allocations_table(self, allocations, start_time=None, end_time=None): """ Prepares the given allocations for the found-allocations table. Only works on IResourceBase contexts. """ if not allocations: return [] scheduler = self.context.scheduler() whole_day_text = self.translate(_(u'Whole day')) def get_time_text(start, end): if utils.whole_day(start, end): return whole_day_text else: return ' - '.join(( utils.localize_date(start, time_only=True), utils.localize_date(end, time_only=True), )) prev_date = None result = [] tz = settings.timezone() for allocation in allocations: if start_time or end_time: s = start_time or allocation.display_start(tz).time() e = end_time or allocation.display_end(tz).time() s, e = allocation.limit_timespan(s, e) time_text = get_time_text(s, e) else: time_text = get_time_text(allocation.display_start(tz), allocation.display_end(tz)) s, e = None, None availability, text, allocation_class = utils.event_availability( self.context, self.request, scheduler, allocation, s, e) date = ', '.join((self.translate( self.short_days[allocation.display_start(tz).weekday()]), utils.localize_date(allocation.display_start(tz), long_format=False))) result.append({ 'id': allocation.id, 'group': allocation.group, 'date': date, 'time': time_text, 'class': utils.event_class(availability), 'is_first_of_date': prev_date != date, 'text': ', '.join(text.split('\n')), 'is_extra_result': getattr(allocation, 'is_extra_result', False) }) prev_date = date return result