Changeset c21134 in indico


Ignore:
Timestamp:
06/23/11 16:41:33 (2 years ago)
Author:
Pedro Ferreira <jose.pedro.ferreira@…>
Branches:
master, burotel, hello-world-walkthrough, ipv6, v0.98-series, v0.98.2, v0.98.3, v0.98b1, v0.98b2, v0.99, 051b2622c51afb171a1dedb46a0df4fbb0cbd02e, 0da0c1403bae8e51d8229f460181c71b9e6dda72
Children:
c3902a
Parents:
7903f4
git-author:
Adrian Moennich <jerome.ernst.monnich@…> (04/08/11 16:02:09)
git-committer:
Pedro Ferreira <jose.pedro.ferreira@…> (06/23/11 16:41:33)
Message:

[FTR] Add booking start/end notification system

  • also store CCID in avatar when using NICE SSO
  • fixes #724

Conflicts:

indico/MaKaC/authentication/NiceAuthentication.py
indico/MaKaC/rb_location.py

Location:
indico
Files:
3 added
17 edited

Legend:

Unmodified
Added
Removed
  • indico/MaKaC/authentication/NiceAuthentication.py

    rf3e592 rc21134  
    5959            email = req.subprocess_env["ADFS_EMAIL"] 
    6060            login = req.subprocess_env["ADFS_LOGIN"] 
     61            personId = req.subprocess_env["ADFS_PERSONID"] 
     62            if personId == '-1': 
     63                personId = None 
    6164            from MaKaC.user import AvatarHolder 
    6265            ah = AvatarHolder() 
     
    7982                if institute != '' and institute != av.getAffiliation(): 
    8083                    av.setAffiliation(institute) 
     84                if personId != None and personId != av.getPersonId(): 
     85                    av.setPersonId(personId) 
    8186                return av 
    8287            else: 
     
    108113                        ah.add(av) 
    109114                        av.activateAccount() 
     115                    if not av.getPersonId(): 
     116                        av.setPersonId(personId) 
    110117                    return av 
    111118        return None 
  • indico/MaKaC/plugins/RoomBooking/default/reservation.py

    r336214 rc21134  
    2323from ZODB.PersistentMapping import PersistentMapping 
    2424from persistent import Persistent 
     25from pytz import timezone 
    2526 
    2627from MaKaC.rb_factory import Factory 
     
    2930from MaKaC.rb_location import CrossLocationQueries 
    3031from MaKaC.plugins.RoomBooking.default.factory import Factory 
     32from modules.scheduler import Client, tasks 
    3133 
    3234from datetime import datetime 
    3335from MaKaC.common.logger import Logger 
     36from MaKaC.common.info import HelperMaKaCInfo 
     37from MaKaC.plugins.base import Observable 
     38from MaKaC.plugins.RoomBooking.notifications import ReservationStartEndNotification 
    3439 
    3540# Branch name in ZODB root 
     
    3944_DAY_RESERVATIONS_INDEX = 'DayReservationsIndex' 
    4045 
    41 class Reservation( Persistent, ReservationBase ): 
     46class Reservation( Persistent, ReservationBase, Observable ): 
    4247    """ 
    4348    ZODB specific implementation. 
     
    5358        self.useVC = [] 
    5459        self.resvHistory = ResvHistoryHandler() 
     60        self.startEndNotification = None 
    5561 
    5662    def getUseVC( self ): 
     
    125131        self._addToDayReservationsIndex() 
    126132 
     133        self._notify('reservationCreated') 
     134 
    127135        # Warning: 
    128136        # createdBy, once assigned to rerservation, CAN NOT be changed later (index!) 
    129137        # room, once assigned to reservation, CAN NOT be changed later (index!) 
     138 
     139    def update(self): 
     140        ReservationBase.update(self) 
     141        self._notify('reservationUpdated') 
     142 
     143    def getStartEndNotification(self): 
     144        if hasattr(self, '_startEndNotification') and self._startEndNotification is not None: 
     145            return self._startEndNotification 
     146        self._startEndNotification = ReservationStartEndNotification(self) 
     147        return self._startEndNotification 
     148 
     149    def getLocalizedStartDT(self): 
     150        tz = HelperMaKaCInfo.getMaKaCInfoInstance().getTimezone() 
     151        return timezone(tz).localize(self._utcStartDT) 
     152 
     153    def getLocalizedEndDT(self): 
     154        tz = HelperMaKaCInfo.getMaKaCInfoInstance().getTimezone() 
     155        return timezone(tz).localize(self._utcEndDT) 
    130156 
    131157    def indexDayReservations( self ): 
     
    156182        # Update day => reservations index 
    157183        self._removeFromDayReservationsIndex() 
     184 
     185        self._notify('reservationDeleted') 
    158186 
    159187    def _addToDayReservationsIndex( self ): 
  • indico/MaKaC/plugins/RoomBooking/options.py

    r107f4e rc21134  
    1919## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 
    2020 
     21_emailReplacerNote = """ 
     22You can use the following placeholders:<br />{bookedForUser}, {roomName}, {roomAtts[ATTNAME]}, {bookingStart}, {bookingEnd}, {detailsLink} 
     23""".strip() 
     24 
     25_emailSubjectReplacerNote = """ 
     26You can use the following placeholders:<br />{roomName}, {roomAtts[ATTNAME]}, {bookingStart}, {bookingEnd} 
     27""".strip() 
     28 
    2129globalOptions = [ 
    22                  ( "AuthorisedUsersGroups", {"description": "Users and Groups authorised for roombooking module", 
    23                                        "type": 'usersGroups', 
    24                                        "defaultValue": [], 
    25                                        "editable": True, 
    26                                        "visible": True}) 
    27                  ] 
     30    ("AuthorisedUsersGroups", {"description": "Users and Groups authorised for roombooking module", 
     31                          "type": 'usersGroups', 
     32                          "defaultValue": [], 
     33                          "editable": True, 
     34                          "visible": True}), 
     35    ("bookingsForRealUsers", { 
     36        "description": _("Should bookings require an existing user in the 'booked for' field"), 
     37        "type" : bool, 
     38        "defaultValue": False}), 
     39    ("notificationEnabled", { 
     40        "description": _("Enable the tasks for booking start/end notification. Only bookings created/modified after enabling it will trigger notifications"), 
     41        "type" : bool, 
     42        "defaultValue": False}), 
     43    ("notificationEmails", { 
     44        "description": _("Email addresses which will receive booking start/end notifications"), 
     45        "type": list, 
     46        "defaultValue": [], 
     47        "editable": True, 
     48        "visible": True}), 
     49    ("notificationEmailsToBookedFor", { 
     50        "description": _("Should the emails listed in 'booked for' also receive notification emails"), 
     51        "type" : bool, 
     52        "defaultValue": False}), 
     53    ("startNotificationEmailSubject", { 
     54        "description": _("Email subject when a booking starts"), 
     55        "type" : str, 
     56        "defaultValue": '', 
     57        "note": _emailSubjectReplacerNote}), 
     58    ("startNotificationEmail", { 
     59        "description": _("Email to send when a booking starts"), 
     60        "type" : 'textarea', 
     61        "defaultValue": '', 
     62        "note": _emailReplacerNote}), 
     63    ("endNotificationEmailSubject", { 
     64        "description": _("Email subject when a booking ends"), 
     65        "type" : str, 
     66        "defaultValue": '', 
     67        "note": _emailSubjectReplacerNote}), 
     68    ("endNotificationEmail", { 
     69        "description": _("Email to send when a booking ends"), 
     70        "type" : 'textarea', 
     71        "defaultValue": '', 
     72        "note": _emailReplacerNote}), 
     73    ("notificationBefore", {"description" : _("Trigger start notifications X minutes before the booking starts. Changes will not affect existing bookings"), 
     74                           "type": int, 
     75                           "defaultValue": 0} ) 
     76] 
  • indico/MaKaC/plugins/base.py

    r2da594 rc21134  
    508508 
    509509        return {"description": description, 
     510                "note": attributes.get("note", None), 
    510511                "type": optionType, 
    511512                "subType": attributes.get("subType", None), 
     
    582583        self.__options[name] = PluginOption(name, attributes["description"], attributes["type"], 
    583584                                            attributes["defaultValue"], attributes["editable"], attributes["visible"], 
    584                                             attributes["mustReload"], True, order, attributes["subType"]) 
     585                                            attributes["mustReload"], True, order, attributes["subType"], attributes["note"]) 
    585586        self._notifyModification() 
    586587 
     
    594595        option.setPresent(True) 
    595596        option.setDescription(attributes["description"]) 
     597        option.setNote(attributes["note"]) 
    596598        option.setType(attributes["type"]) 
    597599        option.setSubType(attributes["subType"]) 
     
    11391141        'password': str, 
    11401142        'ckEditor': str, 
     1143        'textarea': str, 
    11411144        'list_multiline': list, 
    11421145        'links': list 
    11431146    } 
    11441147 
    1145     def __init__(self, name, description, valueType, value=None, editable=True, visible=True, mustReload=False, present=True, order=0, subType=None): 
     1148    def __init__(self, name, description, valueType, value=None, editable=True, visible=True, mustReload=False, present=True, order=0, subType=None, note=None): 
    11461149        self.__name = name 
    11471150        self.__description = description 
     1151        self.__note = note 
    11481152        self.__type = valueType 
    11491153        self.__subType = subType 
     
    11651169        return self.__description 
    11661170 
     1171    def getNote(self): 
     1172        return self.__note 
     1173 
    11671174    def getType(self): 
    11681175        return self.__type 
     
    11791186    def setDescription(self, description): 
    11801187        self.__description = description 
     1188 
     1189    def setNote(self, note): 
     1190        self.__note = note 
    11811191 
    11821192    def isPresent(self): 
  • indico/MaKaC/rb_location.py

    r8a8251 rc21134  
    364364        Parses guidString into ReservationGUID object. 
    365365        """ 
    366         # TODO: check if this code is used. self is not defined, so it will fail 
    367366        try: 
    368367            loc, id = guidString.split( "|" ) 
    369368            loc = loc.strip(); id = int( id.strip() ) 
    370             self.location = Location.parse( loc ) 
    371             if not self.location: 
     369            location = Location.parse( loc ) 
     370            if not location: 
    372371                raise MaKaCError('invalid location') 
    373             self.id = id 
     372            return ReservationGUID(location, id) 
    374373        except: 
    375             raise guidString + ' - invalid ReservationGUID string' 
     374            raise MaKaCError(guidString + ' - invalid ReservationGUID string') 
    376375 
    377376    def getReservation( self ): 
  • indico/MaKaC/rb_reservation.py

    r7903f4 rc21134  
    13411341        return addrs 
    13421342 
     1343    def _getBookedForUser(self): 
     1344        if not self.bookedForId: 
     1345            return None 
     1346        return AvatarHolder().getById(self.bookedForId) 
     1347 
     1348    def _setBookedForUser(self, avatar): 
     1349        self.bookedForId = avatar and avatar.getId() 
     1350 
    13431351    def _eval_str( self, s ): 
    13441352        ixPrv = 0 
     
    14831491 
    14841492    # Who and why 
     1493    bookedForId = None    # str - for whom it is booked; avatar id (if enabled in options) 
     1494    bookedForUser = property(_getBookedForUser, _setBookedForUser) 
    14851495    bookedForName = None  # str - for whom it is booked; free text 
    14861496    contactEmail = None   # str - contact; typically the person for whom the booking is done 
  • indico/MaKaC/rb_room.py

    r8a8251 rc21134  
    713713     isReservable: #{self.isReservable} 
    714714rNeedConfirmation: #{self.resvsNeedConfirmation} 
     715startNotification: #{self.resvStartNotification} 
     716  endNotification: #{self.resvEndNotification} 
    715717 
    716718             site: #{self.site} 
     
    779781    externalId = None     # str - custom external room id, i.e. for locating on the map 
    780782 
     783    resvStartNotification = False # bool - whether to send notifications on booking start 
     784    resvEndNotification = False # bool - whether to send notifications on booking end 
     785 
    781786    telephone = None      # str 
    782787    surfaceArea = None    # int, positive - in meters^2 
  • indico/MaKaC/user.py

    rc3e1091 rc21134  
    538538        """ 
    539539        self.id = "" 
     540        self.personId = None 
    540541        self.name = "" 
    541542        self.surName = "" 
     
    979980    def getId(self): 
    980981        return self.id 
     982 
     983    def setPersonId(self, personId): 
     984        self.personId = personId 
     985 
     986    def getPersonId(self): 
     987        return getattr(self, 'personId', None) 
    981988 
    982989    def setName(self, name): 
  • indico/MaKaC/webinterface/pages/roomBooking.py

    r19825c rc21134  
    380380class WPRoomBookingBookingForm( WPRoomBookingBase ): 
    381381 
     382    def getJSFiles(self): 
     383        return WPRoomBookingBase.getJSFiles(self) + \ 
     384               self._includeJSPackage('Management') 
     385 
    382386    def __init__( self, rh ): 
    383387        self._rh = rh 
  • indico/MaKaC/webinterface/rh/roomBooking.py

    ra7568a rc21134  
    4747from MaKaC.plugins.RoomBooking.default.reservation import ResvHistoryEntry 
    4848from MaKaC.search.cache import MapOfRoomsCache 
     49from MaKaC.plugins.RoomBooking.common import getRoomBookingOption 
    4950 
    5051class CandidateDataFrom( object ): 
     
    210211        session.setVar( "isReservable", c.isReservable ) 
    211212        session.setVar( "resvsNeedConfirmation", c.resvsNeedConfirmation ) 
     213        session.setVar( "resvStartNotification", c.resvStartNotification ) 
     214        session.setVar( "resvEndNotification", c.resvEndNotification ) 
    212215 
    213216        session.setVar( "responsibleId", c.responsibleId ) 
     
    283286        candRoom.isReservable = True 
    284287        candRoom.resvsNeedConfirmation = False 
     288        candRoom.resvStartNotification = False 
     289        candRoom.resvEndNotification = False 
    285290        candRoom.photoId = None 
    286291        candRoom.externalId = None 
     
    306311        candRoom.isReservable = bool( session.getVar( "isReservable" ) ) 
    307312        candRoom.resvsNeedConfirmation = bool( session.getVar( "resvsNeedConfirmation" ) ) 
     313        candRoom.resvStartNotification = bool( session.getVar( "resvStartNotification" ) ) 
     314        candRoom.resvEndNotification = bool( session.getVar( "resvEndNotification" ) ) 
    308315 
    309316        candRoom.responsibleId = session.getVar( "responsibleId" ) 
     
    340347        candRoom.isReservable = bool( params.get( "isReservable" ) ) # Safe 
    341348        candRoom.resvsNeedConfirmation = bool( params.get( "resvsNeedConfirmation" ) ) # Safe 
     349        candRoom.resvStartNotification = bool( params.get( "resvStartNotification" ) ) 
     350        candRoom.resvEndNotification = bool( params.get( "resvEndNotification" ) ) 
     351 
    342352 
    343353        candRoom.responsibleId = params.get( "responsibleId" ) 
     
    386396        session.setVar( "endDT", c.endDT ) 
    387397        session.setVar( "repeatability", c.repeatability ) 
    388         session.setVar( "bookedForName", c.bookedForName ) 
     398        session.setVar( "bookedForId", c.bookedForId ) 
     399        if c.bookedForId: 
     400            session.setVar( "bookedForName", c.bookedForUser.getFullName() ) 
     401        else: 
     402            session.setVar( "bookedForName", c.bookedForName ) 
    389403        session.setVar( "contactPhone", c.contactPhone ) 
    390404        session.setVar( "contactEmail", c.contactEmail ) 
     
    407421        errors = [] 
    408422        self._thereAreConflicts = False 
    409         if not c.bookedForName: 
     423        if getRoomBookingOption('bookingsForRealUsers') and not c.bookedForUser: 
     424            errors.append( "Booked for can not be blank" ) 
     425        elif not getRoomBookingOption('bookingsForRealUsers') and not c.bookedForName: 
    410426            errors.append( "Booked for can not be blank" ) 
    411427        if not c.reason: 
     
    446462        candResv.endDT = session.getVar( "endDT" ) 
    447463        candResv.repeatability = session.getVar( "repeatability" ) 
     464        candResv.bookedForId = session.getVar( "bookedForId" ) 
    448465        candResv.bookedForName = session.getVar( "bookedForName" ) 
    449466        candResv.contactPhone = session.getVar( "contactPhone" ) 
     
    478495        candResv.endDT = self._endDT 
    479496        candResv.repeatability = self._repeatability 
    480         candResv.bookedForName = params["bookedForName"] 
     497        candResv.bookedForId = params.get("bookedForId") 
     498        candResv.bookedForName = params.get("bookedForName") 
    481499        candResv.contactEmail = setValidEmailSeparators(params["contactEmail"]) 
    482500        candResv.contactPhone = params["contactPhone"] 
     
    562580                candResv.repeatability = int(repeatability) 
    563581        if self._getUser(): 
     582            if candResv.bookedForUser is None: 
     583                candResv.bookedForUser = self._getUser() 
    564584            if candResv.bookedForName == None: 
    565585                candResv.bookedForName = self._getUser().getFullName() 
     
    569589                candResv.contactPhone = self._getUser().getTelephone() 
    570590        else: 
     591            candResv.bookedForUser = None 
    571592            candResv.bookedForName = candResv.contactEmail = candResv.contactPhone = "" 
    572593        if candResv.reason == None: 
     
    584605            if ws.getVar( "defaultRepeatability" ) != None: 
    585606                candResv.repeatability = ws.getVar( "defaultRepeatability" ) 
     607            if ws.getVar( "defaultBookedForId" ): 
     608                candResv.bookedForId = ws.getVar( "defaultBookedForId" ) 
    586609            if ws.getVar( "defaultBookedForName" ): 
    587610                candResv.bookedForName = ws.getVar( "defaultBookedForName" ) 
     
    627650        websession.setVar( "defaultEndDT", None ) 
    628651        websession.setVar( "defaultRepeatability", None ) 
     652        websession.setVar( "defaultBookedForId", None ) 
    629653        websession.setVar( "defaultBookedForName", None ) 
    630654        websession.setVar( "defaultReason", None ) 
     
    12261250 
    12271251        self._clearSessionState() 
     1252        self._requireRealUsers = getRoomBookingOption('bookingsForRealUsers') 
    12281253 
    12291254 
  • indico/MaKaC/webinterface/tpls/AdminPluginsOptionList.tpl

    rfc4880 rc21134  
    362362                    <input name="<%= name %>" type="checkbox" size="50" <%=checked%>> 
    363363                    <% end %> 
    364                     <% elif option.getType() == 'list_multiline': %> 
     364                    <% elif option.getType() in ('list_multiline', 'textarea'): %> 
    365365                    <textarea name="<%= name %>" cols="38"><%= value %></textarea> 
    366366                    <% end %> 
     
    378378                <% end %> 
    379379            </td> 
    380             <% if option.getType() == int or option.getType() == list or option.getType() == "list_multiline" or option.getType() == dict: %> 
     380            <% if option.getType() == int or option.getType() == list or option.getType() == "list_multiline" or option.getType() == dict or option.getNote(): %> 
    381381            <td style="width: 40%"> 
    382382                <% if option.getType() == int: %> 
     
    391391                <% elif option.getType() == dict: %> 
    392392                <span style="color: orange; font-size: smaller;"><%= _("Please input keys and values in Python syntax. No unicode objects allowed. Example: {\"john\":\"tall\", \"pete\":\"short\"}")%></span> 
     393                <% end %> 
     394                <% elif option.getNote(): %> 
     395                <span style="color: orange; font-size: smaller;"><%= option.getNote() %></span> 
    393396                <% end %> 
    394397            </td> 
  • indico/MaKaC/webinterface/tpls/RoomBookingBookingForm.tpl

    rde25536 rc21134  
    175175                                <td> 
    176176                                    <table width="100%"> 
    177                                         <tr> 
    178                                             <td class="subFieldWidth" align="right" valign="top"><small> <%= _("Name")%>&nbsp;&nbsp;</small></td> 
    179                                             <td align="left" class="blacktext"> 
    180                                                 <input type="text" id="bookedForName" name="bookedForName" style="width: 240px;" value="<%= verbose( candResv.bookedForName ) %>" /> 
    181                                                 <% inlineContextHelp( _("<b>Required.</b> For whom the booking is made.") ) %> 
    182                                             </td> 
    183                                         </tr> 
     177                                        <% if rh._requireRealUsers: %> 
     178                                            <tr> 
     179                                                <td class="subFieldWidth" align="right" valign="top"><small> <%= _("User")%>&nbsp;&nbsp;</small></td> 
     180                                                <td align="left" class="blacktext"> 
     181                                                    <input type="hidden" id="bookedForId" name="bookedForId" value="<%= candResv.bookedForId or '' %>" /> 
     182                                                    <input type="text" id="bookedForName" name="bookedForName" style="width: 240px;" value="<%= candResv.bookedForUser.getFullName() if candResv.bookedForId else candResv.bookedForName %>" onclick="searchForUsers();" readonly="readonly" /> 
     183                                                    <input type="button" value="Search" onclick="searchForUsers();" /> 
     184                                                    <% inlineContextHelp( _("<b>Required.</b> For whom the booking is made.") ) %> 
     185                                                </td> 
     186                                            </tr> 
     187                                        <% end %> 
     188                                        <% else: %> 
     189                                            <tr> 
     190                                                <td class="subFieldWidth" align="right" valign="top"><small> <%= _("Name")%>&nbsp;&nbsp;</small></td> 
     191                                                <td align="left" class="blacktext"> 
     192                                                    <input type="text" id="bookedForName" name="bookedForName" style="width: 240px;" value="<%= verbose( candResv.bookedForName ) %>" /> 
     193                                                    <% inlineContextHelp( _("<b>Required.</b> For whom the booking is made.") ) %> 
     194                                                </td> 
     195                                            </tr> 
     196                                        <% end %> 
    184197                                        <tr> 
    185198                                            <td class="subFieldWidth" align="right" valign="top"><small> <%= _("E-mail")%>&nbsp;&nbsp;</small></td> 
     
    279292            } 
    280293        ); 
     294 
     295        function searchForUsers() { 
     296            var popup = new ChooseUsersPopup($T('Select a user'), 
     297                                         true, 
     298                                         null, false, 
     299                                         true, null, 
     300                                         true, true, 
     301                                         function(users) { 
     302                                             $E('bookedForName').set(users[0].name); 
     303                                             $E('bookedForId').set(users[0].id); 
     304                                             $E('contactEmail').set(users[0].email); 
     305                                         }); 
     306 
     307            popup.execute(); 
     308        } 
     309 
    281310        <% if candResv.room.needsAVCSetup: %> 
    282311            alert("The conference room you have chosen is equiped\\nfor video-conferencing and video-projection.\\nIf you need this equipment, DO NOT FORGET to select it.\\nIf you don't need any of this equipment please choose\\nanother room, if a suitable one is free on a suitable\\nlocation for your meeting.\\n\\n\\n                    Thank you for your understanding.") 
  • indico/MaKaC/webinterface/tpls/RoomBookingRoomForm.tpl

    ra92d2a rc21134  
    3030        <div id="resvsNeedConfirmationCH" class="tip"> 
    3131             <%= _("Whether bookings must be accepted by person responsible.")%> 
     32        </div> 
     33        <div id="resvStartNotificationCH" class="tip"> 
     34             <%= _("Whether to trigger notifications when a booking for the room begins.")%> 
     35        </div> 
     36        <div id="resvEndNotificationCH" class="tip"> 
     37             <%= _("Whether to trigger notifications when a booking for the room ends.")%> 
    3238        </div> 
    3339        <div id="whereIsKeyCH" class="tip"> 
     
    152158                                            <td align="left" class="blacktext"><input type="checkbox" <% if room.resvsNeedConfirmation: %> checked="checked" <% end %> id="resvsNeedConfirmation" name="resvsNeedConfirmation" /> <% contextHelp( 'resvsNeedConfirmationCH' ) %></td> 
    153159                                        </tr> 
    154                                  </table> 
     160                                        <tr> 
     161                                            <td align="right" valign="top"><small> <%= _("Notification on booking start")%>&nbsp;&nbsp;</small></td> 
     162                                            <td align="left" class="blacktext"><input type="checkbox" <% if room.resvStartNotification: %> checked="checked" <% end %> id="resvStartNotification" name="resvStartNotification" /> <% contextHelp( 'resvStartNotificationCH' ) %></td> 
     163                                        </tr> 
     164                                        <tr> 
     165                                            <td align="right" valign="top"><small> <%= _("Notification on booking end")%>&nbsp;&nbsp;</small></td> 
     166                                            <td align="left" class="blacktext"><input type="checkbox" <% if room.resvEndNotification: %> checked="checked" <% end %> id="resvEndNotification" name="resvEndNotification" /> <% contextHelp( 'resvEndNotificationCH' ) %></td> 
     167                                        </tr> 
     168                                    </table> 
    155169                                </td> 
    156170                              </tr> 
     
    178192                                            <td align="left" class="blacktext"><input type="text" id="telephone" name="telephone" value="<%= verbose( room.telephone ) %>" /><% contextHelp( 'telephoneCH' ) %></td> 
    179193                                        </tr> 
    180                                  </table> 
     194                                    </table> 
    181195                                </td> 
    182196                              </tr> 
  • indico/modules/scheduler/__init__.py

    re05440e rc21134  
    2424""" 
    2525 
     26class TaskDelayed(Exception): 
     27    def __init__(self, seconds): 
     28        self.delaySeconds = seconds 
     29 
    2630from indico.modules.scheduler.module import SchedulerModule 
    2731from indico.modules.scheduler.server import Scheduler 
  • indico/modules/scheduler/server.py

    r339487 rc21134  
    398398        else: 
    399399            wclass = ThreadWorker 
    400         self._runningWorkers[curTask.id] = wclass(curTask.id, self._config) 
     400        delay = int_timestamp(self._getCurrentDateTime()) - timestamp 
     401        self._runningWorkers[curTask.id] = wclass(curTask.id, self._config, delay) 
    401402        self._runningWorkers[curTask.id].start() 
    402403 
  • indico/modules/scheduler/slave.py

    r5e086e rc21134  
    2121import time, logging 
    2222 
    23 from indico.modules.scheduler import SchedulerModule, base 
     23from indico.modules.scheduler import SchedulerModule, base, TaskDelayed 
    2424from MaKaC.common import DBMgr 
    2525from MaKaC.plugins.RoomBooking.default.dalManager import DBConnection, DALManager 
     
    3333class _Worker(object): 
    3434 
    35     def __init__(self, taskId, configData): 
     35    def __init__(self, taskId, configData, delay): 
    3636        super(_Worker, self).__init__() 
    3737 
     
    3939        self._taskId = taskId 
    4040        self._config = configData 
     41        self._executionDelay = delay 
    4142 
    4243    def _prepare(self): 
     
    7071        self._prepare() 
    7172 
    72         self._logger.info('Running task %s..' % self._task.id) 
     73        self._logger.info('Running task %s.. (delay: %s)' % (self._task.id, self._executionDelay)) 
    7374 
    7475        # We will try to run the task TASK_MAX_RETRIES 
     
    8586                self._task.prepare() 
    8687 
     88        delayed = False 
    8789        while i < self._config.task_max_tries: 
     90            # Otherwise objects modified in indico itself are not updated here 
     91            if hasattr(self._rbdbi, 'sync'): 
     92                self._rbdbi.sync() 
     93 
    8894            try: 
    8995                if i > 0: 
     
    98104                        i = i + 1 
    99105 
    100                         self._task.start() 
     106                        self._task.start(self._executionDelay) 
    101107                        break 
     108 
     109            except TaskDelayed, e: 
     110                nextRunIn = e.delaySeconds 
     111                self._executionDelay = 0 
     112                delayed = True 
     113                self._logger.info("%s delayed by %d seconds" % (self._task, e.delaySeconds)) 
     114                base.TimeSource.get().sleep(nextRunIn) 
    102115 
    103116            except Exception, e: 
     
    110123                                         (i + 1, nextRunIn)) 
    111124 
    112                     # if i is still low enough, we sleep progressively more 
    113                     # so that if the error is caused by concurrency we don't make 
    114                     # the problem worse by hammering the server. 
    115                     base.TimeSource.get().sleep(nextRunIn) 
     125                # if i is still low enough, we sleep progressively more 
     126                # so that if the error is caused by concurrency we don't make 
     127                # the problem worse by hammering the server. 
     128                base.TimeSource.get().sleep(nextRunIn) 
    116129 
    117130        self._logger.info('Ended on: %s' % self._task.endedOn) 
     
    121134            with self._dbi.transaction(): 
    122135                self._setResult(True) 
    123             if i > 1: 
     136            if i > (1 + int(delayed)): 
    124137                self._logger.warning("%s failed %d times before " 
    125                                      "finishing correctly" % (self._task, i - 1)) 
     138                                     "finishing correctly" % (self._task, i - int(delayed) - 1)) 
    126139        else: 
    127140            with self._dbi.transaction(): 
     
    137150class ThreadWorker(_Worker, threading.Thread): 
    138151 
    139     def __init__(self, tid, configData): 
    140         super(ThreadWorker, self).__init__(tid, configData) 
     152    def __init__(self, tid, configData, delay): 
     153        super(ThreadWorker, self).__init__(tid, configData, delay) 
    141154        self._result = 0 
    142155 
     
    153166class ProcessWorker(_Worker, multiprocessing.Process): 
    154167 
    155     def __init__(self, tid, configData): 
    156         super(ProcessWorker, self).__init__(tid, configData) 
     168    def __init__(self, tid, configData, delay): 
     169        super(ProcessWorker, self).__init__(tid, configData, delay) 
    157170        self._result = multiprocessing.Value('i', 0) 
    158171 
  • indico/modules/scheduler/tasks.py

    r9b342a rc21134  
    3636from indico.util.date_time import int_timestamp 
    3737from indico.modules.scheduler.fossils import ITaskFossil, ITaskOccurrenceFossil 
    38 from indico.modules.scheduler import base 
     38from indico.modules.scheduler import base, TaskDelayed 
    3939from indico.core.index import IUniqueIdProvider, IIndexableByArbitraryDateTime 
     40from MaKaC.common.utils import getEmailList 
     41from MaKaC.plugins.base import Observable 
     42from MaKaC.rb_location import ReservationGUID 
    4043 
    4144""" 
    4245Defines base classes for tasks, and some specific tasks as well 
    4346""" 
    44  
    4547 
    4648class TimedEvent(Persistent, Fossilizable): 
     
    174176        self.setStatus(base.TASK_STATUS_RUNNING) 
    175177 
    176     def start(self): 
    177  
     178    def start(self, delay): 
     179        self._executionDelay = delay 
    178180        try: 
    179181            self.run() 
     
    245247 
    246248 
    247     def start(self): 
    248         super(PeriodicTask, self).start() 
     249    def start(self, delay): 
     250        super(PeriodicTask, self).start(delay) 
    249251 
    250252    def tearDown(self): 
     
    666668        return True 
    667669 
     670class RoomReservationTaskBase(OneShotTask, Observable): 
     671    which = None 
     672    delay = None 
     673 
     674    def __init__(self, resv, startDateTime): 
     675        super(RoomReservationTaskBase, self).__init__(startDateTime) 
     676        self.resvGUID = str(resv.guid) 
     677 
     678    def run(self): 
     679        if self._executionDelay > 20: # assume the task daemon was dead -> delay tasks: 
     680            raise TaskDelayed(self.delay) 
     681        resv = ReservationGUID.parse(self.resvGUID).getReservation() 
     682        if not resv: 
     683            self.getLogger().info('Reservation %r does not exist anymore, not triggering events' % self.resvGUID) 
     684            return 
     685        resv.getStartEndNotification().taskTriggered(self.which, self) 
     686 
     687class RoomReservationStartedTask(RoomReservationTaskBase): 
     688    which = 'start' 
     689    delay = 5 
     690class RoomReservationFinishedTask(RoomReservationTaskBase): 
     691    which = 'end' 
     692    delay = 10 
    668693 
    669694class SampleOneShotTask(OneShotTask): 
Note: See TracChangeset for help on using the changeset viewer.