[gen] Calendar field: added log of event creation, deletion and validation. Validation system: discarded events can now be removed or kept.

This commit is contained in:
Gaetan Delannay 2015-03-04 16:14:55 +01:00
parent 09bf03f9bf
commit 722c5e28c7
3 changed files with 38 additions and 7 deletions

View file

@ -40,7 +40,7 @@ class Validation:
validated events. This class holds information about this validation validated events. This class holds information about this validation
process. For more information, see the Calendar constructor, parameter process. For more information, see the Calendar constructor, parameter
"validation".''' "validation".'''
def __init__(self, method, schema): def __init__(self, method, schema, removeDiscarded=False):
# p_method holds a method that must return True if the currently logged # p_method holds a method that must return True if the currently logged
# user can validate whish events. # user can validate whish events.
self.method = method self.method = method
@ -48,6 +48,8 @@ class Validation:
# and whose values are the event types being the corresponding validated # and whose values are the event types being the corresponding validated
# event types. # event types.
self.schema = schema self.schema = schema
# When discarding events, mmust we simply let them there or remove it?
self.removeDiscarded = removeDiscarded
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Other: class Other:
@ -96,10 +98,14 @@ class Event(Persistent):
self.eventType = eventType self.eventType = eventType
self.timeslot = timeslot self.timeslot = timeslot
def getName(self, allEventNames, xhtml=True): def getName(self, allEventNames=None, xhtml=True):
'''Gets the name for this event, that depends on it type and may include '''Gets the name for this event, that depends on it type and may include
the timeslot if not "main".''' the timeslot if not "main".'''
res = allEventNames[self.eventType] # If we have the translated names for event types, use it.
if allEventNames:
res = allEventNames[self.eventType]
else:
res = self.eventType
if self.timeslot != 'main': if self.timeslot != 'main':
# Prefix it with the timeslot # Prefix it with the timeslot
prefix = xhtml and ('<b>[%s]</b> ' % self.timeslot) or \ prefix = xhtml and ('<b>[%s]</b> ' % self.timeslot) or \
@ -575,6 +581,12 @@ class Calendar(Field):
raise Exception('The first timeslot must have id "main" and is ' \ raise Exception('The first timeslot must have id "main" and is ' \
'the one representing the whole day.') 'the one representing the whole day.')
def log(self, obj, msg, date=None):
'''Logs m_msg, field-specifically prefixed.'''
prefix = '%s:%s' % (obj.id, self.name)
if date: prefix += '@%s' % date.strftime('%Y/%m/%d')
obj.log('%s: %s' % (prefix, msg))
def getPreComputedInfo(self, obj, monthDayOne, grid): def getPreComputedInfo(self, obj, monthDayOne, grid):
'''Returns the result of calling self.preComputed, or None if no such '''Returns the result of calling self.preComputed, or None if no such
method exists.''' method exists.'''
@ -1038,11 +1050,16 @@ class Calendar(Field):
events.data.sort(key=lambda e: timeslots.index(e.timeslot)) events.data.sort(key=lambda e: timeslots.index(e.timeslot))
events._p_changed = 1 events._p_changed = 1
# Span the event on the successive days if required # Span the event on the successive days if required
suffix = ''
if handleEventSpan and eventSpan: if handleEventSpan and eventSpan:
nbOfDays = min(int(eventSpan), self.maxEventLength) nbOfDays = min(int(eventSpan), self.maxEventLength)
for i in range(nbOfDays): for i in range(nbOfDays):
date = date + 1 date = date + 1
self.createEvent(obj, date, timeslot, handleEventSpan=False) self.createEvent(obj, date, timeslot, handleEventSpan=False)
suffix = ', span+%d' % nbOfDays
if handleEventSpan:
msg = 'added %s, slot %s%s' % (eventType, timeslot, suffix)
self.log(obj, msg, date)
def mayDelete(self, obj, events): def mayDelete(self, obj, events):
'''May the user delete p_events?''' '''May the user delete p_events?'''
@ -1060,26 +1077,38 @@ class Calendar(Field):
if not self.getEventsAt(obj, date): return if not self.getEventsAt(obj, date): return
daysDict = getattr(obj, self.name)[date.year()][date.month()] daysDict = getattr(obj, self.name)[date.year()][date.month()]
events = self.getEventsAt(obj, date) events = self.getEventsAt(obj, date)
count = len(events)
eNames = ', '.join([e.getName(xhtml=False) for e in events])
if timeslot == 'main': if timeslot == 'main':
# Delete all events; delete them also in the following days when # Delete all events; delete them also in the following days when
# relevant. # relevant.
del daysDict[date.day()] del daysDict[date.day()]
rq = obj.REQUEST rq = obj.REQUEST
suffix = ''
if handleEventSpan and rq.has_key('deleteNext') and \ if handleEventSpan and rq.has_key('deleteNext') and \
(rq['deleteNext'] == 'True'): (rq['deleteNext'] == 'True'):
nbOfDays = 0
while True: while True:
date = date + 1 date = date + 1
if self.hasEventsAt(obj, date, events): if self.hasEventsAt(obj, date, events):
self.deleteEvent(obj, date, timeslot, self.deleteEvent(obj, date, timeslot,
handleEventSpan=False) handleEventSpan=False)
nbOfDays += 1
else: else:
break break
if nbOfDays: suffix = ', span+%d' % nbOfDays
if handleEventSpan:
msg = '%s deleted (%d)%s.' % (eNames, count, suffix)
self.log(obj, msg, date)
else: else:
# Delete the event at p_timeslot # Delete the event at p_timeslot
i = len(events) - 1 i = len(events) - 1
while i >= 0: while i >= 0:
if events[i].timeslot == timeslot: if events[i].timeslot == timeslot:
msg = '%s deleted at slot %s.' % \
(events[i].getName(xhtml=False), timeslot)
del events[i] del events[i]
self.log(obj, msg, date)
break break
i -= 1 i -= 1
@ -1178,6 +1207,7 @@ class Calendar(Field):
'''Validate or discard events from the request.''' '''Validate or discard events from the request.'''
rq = obj.REQUEST.form rq = obj.REQUEST.form
counts = {'validated': 0, 'discarded': 0} counts = {'validated': 0, 'discarded': 0}
removeDiscarded = self.validation.removeDiscarded
for action in ('validated', 'discarded'): for action in ('validated', 'discarded'):
if not rq[action]: continue if not rq[action]: continue
for info in rq[action].split(','): for info in rq[action].split(','):
@ -1197,12 +1227,13 @@ class Calendar(Field):
if action == 'validated': if action == 'validated':
event.eventType = self.validation.schema[eventType] event.eventType = self.validation.schema[eventType]
else: else:
del events[i] if removeDiscarded: del events[i]
counts[action] += 1 counts[action] += 1
i -= 1 i -= 1
obj.log('%s:%s: %d event(s) validated and %d discarded.' % \
(obj.id, self.name, counts['validated'], counts['discarded']))
if not counts['validated'] and not counts['discarded']: if not counts['validated'] and not counts['discarded']:
return obj.translate('action_null') return obj.translate('action_null')
part = not removeDiscarded and ' (but not removed)' or ''
self.log(obj, '%d event(s) validated and %d discarded%s.' % \
(counts['validated'], counts['discarded'], part))
return obj.translate('validate_events_done', mapping=counts) return obj.translate('validate_events_done', mapping=counts)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -738,7 +738,7 @@ msgstr "Tous les événements sélectionnés seront confirmés, tandis que ceux
#. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded." #. Default: "${validated} event(s) was (were) validated and ${discarded} was (were) discarded."
msgid "validate_events_done" msgid "validate_events_done"
msgstr "${validated} événement(s) a (ont) été validé(s) et ${discarded} a (ont) été rejeté(s)." msgstr "${validated} événement(s) a (ont) été validé(s) et ${discarded} ne l'a (ont) pas été."
#. Default: "Inserted by ${userName}" #. Default: "Inserted by ${userName}"
msgid "history_insert" msgid "history_insert"

BIN
gen/ui/validate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B