source: indico/indico/MaKaC/services/implementation/conference.py @ 77cb9e

burotelhello-world-walkthroughipv6new-webexv0.97-seriesv0.98-seriesv0.98.2v0.98.3v0.98b1v0.98b2v0.99v1.0v1.1
Last change on this file since 77cb9e was 84c86e, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 3 years ago

[FIX] Changed the way start/end date/time works

  • checkbox changed from "keep" to "move", since the default was most likely not the most used use case;
  • changed the algorithm so that an operation that only changes the end date sets moveEntries to 0;
  • Property mode set to 100644
File size: 24.7 KB
Line 
1"""
2Asynchronous request handlers for conference-related data modification.
3"""
4
5from MaKaC.services.implementation.base import ProtectedModificationService,\
6    ListModificationBase, ParameterManager
7from MaKaC.services.implementation.base import ProtectedDisplayService, ServiceBase
8
9import MaKaC.webinterface.displayMgr as displayMgr
10
11from MaKaC.common.Configuration import Config
12from MaKaC.common import filters
13from MaKaC.common.utils import validMail, setValidEmailSeparators
14from MaKaC.common.PickleJar import DictPickler
15from MaKaC.common import indexes, info
16
17from MaKaC.conference import ConferenceHolder
18import MaKaC.conference as conference
19from MaKaC.services.implementation.base import TextModificationBase
20from MaKaC.services.implementation.base import HTMLModificationBase
21from MaKaC.services.implementation.base import DateTimeModificationBase
22from MaKaC.webinterface.rh.reviewingModif import RCReferee, RCPaperReviewManager
23from MaKaC.webinterface.common import contribFilters
24import MaKaC.webinterface.wcomponents as wcomponents
25import MaKaC.webinterface.urlHandlers as urlHandlers
26import MaKaC.common.timezoneUtils as timezoneUtils
27from MaKaC.common.contextManager import ContextManager
28
29import datetime
30from pytz import timezone
31
32from MaKaC.errors import TimingError
33from MaKaC.common.logger import Logger
34from MaKaC.i18n import _
35
36from MaKaC.services.interface.rpc.common import ServiceError, Warning, ResultWithWarning, TimingNoReportError
37
38class ConferenceBase(object):
39    """
40    Base class for conference modification
41    """
42
43    def _checkParams( self ):
44
45        try:
46            self._target = self._conf = ConferenceHolder().getById(self._params["conference"]);
47            if self._target == None:
48                Logger.get('rpc.conference').debug('self._target is null')
49                raise Exception("Null target.")
50        except:
51            raise ServiceError("ERR-E4", "Invalid conference id.")
52
53
54    def _getCheckFlag(self):
55        """
56        Returns the "check" flag, a value that specifies what kind of
57        checking should be done before modifying. Classes that wish
58        to change this behavior should overload it.
59        """
60
61        # automatically adapt everything
62        return 2
63
64
65class ConferenceModifBase(ProtectedModificationService, ConferenceBase):
66    def _checkParams(self):
67        ConferenceBase._checkParams(self)
68        ProtectedModificationService._checkParams(self)
69
70class ConferenceScheduleModifBase(ConferenceModifBase):
71    def _checkParams(self):
72        ConferenceModifBase._checkParams(self)
73
74        self._schEntry = self._conf.getSchedule().getEntryById(self._params["scheduleEntry"])
75        if self._schEntry == None:
76            raise ServiceError("ERR-E4", "Invalid scheduleEntry id.")
77
78    def _checkProtection( self ):
79        self._target = self._schEntry.getOwner()
80        ConferenceModifBase._checkProtection(self)
81
82class ConferenceDisplayBase(ProtectedDisplayService, ConferenceBase):
83
84    def _checkParams(self):
85        ConferenceBase._checkParams(self)
86        ProtectedDisplayService._checkParams(self)
87
88class ConferenceTextModificationBase(TextModificationBase, ConferenceModifBase):
89    #Note: don't change the order of the inheritance here!
90    pass
91
92class ConferenceHTMLModificationBase(HTMLModificationBase, ConferenceModifBase):
93    #Note: don't change the order of the inheritance here!
94    pass
95
96class ConferenceDateTimeModificationBase (DateTimeModificationBase, ConferenceModifBase):
97    #Note: don't change the order of the inheritance here!
98    pass
99
100class ConferenceListModificationBase (ListModificationBase, ConferenceModifBase):
101    #Note: don't change the order of the inheritance here!
102    pass
103
104
105class ConferenceTitleModification( ConferenceTextModificationBase ):
106    """
107    Conference title modification
108    """
109    def _handleSet(self):
110        title = self._value
111        if (title ==""):
112            raise ServiceError("ERR-E2",
113                               "The title cannot be empty")
114        self._target.setTitle(self._value)
115
116    def _handleGet(self):
117        return self._target.getTitle()
118
119
120class ConferenceDescriptionModification( ConferenceHTMLModificationBase ):
121    """
122    Conference description modification
123    """
124    def _handleSet(self):
125        self._target.setDescription(self._value)
126
127    def _handleGet(self):
128        return self._target.getDescription()
129
130class ConferenceAdditionalInfoModification( ConferenceHTMLModificationBase ):
131    """
132    Conference additional info (a.k.a contact info) modification
133    """
134    def _handleSet(self):
135        self._target.setContactInfo(self._value)
136
137    def _handleGet(self):
138        return self._target.getContactInfo()
139
140class ConferenceTypeModification( ConferenceTextModificationBase ):
141    """
142    Conference title modification
143    """
144    def _handleSet(self):
145        curType = self._target.getType()
146        newType = self._value
147        if newType != "" and newType != curType:
148            import MaKaC.webinterface.webFactoryRegistry as webFactoryRegistry
149            wr = webFactoryRegistry.WebFactoryRegistry()
150            factory = wr.getFactoryById(newType)
151            wr.registerFactory(self._target, factory)
152
153            styleMgr = info.HelperMaKaCInfo.getMaKaCInfoInstance().getStyleManager()
154
155            dispMgr = displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self._target)
156            dispMgr.setDefaultStyle(styleMgr.getDefaultStylesheetForEventType(newType))
157
158    def _handleGet(self):
159        return self._target.getType()
160
161
162class ConferenceBookingModification( ConferenceTextModificationBase ):
163    """
164    Conference location name modification
165    """
166    def _handleSet(self):
167        room = self._target.getRoom()
168
169        if  room == None:
170            room = conference.CustomRoom()
171            self._target.setRoom(room)
172
173        # if a room name is not passed, it is assumed
174        # as empty
175        if 'room' in self._value:
176            room.setName( self._value['room'] )
177
178        loc = self._target.getLocation()
179        if not loc:
180            loc = conference.CustomLocation()
181            self._target.setLocation(loc)
182
183        if 'location' in self._value:
184            loc.setName( self._value['location'] )
185
186        loc.setAddress( self._value['address'] )
187
188    def _handleGet(self):
189
190        loc = self._target.getLocation()
191        room = self._target.getRoom()
192        if loc:
193            locName = loc.getName()
194            locAddress = loc.getAddress()
195        else:
196            locName = None
197            locAddress = ''
198        if room:
199            roomName = room.name
200        else:
201            roomName = None
202
203        return { 'location': locName,
204                 'room': roomName,
205                 'address': locAddress }
206
207class ConferenceBookingDisplay( ConferenceDisplayBase ):
208    """
209        Conference location
210    """
211    def _getAnswer(self):
212        loc = self._target.getLocation()
213        room = self._target.getRoom()
214        if loc:
215            locName = loc.getName()
216            locAddress = loc.getAddress()
217        else:
218            locName = ''
219            locAddress = ''
220        if room:
221            roomName = room.name
222        else:
223            roomName = ''
224
225        return { 'location': locName,
226                 'room': roomName,
227                 'address': locAddress }
228
229class ConferenceSpeakerTextModification( ConferenceTextModificationBase ):
230    """ Conference chairman text modification (for conferences and meetings)
231    """
232    def _handleSet(self):
233        self._target.setChairmanText(self._value)
234
235    def _handleGet(self):
236        return self._target.getChairmanText()
237
238class ConferenceOrganiserTextModification( ConferenceTextModificationBase ):
239    """ Conference organiser text modification (for lectures)
240    """
241    def _handleSet(self):
242        self._target.setOrgText(self._value)
243
244    def _handleGet(self):
245        return self._target.getOrgText()
246
247class ConferenceSupportEmailModification( ConferenceTextModificationBase ):
248    """
249    Conference support e-mail modification
250    """
251    def _handleSet(self):
252        # handling the case of a list of emails with separators different than ","
253        emailstr = setValidEmailSeparators(self._value)
254
255        if validMail(emailstr) or emailstr == '':
256            self._target.setSupportEmail(emailstr)
257        else:
258            raise ServiceError('ERR-E0', 'E-mail address %s is not valid!' %
259                               self._value)
260
261    def _handleGet(self):
262        return self._target.getSupportEmail()
263
264class ConferenceSupportModification( ConferenceTextModificationBase ):
265    """
266    Conference support caption and e-mail modification
267    """
268    def _handleSet(self):
269        dMgr = displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self._target)
270        caption = self._value.get("caption","")
271        email = self._value.get("email")
272
273        if caption == "":
274            raise ServiceError("ERR-E2", "The caption cannot be empty")
275        dMgr.setSupportEmailCaption(caption)
276
277        # handling the case of a list of emails with separators different than ","
278        email = setValidEmailSeparators(email)
279
280        if validMail(email) or email == "":
281            self._target.setSupportEmail(email)
282        else:
283            raise ServiceError('ERR-E0', 'E-mail address %s is not valid!' %
284                               self._value)
285
286    def _handleGet(self):
287        dMgr = displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self._target)
288        caption = dMgr.getSupportEmailCaption()
289        email = self._target.getSupportEmail()
290
291        return { "caption": caption,
292                 "email": email }
293
294class ConferenceDefaultStyleModification( ConferenceTextModificationBase ):
295    """
296    Conference default style modification
297    """
298    def _handleSet(self):
299        dispManReg = displayMgr.ConfDisplayMgrRegistery()
300        dispManReg.getDisplayMgr(self._target).setDefaultStyle(self._value)
301
302    def _handleGet(self):
303        dispManReg = displayMgr.ConfDisplayMgrRegistery()
304        return dispManReg.getDisplayMgr(self._target).getDefaultStyle()
305
306class ConferenceVisibilityModification( ConferenceTextModificationBase ):
307    """
308    Conference visibility modification
309    """
310
311    def _handleSet(self):
312        try:
313            val = int(self._value)
314        except ValueError:
315            raise ServiceError("ERR-E1","Invalid value type for property")
316        self._target.setVisibility(val)
317
318    def _handleGet(self):
319        return self._target.getVisibility()
320
321class ConferenceStartEndDateTimeModification( ConferenceModifBase ):
322    """
323    Conference start date/time modification
324
325    When changing the start date / time, the _setParam method will be called
326    by DateTimeModificationBase's _handleSet method.
327    The _setParam method will return None (if there are no problems),
328    or a Warning object if the event start date change was OK but there were
329    side problems, such as an object observing the event start date change
330    could not perform its task
331    (Ex: a videoconference booking could not be moved in time according with
332    the conference's time change)
333    For this, it will check the 'dateChangeNotificationProblems' context variable.
334    """
335
336    def _checkParams(self):
337
338        ConferenceModifBase._checkParams(self)
339
340        pm = ParameterManager(self._params.get('value'), timezone=self._conf.getTimezone())
341
342        self._startDate = pm.extract('startDate', pType=datetime.datetime)
343        self._endDate = pm.extract('endDate', pType=datetime.datetime)
344        self._shiftTimes = pm.extract('shiftTimes', pType=bool)
345
346    def _getAnswer(self):
347
348        ContextManager.set('dateChangeNotificationProblems', {})
349
350        if (self._shiftTimes):
351            moveEntries = 1
352        else:
353            moveEntries = 0
354
355        # first sanity check
356        if (self._startDate > self._endDate):
357            raise ServiceError("ERR-E3",
358                               "Date/time of start cannot "
359                               "be greater than date/time of end")
360
361        # catch TimingErrors that can be returned by the algorithm
362        try:
363            self._target.setDates(self._startDate,
364                                  self._endDate,
365                                  moveEntries = moveEntries)
366        except TimingError,e:
367            raise TimingNoReportError("ERR-E2", e.getMsg(),
368                                      title = _("Cannot set event dates"),
369                                      explanation = e.getExplanation())
370
371        dateChangeNotificationProblems = ContextManager.get('dateChangeNotificationProblems')
372
373        if dateChangeNotificationProblems:
374
375            warningContent = []
376            for problemGroup in dateChangeNotificationProblems.itervalues():
377                warningContent.extend(problemGroup)
378
379            w = Warning(_('Warning'), [_('The start date of your event was changed correctly. '
380                                       'However, there were the following problems:'),
381                                       warningContent])
382
383            return DictPickler.pickle(ResultWithWarning(self._params.get('value'), w))
384
385        else:
386            return self._params.get('value')
387
388class ConferenceListUsedRooms( ConferenceDisplayBase ):
389    """
390    Get rooms that are used in the context of the conference:
391     * Booked in CRBS
392     * Already chosen in sessions
393    """
394    def _getAnswer( self ):
395        """
396        Calls _handle() on the derived classes, in order to make it happen. Provides
397        them with self._value.
398        """
399
400        roomList = []
401        roomList.extend(self._target.getRoomList())
402        roomList.extend(map(lambda x: x._getName(), self._target.getBookedRooms()))
403
404        return roomList
405
406
407class ConferenceDateTimeEndModification( ConferenceDateTimeModificationBase ):
408    """ Conference end date/time modification
409        When changing the end date / time, the _setParam method will be called by DateTimeModificationBase's _handleSet method.
410        The _setParam method will return None (if there are no problems),
411        or a FieldModificationWarning object if the event start date change was OK but there were side problems,
412        such as an object observing the event start date change could not perform its task
413        (Ex: a videoconference booking could not be moved in time according with the conference's time change)
414    """
415    def _setParam(self):
416
417        ContextManager.set('dateChangeNotificationProblems', {})
418
419        if (self._pTime < self._target.getStartDate()):
420            raise ServiceError("ERR-E3",
421                               "Date/time of end cannot "+
422                               "be lower than data/time of start")
423        self._target.setDates(self._target.getStartDate(),
424                              self._pTime.astimezone(timezone("UTC")),
425                              moveEntries=0)
426
427        dateChangeNotificationProblems = ContextManager.get('dateChangeNotificationProblems')
428
429        if dateChangeNotificationProblems:
430            warningContent = []
431            for problemGroup in dateChangeNotificationProblems.itervalues():
432                warningContent.extend(problemGroup)
433
434            return Warning(_('Warning'), [_('The end date of your event was changed correctly.'),
435                                          _('However, there were the following problems:'),
436                                          warningContent])
437        else:
438            return None
439
440
441    def _handleGet(self):
442        return datetime.datetime.strftime(self._target.getAdjustedEndDate(),
443                                          '%d/%m/%Y %H:%M')
444
445
446class ConferenceListContributions (ConferenceListModificationBase):
447    """ Returns a list of all contributions of a conference, ordered by id
448    """
449    def _checkParams(self):
450        ConferenceListModificationBase._checkParams(self)
451        pm = ParameterManager(self._params)
452        self._selTypes = pm.extract("selTypes", pType=list, allowEmpty = True) #ids of selected types
453        self._selTracks = pm.extract("selTracks", pType=list, allowEmpty = True) #ids of selected tracks
454        self._selSessions = pm.extract("selSessions", pType=list, allowEmpty = True) #ids of selected sessions
455
456        self._typeShowNoValue = self._params.get("typeShowNoValue", True)
457        self._trackShowNoValue = self._params.get("trackShowNoValue", True)
458        self._sessionShowNoValue = self._params.get("sessionShowNoValue", True)
459
460        self._showWithReferee = self._params.get("showWithReferee", False)
461        self._showWithEditor = self._params.get("showWithEditor", False)
462        self._showWithReviewer = self._params.get("showWithReviewer", False)
463
464        self._poster = self._params.get("poster", False)
465        self._posterShowNoValue = self._params.get("posterShowNoValue", True)
466
467    def _checkProtection(self):
468        if not RCPaperReviewManager.hasRights(self) and not RCReferee.hasRights(self):
469            ProtectedModificationService._checkProtection(self)
470
471    def _handleGet(self):
472        contributions = self._conf.getContributionList()
473
474        filter = {}
475
476        #filtering if the active user is a referee: he can only see his own contribs
477        isOnlyReferee = RCReferee.hasRights(self) \
478                        and not RCPaperReviewManager.hasRights(self) \
479                        and not self._conf.canModify(self.getAW())
480        if isOnlyReferee:
481            filter["referee"] = self._getUser()
482        elif self._showWithReferee:
483            filter["referee"] = "any"
484        else:
485            filter["referee"] = None
486
487        if self._showWithEditor:
488            filter["editor"] = "any"
489        else:
490            filter["editor"] = None
491        if self._showWithReviewer:
492            filter["reviewer"] = "any"
493        else:
494            filter["reviewer"] = None
495
496
497        #note by David: I added "if self._selTypes..." and the other ifs after this line,
498        #in order to make the recording request load contributions work
499        #but, it may break the paper reviewing module -> assign contributions filter
500        if self._selTypes:
501            filter["type"] = self._selTypes
502        if self._selTracks:
503            filter["track"] = self._selTracks
504        if self._selSessions:
505            filter["session"] = self._selSessions
506        if self._poster:
507            filter["poster"] = self._poster
508
509        filterCrit = ContributionsReviewingFilterCrit(self._conf, filter)
510        sortingCrit = contribFilters.SortingCriteria(["number"])
511
512        if self._selTypes:
513            filterCrit.getField("type").setShowNoValue( self._typeShowNoValue )
514        if self._selTracks:
515            filterCrit.getField("track").setShowNoValue( self._trackShowNoValue )
516        if self._selSessions:
517            filterCrit.getField("session").setShowNoValue( self._sessionShowNoValue )
518        if self._poster:
519            filterCrit.getField("poster").setShowNoValue( self._posterShowNoValue )
520
521        filterCrit.getField("referee").setShowNoValue( not isOnlyReferee )
522
523        f= filters.SimpleFilter(filterCrit, sortingCrit)
524        contributions = f.apply(contributions)
525
526        return DictPickler.pickle(contributions)
527
528#########################
529# Contribution filtering
530#########################
531
532class ContributionsReviewingFilterCrit(filters.FilterCriteria):
533    _availableFields = {
534        contribFilters.RefereeFilterField.getId() : contribFilters.RefereeFilterField,
535        contribFilters.EditorFilterField.getId() : contribFilters.EditorFilterField,
536        contribFilters.ReviewerFilterField.getId() : contribFilters.ReviewerFilterField,
537        contribFilters.TypeFilterField.getId() : contribFilters.TypeFilterField,
538        contribFilters.TrackFilterField.getId() : contribFilters.TrackFilterField,
539        contribFilters.SessionFilterField.getId() : contribFilters.SessionFilterField,
540        contribFilters.PosterFilterField.getId() : contribFilters.PosterFilterField
541    }
542
543#############################
544# Conference Modif Display  #
545#############################
546
547class ConferencePicDelete(ConferenceModifBase):
548
549    def _checkParams(self):
550        ConferenceModifBase._checkParams(self)
551
552        pm = ParameterManager(self._params)
553
554        self._id = pm.extract("picId", pType=str, allowEmpty=False)
555
556    def _getAnswer(self):
557        im = displayMgr.ConfDisplayMgrRegistery().getDisplayMgr(self._conf).getImagesManager()
558        im.removePic(self._id)
559
560#############################
561# Conference cretion        #
562#############################
563
564class ShowConcurrentEvents(ServiceBase):
565
566    def _checkParams(self):
567        ServiceBase._checkParams(self)
568
569        pm = ParameterManager(self._params)
570
571        self._tz = pm.extract("timezone", pType=str, allowEmpty=False)
572        pm.setTimezone(self._tz)
573        self._sDate = pm.extract("sDate", pType=datetime.datetime, allowEmpty=False)
574        self._eDate = pm.extract("eDate", pType=datetime.datetime, allowEmpty=False)
575
576    def _getAnswer( self ):
577        im = indexes.IndexesHolder()
578        ch = ConferenceHolder()
579        calIdx = im.getIndex("calendar")
580        evtIds = calIdx.getObjectsIn(self._sDate, self._eDate)
581
582        evtsByCateg={}
583        for evtId in evtIds:
584            try:
585                evt = ch.getById(evtId)
586                categs =evt.getOwnerList()
587                categname =categs[0].getName()
588                if not evtsByCateg.has_key(categname):
589                    evtsByCateg[categname] = []
590                evtsByCateg[categname].append((evt.getTitle().strip(),evt.getAdjustedStartDate().strftime('%d/%m/%Y %H:%M '),evt.getAdjustedEndDate().strftime('%d/%m/%Y %H:%M '), evt.getTimezone()))
591
592            except Exception:
593                continue
594        return evtsByCateg
595
596
597class ConferenceGetFieldsAndContribTypes(ConferenceDisplayBase):
598    def _getAnswer( self ):
599        afm = self._target.getAbstractMgr().getAbstractFieldsMgr()
600        afmDict =  dict([(f.getId(), f.getName()) for f in afm.getFields()])
601        cTypes = self._target.getContribTypeList()
602        cTypesDict =  dict([(ct.getId(), ct.getName()) for ct in cTypes])
603        return [afmDict, cTypesDict]
604
605
606class ConferenceParticipationForm(ConferenceDisplayBase):
607    def _getAnswer(self):
608
609        params = {}
610
611        if self._conf.getStartDate() < timezoneUtils.nowutc() :
612            return """This event began on %s, you cannot apply for
613                      participation after the event began."""%self._conf.getStartDate()
614
615        if not self._conf.getParticipation().isAllowedForApplying() :
616            return """Participation in this event is restricted to persons invited.
617                      If you insist on taking part in this event, please contact the event manager."""
618
619        p = wcomponents.WNewPerson()
620
621        params["formAction"] = str(urlHandlers.UHConfParticipantsAddPending.getURL(self._conf))
622        params["formTitle"] = None
623        params["cancelButtonParams"] = """ type="button" id="cancelRegistrationButton" """
624
625        params["titleValue"] = ""
626        params["surNameValue"] = ""
627        params["nameValue"] = ""
628        params["emailValue"] = ""
629        params["addressValue"] = ""
630        params["affiliationValue"] = ""
631        params["phoneValue"] = ""
632        params["faxValue"] = ""
633
634        user = self._getUser()
635        if user is not None :
636            params["titleValue"] = user.getTitle()
637            params["surNameValue"] = user.getFamilyName()
638            params["nameValue"] = user.getName()
639            params["emailValue"] = user.getEmail()
640            params["addressValue"] = user.getAddress()
641            params["affiliationValue"] = user.getAffiliation()
642            params["phoneValue"] = user.getTelephone()
643            params["faxValue"] = user.getFax()
644
645            params["disabledTitle"] = params["disabledSurName"] = True
646            params["disabledName"] = params["disabledEmail"] = True
647            params["disabledAddress"] = params["disabledPhone"] = True
648            params["disabledFax"] = params["disabledAffiliation"] = True
649
650        return p.getHTML(params)
651
652methodMap = {
653    "main.changeTitle": ConferenceTitleModification,
654    "main.changeSupportEmail": ConferenceSupportEmailModification,
655    "main.changeSupport": ConferenceSupportModification,
656    "main.changeSpeakerText": ConferenceSpeakerTextModification,
657    "main.changeOrganiserText": ConferenceOrganiserTextModification,
658    "main.changeDefaultStyle": ConferenceDefaultStyleModification,
659    "main.changeVisibility": ConferenceVisibilityModification,
660    "main.changeType": ConferenceTypeModification,
661    "main.changeDescription": ConferenceDescriptionModification,
662    "main.changeAdditionalInfo": ConferenceAdditionalInfoModification,
663    "main.changeDates": ConferenceStartEndDateTimeModification,
664    "main.changeBooking": ConferenceBookingModification,
665    "main.displayBooking": ConferenceBookingModification,
666    "rooms.list" : ConferenceListUsedRooms,
667    "contributions.list" : ConferenceListContributions,
668    "pic.delete": ConferencePicDelete,
669    "showConcurrentEvents": ShowConcurrentEvents,
670#    "getFields": ConferenceGetFields,
671    "getFieldsAndContribTypes": ConferenceGetFieldsAndContribTypes,
672    "getParticipationForm": ConferenceParticipationForm
673    }
Note: See TracBrowser for help on using the repository browser.