[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:
parent
09bf03f9bf
commit
722c5e28c7
|
@ -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)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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
BIN
gen/ui/validate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 208 B |
Loading…
Reference in a new issue