class ApplicationSite(ResolverMixin): ''' Application site manager An instance of this class is used to handle url of registered applications. ''' def __init__(self, url, config): self.route = url self.url = url self.config = config self.settings = config self.editavailable = config.CONTENT_INLINE_EDITING.get('available',False) self.editurl = config.CONTENT_INLINE_EDITING.get('preurl','/edit/') self._registry = {} self._nameregistry = OrderedDict() self.choices = [('','-----------------')] self.ModelApplication = ModelApplication def __repr__(self): return '{0} - {1}'.format(self.route,'loaded' if self.isloaded else 'not loaded') __str__ = __repr__ def load_initial(self): baseurl = self.config.CONTENT_INLINE_EDITING.get('pagecontent', '/content/') self.register(ContentSite(baseurl, BlockContent, editavailable = False)) def count(self): return len(self._registry) def _load(self): """Registers an instance of :class:`djpcms.views.appsite.Application` to the site. If a model is already registered, this will raise AlreadyRegistered.""" name = self.settings.APPLICATION_URL_MODULE appurls = () if name: app_module = import_module(name) appurls = app_module.appurls self.load_initial() for application in appurls: self.register(application) url = self.make_url urls = () # Add in each model's views. for app in self._nameregistry.values(): baseurl = app.baseurl if baseurl: urls += url('^{0}(.*)'.format(baseurl[1:]), app, name = app.name), return urls def register(self, application): if not isinstance(application,Application): raise DjpcmsException('Cannot register application. Is is not a valid one.') if application.name in self._nameregistry: raise AlreadyRegistered('Application %s already registered as application' % application) self._nameregistry[application.name] = application application.register(self) model = getattr(application,'model',None) if model: if model in self._registry: raise AlreadyRegistered('Model %s already registered as application' % model) self._registry[model] = application else: pass def unregister(self, model): '''Unregister the :class:`djpcms.views.appsite.ModelApplication registered for *model*. Return the application class which has been unregistered.''' appmodel = self._registry.pop(model,None) if appmodel: self._nameregistry.pop(appmodel.name,None) return None if not appmodel else appmodel.__class__ def clear(self): '''Clear the site from all applications''' ResolverMixin.clear(self) del self.choices[1:] self._nameregistry.clear() self._registry.clear() def for_model(self, model): '''Obtain a :class:`djpcms.views.appsite.ModelApplication` for model *model*. If the application is not available, it returns ``None``. Never fails.''' try: return self._registry.get(model,None) except: return None def getapp(self, appname): '''Given a *appname* in the form of appname-appview returns the application handler. If the appname is not available, it raises a KeyError''' names = appname.split('-') if len(names) == 2: name = names[0] app_code = names[1] appmodel = self._nameregistry.get(name,None) if appmodel: return appmodel.getview(app_code) appmodel = self._nameregistry.get(appname,None) if appmodel is None: raise ApplicationNotAvailable('Application {0} not available.'.format(appname)) return appmodel.root_application def get_instanceurl(self, instance, view_name = 'view', **kwargs): '''Calculate a url given a instance''' app = self.for_model(instance.__class__) if app: view = app.getview(view_name) if view: try: return view.get_url(None, instance = instance, **kwargs) except: return None return None def count(self): return len(self._registry) def as_wsgi(self): return make_wsgi(self)
class ApplicationSites(ResolverMixin): '''This class is used as a singletone and holds information of djpcms routes''' def __init__(self): self._settings = None self._default_settings = None self.route = None self.sites = OrderedDict() def __get_settings(self): if not self._settings: if not self._default_settings: self._default_settings = get_settings() return self._default_settings else: return self._settings settings = property(__get_settings) def _load(self): '''Load sites''' from djpcms.apps.cache import PageCache self.pagecache = PageCache() settings = self.settings for site in self.sites.values(): site.pagecache = self.pagecache site.load() import_modules(settings.DJPCMS_PLUGINS) import_modules(settings.DJPCMS_WRAPPERS) url = self.make_url urls = () if settings.CONTENT_INLINE_EDITING['available']: edit = settings.CONTENT_INLINE_EDITING['preurl'] for u,site in self.sites.items(): urls += url(r'^{0}/{1}(.*)'.format(edit,u[1:]), editHandler(site)), for u,site in self.sites.items(): urls += url(r'^{0}(.*)'.format(u[1:]), site), return urls def make(self, name, settings = None, route = None, clearlog = True, **kwargs): '''Initialise DjpCms from a directory or a file''' import djpcms # # if not a directory it may be a file if os.path.isdir(name): appdir = name elif os.path.isfile(name): appdir = os.path.split(os.path.realpath(name))[0] else: try: mod = import_module(name) appdir = mod.__path__[0] except ImportError: raise ValueError('Could not find directory or file {0}'.format(name)) path = os.path.realpath(appdir) base,name = os.path.split(path) if base not in sys.path: sys.path.insert(0, base) # Import settings settings = settings or 'settings' if '.' in settings: settings_module_name = settings os.environ['DJANGO_SETTINGS_MODULE'] = settings else: sett = '{0}.py'.format(os.path.join(path,settings)) if os.path.isfile(sett): spath, settings = os.path.split(settings) settings_module_name = '{0}.{1}'.format(name,settings) os.environ['DJANGO_SETTINGS_MODULE'] = settings_module_name else: settings_module_name = None # IMPORTANT! NEED TO IMPORT HERE TO PREVENT DJANGO TO IMPORT FIRST settings = get_settings(settings_module_name, SITE_DIRECTORY = path, SITE_MODULE = name, **kwargs) # If no settings available get the current one if self._settings is None: self._settings = settings # Add template media directory to template directories path = os.path.join(djpcms.__path__[0],'media','djpcms') if path not in settings.TEMPLATE_DIRS: settings.TEMPLATE_DIRS += path, djpcms.init_logging(clearlog) self.logger = logging.getLogger('ApplicationSites') return self._create_site(route,settings) def _create_site(self,url,settings): from djpcms.apps import appsites url = self.makeurl(url) self.logger.info('Creating new site at route "{0}"'.format(url)) site = self.get(url,None) if site: raise AlreadyRegistered('Site with url {0} already avalable "{1}"'.format(url,site)) site = appsites.ApplicationSite(self.makeurl(url),settings) self.sites[site.route] = site self._urls = None return site def get(self, name, default = None): return self.sites.get(name,default) def get_or_create(self, name, settings = None, route = None): route = self.makeurl(route) site = self.get(route,None) if site: return site else: return self.make(name,settings,route) def makeurl(self, url = None): url = url or '/' if not url.endswith('/'): url += '/' if not url.startswith('/'): url = '/' + url return url def get_site(self, url = None): url = self.makeurl(url) site = self.get(url,None) if not site: try: res = self.resolve(url[1:]) return res[0] except: return None else: return site def get_urls(self): urls = [] for site in self.values(): urls.extend(site.get_urls()) return urls def get_url(self, model, view_name, instance = None, url = None, **kwargs): site = self.get_site(url) if not site: return None if not isinstance(model,type): instance = model model = instance.__class__ app = site.for_model(model) if app: view = app.getview(view_name) if view: try: return view.get_url(None, instance = instance, **kwargs) except: return None return None def view_from_page(self, page): site = self.get_site(page.url) def clear(self): self.sites.clear() ResolverMixin.clear(self) def wsgi(self, environ, start_response): '''WSGI handler''' cleaned_path = self.clean_path(environ) if isinstance(cleaned_path,self.http.HttpResponseRedirect): return cleaned_path path = cleaned_path[1:] site,view,kwargs = self.resolve(path) request = site.http.Request(environ) request.site = site djp = view(request, **kwargs) return djp.response() def djp(self, request, path): '''Entry points for requests''' site,view,kwargs = self.resolve(path) request.site = site djp = view(request, **kwargs) setattr(request,'instance',djp.instance) return djp def request_handler(self, request, url): '''Entry points for requests''' cleaned_path = self.clean_path(request.environ) if isinstance(cleaned_path,self.http.HttpResponse): return cleaned_path try: djp = self.djp(request,url) if isinstance(djp,self.http.HttpResponse): return djp else: return djp.response() except PermissionDenied as e: settings = request.site.settings if settings.HTTP_LIBRARY == 'django': from django.core import exceptions raise exceptions.PermissionDenied(e) else: raise