Changeset d2f974 in indico
- Timestamp:
- 08/23/11 15:38:51 (21 months ago)
- Branches:
- master, hello-world-walkthrough, ipv6, v0.98-series, v0.98.2, v0.98.3, v0.98b2, v0.99, 051b2622c51afb171a1dedb46a0df4fbb0cbd02e, 0da0c1403bae8e51d8229f460181c71b9e6dda72
- Children:
- b18213
- Parents:
- 6ce88b
- git-author:
- Adrian Moennich <jerome.ernst.monnich@…> (05/16/11 16:39:40)
- git-committer:
- Jose Benito <jose.benito.gonzalez@…> (08/23/11 15:38:51)
- Location:
- indico
- Files:
-
- 1 added
- 4 edited
-
MaKaC/plugins/RoomBooking/export.py (added)
-
MaKaC/plugins/base.py (modified) (6 diffs)
-
web/http_api/__init__.py (modified) (1 diff)
-
web/http_api/export.py (modified) (8 diffs)
-
web/http_api/handlers.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
indico/MaKaC/plugins/base.py
r70cbfb rd2f974 488 488 self.__options = {} 489 489 self.__actions = {} 490 self.__exporters = [] 490 491 491 492 self.__usable = False … … 706 707 ############## end of actions related ############### 707 708 709 ############## exporters related ############### 710 def updateAllExporters(self, retrievedPluginExporters): 711 self.__exporters = [] 712 if retrievedPluginExporters is not None: 713 self.__exporters = retrievedPluginExporters 714 self._notifyModification() 715 716 def getExporterList(self): 717 try: 718 return self.__exporters 719 except: 720 self.__exporters = [] 721 return self.__exporters 722 723 ############## end of exporters related ############### 724 708 725 def _notifyModification(self): 709 726 self._p_changed = 1 … … 786 803 p.updateAllActions(pluginModule.actions.pluginActions) 787 804 805 if hasattr(pluginModule, "export") and \ 806 hasattr(pluginModule.options, "globalExporters"): 807 p.updateAllExporters(pluginModule.export.globalExporters) 808 788 809 self._updateComponentInfo(p, pluginModule) 789 810 self._updateHandlerInfo(p, pluginModule) … … 823 844 self.__visible = ptypeMetadata['visible'] 824 845 825 # components, handlers, options and actions846 # components, handlers, options, actions and exporters 826 847 self._updateComponentInfo(self, ptypeModule) 827 848 self._updateRHMapInfo(self, ptypeModule) … … 829 850 self.updateAllOptions(self._retrievePluginTypeOptions()) 830 851 self.updateAllActions(self._retrievePluginTypeActions()) 852 self.updateAllExporters(self._retrievePluginTypeExporters()) 831 853 832 854 … … 893 915 if hasActionsModule and hasPluginTypeActions: 894 916 return self.getModule().actions.pluginTypeActions 917 else: 918 return None 919 920 def _retrievePluginTypeExporters(self): 921 922 hasExportModule = hasattr(self.getModule(), "export") 923 hasGlobalExportersVariable = hasExportModule and hasattr(self.getModule().export, "globalExporters") 924 if hasExportModule and hasGlobalExportersVariable: 925 return self.getModule().export.globalExporters 895 926 else: 896 927 return None -
indico/web/http_api/__init__.py
r276f7e rd2f974 23 23 """ 24 24 25 from indico.web.http_api.export import ExportInterface, LimitExceededException 25 from indico.web.http_api.export import ExportInterface, LimitExceededException, Exporter 26 26 27 27 API_MODE_KEY = 0 # public requests without API key, authenticated requests with api key -
indico/web/http_api/export.py
r6ce88b rd2f974 26 26 import fnmatch 27 27 import itertools 28 import pytz 28 29 import re 29 30 from zope.interface import Interface, implements … … 52 53 from MaKaC.common.info import HelperMaKaCInfo 53 54 from MaKaC.conference import ConferenceHolder 55 from MaKaC.plugins.base import PluginsHolder 54 56 55 57 from indico.web.http_api.util import get_query_parameter, remove_lists … … 68 70 69 71 70 class IExport(Interface): 71 72 def category(cls, idlist, fromDT, toDT, location=None, limit=None, 73 orderBy=None, descending=False, detail="events"): 74 """ 75 TODO: Document this 76 """ 77 78 def event(cls, idlist, orderBy=None, descending=False, detail="events"): 79 """ 80 TODO: Document this 81 """ 72 class Exporter(object): 73 EXPORTER_LIST = [] 74 TYPES = None # abstract 75 RE = None # abstract 76 DEFAULT_DETAIL = None # abstract 77 MAX_RECORDS = None # abstract 78 79 @classmethod 80 def parseRequest(cls, path, qdata): 81 """Parse a request path and return an exporter and the requested data type.""" 82 exporters = itertools.chain(cls.EXPORTER_LIST, cls._getPluginExporters()) 83 for expCls in exporters: 84 m = expCls._matchPath(path) 85 if m: 86 gd = m.groupdict() 87 g = m.groups() 88 type = g[0] 89 format = g[-1] 90 if format not in ExportInterface.getAllowedFormats(): 91 return None, None 92 return expCls(qdata, type, gd), format 93 return None, None 94 95 @staticmethod 96 def register(cls): 97 """Register an exporter that is not part of a plugin. 98 99 To use it, simply decorate the exporter class with this method.""" 100 assert cls.RE is not None 101 Exporter.EXPORTER_LIST.append(cls) 102 return cls 103 104 @classmethod 105 def _matchPath(cls, path): 106 if not hasattr(cls, '_RE'): 107 types = '|'.join(cls.TYPES) 108 cls._RE = re.compile(r'/export/(' + types + r')/' + cls.RE + r'\.(\w+)$') 109 return cls._RE.match(path) 110 111 @classmethod 112 def _getPluginExporters(cls): 113 for plugin in PluginsHolder().getPluginTypes(): 114 for expClsName in plugin.getExporterList(): 115 yield getattr(plugin.getModule().export, expClsName) 116 117 def __init__(self, qdata, type, urlParams): 118 self._qdata = qdata 119 self._type = type 120 self._urlParams = urlParams 121 122 def _getParams(self): 123 self._offset = get_query_parameter(self._qdata, ['O', 'offset'], 0, integer=True) 124 self._orderBy = get_query_parameter(self._qdata, ['o', 'order'], 'start') 125 self._descending = get_query_parameter(self._qdata, ['c', 'descending'], False) 126 self._detail = get_query_parameter(self._qdata, ['d', 'detail'], self.DEFAULT_DETAIL) 127 tzName = get_query_parameter(self._qdata, ['tz'], None) 128 if tzName is None: 129 info = HelperMaKaCInfo.getMaKaCInfoInstance() 130 tzName = info.getTimezone() 131 self._tz = pytz.timezone(tzName) 132 max = self.MAX_RECORDS.get(self._detail, 10000) 133 self._userLimit = get_query_parameter(self._qdata, ['n', 'limit'], 0, integer=True) 134 if self._userLimit > max: 135 raise HTTPAPIError("You can only request up to %d records per request with the detail level '%s'" % 136 (max, self._detail), apache.HTTP_BAD_REQUEST) 137 self._limit = self._userLimit if self._userLimit > 0 else max 138 139 def __call__(self, aw): 140 """Perform the actual exporting""" 141 self._getParams() 142 resultList = [] 143 complete = True 144 145 func = getattr(self, 'export_' + self._type, None) 146 if not func: 147 raise NotImplementedError('export_' + self._type) 148 149 try: 150 for obj in func(aw): 151 resultList.append(obj) 152 except LimitExceededException: 153 complete = (self._limit == self._userLimit) 154 155 return resultList, complete 82 156 83 157 84 158 class ExportInterface(object): 85 implements(IExport)86 87 159 _deltas = {'yesterday': timedelta(-1), 88 160 'tomorrow': timedelta(1)} … … 166 238 if counter >= limit: 167 239 raise LimitExceededException() 168 if obj not in exclude and obj.canAccess(self._aw):240 if obj not in exclude and (not hasattr(obj, 'canAccess') or obj.canAccess(self._aw)): 169 241 self._intermediateResults.append(obj) 170 242 yield obj … … 201 273 @classmethod 202 274 def _getDetailInterface(cls, detail): 275 raise HTTPAPIError('Invalid detail level: %s' % detail, apache.HTTP_BAD_REQUEST) 276 277 def _iterateOver(self, iterator, offset, limit, orderBy, descending, filter=None): 278 """ 279 Iterates over a maximum of `limit` elements, starting at the 280 element number `offset`. The elements will be ordered according 281 to `orderby` and `descending` (slooooow) and filtered by the 282 callable `filter`: 283 """ 284 285 if filter: 286 iterator = itertools.ifilter(filter, iterator) 287 sortedIterator = self._sortedIterator(iterator, limit, orderBy, descending) 288 # Skip offset elements - http://docs.python.org/library/itertools.html#recipes 289 next(itertools.islice(sortedIterator, offset, offset), None) 290 return sortedIterator 291 292 293 @Exporter.register 294 class CategoryEventExporter(Exporter): 295 TYPES = ('event', 'categ') 296 RE = r'(?P<idlist>\w+(?:-\w+)*)' 297 DEFAULT_DETAIL = 'events' 298 MAX_RECORDS = { 299 'events': 10000, 300 'contributions': 500, 301 'subcontributions': 500, 302 'sessions': 100, 303 } 304 305 def _getParams(self): 306 super(CategoryEventExporter, self)._getParams() 307 self._idList = self._urlParams['idlist'].split('-') 308 309 def export_categ(self, aw): 310 expInt = CategoryEventExportInterface(aw) 311 return expInt.category(self._idList, self._tz, self._offset, self._limit, self._detail, self._orderBy, self._descending, self._qdata) 312 313 def export_event(self, aw): 314 expInt = CategoryEventExportInterface(aw) 315 return expInt.event(self._idList, self._tz, self._offset, self._limit, self._detail, self._orderBy, self._descending, self._qdata) 316 317 318 class CategoryEventExportInterface(ExportInterface): 319 @classmethod 320 def _getDetailInterface(cls, detail): 203 321 if detail == 'events': 204 322 return IConferenceMetadataFossil … … 211 329 raise HTTPAPIError('Invalid detail level: %s' % detail, apache.HTTP_BAD_REQUEST) 212 330 213 def _iterateOver(self, iterator, offset, limit, orderBy, descending, filter=None):214 """215 Iterates over a maximum of `limit` elements, starting at the216 element number `offset`. The elements will be ordered according217 to `orderby` and `descending` (slooooow) and filtered by the218 callable `filter`:219 """220 221 if filter:222 iterator = itertools.ifilter(filter, iterator)223 sortedIterator = self._sortedIterator(iterator, limit, orderBy, descending)224 # Skip offset elements - http://docs.python.org/library/itertools.html#recipes225 next(itertools.islice(sortedIterator, offset, offset), None)226 return sortedIterator227 228 331 def category(self, idlist, tz, offset, limit, detail, orderBy, descending, qdata): 229 230 332 fromDT = get_query_parameter(qdata, ['f', 'from']) 231 333 toDT = get_query_parameter(qdata, ['t', 'to']) … … 257 359 258 360 def event(self, idlist, tz, offset, limit, detail, orderBy, descending, qdata): 259 # TODO: use iterators260 261 361 ch = ConferenceHolder() 262 362 … … 271 371 for event in self._iterateOver(_iterate_objs(idlist), offset, limit, orderBy, descending): 272 372 yield fossilize(event, iface, tz=tz) 273 274 373 275 374 Serializer.register('html', HTML4Serializer) -
indico/web/http_api/handlers.py
r6ce88b rd2f974 26 26 import hashlib 27 27 import hmac 28 import itertools 28 29 import re 29 30 import time … … 34 35 35 36 # indico imports 36 from indico.web.http_api import ExportInterface, LimitExceededException 37 from indico.web.http_api import ExportInterface, LimitExceededException, Exporter 37 38 from indico.web.http_api.auth import APIKeyHolder 38 39 from indico.web.http_api.cache import RequestCache … … 48 49 from MaKaC.accessControl import AccessWrapper 49 50 from MaKaC.common.info import HelperMaKaCInfo 51 from MaKaC.plugins.base import PluginsHolder 50 52 51 53 # Maximum number of records that will get exported for each detail level … … 130 132 return aw 131 133 132 133 def getExportHandler(path):134 """Get the export handler, handler args and return type from a path"""135 func = None136 match = None137 for pathRe, handlerFunc in EXPORT_URL_MAP.iteritems():138 match = pathRe.match(path)139 if match:140 func = handlerFunc141 break142 143 groups = match and match.groups()144 if not match or groups[-1] not in ExportInterface.getAllowedFormats():145 return None, None, None146 return globals()[func], groups[:-1], groups[-1]147 148 149 def handler_event_categ(aw, qdata, dtype, idlist):150 idlist = idlist.split('-')151 152 expInt = ExportInterface(aw)153 tzName = get_query_parameter(qdata, ['tz'], None)154 detail = get_query_parameter(qdata, ['d', 'detail'], 'events')155 userLimit = get_query_parameter(qdata, ['n', 'limit'], 0, integer=True)156 offset = get_query_parameter(qdata, ['O', 'offset'], 0, integer=True)157 orderBy = get_query_parameter(qdata, ['o', 'order'], 'start')158 descending = get_query_parameter(qdata, ['c', 'descending'], False)159 160 if tzName is None:161 info = HelperMaKaCInfo.getMaKaCInfoInstance()162 tzName = info.getTimezone()163 164 tz = pytz.timezone(tzName)165 166 max = MAX_RECORDS.get(detail, 10000)167 if userLimit > max:168 raise HTTPAPIError("You can only request up to %d records per request with the detail level '%s" %169 (max, detail), apache.HTTP_BAD_REQUEST)170 171 # impose a hard limit172 limit = userLimit if userLimit > 0 else max173 174 if dtype == 'categ':175 iterator = expInt.category(idlist, tz, offset, limit, detail, orderBy, descending, qdata)176 elif dtype == 'event':177 iterator = expInt.event(idlist, tz, offset, limit, detail, orderBy, descending, qdata)178 179 resultList = []180 complete = True181 182 try:183 for obj in iterator:184 resultList.append(obj)185 except LimitExceededException:186 complete = (limit == userLimit)187 188 return resultList, complete189 190 134 def handler(req, **params): 191 135 path, query = req.URLFields['PATH_INFO'], req.URLFields['QUERY_STRING'] … … 206 150 207 151 # Get our handler function and its argument and response type 208 func, args, dformat = getExportHandler(path)152 func, dformat = Exporter.parseRequest(path, qdata) 209 153 if func is None or dformat is None: 210 154 raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND … … 236 180 if result is None: 237 181 # Perform the actual exporting 238 result, complete = func(aw , qdata, *args)182 result, complete = func(aw) 239 183 if result is not None and add_to_cache: 240 184 cache.cacheObject(cache_key, (result, complete))
Note: See TracChangeset
for help on using the changeset viewer.
