--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/soc/modules/core.py Sun May 24 21:40:37 2009 +0200
@@ -0,0 +1,235 @@
+# Copyright 2009 the Melange authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""The Melange Core module.
+"""
+
+__authors__ = [
+ '"Sverre Rabbelier" <sverre@rabbelier.nl>',
+ '"Lennard de Rijk" <ljvderijk@gmail.com>',
+ ]
+
+
+from django.conf.urls import defaults
+
+import settings
+import soc.cache.sidebar
+
+
+class Error(Exception):
+ """Error class for the callback module.
+ """
+
+ pass
+
+
+class APIVersionMismatch(Error):
+ """Error raised when API version mismatches.
+ """
+
+ MISMATCH_MSG_FMT = "API mismatch, expected '%d', got '%d'."
+
+ def __init__(self, expected, actual):
+ """Instantiates a new exception with a customized message.
+ """
+
+ msg = self.MISMATCH_MSG_FMT % (expected, actual)
+ super(APIVersionMismatch, self).__init__(msg)
+
+
+class MissingService(Error):
+ """Error raised when a required service is missing.
+ """
+
+ MISSING_SERVICE_FMT = "Required service '%s' is not registered, known: %s"
+
+ def __init__(self, service, services):
+ """Instantiates a new exception with a customized message.
+ """
+
+ msg = self.MISSING_SERVICE_FMT % (service, services)
+ super(MissingService, self).__init__(msg)
+
+
+class NonUniqueService(Error):
+ """Error raised when a required service is missing.
+ """
+
+ NON_UNIQUE_SERVICE_FMT = "Unique service '%s' called a second time, known: %s."
+
+ def __init__(self, service, services):
+ """Instantiates a new exception with a customized message.
+ """
+
+ msg = self.NON_UNIQUE_SERVICE_FMT % (service, services)
+ super(NonUniqueService, self).__init__(msg)
+
+
+class Core(object):
+ """The core handler that controls the Melange API.
+ """
+
+ def __init__(self):
+ """Creates a new instance of the Core.
+ """
+
+ self.API_VERSION = 1
+
+ self.registered_callbacks = []
+ self.capability = []
+ self.services = []
+
+ self.sitemap = []
+ self.sidebar = []
+
+ ##
+ ## internal
+ ##
+
+ def getService(self, callback, service):
+ """Retrieves the specified service from the callback if supported.
+
+ Args:
+ callback: the callback to retrieve the capability from
+ service: the service to retrieve
+ """
+
+ if not hasattr(callback, service):
+ return False
+
+ func = getattr(callback, service)
+
+ if not callable(func):
+ return False
+
+ return func
+
+ ##
+ ## Core code
+ ##
+
+ def getPatterns(self):
+ """Returns the Django patterns for this site.
+ """
+
+ self.callService('registerWithSitemap', True)
+ return defaults.patterns(None, *self.sitemap)
+
+ @soc.cache.sidebar.cache
+ def getSidebar(self, id, user):
+ """Constructs a sidebar for the current user.
+ """
+
+ self.callService('registerWithSidebar', True)
+
+ sidebar = []
+
+ for i in self.sidebar:
+ menus = i(id, user)
+
+ for menu in (menus if menus else []):
+ sidebar.append(menu)
+
+ return sorted(sidebar, key=lambda x: x.get('group'))
+
+ def callService(self, service, unique, *args, **kwargs):
+ """Calls the specified service on all callbacks.
+ """
+
+ if unique and (service in self.services):
+ return
+
+ results = []
+
+ for callback in self.registered_callbacks:
+ func = self.getService(callback, service)
+ if not func:
+ continue
+
+ result = func(*args, **kwargs)
+ results.append(result)
+
+ self.services.append(service)
+ return results
+
+ def registerModuleCallbacks(self):
+ """Retrieves all callbacks for the modules of this site.
+
+ Callbacks for modules without a version number or the wrong API_VERSION
+ number are dropped. They won't be called.
+ """
+
+ fmt = settings.MODULE_FMT
+ modules = ['soc_core'] + settings.MODULES
+ modules = [__import__(fmt % i, fromlist=['']) for i in modules]
+
+ for callback_class in [i.getCallback() for i in modules]:
+ if callback_class.API_VERSION != self.API_VERSION:
+ raise callback.APIVersionMismatch(self.API_VERSION,
+ callback_class.API_VERSION)
+
+
+ callback = callback_class(self)
+ self.registered_callbacks.append(callback)
+
+ return True
+
+ ##
+ ## Module code
+ ##
+
+ def registerCapability(self, capability):
+ """Registers the specified capability.
+ """
+
+ self.capabilities.append(capability)
+
+ def requireCapability(self, capability):
+ """Requires that the specified capability is present.
+ """
+
+ if capability in self.capabilities:
+ return True
+
+ raise MissingCapability(capability, self.capability)
+
+ def requireService(self, service):
+ """Requires that the specified service has been called.
+ """
+
+ if service in self.services:
+ return True
+
+ raise MissingService(service, self.services)
+
+ def requireUniqueService(self, service):
+ """Requires that the specified service is called exactly once.
+ """
+
+ if service not in self.services:
+ return True
+
+ raise NonUniqueService(service, self.services)
+
+ def registerSitemapEntry(self, entries):
+ """Registers the specified entries with the sitemap.
+ """
+
+ self.sitemap.extend(entries)
+
+ def registerSidebarEntry(self, entry):
+ """Registers the specified entry with the sidebar.
+ """
+
+ self.sidebar.append(entry)