source: indico/indico/MaKaC/plugins/Collaboration/http_api.py @ 1d5dc6

hello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.99v1.0v1.1
Last change on this file since 1d5dc6 was 1d5dc6, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 17 months ago

[FIX] Improved separation from core in ical

  • Property mode set to 100644
File size: 10.2 KB
Line 
1# -*- coding: utf-8 -*-
2##
3##
4## This file is part of CDS Indico.
5## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2011 CERN.
6##
7## CDS Indico is free software; you can redistribute it and/or
8## modify it under the terms of the GNU General Public License as
9## published by the Free Software Foundation; either version 2 of the
10## License, or (at your option) any later version.
11##
12## CDS Indico is distributed in the hope that it will be useful, but
13## WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15## General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21import icalendar as ical
22
23from indico.web.http_api import HTTPAPIHook, DataFetcher
24from indico.web.http_api.ical import ICalSerializer
25from indico.web.http_api.util import get_query_parameter
26from indico.web.http_api.responses import HTTPAPIError
27from indico.web.wsgi import webinterface_handler_config as apache
28from indico.util.fossilize import fossilize, IFossil
29from indico.util.fossilize.conversion import Conversion
30
31from MaKaC.webinterface.rh.collaboration import RCCollaborationAdmin
32from MaKaC.common.indexes import IndexesHolder
33from MaKaC.plugins.Collaboration.RecordingManager.common import createIndicoLink
34from MaKaC.plugins.Collaboration.collaborationTools import CollaborationTools
35from MaKaC.conference import ConferenceHolder
36from MaKaC.plugins.Collaboration.base import SpeakerStatusEnum
37from MaKaC.plugins.Collaboration.fossils import ICollaborationMetadataFossil
38
39
40globalHTTPAPIHooks = ['CollaborationAPIHook', 'CollaborationExportHook', 'VideoEventHook']
41
42
43def serialize_collaboration_alarm(fossil, now):
44    alarm = ical.Alarm()
45    trigger = "-PT" + str(fossil['alarm']) + "M"  # iCalendar spec for pre-event trigger
46    alarm.set('trigger', trigger)
47    alarm.set('action', 'DISPLAY')
48    alarm.set('summary', "[" + fossil['type'] + "] " + fossil['status'] + " - " + fossil['title'].decode('utf-8'))
49    alarm.set('description', str(fossil['url']))
50    return alarm
51
52
53def serialize_collaboration(fossil, now):
54    event = ical.Event()
55    url = str(fossil['url'])
56    event.set('uid', 'indico-collaboration-%s@cern.ch' % fossil['uniqueId'])
57    event.set('dtstamp', now)
58    event.set('dtstart', fossil['startDate'])
59    event.set('dtend', fossil['endDate'])
60    event.set('url', url)
61    event.set('categories', "VideoService - " + fossil['type'])
62    event.set('summary', "[" + fossil['type'] + "] " + fossil['status'] + " - " + fossil['title'].decode('utf-8'))
63    event.set('description', url)
64
65    # If there is an alarm required, add a subcomponent to the Event
66    if fossil.has_key('alarm'):
67        event.add_component(serialize_collaboration_alarm(fossil, now))
68
69    return event
70
71
72# the iCal serializer needs some extra info on how to display things
73ICalSerializer.register_mapper('collaborationMetadata', serialize_collaboration)
74
75
76class CollaborationAPIHook(HTTPAPIHook):
77    PREFIX = 'api'
78    TYPES = ('recordingManager',)
79    RE = r'createLink'
80    GUEST_ALLOWED = False
81    VALID_FORMATS = ('json',)
82    COMMIT = True
83    HTTP_POST = True
84
85    def _hasAccess(self, aw):
86        return RCCollaborationAdmin.hasRights(user=aw.getUser())
87
88    def _getParams(self):
89
90        super(CollaborationAPIHook, self)._getParams()
91        self._indicoID = get_query_parameter(self._queryParams, ['iid', 'indicoID'])
92        self._cdsID = get_query_parameter(self._queryParams, ['cid', 'cdsID'])
93
94    def api_recordingManager(self, aw):
95        if not self._indicoID or not self._cdsID:
96            raise HTTPAPIError('A required argument is missing.', apache.HTTP_BAD_REQUEST)
97
98        success = createIndicoLink(self._indicoID, self._cdsID)
99        return {'success': success}
100
101
102class CollaborationExportHook(HTTPAPIHook):
103    TYPES = ('eAgreements', )
104    RE = r'(?P<confId>\w+)'
105    GUEST_ALLOWED = False
106    VALID_FORMATS = ('json', 'jsonp', 'xml')
107
108    def _hasAccess(self, aw):
109        return RCCollaborationAdmin.hasRights(user=aw.getUser())
110
111    def _getParams(self):
112        super(CollaborationExportHook, self)._getParams()
113        self._conf = ConferenceHolder().getById(self._pathParams['confId'], True)
114        if not self._conf:
115            raise HTTPAPIError('Conference does not exist.', apache.HTTP_BAD_REQUEST)
116
117    def export_eAgreements(self, aw):
118        manager = self._conf.getCSBookingManager()
119        requestType = CollaborationTools.getRequestTypeUserCanManage(self._conf, aw.getUser())
120        contributions = manager.getContributionSpeakerByType(requestType)
121        for cont, speakers in contributions.items():
122            for spk in speakers:
123                sw = manager.getSpeakerWrapperByUniqueId('%s.%s' % (cont, spk.getId()))
124                if not sw:
125                    continue
126                signed = None
127                if sw.getStatus() in (SpeakerStatusEnum.FROMFILE, SpeakerStatusEnum.SIGNED):
128                    signed = True
129                elif sw.getStatus() == SpeakerStatusEnum.REFUSED:
130                    signed = False
131                yield {
132                    'confId': sw.getConference().getId(),
133                    'contrib': cont,
134                    'type': sw.getRequestType(),
135                    'status': sw.getStatus(),
136                    'signed': signed,
137                    'speaker': {
138                        'id': spk.getId(),
139                        'name': spk.getFullName(),
140                        'email': spk.getEmail()
141                    }
142                }
143
144
145class VideoEventHook(HTTPAPIHook):
146    """
147    This has been defined as a separate hook to CollaborationExportHook et al
148    due to the different input expected for both. It would be beneficial to
149    find a way to amalgamate the two at a later date.
150    """
151
152    TYPES = ('video', )
153    RE = r'(?P<idlist>\w+(?:-\w+)*)'
154    DEFAULT_DETAIL = 'all'
155    MAX_RECORDS = { # @TODO: Ascertain reasonable limits for each section.
156        'all': 100000,
157        'vidyo': 50000,
158        'webcast': 50000,
159        'mcu': 50000,
160        'evo': 50000
161    }
162
163    def _getParams(self):
164        super(VideoEventHook, self)._getParams()
165
166        """ In this case, idlist refers to the different indicies which can
167            be called, e.g: vidyo, evo, mcu etc.
168        """
169        self._idList = self._pathParams['idlist'].split('-')
170
171        if not self._queryParams.has_key('alarms'):
172            self._alarms = None
173        else:
174            self._alarms = get_query_parameter(self._queryParams, ['alarms'], 0, True)
175
176    def export_video(self, aw):
177        expInt = VideoEventFetcher(aw, self)
178        return expInt.video(self._idList, self._alarms)
179
180
181class VideoEventFetcher(DataFetcher):
182    DETAIL_INTERFACES = {
183        'all' : ICollaborationMetadataFossil
184    }
185    ID_TO_IDX = {
186        'all' : 'all',
187        'vidyo' : 'Vidyo',
188        'webcast' : 'WebcastRequest',
189        'recording' : 'RecordingRequest',
190        'mcu' : 'CERNMCU',
191        'evo' : 'EVO'
192    }
193
194    def __init__(self, aw, hook):
195        super(VideoEventFetcher, self).__init__(aw, hook)
196        self._alarm = None
197
198    def _postprocess(self, obj, fossil, iface):
199        if self._alarm is not None:
200            fossil['alarm'] = self._alarm
201
202        return fossil
203
204    def video(self, idList, alarm = None):
205        idx = IndexesHolder().getById('collaboration');
206        bookings = []
207        dateFormat = '%d/%m/%Y'
208        self._alarm = alarm
209
210        for id in idList:
211            tempBookings = idx.getBookings(self.ID_TO_IDX[id], "conferenceStartDate",
212                                           self._orderBy, self._fromDT, self._toDT,
213                                           'UTC', False, None, None, False, dateFormat)
214            bookings.extend(tempBookings.getResults())
215
216        """ Iterate the bookings and yield the results for fossilization, the form
217            by this point should be objs[i] = tuple('arranger', [CSBooking Objects]).
218        """
219        def _iter_bookings(objs):
220            for obj in objs:
221                for bk in obj[1]:
222                    bk._conf = obj[0] # Ensure all CSBookings are aware of their Conference
223
224                    """ This is for plugins whose structure include 'talkSelected',
225                        examples of which in CERN Indico being WebcastRequest and
226                        RecordingRequest.
227                    """
228                    if bk.hasTalkSelection():
229                        ts = bk.getTalkSelectionList()
230                        contributions = []
231
232                        if ts is None: # No individual talks, therefore an event for every contribution
233                            contributions = bk._conf.getContributionList()
234                        else:
235                            for contribId in ts:
236                                tempContrib = bk._conf.getContributionById(contribId)
237                                contributions.append(tempContrib)
238
239                        if len(contributions) == 0: # If we are here, no contributions but a request exists.
240                            bk.setStartDate(bk._conf.getStartDate())
241                            bk.setEndDate(bk._conf.getEndDate())
242                            yield bk
243                        else: # contributions is the list of all to be exported now
244                            for contrib in contributions:
245                                if contrib.isScheduled():
246                                    bk.setStartDate(contrib.getStartDate())
247                                    bk.setEndDate(contrib.getEndDate())
248                                else:
249                                    bk.setStartDate(bk._conf.getStartDate())
250                                    bk.setEndDate(bk._conf.getEndDate())
251                                yield bk
252
253                        continue
254
255                    yield bk
256
257        """ Simple filter, as this method can return None for Pending and True
258            for accepted, both are valid booking statuses for exporting.
259        """
260        def filter(obj):
261            return obj.getAcceptRejectStatus() is not False
262
263        iface = self.DETAIL_INTERFACES.get('all')
264
265        for booking in self._process(_iter_bookings(bookings), filter, iface):
266            yield booking
Note: See TracBrowser for help on using the repository browser.