Changeset 2f5998 in indico
- Timestamp:
- 01/18/11 19:53:45 (2 years ago)
- Branches:
- master, burotel, hello-world-walkthrough, ipv6, v0.98-series, v0.98.2, v0.98.3, v0.98b1, v0.98b2, v0.99, 051b2622c51afb171a1dedb46a0df4fbb0cbd02e, d9941f8582b36b24821a11ea5ba16fda6a457fb1
- Children:
- 1845d0
- Parents:
- 869ccc
- git-author:
- Cesar Munoz Orena <cesar.munoz.orena@…> (12/15/10 17:27:01)
- git-committer:
- Jose Benito <jose.benito.gonzalez@…> (01/18/11 19:53:45)
- Files:
-
- 2 added
- 25 edited
-
bin/migration/migrate_0.97_0.98.py (modified) (1 diff)
-
indico/MaKaC/common/Configuration.py (modified) (1 diff)
-
indico/MaKaC/common/TemplateExec.py (modified) (2 diffs)
-
indico/MaKaC/plugins/Collaboration/actions.py (modified) (1 diff)
-
indico/MaKaC/plugins/InstantMessaging/XMPP/bot.py (modified) (2 diffs)
-
indico/MaKaC/plugins/InstantMessaging/XMPP/components.py (modified) (4 diffs)
-
indico/MaKaC/plugins/InstantMessaging/XMPP/ext/code.py (added)
-
indico/MaKaC/plugins/InstantMessaging/XMPP/handlers.py (modified) (7 diffs)
-
indico/MaKaC/plugins/InstantMessaging/XMPP/options.py (modified) (2 diffs)
-
indico/MaKaC/plugins/InstantMessaging/__init__.py (modified) (1 diff)
-
indico/MaKaC/plugins/InstantMessaging/indexes.py (modified) (1 diff)
-
indico/MaKaC/plugins/InstantMessaging/options.py (modified) (1 diff)
-
indico/MaKaC/plugins/InstantMessaging/pages.py (modified) (4 diffs)
-
indico/MaKaC/plugins/InstantMessaging/rh.py (modified) (2 diffs)
-
indico/MaKaC/plugins/base.py (modified) (16 diffs)
-
indico/MaKaC/plugins/helpers.py (modified) (3 diffs)
-
indico/MaKaC/plugins/loader.py (modified) (6 diffs)
-
indico/MaKaC/plugins/util.py (modified) (4 diffs)
-
indico/MaKaC/webinterface/stylesheets/include/indico.xsl (modified) (2 diffs)
-
indico/MaKaC/webinterface/tpls/AdminPlugins.tpl (modified) (2 diffs)
-
indico/MaKaC/webinterface/tpls/AdminPluginsMainTab.tpl (modified) (2 diffs)
-
indico/MaKaC/webinterface/tpls/AdminPluginsOptionList.tpl (modified) (3 diffs)
-
indico/MaKaC/webinterface/tpls/ConfModifChat.tpl (modified) (1 diff)
-
indico/MaKaC/webinterface/tpls/ConferenceInstantMessaging.tpl (modified) (3 diffs)
-
indico/htdocs/css/Default.css (modified) (1 diff)
-
indico/htdocs/images/greyedOutSection.png (added)
-
indico/htdocs/js/indico/Plugins/InstantMessaging.js (modified) (16 diffs)
Legend:
- Unmodified
- Added
- Removed
-
bin/migration/migrate_0.97_0.98.py
r43f6a0 r2f5998 54 54 55 55 56 def runPluginMigration(): 57 58 # TODO: for each Plugin/PluginType, add __notUsableReason attribute (default None) 59 56 60 def main(): 57 61 runTaskMigration() -
indico/MaKaC/common/Configuration.py
ra755c1 r2f5998 160 160 "enabledSection": "enabledSection.png", 161 161 "disabledSection": "disabledSection.png", 162 "greyedOutSection": "greyedOutSection.png", 162 163 "tick": "tick.png", 163 164 "cross": "cross.png", -
indico/MaKaC/common/TemplateExec.py
r565750f r2f5998 34 34 import MaKaC.common.info as info 35 35 36 36 from MaKaC.common.logger import Logger 37 37 38 38 … … 404 404 try: open( ERROR_PATH + "/" + tplFilename + ".tpl.py", "w" ).write( pythonCode ) 405 405 except: pass 406 Logger.get('tplexec').exception('Template error') 406 407 raise 407 408 except Exception, e: -
indico/MaKaC/plugins/Collaboration/actions.py
r7abf81 r2f5998 59 59 commonIndexes = {} 60 60 plugins = self._pluginType.getPluginList(doSort = True, includeNonActive = True) 61 pluginNames = [p.get Name() for p in plugins]61 pluginNames = [p.getId() for p in plugins if p.isActive()] 62 62 63 63 for pluginName in pluginNames: -
indico/MaKaC/plugins/InstantMessaging/XMPP/bot.py
rbc991f r2f5998 24 24 25 25 from MaKaC.services.interface.rpc.common import ServiceError, NoReportError 26 from MaKaC.i18n import _ 26 27 27 28 class IndicoXMPPBotBase(object): … … 55 56 def treatError(self, error, msg=''): 56 57 """ Gets the response from the XMPP driver and, in case of error, returns the appropiate message""" 57 return {'error':error, 'reason':msg if msg!= '' else 'There was a problem while connecting our XMPP server. Please try again later'}58 return {'error':error, 'reason':msg if msg!= '' else _('There was a problem while connecting our XMPP server. Please try again later')} 58 59 59 60 def run(self): -
indico/MaKaC/plugins/InstantMessaging/XMPP/components.py
r869ccc r2f5998 23 23 from MaKaC.plugins.base import Observable, PluginsHolder 24 24 from MaKaC.plugins.util import PluginsWrapper, PluginFieldsWrapper 25 from MaKaC.plugins.helpers import DBHelpers, MailHelper, DesktopLinkGenerator, WebLinkGenerator,GeneralLinkGenerator25 from MaKaC.plugins.helpers import DBHelpers, MailHelper, GeneralLinkGenerator 26 26 from MaKaC.plugins.InstantMessaging.indexes import IndexByConf, IndexByCRName, IndexByID, IndexByUser 27 27 from MaKaC.plugins.InstantMessaging.Chatroom import XMPPChatroom … … 39 39 from MaKaC.services.interface.rpc.common import ServiceError, NoReportError 40 40 import zope.interface 41 import random42 41 43 42 … … 99 98 out.writeTag("createdInLocalServer", chatroom.getCreatedInLocalServer()) 100 99 out.openTag("links") 101 if DesktopLinkGenerator(chatroom).isActive() or WebLinkGenerator(chatroom).isActive() orlinksList.__len__() > 0:100 if linksList.__len__() > 0: 102 101 out.writeTag("linksToShow", 'true') 103 102 else: 104 103 out.writeTag("linksToShow", 'false') 105 106 if DesktopLinkGenerator(chatroom).isActive():107 out.writeTag("desktop", DesktopLinkGenerator(chatroom).generate())108 else:109 out.writeTag("desktop", 'false')110 111 if WebLinkGenerator(chatroom).isActive():112 out.writeTag("web", WebLinkGenerator(chatroom).generate())113 else:114 out.writeTag("web", 'false')115 104 116 105 for link in linksList: … … 282 271 room = params['room'] 283 272 conf = ConferenceHolder().getById(params['conf']) 284 #without the randomnumber added it would only send 1 mail, because for every new chat room it'd think that there has been a retry285 ExternalOperationsManager.execute(cls, "add_"+str(cls.__class__)+str(r andom.random()), cls.performOperation, 'create', conf, room, room, conf)273 #without the number added it would only send 1 mail, because for every new chat room it'd think that there has been a retry 274 ExternalOperationsManager.execute(cls, "add_"+str(cls.__class__)+str(room.getId()), cls.performOperation, 'create', conf, room, room, conf) 286 275 287 276 @classmethod -
indico/MaKaC/plugins/InstantMessaging/XMPP/handlers.py
r869ccc r2f5998 21 21 22 22 import urllib2, datetime, os, tempfile, stat 23 from MaKaC.webinterface import urlHandlers 23 24 from MaKaC.plugins.InstantMessaging.Chatroom import XMPPChatroom 24 25 from MaKaC.plugins.InstantMessaging.handlers import ChatroomBase … … 33 34 from MaKaC.plugins import Observable 34 35 from MaKaC.plugins.util import PluginFieldsWrapper 35 from MaKaC.plugins.helpers import DBHelpers, MailHelper, DeleteLogLinkGenerator, LogLinkGenerator 36 from MaKaC.plugins.helpers import DBHelpers, MailHelper, DeleteLogLinkGenerator, LogLinkGenerator, generateCustomLinks, generateLogLink, XMPPLogsActivated 37 from MaKaC.i18n import _ 36 38 37 39 from MaKaC.plugins.InstantMessaging.XMPP.bot import IndicoXMPPBotRoomExists, IndicoXMPPBotCreateRoom, IndicoXMPPBotEditRoom, IndicoXMPPBotDeleteRoom, IndicoXMPPBotGetPreferences … … 150 152 return self.proccessAnswer(self._bot) 151 153 152 def _executeExternalOperation(self, bot, operName, messageName): 153 """ we need the instance of the XMPP operation we're going to do, and also its name. 154 Finally, we'll need the name of the error message to show in case something happens""" 155 154 def addLinks2FossilizedCR(fossilizedRoom, room): 155 """ Adds the neccesary links to retrieve logs and also to join the chat room through all the links specified by the user""" 156 # add links to join the room 157 generateCustomLinks(fossilizedRoom, room) 158 # add link to retrieve logs 159 generateLogLink(fossilizedRoom, room, room.getConference() if len(room.getConferences()) is 1 else room.getConference().values()[0]) 160 161 return True 156 162 157 163 class CreateChatroom( XMPPChatroomService ): … … 199 205 200 206 ContextManager.get('mailHelper').sendMails() 201 return self._room.fossilize(tz=tz) 207 fossilizedRoom = self._room.fossilize(tz=tz) 208 addLinks2FossilizedCR(fossilizedRoom, self._room) 209 210 return fossilizedRoom 202 211 203 212 … … 313 322 314 323 # make the log folder unaccessible in the future 315 url = DeleteLogLinkGenerator(self._room).generate() 316 req = urllib2.Request(url, None, {'Accept-Charset' : 'utf-8'}) 317 document = urllib2.urlopen(req) 318 Logger.get('InstantMessaging (XMPP-Indico server)').info("The room %s has been deleted by the user %s at %s hours" %(self._title, self._user.getName(), nowutc())) 324 if len(self._room.getConferences()) is 0: 325 # we only "delete" logs when there are no conferences associated with the chat room 326 url = DeleteLogLinkGenerator(self._room).generate() 327 req = urllib2.Request(url, None, {'Accept-Charset' : 'utf-8'}) 328 document = urllib2.urlopen(req) 329 Logger.get('InstantMessaging (XMPP-Indico server)').info("The room %s has been deleted by the user %s at %s hours" %(self._title, self._user.getName(), nowutc())) 319 330 320 331 ContextManager.get('mailHelper').sendMails() … … 345 356 # this method will fill the self._bot._form attr 346 357 self.roomPreferencesXMPP(self._botJID, self._botPass, self._room) 347 348 358 #get the preferences and check updates 349 for preference in self._bot._form. fields:350 if preference .varin fieldsToCheck.keys():359 for preference in self._bot._form.values['fields']: 360 if preference[0] in fieldsToCheck.keys(): 351 361 #we execute setDescription or setPassword with the new value 352 getattr(self._room, 'set'+ fieldsToCheck[preference .var])(preference.value.pop())362 getattr(self._room, 'set'+ fieldsToCheck[preference[0]])(preference[1].values['value']) 353 363 354 364 return self._room.fossilize() … … 389 399 room.setConference(ConferenceHolder().getById(self._conference)) 390 400 self._notify('addConference2Room', {'room': room, 'conf': self._conference}) 391 rooms.append(room.fossilizeMultiConference(ConferenceHolder().getById(self._conference))) 401 fossilizedRoom = room.fossilizeMultiConference(ConferenceHolder().getById(self._conference)) 402 addLinks2FossilizedCR(fossilizedRoom, room) 403 rooms.append(fossilizedRoom) 392 404 except NoReportError, e: 393 405 Logger.get('InstantMessaging (XMPP-Indico server)').error("Error adding chat rooms. User: %s. Chat room: %s. Traceback: %s" %(self._aw.getUser().getFullName(), roomID, e)) -
indico/MaKaC/plugins/InstantMessaging/XMPP/options.py
rc1435a r2f5998 57 57 "defaultValue": "<table width=\"100%\" align=\"center\" border=\"0\">\ 58 58 <tr>\ 59 <td class=\"groupTitle\" style=\"padding-top:50px\">How to connect to the chat</td>\59 <td class=\"groupTitle\">How to connect to the chat</td>\ 60 60 </tr>\ 61 61 <tr>\ … … 71 71 </table>"}), 72 72 73 ("joinDesktopClients", {"description": _("Show a link to join a chat room through desktop clients, like Pidgin"), 73 ("activateLogs", {"description": _("Make possible to see chat logs and attach them to the material \ 74 \ 75 REMEMBER, you will need to put in the Jappix dir the code.py file contained in the ext folder, inside the XMPP plugin."), 74 76 "type": bool, 75 "defaultValue": True, 76 "editable": True, 77 "visible": True}), 78 ("joinWebClient", {"description": _("Show a link to join a chat room through our web client"), 79 "type": bool, 80 "defaultValue": True, 77 "defaultValue": False, 81 78 "editable": True, 82 79 "visible": True}) 80 # ("joinWebClient", {"description": _("Show a link to join a chat room through our web client"), 81 # "type": bool, 82 # "defaultValue": True, 83 # "editable": True, 84 # "visible": True}) 83 85 ] -
indico/MaKaC/plugins/InstantMessaging/__init__.py
rc1435a r2f5998 24 24 __metadata__ = { 25 25 'name': "Instant Messaging", 26 'description': _("Instant Messaging Plugins") 26 'description': _("Instant Messaging Plugins"), 27 'requires': ['sleekxmpp'] 27 28 } -
indico/MaKaC/plugins/InstantMessaging/indexes.py
rc1435a r2f5998 25 25 from persistent import Persistent 26 26 from MaKaC.plugins.util import PluginFieldsWrapper 27 from MaKaC.i18n import _ 27 28 28 29 class IMIndex(Persistent): -
indico/MaKaC/plugins/InstantMessaging/options.py
r869ccc r2f5998 24 24 ("customLinks", {"description": _("Create your own links to the chat rooms"), 25 25 "type": 'links', 26 "defaultValue": [ ],26 "defaultValue": [{'name': 'your desktop client', 'structure': 'xmpp:*chatroom*@*host*?join'}], 27 27 "editable": True, 28 28 "visible": True}) -
indico/MaKaC/plugins/InstantMessaging/pages.py
r869ccc r2f5998 30 30 from MaKaC.plugins.util import PluginFieldsWrapper 31 31 from MaKaC.webinterface.rh.conferenceModif import RHMaterialsShow 32 from MaKaC.plugins.helpers import GeneralLinkGenerator 32 from MaKaC.plugins.helpers import generateCustomLinks, generateLogLink, XMPPLogsActivated 33 from MaKaC.i18n import _ 33 34 34 35 … … 113 114 chatrooms = {} 114 115 vars['links'] = {} 116 115 117 for cr in chatrooms: 116 118 vars['links'][cr.getId() ] = {} 117 if PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinDesktopClients'): 118 vars['links'][cr.getId()]['web'] = DesktopLinkGenerator(cr).generate() 119 if PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinWebClient'): 120 vars['links'][cr.getId()]['desktop'] = WebLinkGenerator(cr).generate() 121 122 vars['links'][cr.getId()]['logs'] = urlHandlers.UHConfModifChatSeeLogs.getURL(self._conf) 123 vars['links'][cr.getId()]['logs'].addParam('chatroom', cr.getId()) 124 vars['links'][cr.getId()]['logs'] = vars['links'][cr.getId()]['logs'].__str__() 119 generateCustomLinks(vars["links"][cr.getId()], cr) 120 generateLogLink(vars["links"][cr.getId()], cr, self._conf) 125 121 126 122 vars['DefaultServer'] = PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('chatServerHost') … … 129 125 vars["tz"] = DisplayTZ(self._aw,self._conf).getDisplayTZ() 130 126 vars["MaterialUrl"] = RHMaterialsShow._uh().getURL(self._conf).__str__() 127 vars["ShowLogsLink"] = XMPPLogsActivated() 131 128 132 129 return vars … … 151 148 vars["Chatrooms"] = None 152 149 vars["Links"] = {} 153 linksList = PluginsHolder().getPluginType('InstantMessaging').getOption('customLinks').getValue()154 150 for cr in vars["Chatrooms"]: 155 151 vars["Links"][cr.getId()] = {} 156 for link in linksList: 157 self.addLink(vars["Links"], link['name'], GeneralLinkGenerator(cr, link['structure']).generate(), cr.getId()) 158 159 #in case it's neccesary, generate for web clients and desktop clients 160 if DesktopLinkGenerator(cr).isActive(): 161 self.addLink(vars["Links"], 'your desktop client', DesktopLinkGenerator(cr).generate(), cr.getId()) 162 if WebLinkGenerator(cr).isActive(): 163 self.addLink(vars["Links"], 'web client', WebLinkGenerator(cr).generate(), cr.getId()) 152 generateCustomLinks(vars["Links"][cr.getId()], cr) 164 153 165 154 return vars 166 155 167 def addLink(self, var, linkName, link, chatroomId):168 """ Adds a link to the chat room if it's specified to do so"""169 var[chatroomId][linkName] = {}170 var[chatroomId][linkName]['name'] = linkName171 var[chatroomId][linkName]['link'] = link172 -
indico/MaKaC/plugins/InstantMessaging/rh.py
r4bd938 r2f5998 27 27 from MaKaC.webinterface.rh.conferenceDisplay import RHConferenceBaseDisplay 28 28 from MaKaC.webinterface.rh.conferenceModif import RHConferenceModifBase 29 from MaKaC.i18n import _ 29 30 import urllib2 30 31 … … 85 86 req = urllib2.Request(url, None, {'Accept-Charset' : 'utf-8'}) 86 87 document = urllib2.urlopen(req).read() 88 if document is '': 89 return _('No logs were found for these dates') 87 90 return document 88 91 -
indico/MaKaC/plugins/base.py
r869ccc r2f5998 341 341 ptypes = PluginLoader.getPluginTypeList() 342 342 343 for p luginTypeNamein ptypes:344 345 if self.hasPluginType(p luginTypeName, mustBePresent=False, mustBeActive=False):346 p luginType = self.getPluginType(pluginTypeName)347 p luginType.setPresent(True)343 for ptypeId in ptypes: 344 345 if self.hasPluginType(ptypeId, mustBePresent=False, mustBeActive=False): 346 ptype = self.getPluginType(ptypeId) 347 ptype.setPresent(True) 348 348 else: 349 pluginType = PluginType(pluginTypeName) 350 self.add(pluginType) 351 pluginType.updateInfo() 349 ptype = PluginType(ptypeId) 350 self.add(ptype) 351 352 ptype.configureFromMetadata(processPluginMetadata(ptype.getModule())) 353 missingDeps = ptype.getModule().__missing_deps__ 354 355 # if there are dependencies missing, set as not usable 356 if len(missingDeps) > 0: 357 ptype.setUsable(False, reason = "Dependencies missing: %s " % \ 358 missingDeps) 359 if ptype.isActive(): 360 ptype.setActive(False) 361 else: 362 ptype.setUsable(True) 363 364 ptype.updateInfo() 352 365 353 366 def clearPluginInfo(self): … … 373 386 374 387 def hasPluginType(self, name, mustBePresent=True, mustBeActive=True): 375 """ Returns True if there is a PluginType with the given name. 388 """ 389 Returns True if there is a PluginType with the given name. 376 390 """ 377 391 if self.hasKey(name): … … 451 465 self.__actions = {} 452 466 467 self.__usable = False 468 453 469 ############## actions related ############### 454 470 @classmethod … … 665 681 self._p_changed = 1 666 682 683 def setUsable(self, value, reason = ''): 684 self.__notUsableReason = None if value else reason 685 686 def getNotUsableReason(self): 687 return self.__notUsableReason 688 689 def isUsable(self): 690 return self.__notUsableReason == None 691 667 692 668 693 class PluginType (PluginBase): … … 671 696 """ 672 697 673 def __init__(self, name, description=None):698 def __init__(self, ptypeId, description=None): 674 699 """ Constructor 675 700 -name: a string with the type name. e.g. "Collaboration" … … 680 705 """ 681 706 PluginBase.__init__(self) 682 self.__id = name683 self.__name = name707 self.__id = ptypeId 708 self.__name = ptypeId 684 709 self.__description = description 685 710 self.__present = True … … 688 713 self._active = False 689 714 690 def _updatePluginInfo(self, pluginModule, metadata):691 692 #if it already existed, we mark it as present 693 pluginName = metadata['name']694 695 if self.hasPlugin(p luginName):696 p = self.getPlugin(p luginName)715 def configureFromMetadata(self, metadata): 716 self.__name = metadata['name'] 717 718 def _updatePluginInfo(self, pid, pluginModule, metadata): 719 720 if self.hasPlugin(pid): 721 p = self.getPlugin(pid) 697 722 p.setDescription(metadata['description']) 698 723 p.setPresent(True) … … 700 725 #if it didn't exist, we create it 701 726 else: 702 p = Plugin(p luginName,727 p = Plugin(pid, 703 728 pluginModule.__name__, 704 729 self, … … 707 732 self.addPlugin(p) 708 733 709 p.setTestPlugin(metadata['testPlugin']) 710 711 if hasattr(pluginModule, "options") and \ 712 hasattr(pluginModule.options, "globalOptions"): 713 p.updateAllOptions(pluginModule.options.globalOptions) 714 715 if hasattr(pluginModule, "actions") and \ 716 hasattr(pluginModule.actions, "pluginActions"): 717 p.updateAllActions(pluginModule.actions.pluginActions) 718 719 self._updateComponentInfo(p, pluginModule) 720 self._updateRHMapInfo(p, pluginModule) 721 self._updateHandlerInfo(p, pluginModule) 734 p.configureFromMetadata(processPluginMetadata(p.getModule())) 735 736 missingDeps = p.getModule().__missing_deps__ 737 738 if len(missingDeps) > 0: 739 p.setUsable(False, reason = "Dependencies missing: %s " % missingDeps) 740 741 if p.isActive(): 742 p.setActive(False) 743 744 else: 745 p.setUsable(True) 746 747 # only set options, actions, components and handlers if plugin is active 748 if p.isActive(): 749 if hasattr(pluginModule, "options") and \ 750 hasattr(pluginModule.options, "globalOptions"): 751 p.updateAllOptions(pluginModule.options.globalOptions) 752 753 if hasattr(pluginModule, "actions") and \ 754 hasattr(pluginModule.actions, "pluginActions"): 755 p.updateAllActions(pluginModule.actions.pluginActions) 756 757 self._updateComponentInfo(p, pluginModule) 758 self._updateRHMapInfo(p, pluginModule) 759 self._updateHandlerInfo(p, pluginModule) 722 760 723 761 def updateInfo(self): … … 742 780 continue 743 781 else: 744 self._updatePluginInfo(pluginModule, metadata) 782 self._updatePluginInfo(pluginModule.__name__.split('.')[-1], 783 pluginModule, 784 metadata) 745 785 746 786 ptypeModule = self.getModule() … … 753 793 754 794 # components, handlers, options and actions 755 self._updateComponentInfo(self, ptypeModule) 756 self._updateRHMapInfo(self, ptypeModule) 757 self._updateHandlerInfo(self, ptypeModule) 758 self.updateAllOptions(self._retrievePluginTypeOptions()) 759 self.updateAllActions(self._retrievePluginTypeActions()) 795 if self.isActive(): 796 # components, handlers, options and actions 797 self._updateComponentInfo(self, ptypeModule) 798 self._updateRHMapInfo(self, ptypeModule) 799 self._updateHandlerInfo(self, ptypeModule) 800 self.updateAllOptions(self._retrievePluginTypeOptions()) 801 self.updateAllActions(self._retrievePluginTypeActions()) 760 802 761 803 … … 924 966 925 967 926 def __init__(self, name, moduleName, owner, description=None, active=False):968 def __init__(self, pid, moduleName, owner, description=None, active=False): 927 969 """ Constructor 928 970 -moduleName: the module name corresponding to this plugin. e.g. "MaKaC.plugins.Collaboration.EVO" … … 938 980 """ 939 981 PluginBase.__init__(self) 940 self.__name = name 982 self.__name = pid 983 self.__id = pid 941 984 self.__owner = owner 942 985 self.__present = True … … 948 991 self._storage = OOBTree() # storage..... 949 992 993 def configureFromMetadata(self, metadata): 994 self.__name = metadata['name'] 995 self._testPlugin = metadata['testPlugin'] 996 950 997 def getId(self): 951 return self.__ name998 return self.__id 952 999 953 1000 def getName(self): … … 967 1014 968 1015 def getModule(self): 969 return PluginLoader.getPluginByTypeAnd Name(self.getType(), self.getName())1016 return PluginLoader.getPluginByTypeAndId(self.getType(), self.getId()) 970 1017 971 1018 def getType(self): 972 return self.getOwner().get Name()1019 return self.getOwner().getId() 973 1020 974 1021 def hasDescription(self): … … 986 1033 def setActive(self, value): 987 1034 self.__active = value 988 if value is True:989 # register the components related to the plugin1035 if value: 1036 # register the components related to the plugin 990 1037 PluginsHolder().getComponentsManager().addPlugin(self.getName()) 991 1038 else: 992 # unregister the components related to the plugin1039 # unregister the components related to the plugin 993 1040 PluginsHolder().getComponentsManager().cleanPlugin(self.getName()) 994 1041 995 1042 def toggleActive(self): 996 if not self.isActive(): 997 self.__active = True 998 #register the components related to the plugin 999 PluginsHolder().getComponentsManager().addPlugin(self.getName()) 1000 else: 1001 self.__active = False 1002 #unregister the components related to the plugin 1003 PluginsHolder().getComponentsManager().cleanPlugin(self.getName()) 1004 1005 def setTestPlugin(self, testPlugin): 1006 self._testPlugin = testPlugin 1043 self.setActive(not self.isActive()) 1007 1044 1008 1045 def isTestPlugin(self): -
indico/MaKaC/plugins/helpers.py
r869ccc r2f5998 23 23 from MaKaC.services.interface.rpc.common import ServiceError, NoReportError 24 24 from MaKaC.plugins.util import PluginFieldsWrapper 25 from MaKaC.webinterface import urlHandlers 25 26 from MaKaC.plugins.InstantMessaging.indexes import CounterIndex, IndexByConf, IndexByID, IndexByUser 27 from MaKaC.i18n import _ 26 28 27 29 import string … … 132 134 def generate(self): 133 135 # we're not converting to lowercase because it might depend on the protocol 134 linkWithoutNick = string.replace(string.replace(self._structure, ' /chatroom/', self._chatroom.getTitle()), '/host/', self._chatroom.getHost())136 linkWithoutNick = string.replace(string.replace(self._structure, '*chatroom*', self._chatroom.getTitle()), '*host*', self._chatroom.getHost()) 135 137 if self._nick: 136 return string.replace(linkWithoutNick, ' /nickname/', self._nick)138 return string.replace(linkWithoutNick, '*nickname*', self._nick) 137 139 else: 138 140 return linkWithoutNick 141 142 def generateCustomLinks(var, chatroom): 143 linkList = PluginFieldsWrapper('InstantMessaging').getOption('customLinks') 144 # if some link type is specified 145 if linkList.__len__() > 0: 146 var['custom'] = [] 147 for link in linkList: 148 addLink(var['custom'], link['name'], GeneralLinkGenerator(chatroom, link['structure']).generate(), chatroom.getId()) 149 150 def generateLogLink(var, chatroom, conf): 151 if XMPPLogsActivated(): 152 var['logs'] = urlHandlers.UHConfModifChatSeeLogs.getURL(conf) 153 var['logs'].addParam('chatroom', chatroom.getId()) 154 var['logs'] = var['logs'].__str__() 155 156 def XMPPLogsActivated(): 157 return PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('activateLogs') 158 159 def addLink(var, linkName, link, chatroomId): 160 """ Adds a link to the chat room if it's specified to do so""" 161 clink = {} 162 clink['name'] = linkName 163 clink['link'] = link 164 var.append(clink) 165 139 166 140 167 class WebLinkGenerator(LinkGenerator): … … 165 192 def isActive(self): 166 193 return PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinDesktopClients') 194 167 195 168 196 class LogLinkGenerator(LinkGenerator): -
indico/MaKaC/plugins/loader.py
rc1435a r2f5998 18 18 ## along with CDS Indico; if not, write to the Free Software Foundation, Inc., 19 19 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 20 import os 21 import sys 20 21 """ 22 This module defines the PluginLoader class, that is responsible for providing methods 23 that allow loading plugins from the python path, and cataloguing them accordingly 24 """ 25 26 # system imports 27 import os, sys, pkg_resources 28 29 # database 30 from persistent import Persistent 31 32 # legacy MaKaC imports 22 33 from MaKaC.common.logger import Logger 34 from MaKaC.errors import PluginError 35 36 # package 23 37 from MaKaC.plugins.util import processPluginMetadata 24 38 25 from persistent import Persistent26 27 from MaKaC.errors import PluginError28 39 29 40 class ModuleLoadException(Exception): … … 31 42 32 43 class PluginLoader(object): 33 """ Utility class that has methods to deal with plugins at low level.34 35 There is an important class variable "_pluginsLoaded" that will store if the plugins have already been loaded in this request.36 Sometimes a single request will need information about the plugins multiple times, in this way they are only loaded once.37 Ideally plugins should only be loaded once during the execution time of the Apache Server but different request don't38 (normally) share memory so this variable will (normally) start with a value of False.39 However sometimes it happens that the value of this variable can be True at the beginning of a request, and plugins are40 already loaded into memory. It is not clear when this happens; probably it depends on the execution model of Apache41 (prefork or multithread). Even with prefork, sometimes Apache (or mod_python) seems to recycle processes from one request42 to the next and the plugins will be in memory at the beginning of a request.43 44 Methods that should be used from outside:45 -loadPlugins: explores the subfolder structure of the MaKaC/plugins folder and loads the plugins into memory.46 the modules are stored into the class attribute "pluginList"47 the dictionaries with the plugin options, if existant, are stored into the class attribute "pluginTypeOptions"48 the plugin descriptions, if existant, are stored into the class attribute "pluginTypeDescriptions"49 -reloadPlugins: forces to reload the plugins if they are already in memory50 -reloadPluginType: forces to reload plugins if they are already in memory, but only those of a given type (e.g. "epayment", "Collaboration").51 -getPluginByTypeAndName: given a type (e.g. "Collaboration"), and a name (e.g. "EVO"), a module object corresponding to that plugin is returned52 -getPluginType: given a type (e.g. "Collaboration"), a module object corresponding to that plugin type is returned53 -getTypeList: returns a list of strings with the plugin types (e.g. ["epayment", "Collaboration"]54 44 """ 55 56 # A dictionary where the keys are plugin type names (e.g. "Collaboration", "RoomBooking", 45 Loads the plugins/types from the source code. Execution of the contained methods 46 should be avoided (currently invoked manually), as it is naturally slow. 47 48 TODO: Use setuptools extension points? 49 """ 50 51 # A dictionary where the keys are plugin type names 57 52 # and the values are modules (e.g. MaKaC.plugins.Collaboration) 58 pluginTypeModules = {} 59 60 # A dictionary where the keys are plugin type names (e.g. "Collaboration", "RoomBooking", 61 # and the values are also dictionaries. 62 # These second-level dictionaries have plugin names as keys (e.g. "EVO", "Vidyo"), 63 # and python module objects as values 64 pluginModules = {} 65 66 pluginTypesLoaded = set() 67 68 pluginsDir = os.path.abspath(sys.modules["MaKaC.plugins"].__path__[0]) 53 _ptypeModules = {} 54 55 # A dictionary where the keys are plugin type names 56 # and the values are plugin module dictionaries (plugin_name:module). 57 _pmodules = {} 58 59 _ptypesLoaded = set() 60 _pluginsDir = os.path.abspath(sys.modules["MaKaC.plugins"].__path__[0]) 69 61 70 62 @classmethod 71 63 def loadPlugins(cls): 72 """ Explores the subfolder structure of the MaKaC/plugins folder and loads the plugins into memory. 73 The modules are stored into the class attribute "pluginModules" 74 The dictionaries with the plugin options, if existant, are stored into the class attribute "pluginTypeOptions" 75 The plugin descriptions, if existant, are stored into the class attribute "pluginTypeDescriptions" 64 """ 65 Explores the subfolder structure of the MaKaC/plugins folder and loads the 66 plugins into memory. 76 67 """ 77 68 78 69 #we loop through all the files and folders of indico/MaKaC/plugins/ 79 for itemName in os.listdir(cls. pluginsDir):70 for itemName in os.listdir(cls._pluginsDir): 80 71 #we only go deeper for folders 81 if os.path.isdir(os.path.join(cls. pluginsDir, itemName)):82 if not itemName in cls. pluginTypesLoaded:72 if os.path.isdir(os.path.join(cls._pluginsDir, itemName)): 73 if not itemName in cls._ptypesLoaded: 83 74 cls.loadPluginType(itemName) 84 cls. pluginTypesLoaded.add(itemName)75 cls._ptypesLoaded.add(itemName) 85 76 86 77 @classmethod 87 78 def reloadPlugins(cls): 88 """ Forces to reload the plugins if they are already in memory 89 """ 90 cls.pluginTypeModules = {} 91 cls.pluginModules = {} 92 cls.pluginTypesLoaded = set() 79 """ 80 Forces the reload of all plugins if they are already in memory 81 """ 82 cls._ptypeModules = {} 83 cls._pmodules = {} 84 cls._ptypesLoaded = set() 93 85 cls.loadPlugins() 94 86 95 87 @classmethod 96 def reloadPluginType(cls, pluginTypeName): 97 """ Forces to reload plugins if they are already in memory, but only those of a given type (e.g. "epayment", "Collaboration"). 98 """ 99 if pluginTypeName in cls.pluginTypesLoaded: 100 del cls.pluginTypeModules[pluginTypeName] 101 cls.pluginModules[pluginTypeName] = {} 102 cls.pluginTypesLoaded.remove(pluginTypeName) 103 cls.loadPluginType(pluginTypeName.translate(None, ' ')) 104 cls.pluginTypesLoaded.add(pluginTypeName) 105 106 @classmethod 107 def getPluginsByType(cls, pluginTypeName): 108 """ Given a plugin type name (e.g. "Collaboration"), a list of modules corresponding to the plugins of that type is returned. 109 """ 110 if not pluginTypeName in cls.pluginTypesLoaded: 111 cls.reloadPluginType(pluginTypeName) 112 return cls.pluginModules[pluginTypeName].values() 113 114 @classmethod 115 def getPluginType(cls, pluginTypeName): 116 """ Returns the module of a plugin type given its name 117 e.g. pluginTypeName = "Collaboration" will return the MaKaC.plugins.Collaboration module object 118 """ 119 if not pluginTypeName in cls.pluginTypesLoaded: 120 cls.reloadPluginType(pluginTypeName) 121 122 return cls.pluginTypeModules[pluginTypeName] 123 124 @classmethod 125 def getPluginByTypeAndName(cls, pluginTypeName, pluginName): 126 """ Returns the module of a plugin given the names of the plugin and its type, 127 e.g. pluginTypeName = "Collaboration" and pluginName = "EVO" 128 """ 129 if not pluginTypeName in cls.pluginTypesLoaded: 130 cls.reloadPluginType(pluginTypeName) 131 132 modulesDict = cls.pluginModules[pluginTypeName.translate(None, ' ')] 88 def reloadPluginType(cls, ptypeId): 89 """ 90 Forces the reload of all plugins in a type if they are already in memory 91 """ 92 if ptypeId in cls._ptypesLoaded: 93 del cls._ptypeModules[ptypeId] 94 cls._pmodules[ptypeId] = {} 95 cls._ptypesLoaded.remove(ptypeId) 96 97 cls.loadPluginType(ptypeId) 98 cls._ptypesLoaded.add(ptypeId) 99 100 @classmethod 101 def getPluginsByType(cls, ptypeId): 102 """ 103 Given a plugin type name (e.g. "Collaboration"), a list of modules 104 corresponding to the plugins of that type is returned. 105 """ 106 if not ptypeId in cls._ptypesLoaded: 107 cls.reloadPluginType(ptypeId) 108 return cls._pmodules[ptypeId].values() 109 110 @classmethod 111 def getPluginType(cls, ptypeId): 112 """ 113 Returns the module object of a plugin type given its name 114 """ 115 if not ptypeId in cls._ptypesLoaded: 116 cls.reloadPluginType(ptypeId) 117 118 return cls._ptypeModules[ptypeId] 119 120 @classmethod 121 def getPluginByTypeAndId(cls, ptypeId, pluginName): 122 """ 123 Returns the module object of a plugin given the names of the plugin and its 124 type 125 """ 126 if not ptypeId in cls._ptypesLoaded: 127 cls.reloadPluginType(ptypeId) 128 129 modulesDict = cls._pmodules[ptypeId] 133 130 134 131 if pluginName in modulesDict: 135 132 return modulesDict[pluginName] 136 133 else: 137 raise PluginError("Tried to get a plugin of the type " + pluginTypeName + " with name " + pluginName + " but there is no plugin called " + pluginName) 134 raise PluginError("Tried to get a plugin of the type %s with name %s " 135 "but there is no such plugin" % (ptypeId, 136 pluginName)) 138 137 139 138 @classmethod 140 139 def getPluginTypeList(cls): 141 """ Returns a list of strings with the plugin types (e.g. ["epayment", "Collaboration"] 140 """ 141 Returns a list of strings with the plugin types (names) 142 142 """ 143 143 cls.loadPlugins() 144 return list(cls. pluginTypesLoaded)144 return list(cls._ptypesLoaded) 145 145 146 146 @classmethod 147 147 def importName(cls, moduleName, name): 148 """ Import a named object from a module in the context of this function, 149 which means you should use fully qualified module paths. 150 151 Return None on failure. 148 """ 149 Import a named object from a module in the context of this function, 150 which means you should use fully qualified module paths. 152 151 """ 153 152 … … 157 156 except: 158 157 Logger.get('plugins.loader').exception( 159 " Syntax error loading %s ('%s')" % (moduleName,160 name))158 "Error loading %s ('%s')" % (moduleName, 159 name)) 161 160 raise ModuleLoadException("Impossible to load %s ('%s')" % \ 162 161 (moduleName, name)) … … 168 167 169 168 @classmethod 170 def loadPluginType(cls, pluginTypeName): 171 172 #we load the plugin type module 169 def _checkSetuptoolsDependencies(cls, deplist, name): 170 """ 171 Checks the dependencies for a given plugin/type, using setuptools 172 """ 173 missing = [] 174 175 for dep in deplist: 176 try: 177 pkg_resources.require(dep) 178 except pkg_resources.DistributionNotFound: 179 Logger.get('plugins.loader').warning("Requirement '%s' not met for %s" % 180 (dep, name)) 181 missing.append(dep) 182 183 return missing 184 185 @classmethod 186 def loadPluginType(cls, ptypeId): 187 """ 188 Loads a plugin type, going through its source tree and loading each plugin 189 as well. 190 """ 191 192 # we load the plugin type module 173 193 try: 174 pluginTypeModule = cls.importName("MaKaC.plugins", pluginTypeName) 175 except ImportError: 176 raise Exception("Tried to load the plugin type: %s but the module MaKaC.plugins.%s did not exist" % (pluginTypeName, pluginTypeName)) 177 except KeyError: 178 raise Exception("Tried to load the plugin type: %s but the module MaKaC.plugins.%s did not exist" % (pluginTypeName, pluginTypeName)) 179 180 # we build the package name of a plugin type, e.g. MaKaC.plugins.Collaboration 181 pluginTypePackageName = "MaKaC.plugins.%s" % pluginTypeName 182 metadata = processPluginMetadata(pluginTypeModule) 183 184 #we check that the plugin type does not have an "ignore" attribute 194 ptypeModule = cls.importName("MaKaC.plugins", ptypeId) 195 except (ImportError, KeyError): 196 raise Exception("Tried to load the plugin type: %s but the module " 197 "MaKaC.plugins.%s did not exist" % (ptypeId, 198 ptypeId)) 199 200 metadata = processPluginMetadata(ptypeModule) 201 202 # check if the plugin should be ignored 185 203 if metadata['ignore']: 186 204 # stop loading here! 187 205 return 188 206 189 #if ignore == False, we store the plugin type module in cls.pluginTypeModules 190 cls.pluginTypeModules[pluginTypeName] = pluginTypeModule 191 192 # absolute path of a plugin type folder, e.g. /xxxxx/MaKaC/plugins/Collaboration/ 193 pluginTypePath = os.path.join(cls.pluginsDir, pluginTypeName) 194 195 #we loop through all the files and folders of the plugin type folder 196 for itemName in os.listdir(pluginTypePath): 197 198 # we strip the extension from the item name 199 # splitext returns a tuple (name, file extension). Ex: ("conference", ".py") 200 # if no extension, the 2nd element of the tuple will be an empty string 201 itemName, ext = os.path.splitext(itemName) 202 # case where we found a folder, i.e. a plugin folder (e.g. /xxxx/MaKaC/plugins/Collaboration/EVO/) 203 if os.path.isdir(os.path.join(cls.pluginsDir, pluginTypeName, itemName)): 204 205 # we attempt to import the folder as a module. This will only work if there's an __init__.py inside the folder 206 try: 207 pluginModule = cls.importName(pluginTypePackageName, itemName) 208 209 except ImportError: 210 raise Exception("Tried to load the plugin %s but the module MaKaC.plugins.%s.%s did not exist. Is there an __init__.py?" % (pluginTypeName, pluginTypeName, itemName)) 211 except KeyError: 212 raise Exception("Tried to load the plugin %s but the module MaKaC.plugins.%s.%s did not exist. Is there an __init__.py?" % (pluginTypeName, pluginTypeName, itemName)) 213 214 # we check that it was indeed a module. 215 216 if pluginModule: 217 pluginMetadata = processPluginMetadata(pluginModule) 218 else: 219 # Not a module? Nothing to do here... 207 #if ignore == False, we store the plugin type module in cls._ptypeModules 208 cls._ptypeModules[ptypeId] = ptypeModule 209 210 missingDeps = cls._checkSetuptoolsDependencies(metadata['requires'], 211 ptypeId) 212 213 # save missing dependency info, so that the holder will know the module state 214 ptypeModule.__missing_deps__ = missingDeps 215 216 # check dependencies 217 if len(missingDeps) > 0: 218 # if some dependencies are not met, don't load submodules 219 cls._pmodules[ptypeId] = {} 220 221 Logger.get('plugins.loader').warning( 222 "Plugin type %s has unmet dependencies. It will be deactivated." % 223 ptypeId) 224 return 225 else: 226 # absolute path of a plugin type folder 227 ptypePath = os.path.join(cls._pluginsDir, ptypeId) 228 229 # we loop through all the files and folders of the plugin type folder 230 for itemName in os.listdir(ptypePath): 231 232 # we strip the extension from the item name 233 # splitext returns a tuple (name, file extension) 234 cls._loadPluginFromDir(ptypePath, ptypeId, ptypeModule, itemName) 235 236 @classmethod 237 def _loadPluginFromDir(cls, ptypePath, ptypeId, ptypeModule, pid): 238 """ 239 Loads a possible plugin from a directory 240 """ 241 242 pid, ext = os.path.splitext(pid) 243 244 # in case where we found a folder, i.e. a plugin folder 245 if os.path.isdir(os.path.join(cls._pluginsDir, ptypeId, pid)): 246 247 # we attempt to import the folder as a module. 248 # This will only work if there's an __init__.py inside the folder 249 try: 250 pmodule = cls.importName(ptypeModule.__name__, pid) 251 252 except (ImportError, KeyError): 253 raise Exception("Tried to load the plugin %s but the module " 254 "MaKaC.plugins.%s.%s did not exist. " 255 "Is there an __init__.py?" % 256 (ptypeId, ptypeId, pid)) 257 258 # we check that it was indeed a module. 259 if pmodule: 260 pmetadata = processPluginMetadata(pmodule) 261 else: 262 # Not a module? Nothing to do here... 263 return 264 265 # If it was a module, we check that the "type" field in the metadata 266 # of the plugin corresponds to the plugin type we are currently processing 267 if pmetadata['type'] == ptypeId: 268 269 # if this is the first plugin for this plugin type 270 if not ptypeId in cls._pmodules: 271 cls._pmodules[ptypeId] = {} 272 273 missingDeps = cls._checkSetuptoolsDependencies(pmetadata['requires'], 274 pid) 275 276 # save missing dependency info, so that the holder will know the 277 # module state 278 pmodule.__missing_deps__ = missingDeps 279 280 # check dependencies 281 if len(missingDeps) > 0: 282 # if some dependencies are not met, don't load submodules 283 cls._pmodules[ptypeId][pid] = pmodule 284 285 Logger.get('plugins.loader').warning( 286 "Plugin %s has unmet dependencies. It will be deactivated." % 287 pid) 220 288 return 221 # If it was a module, we check that there is a 222 # "pluginType" variable in the __init__.py of the plugin and that it corresponds 223 # to the plugin type we are currently processing 224 if pluginTypeName == pluginMetadata['type']: 225 cls.pluginTypeModules[pluginTypeName].__dict__[itemName] = pluginModule 226 227 #if this is the first plugin for this plugin type, we add 228 #a new key to the cls.pluginModules dictionary 229 if not pluginTypeName in cls.pluginModules.keys(): 230 cls.pluginModules[pluginTypeName] = {} 231 232 #we store the module inside the cls.pluginModules object 233 #note: we do not use itemName (the name of the folder) and use instead 234 # the "pluginName" variable in the __init__.py file of the plugin, 235 # which is its "true" name 236 cls.pluginModules[pluginTypeName][pluginMetadata['name']] = pluginModule 237 238 #we build the path of the plugin 239 pluginPath = os.path.join(pluginTypePath, itemName) 240 241 cls.loadSubModules(pluginModule, pluginPath) 242 else: 243 Logger.get("plugins.loader").warning("Module of type %s inside %s" % 244 (pluginMetadata['type'], 245 pluginTypeName)) 246 247 elif ext == ".py" and itemName != "__init__": 248 pluginTypeSubModule = cls.importName(pluginTypePackageName, itemName) 249 250 if pluginTypeSubModule: 251 cls.pluginTypeModules[pluginTypeName].__dict__[itemName] = pluginTypeSubModule 289 290 291 cls._ptypeModules[ptypeId].__dict__[pid] = pmodule 292 293 # we store the module inside the cls._pmodules object 294 cls._pmodules[ptypeId][pid] = pmodule 295 296 #we build the path of the plugin 297 pluginPath = os.path.join(ptypePath, pid) 298 299 cls.loadSubModules(pmodule, pluginPath) 300 else: 301 Logger.get("plugins.loader").warning("Module of type %s inside %s" % 302 (pmetadata['type'], 303 ptypeId)) 304 305 elif ext == ".py" and pid != "__init__": 306 ptypeSubModule = cls.importName(ptypeModule.__name__, pid) 307 308 if ptypeSubModule: 309 cls._ptypeModules[ptypeId].__dict__[pid] = ptypeSubModule 252 310 253 311 254 312 @classmethod 255 313 def loadSubModules(cls, module, modulePath): 314 """ 315 Loads the submodules of a plugin (recursively) 316 """ 256 317 257 318 #dictionary whose keys are submodule names, and whose values are module objects 258 #after finding the submodules, we will add them to the __dict__ of the module259 319 foundSubModules = {} 260 320 … … 263 323 264 324 # we strip the extension from the item name 265 # splitext returns a tuple (name, file extension). Ex: ("conference", ".py")266 # if no extension, the 2nd element of the tuple will be an empty string267 325 itemName, ext = os.path.splitext(itemName) 268 326 269 # if the item is a directory, we may have found a subpackage (also a submodule)327 # if the item is a directory, we may have found a subpackage 270 328 if os.path.isdir(os.path.join(modulePath, itemName)): 271 329 272 #this will return a module if the subdirectory has an __init__.py inside, otherwise will raise KeyError273 330 try: 274 331 subModule = cls.importName(module.__name__, itemName) 275 332 except KeyError: 276 # we hit a folder that is not a package, such277 # plugins are allowed to have those333 # we hit a folder that is not a package, such 334 # plugins are allowed to have those 278 335 continue 279 336 280 337 281 # we store the submodule in the foundSubModules dictionary338 # we store the submodule in the foundSubModules dictionary 282 339 foundSubModules[itemName] = subModule 283 # we make a recursive call340 # we make a recursive call 284 341 cls.loadSubModules(subModule, os.path.join(modulePath, itemName)) 285 342 286 #if the item is a .py file and not __init__, its a submodule that is not a package 343 # if the item is a .py file and not __init__, it's a submodule that is 344 # not a package 287 345 elif ext == ".py" and itemName != "__init__": 288 346 289 # this should return a subModule, unless there has been an error during import290 347 # this should return a subModule, unless there 348 # has been an error during import 291 349 subModule = cls.importName(module.__name__, itemName) 292 350 foundSubModules[itemName] = subModule 293 351 294 #once we have found all the submodules, we make sure they are in the __dict__ of the module: 352 # once we have found all the submodules, we make sure they are in the 353 # __dict__ of the module: 295 354 for subModuleName, subModule in foundSubModules.iteritems(): 296 355 module.__dict__[subModuleName] = subModule 297 #also, if there is a "modules" variable in the __init__.py of the plugin, we store the submodules there 298 #(needed by epayment plugins, for example) 356 357 # also, if there is a "modules" variable in the __init__.py of the 358 # plugin, we store the submodules there 359 # (needed by legacy epayment modules) 299 360 if hasattr(module, "modules"): 300 361 module.modules[subModuleName] = subModule … … 302 363 303 364 class GlobalPluginOptions(Persistent): 304 """ A class that stores global information about all plugins. 365 """ 366 A class that stores global information about all plugins. 305 367 """ 306 368 -
indico/MaKaC/plugins/util.py
rc1435a r2f5998 31 31 'ignore': False, 32 32 'visible': True, 33 'testPlugin': False 33 'testPlugin': False, 34 'requires': [] 34 35 } 35 36 … … 44 45 45 46 class PluginsWrapper(object): 46 def __init__(self, pluginType, plugin ):47 def __init__(self, pluginType, plugin=None): 47 48 self._pluginType = pluginType 48 49 self._plugin = plugin 49 50 try: 50 51 from MaKaC.plugins import PluginsHolder 51 self._plugin = PluginsHolder().getPluginType(pluginType).getPlugin(plugin) 52 if self._plugin: 53 self._plugin = PluginsHolder().getPluginType(pluginType).getPlugin(plugin) 54 else: 55 self._pluginType = PluginsHolder().getPluginType(pluginType) 52 56 except Exception, e: 53 57 Logger.get('Plugins').error("Exception while trying to access either the plugin type %s or the plugin %s: %s" % (pluginType, plugin, str(e))) … … 60 64 """Provides a simple interface to access fields of a given plugin""" 61 65 62 def __init__(self, pluginType, plugin ):66 def __init__(self, pluginType, plugin=None): 63 67 PluginsWrapper.__init__(self, pluginType, plugin) 64 68 65 69 def getOption(self, optionName): 66 70 try: 67 return self._plugin.getOption(optionName).getValue() 71 if self._plugin: 72 return self._plugin.getOption(optionName).getValue() 73 else: 74 return self._pluginType.getOption(optionName).getValue() 68 75 except Exception, e: 69 76 Logger.get('Plugins').error("Exception while trying to access the option %s in the plugin %s: %s" % (self._pluginType, self._plugin, str(e))) … … 72 79 def getAttribute(self, attribute): 73 80 try: 74 return getattr(self._plugin, attribute) 81 if self._plugin: 82 return getattr(self._plugin, attribute) 83 else: 84 return getattr(self._pluginType, attribute) 75 85 except AttributeError: 76 86 Logger.get('Plugins').error("No attribute %s in plugin %s" % (attribute, self._plugin)) -
indico/MaKaC/webinterface/stylesheets/include/indico.xsl
r869ccc r2f5998 755 755 <span style="margin-left: 20px;"></span> 756 756 <span class="CRDisplayMoreInfo" id="CRMoreInfo{./id}">More Info</span> 757 <span style="margin-left:8px;margin-right:8px;">|</span>758 757 759 758 <xsl:if test="./links/linksToShow != 'false'"> 759 <span style="margin-left:8px;margin-right:8px;">|</span> 760 760 <span style="font-weight: bold;"><a id="joinLink{./id}" name="{./id}" class="dropDownMenu highlight" href="#">Join now!</a></span> 761 761 </xsl:if> … … 895 895 <xsl:text disable-output-escaping="yes"><![CDATA['){]]></xsl:text> 896 896 897 <xsl:if test="./links/web != 'false'" disable-output-escaping="yes"> 898 <xsl:text disable-output-escaping="yes"><![CDATA[ 899 menuItems['Using web client'] =']]></xsl:text> <xsl:value-of select="./links/web" disable-output-escaping="yes"/> 900 <xsl:text disable-output-escaping="yes"><![CDATA['; 901 ]]></xsl:text> </xsl:if> 902 903 <xsl:if test="./links/desktop != 'false'" disable-output-escaping="yes"> 904 <xsl:text disable-output-escaping="yes"><![CDATA[ 905 menuItems['Using your desktop client'] =']]></xsl:text> <xsl:value-of select="./links/desktop" disable-output-escaping="yes"/> 906 <xsl:text disable-output-escaping="yes"><![CDATA['; 907 ]]></xsl:text> </xsl:if> 897 908 898 909 899 <xsl:for-each select="./links/customLink"><xsl:text disable-output-escaping="yes"><![CDATA[ -
indico/MaKaC/webinterface/tpls/AdminPlugins.tpl
r3eae79 r2f5998 30 30 <tr> 31 31 <td> 32 <% if plugin.isActive(): %> 32 <% if not plugin.isUsable(): %> 33 <img class="imglink" alt="<%= _("Not in usable state")%>" src="<%=Config.getInstance().getSystemIconURL( 'greyedOutSection' )%>"/> 34 <% end %> 35 <% elif plugin.isActive(): %> 33 36 <a href="<%=urlHandlers.UHAdminTogglePlugin.getURL(plugin)%>"> 34 37 <img class="imglink" alt="<%= _("Click to disable")%>" src="<%=Config.getInstance().getSystemIconURL( 'enabledSection' )%>"/> … … 40 43 </a> 41 44 <% end %> 45 <% if not plugin.isUsable(): %> 46 <%= plugin.getName() %> 47 <small class="smallRed"> 48 (<%= plugin.getNotUsableReason() %>) 49 </small> 50 <% end %> 51 <% else: %> 42 52 <a href="<%=urlHandlers.UHAdminTogglePlugin.getURL(plugin)%>"> 43 53 <%= plugin.getName() %> 44 54 </a> 55 <% end %> 45 56 <% if plugin.hasDescription(): %> 46 57 <span style="margin-left: 2em;"> -
indico/MaKaC/webinterface/tpls/AdminPluginsMainTab.tpl
rc1435a r2f5998 51 51 <td> 52 52 <a href="<%=urlHandlers.UHAdminTogglePluginType.getURL(pluginType)%>"> 53 <% if pluginType.isActive(): %> 53 <% if not pluginType.isUsable(): %> 54 <img class="imglink" alt="<%= _("Not in usable state")%>" src="<%=Config.getInstance().getSystemIconURL( 'greyedOutSection' )%>"/> 55 <% end %> 56 <% elif pluginType.isActive(): %> 54 57 <img class="imglink" alt="<%= _("Click to disable")%>" src="<%=Config.getInstance().getSystemIconURL( 'enabledSection' )%>"/> 55 58 <% end %> … … 58 61 <% end %> 59 62 </a> 60 < a href="<%=urlHandlers.UHAdminTogglePluginType.getURL(pluginType)%>" onclick="return confirm('<%= _('This will reload all the plugins too. Do you want to continue?')%>');">63 <% if not pluginType.isUsable(): %> 61 64 <%= pluginType.getName() %> 62 </a> 65 <small class="smallRed"> 66 (<%= pluginType.getNotUsableReason() %>) 67 </small> 68 <% end %> 69 <% else: %> 70 <a href="<%=urlHandlers.UHAdminTogglePluginType.getURL(pluginType)%>" onclick="return confirm('<%= _('This will reload all the plugins too. Do you want to continue?')%>');"> 71 <%= pluginType.getName() %> 72 </a> 73 <% end %> 63 74 <% if pluginType.hasDescription(): %> 64 75 <span style="margin-left: 2em;"> -
indico/MaKaC/webinterface/tpls/AdminPluginsOptionList.tpl
r869ccc r2f5998 80 80 var linksTable = Html.table({style: {padding: pixels(10)}}, linksBody); 81 81 linksBody.append( Html.tr({style: {marginTop: pixels(10)}}, Html.td({style:{whiteSpace: "nowrap", fontWeight:"bold"}}, $T('Link name')), 82 Html.td({style:{whiteSpace: "nowrap", fontWeight:"bold"}}, $T(' Link structure'))) );82 Html.td({style:{whiteSpace: "nowrap", fontWeight:"bold"}}, $T('URL'))) ); 83 83 each(<%= option.getValue() %>, function(link){ 84 var removeButton = Html.input("button", {style:{marginRight: pixels(5)}}, $T('Remove')); 85 var newRow = Html.tr({style: {marginTop: pixels(10)}}, Html.td({style: {marginRight: pixels(10), whiteSpace: "nowrap"}},link.name), 86 Html.td({style: {marginRight: pixels(10), whiteSpace: "nowrap"}},link.structure), 87 Html.td({style:{whiteSpace: "nowrap"}},removeButton)) 88 linksBody.append(newRow); 89 removeButton.observeClick(function(){ 84 var removeButton = Widget.link(command(function(){ 90 85 var killProgress = IndicoUI.Dialogs.Util.progress($T("Creating new type of link...")); 91 86 indicoRequest( … … 106 101 } 107 102 ); 108 }); 103 }, IndicoUI.Buttons.removeButton())); 104 var newRow = Html.tr({style: {marginTop: pixels(10)}}, Html.td({style: {marginRight: pixels(10), whiteSpace: "nowrap"}},link.name), 105 Html.td({style: {marginRight: pixels(10), whiteSpace: "nowrap"}},link.structure), 106 Html.td({style:{whiteSpace: "nowrap"}},removeButton)) 107 linksBody.append(newRow); 108 109 109 110 }); 110 111 $E('links<%=name%>').append(linksTable); … … 113 114 $E('links<%=name%>').append(Html.div({style: {marginTop: pixels(10), marginBottom: pixels(10), whiteSpace: "nowrap"}}, $T('No links created yet. Click in Add new link if you want to do so!'))); 114 115 } 115 var addButton = Html.input("button", {style:{margin Right: pixels(5)}}, $T('Add new link'));116 var addButton = Html.input("button", {style:{marginLeft: pixels(100)}}, $T('Add new link')); 116 117 117 118 addButton.observeClick(function() { 118 var errorLabel=Html.label({style:{float: 'right', display: 'none'}, className: " invalid"}, 'Name already in use');119 var errorLabel=Html.label({style:{float: 'right', display: 'none'}, className: " invalid"}, $T('Name already in use')); 119 120 var linkName = new AutocheckTextBox({name: 'name', id:"linkname"}, errorLabel); 120 121 var linkStructure = Html.input("text", {}); 121 var linksPopup = new ConfirmPopupWithPM($T('Select the name of the link and its structure'), 122 IndicoUtil.createFormFromMap([ 123 [$T('Link name'), Html.div({}, linkName.draw(), errorLabel)], 124 [$T('Link structure'), Html.div({}, linkStructure)], 125 [Html.ul({style: {fontWeight: "bold"}},$T('The following patterns will be substituted:'), 126 Html.li({style: {fontWeight: "lighter"}},$T('/chatroom/ by the chat room name')), 127 Html.li({style: {fontWeight: "lighter"}},$T('/host/ by the specified host')), 128 Html.li({style: {fontWeight: "lighter"}},$T('/nickname/ by the nick chosen by the user.')))] 129 ]), 122 var div = Html.div({},IndicoUtil.createFormFromMap([ 123 [$T('Link name'), Html.div({}, linkName.draw(), errorLabel)], 124 [$T('URL'), Html.div({}, linkStructure)]]), 125 Html.div({}, 126 (Html.ul({style: {fontWeight: "bold"}},$T('In the URL field, the following patterns will be changed:'), 127 Html.li({style: {fontWeight: "lighter"}},$T('*chatroom* by the chat room name')), 128 Html.li({style: {fontWeight: "lighter"}},$T('*host* by the specified host')), 129 Html.li({style: {fontWeight: "lighter"}},$T('*nickname* by the nick chosen by the user.'))) 130 )), 131 Html.div({style:{color: "orange", fontSize: "smaller"}}, $T('Example: http://*host*/resource/?x=*chatroom*@conference.*host*?join'))); 132 var linksPopup = new ConfirmPopupWithPM($T('Select the name of the link and its URL'), 133 div, 130 134 function(value){ 131 135 if(value){ -
indico/MaKaC/webinterface/tpls/ConfModifChat.tpl
r474924 r2f5998 51 51 /* ------------------------------ GLOBAL VARIABLES ------------------------------- */ 52 52 53 <% from MaKaC.plugins.util import PluginFieldsWrapper %>54 55 var showDesktopLink = <%=jsonEncode( PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinDesktopClients') )%>;56 var showWebLink = <%=jsonEncode( PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinWebClient') )%>;57 53 var chatrooms = $L(<%= jsonEncode(Chatrooms) %>); 58 54 var links = $O(<%= jsonEncode(links) %>); 55 var showLogsLink = <%= jsonEncode(ShowLogsLink) %>; 59 56 60 57 var defaultHost = <%= jsonEncode(DefaultServer) %>; -
indico/MaKaC/webinterface/tpls/ConferenceInstantMessaging.tpl
r869ccc r2f5998 1 1 <% declareTemplate(newTemplateStyle=True) %> 2 2 3 <% from MaKaC.plugins.helpers import WebLinkGenerator, DesktopLinkGenerator %>4 3 <% from MaKaC.plugins.util import PluginFieldsWrapper %> 5 6 <script type="text/javascript">7 var showDesktopLink = <%=jsonEncode( PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinDesktopClients') )%>;8 var showWebLink = <%=jsonEncode( PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinWebClient') )%>;9 </script>10 4 11 5 <table width="100%" align="center" border="0" cellpadding="5px"> … … 50 44 <td style="font-style:italic;"> - </td> 51 45 <% end %> 52 <% if PluginFieldsWrapper('InstantMessaging' , 'XMPP').getOption('joinDesktopClients') or PluginFieldsWrapper('InstantMessaging', 'XMPP').getOption('joinWebClient'): %>46 <% if PluginFieldsWrapper('InstantMessaging').getOption('customLinks').__len__() > 0: %> 53 47 <td style="font-weight: bold;" nowrap><a id="joinLink<%= cr.getId() %>" name = "<%= cr.getId() %>" class="dropDownMenu highlight" href="#"><%= _("Join now!")%></a></td> 54 48 <% end %> … … 79 73 var links = <%= Links %>; 80 74 var crId = joinLink.dom.name; 81 each(links[crId] , function(linkType){75 each(links[crId].custom, function(linkType){ 82 76 menuItems['Using ' + linkType.name] = linkType.link; 83 77 }); -
indico/htdocs/css/Default.css
r3b1e93 r2f5998 6420 6420 } 6421 6421 6422 .smallRed { 6423 font-size: 9px; 6424 color: #881122; 6425 } 6426 6427 6422 6428 tr.selectedItem td { 6423 6429 color: #000; -
indico/htdocs/js/indico/Plugins/InstantMessaging.js
r869ccc r2f5998 163 163 showInfo[result.id] = true; // we initialize the show info boolean for this chatroom 164 164 each(result, function(cr){ 165 links.set(cr.id, {}); 166 links.get(cr.id)['custom'] = cr.custom; 167 if(showLogsLink){ 168 links.get(cr.id)['logs'] = cr.logs; 169 } 165 170 chatrooms.append(cr); 166 171 }); … … 277 282 disableCustomId(defaultHost); 278 283 }); 279 var createCHRadioButtonLabel = Html.label({style:{fontWeight:"normal"}}, "Default ");284 var createCHRadioButtonLabel = Html.label({style:{fontWeight:"normal"}}, $T("Default ")); 280 285 createCHRadioButtonLabel.dom.htmlFor = "createCH"; 281 286 … … 285 290 enableCustomId(customHost); 286 291 }); 287 var defineCHRadioButtonLabel = Html.label({style:{fontWeight:"normal"}}, "Custom");292 var defineCHRadioButtonLabel = Html.label({style:{fontWeight:"normal"}}, $T("Custom")); 288 293 defineCHRadioButtonLabel.dom.htmlFor = "defineCH"; 289 294 … … 291 296 this.parameterManager.add(defineCHText, 'text', false); 292 297 293 self.errorLabel=Html.label({style:{float: 'right', display: 'none'}, className: " invalid"}, 'Name already in use');298 self.errorLabel=Html.label({style:{float: 'right', display: 'none'}, className: " invalid"}, $T('Name already in use')); 294 299 295 300 self.crName = new AutocheckTextBox({style: {width: '300px'}, name: 'title', id:"CRname"}, self.errorLabel); … … 312 317 text.indexOf('>') != -1 || 313 318 text.indexOf('@') != -1){ 314 return Html.span({}, "You introduced an invalid character in the name, don't use spaces, \', \", &, /, :, <, > or @");319 return Html.span({}, $T("You introduced an invalid character in the name, don't use spaces, \', \", &, /, :, <, > or @")); 315 320 } 316 321 }), self.errorLabel)], … … 416 421 hideAllInfoRows(false); 417 422 showInfo[result.id] = true; // we initialize the show info boolean for this chat room 423 links.set(result.id, {}); 424 links.get(result.id)['custom'] = result.custom; 425 if(showLogsLink){ 426 links.get(result.id)['logs'] = result.logs; 427 } 418 428 chatrooms.append(result); 419 429 showAllInfoRows(false); … … 479 489 this.popupType = popupType; 480 490 if (popupType === 'create') { 481 var title = " Chat room creation";491 var title = $T(" Chat room creation"); 482 492 } else if (popupType === 'edit') { 483 493 this.chatroom = chatroom; 484 var title = ' Chat room modification';494 var title = $T(' Chat room modification'); 485 495 } 486 496 … … 732 742 function() {checkStatus(chatroom);} , 733 743 Html.img({ 734 alt: "Refresh chat room data",735 title: "Refresh chat room data",744 alt: $T("Refresh chat room data"), 745 title: $T("Refresh chat room data"), 736 746 src: imageSrc("reload"), 737 747 style: { … … 744 754 var checkStatusButton = 745 755 Html.img({ 746 alt: "Refresh not available in external servers",747 title: "Refresh not available in external servers",756 alt: $T("Refresh not available in external servers"), 757 title: $T("Refresh not available in external servers"), 748 758 src: imageSrc("reload_faded"), 749 759 style: { … … 755 765 row.append(cellEditRemove); 756 766 757 var joinNow = Html.td({id:"joinLink", name:"joinLink", className : "dropDownMenu highlight", style:{fontWeight: "bold", whiteSpace: "nowrap"}}, Html.a({href: "#"}, $T("Join now!")) ); 758 row.append(joinNow); 759 showLinkMenu(joinNow, chatroom); 760 761 if(chatroom.createdInLocalServer && links.get(chatroom.id)){ 762 var logs = Html.td({id:"logsLink", name:"logsLink", className : "dropDownMenu highlight", style:{fontWeight: "bold", whiteSpace: "nowrap"}}, " | ", Html.a({href: "#"}, $T("Logs")) ); 767 if(links.get(chatroom.id).custom){ 768 var joinNow = Html.td({id:"joinLink", name:"joinLink", className : "dropDownMenu highlight", style:{fontWeight: "bold", whiteSpace: "nowrap"}}, Html.a({href: "#"}, $T("Join now!")) ); 769 row.append(joinNow); 770 showLinkMenu(joinNow, chatroom); 771 } 772 773 if(links.get(chatroom.id).custom && chatroom.createdInLocalServer && links.get(chatroom.id) && showLogsLink){ 774 var sepBar = Html.td({style:{fontWeight: "bold", whiteSpace: "nowrap"}}, " | "); 775 row.append(sepBar); 776 } 777 778 if(chatroom.createdInLocalServer && links.get(chatroom.id) && showLogsLink){ 779 var logs = Html.td({id:"logsLink", name:"logsLink", className : "dropDownMenu highlight", style:{fontWeight: "bold", whiteSpace: "nowrap"}}, Html.a({href: "#"}, $T("Logs")) ); 763 780 row.append(logs); 764 781 showLogOptions(logs, chatroom); … … 780 797 } 781 798 var menuItems = {}; 782 if (showDesktopLink){ 783 menuItems['Using web client'] = links.get(chatroom.id).desktop; 784 } 785 if (showWebLink){ 786 menuItems['Using your desktop client'] = links.get(chatroom.id).web; 787 } 799 800 each(links.get(chatroom.id).custom, function(linkType){ 801 menuItems['Using ' + linkType.name] = linkType.link; 802 }); 788 803 joinMenu = new PopupMenu(menuItems, [element], 'categoryDisplayPopupList'); 789 804 var pos = element.getAbsolutePosition(); … … 851 866 var form = createBaseForm(); 852 867 853 menuItems[ 'See logs'] = new LogPopup($T('Select the dates to retrieve the logs'),868 menuItems[$T('See logs')] = new LogPopup($T('Select the dates to retrieve the logs'), 854 869 form.content, 855 870 function(value){ … … 878 893 ); 879 894 var requestOk = false; 880 menuItems[ 'Attach logs to event material'] = new LogPopup($T('Select the name that logs will have in the material section'),895 menuItems[$T('Attach logs to event material')] = new LogPopup($T('Select the name that logs will have in the material section'), 881 896 materialContent, 882 897 function(value){ … … 891 906 confId: conferenceID, 892 907 crId: chatroom.id, 893 sdate: form2.sdate.get()?form .sdate.get().replace(/\//g,"-"):null,894 edate: form2.edate.get()?form .edate.get().replace(/\//g,"-"):null,908 sdate: form2.sdate.get()?form2.sdate.get().replace(/\//g,"-"):null, 909 edate: form2.edate.get()?form2.edate.get().replace(/\//g,"-"):null, 895 910 getAll: form2.getall.get(), 896 911 forEvent: form2.forevent.get(), … … 1042 1057 */ 1043 1058 var displayChatrooms = function() { 1044 var killProgress = IndicoUI.Dialogs.Util.progress( "Loading list of chatrooms...");1059 var killProgress = IndicoUI.Dialogs.Util.progress($T("Loading list of chatrooms...")); 1045 1060 // We bind the watchlist and the table through the template 1046 1061 bind.element($E("chatroomsTableBody"), chatrooms, chatroomTemplate); … … 1057 1072 if (length == 0) { 1058 1073 var cell = Html.td(); 1059 cell.set(Html.span('', 'Currently no chatrooms have been created'));1074 cell.set(Html.span('',$T('Currently no chatrooms have been created'))); 1060 1075 headRow.set(cell); 1061 1076 } else {
Note: See TracChangeset
for help on using the changeset viewer.
