def handle(self, req): """Handle the request. The Wiking Handler passes the request to the current application for further processing. All errors and exceptions are handled by the handler. The return value may be one of three kinds: * 'wiking.Response' instance representing directly the HTTP response data and headers. * 'wiking.Document' instance, which is automatically converted to a 'wiking.Response' by 'wiking.Handler' exporting the document into HTML through 'wiking.Exporter'. The method may also raise 'RequestError' exceptions to indicate special states or 'Redirect' exceptions to perform HTTP redirection. The default implementation uses static mapping of request paths (URI) to wiking modules defined by the class constant '\_MAPPING' to determine which module is responsible for processing the request and passes the request along to an instance of this module. 'NotFound' is raised if the mapping doesn't define an item for the current request URI. You may re-implement this method if a different logic is more suitable for your application. """ if not req.unresolved_path: # The request to the server's root URI is automatically redirected # to the first menu item's URI. Redirection to hidden items is # avoided particularly because of default items added automatically # to the menu in CMS, such as _registration. If the real menu is # empty, we don't want these items to be used for redirection. menu = [item for item in self.menu(req) if not item.hidden()] # The authentication must be performed before redirection, because # the current request may include login/logout commands which would # be discarded by the redirection. user = req.user() if menu: raise wiking.Redirect(menu[0].id()) elif not user: # Here we handle the common case, that the menu is empty for # non-authenticated users and will be non-empty after the user # authenticates. This presumption may not be theoretically # valid in all cases, but it typically works as expected. If # the application doesn't want this behavior, it should not # return an empty menu. raise wiking.AuthenticationError() else: raise wiking.Forbidden() identifier = req.unresolved_path[0] try: modname = self._mapping[identifier] except KeyError: raise wiking.NotFound() mod = wiking.module(modname) assert isinstance(mod, wiking.RequestHandler) req.unresolved_path.pop(0) return req.forward(mod)
def handle(self, req): req.wmi = False # Will be set to True by `WikingManagementInterface' if needed. preview_mode_param = req.param(self._PREVIEW_MODE_PARAM) if preview_mode_param is not None: req.set_cookie(self._PREVIEW_MODE_COOKIE, preview_mode_param == '1' and '1' or None) wiking.module.CachedTables.reload_info(req) wiking.module.Config.configure(req) modname = self._resolve_modname(req) if modname: return req.forward(wiking.module(modname)) else: try: return super(Application, self).handle(req) except wiking.Forbidden: # The parent method raises Forbidden when there are no menu items to redirect to. if req.check_roles(Roles.CONTENT_ADMIN): # Give the administrator some hints on a fresh install. if wiking.module.Pages.empty(req): return wiking.Document( title=_("Welcome to Wiking CMS"), content=lcg.Container((lcg.p("There are currently no pages."), lcg.p(lcg.link("/?action=insert", _("Create a new page"))))), ) elif not self.preview_mode(req): req.message(_("There are no published pages. " "You need to switch to the Preview mode " "to be able to access the unpublished pages."), req.WARNING) raise
def _descr(self, rrecord, modname): import wiking module = wiking.module(modname) if module: return module.descr() or module.title() else: return None
def _authorized(self, req, action, record=None, **kwargs): roles = wiking.module('Application').authorized_roles(req, self, action=action, record=record) if req.check_roles(roles): return True elif wiking.Roles.OWNER in roles: return self._check_owner(req, action, record=record) else: return False
def login_hook(self, req, user): if not wiking.module.Users.user(req, user.login()): # See 'user()' for comments. regcode = wiking.module('wiking.cms.Users').regenerate_registration_code(user) req.message(_("User %s is already registered for another site. " "Please, confirm the account for this site.", user.login())) raise wiking.Redirect(req.module_uri('Registration'), action='reinsert', login=user.login(), regcode=regcode)
def action_view(self, req, record): text = record['content'].value() modname = record['modname'].value() globals = self.globals(req) storage = self._attachment_storage(record) if storage: resources = storage.resources() else: resources = () if text: text = lcg.MacroParser(globals=globals).parse(text) parser = lcg.Parser() if self._SEPARATOR.search(text): pre, post = [parser.parse(part) for part in self._SEPARATOR.split(text, maxsplit=2)] else: pre, post = parser.parse(text), [] else: pre, post = [], [] if modname is not None: binding = self._embed_binding(modname) result = req.forward(wiking.module(modname), binding=binding, record=record, title=record['title'].value()) if isinstance(result, wiking.Document): # Embed the resulting document into the current menu item content. content = result.content() if isinstance(content, (tuple, list)): content = list(content) else: content = [content] document = result.clone(title=self._document_title(req, record), subtitle=None, content=lcg.Container(pre + content + post, resources=resources), globals=globals) else: # A wiking.Response instance has been returned by the embedded module. return result elif text is None and record['parent'].value() is None: # Redirect to the first subitem from empty top level items. rows = self._data.get_rows(parent=record['menu_item_id'].value(), published=True, sorting=self._sorting) # TODO: Use only items, which are visible to the current user (access rights). if rows: raise wiking.Redirect('/' + self._menu_item_identifier(rows[0])) else: document = self._document(req, lcg.Container([], resources=resources), record, globals=globals) else: document = self._document(req, lcg.Container(pre + post, resources=resources), record, globals=globals) if modname is None: # Module access is logged in EmbeddablePytisModule._handle(). wiking.module.AccessLog.log(req, None, None) return document
def user(self, req, login): user = wiking.module.Users.user(req, login) if user is None and wiking.cms.cfg.allow_registration: # It is possible, that the user doesn't exist in the # application specific users table, but exists in the base # table of wiking CMS (the user was registered for some other # application sharing the same database). Here we test if # that's the case and handle the situation in the login_hook() # below. user = wiking.module('wiking.cms.Users').user(req, login) if user and user.state() == Users.AccountState.NEW: user = None return user
def handle(self, req): if req.unresolved_path: try: modname = self._MAPPING[req.unresolved_path[0]] except KeyError: modname = 'Menu' else: # Consume the unresolved path if it was in static mapping or leave it for further # resolution when passing to Menu. del req.unresolved_path[0] return req.forward(wiking.module(modname)) else: return super(Application, self).handle(req)
def handle(self, req): """Handle the request. The Wiking Handler passes the request to the current application for further processing. All errors and exceptions are handled by the handler. The return value and possible exceptions is the same as described in 'RequestHandler.handle()'. The default implementation uses static mapping of request paths (URI) to wiking modules defined by the class constant '_MAPPING' to determine which module is responsible for processing the request and passes the request along to an instance of this module. 'NotFound' is raised if the mapping doesn't define an item for the current request URI. You may re-implement this method if a different logic is more suitable for your application. """ if not req.unresolved_path: # The request to the server's root URI is automatically redirected # to the first menu item's URI. Redirection to hidden items is # avoided particularly because of default items added automatically # to the menu in CMS, such as _registration. If the real menu is # empty, we don't want these items to be used for redirection. menu = [item for item in self.menu(req) if not item.hidden()] # The authentication must be performed before redirection, because # the current request may include login/logout commands which would # be discarded by the redirection. user = req.user() if menu: raise wiking.Redirect(menu[0].id()) elif not user: # Here we handle the common case, that the menu is empty for # non-authenticated users and will be non-empty after the user # authenticates. This presumption may not be theoretically # valid in all cases, but it typically works as expected. If # the application doesn't want this behavior, it should not # return an empty menu. raise wiking.AuthenticationError() else: raise wiking.Forbidden() identifier = req.unresolved_path[0] try: modname = self._mapping[identifier] except KeyError: raise wiking.NotFound() mod = wiking.module(modname) assert isinstance(mod, wiking.RequestHandler) req.unresolved_path.pop(0) return req.forward(mod)
def authenticate(self, req, login, password, auth_type): user = wiking.module.Users.user(req, login) if user is None and wiking.cms.cfg.allow_registration: # It is possible, that the user doesn't exist in the # application specific users table, but exists in the base # table of wiking CMS (the user was registered for some other # application sharing the same database). Here we test if # that's the case and handle the situation in the login_hook() # below. u = wiking.module('wiking.cms.Users').user(req, login) if u and u.state() != Users.AccountState.NEW: user = u if user: stored_password = user.data()['password'].value() if wiking.cms.cfg.password_storage.check_password(password, stored_password): return user wiking.module.LoginFailures.failure(req, login, auth_type) return None
def handle(self, req): req.wmi = False # Will be set to True by `WikingManagementInterface' if needed. preview_mode_param = req.param(self._PREVIEW_MODE_PARAM) if preview_mode_param is not None: req.set_cookie(self._PREVIEW_MODE_COOKIE, preview_mode_param == '1' and '1' or None) wiking.module.CachedTables.reload_info(req) wiking.module.Config.configure(req) if req.unresolved_path: try: modname = self._mapping[req.unresolved_path[0]] except KeyError: modname = 'Pages' else: # Consume the unresolved path if it was in static mapping or # leave it for further resolution when passing to Pages. del req.unresolved_path[0] elif req.param('action'): if req.param('_manage_cms_panels') == '1': modname = 'Panels' else: modname = 'Pages' else: try: return super(Application, self).handle(req) except wiking.Forbidden: # The parent method raises Forbidden when there are no menu items to redirect to. if req.check_roles(Roles.CONTENT_ADMIN): # Give the administrator some hints on a fresh install. if wiking.module.Pages.empty(req): raise wiking.Abort(_("Welcome to Wiking CMS"), lcg.Container((lcg.p("There are currently no pages."), lcg.p(lcg.link("/?action=insert", _("Create a new page")))))) elif not self.preview_mode(req): req.message(_("There are no published pages. " "You need to switch to the Preview mode " "to be able to access the unpublished pages."), req.WARNING) raise return req.forward(wiking.module(modname))
def login_hook(self, req, user): import wiking.cms.texts if not wiking.module.Users.user(req, user.login()): # This account needs re-registration. See 'user()' for comments. regcode = wiking.module('wiking.cms.Users').regenerate_registration_code(user) req.message(_("User %s is already registered for another site. " "Please, confirm the account for this site.", user.login())) raise wiking.Redirect(req.module_uri('Registration'), action='reinsert', login=user.login(), regcode=regcode) # This is done in the login hook to display the message only once after logging in... state = user.state() text = wiking.module.Texts.text if state == Users.AccountState.DISABLED: message = text(wiking.cms.texts.disabled) elif state == Users.AccountState.NEW: uri = req.make_uri(req.module_uri('Registration'), action='confirm', uid=user.uid()) message = text(wiking.cms.texts.unconfirmed).interpolate(lambda x: dict(uri=uri)[x]) elif state == Users.AccountState.UNAPPROVED: message = text(wiking.cms.texts.unapproved) else: return req.message(message, req.WARNING, formatted=True)
def item(row): menu_item_id = row['menu_item_id'].value() identifier = self._menu_item_identifier(row) titles, descriptions = translations[menu_item_id] title = lcg.SelfTranslatableText(identifier, translations=titles) descr = lcg.SelfTranslatableText('', translations=descriptions) modname = row['modname'].value() if modname is not None: try: module = wiking.module(modname) except AttributeError: # We want the website to work even if the module was uninstalled or renamed. submenu = [] else: submenu = list(module.submenu(req, menu_item_id)) else: submenu = [] submenu += [item(r) for r in children.get(menu_item_id, ())] # TODO: Optimize (avoid separate DB queries for each menu item). hidden = not req.check_roles(rights.permitted_roles(menu_item_id, 'show')) active = req.check_roles(rights.permitted_roles(menu_item_id, 'visit')) return wiking.MenuItem(identifier, title, descr=descr, hidden=hidden, active=active, variants=tuple(titles.keys()), submenu=submenu,)
def module_uri(self, req, modname): """Return the base URI of given Wiking module (relative to server root). This method implements the interface defined by 'wiking.Application.module_uri()' specifically for the Wiking CMS application. The method bahaves as follows: 1. Static URI mapping (see 'wiking.Application._MAPPING') is searched first. If the module is found there, the corresponding path is returned. 2. If the above fails, the module is searched within CMS pages as their extension module. If the module is found as an extension module of a particular page, the path to that page (including the subpath to the module) is returned. Beware that if the same module had been used as an extension module for more than one page, there would be no way to distinguish which page to use to form the path and thus None is returned in such cases. 3. If the above fails and the module is derived from 'CMSExtensionModule', its parent module is searched according to 2. and if found, the corresponding path plus the path to the submodule is returned. 4. If the above fails and the module is accessible through the Wikimg Management Interface, the WMI uri is returned. 5. If all the above fails, None is returned. Particularly, this happens for modules, which are not directly associated with any page, which may also be the case for modules accessible through bindings to other modules. The mapping used in step 1. is called static, because it is a hardcoded assignment of URIs of modules needed for Wiking CMS to run (such as 'Documentation', 'Resources', etc). The user is not able to change this mapping. The convention is, that URIs in the static mapping in Wiking CMS start with an underscore to prevent conflicts with user defined URIs (identifiers) of CMS pages (which are dynamic from this perspective — the user may change them). Examples (calling through 'wiking.Request.module_uri()'): req.module_uri('Documentation') Returns '/_doc'. req.module_uri('Users') Returns '/users' if the module 'Users' is used in a CMS page with an identifier 'users'. If the module is not used in any CMS page '/_wmi/users/Users' is returned. req.module_uri('Planner') Returns '/events' if the module 'Planner' is used in a CMS page with an identifier 'events' or None if it is not used. req.module_uri('BugComments') Returns '/bts/bug-comments' if the CMS extension module 'BugTrackingSystem' is used in a page with an identifier 'bts' and 'BugComments' is a submodule of 'BugTrackingSystem' with a static subpath 'bug-comments'). """ # Try the static mapping first. uri = super(Application, self).module_uri(req, modname) if uri is None: # Try if the module is directly embedded in a page. uri = wiking.module.Pages.module_uri(req, modname) if uri is None: # If not embeded directly, try if it is a submodule of an embedded module. mod = wiking.module(modname) if isinstance(mod, CMSExtensionModule): parent = mod.parent() if parent is None: # Hack: Instantiate all CMSExtension modules to get # the parent, as parentship is initialized on # CMSExtension module for all its child # CMSExtensionModule submodules. for modname_, modcls in wiking.cfg.resolver.walk(CMSExtension): wiking.module(modname_) parent = mod.parent() # It's hopefully not None now... if parent is not None: uri = parent.submodule_uri(req, modname) if uri is None: uri = wiking.module.WikingManagementInterface.module_uri(req, modname) return uri
def menu(self, req): modname = req.wmi and 'WikingManagementInterface' or 'Pages' return wiking.module(modname).menu(req)
def globals(self, req): globals = {} for modname in self._SUBSTITUTION_PROVIDERS: module = wiking.module(modname) globals.update(module.variables(req)) return globals
def _new_uid_filter(self, row, name): assigned_users = wiking.module(self._resolver).assigned_users(row['name']) return pd.AND(*[pd.NE('uid', u) for u in assigned_users])
def _new_uid_filter(self, row, name): assigned_users = wiking.module(self._resolver).assigned_users( row['name']) return pd.AND(*[pd.NE('uid', u) for u in assigned_users])
def _authorized(self, req, action=None): return req.check_roles(wiking.module('Application').authorized_roles(req, self, action=action))
def _reload_actions(self, record): import wiking def action_descr(module, action): if issubclass(module, wiking.PytisModule): for a in module.Spec.actions: if a.name() == action: return a.descr() or a.title() try: return dict(self._DEFAULT_ACTIONS)[action] except KeyError: method = getattr(module, 'action_' + action) docstring = method.__doc__ return docstring and docstring.splitlines()[0] or _( "Neuvedeno") module = wiking.module(record['modname'].value()) if module: data = pytis.util.data_object(self._spec_name('Actions')) data.select(condition=pd.EQ('mod_id', record['mod_id'])) existing_actions = {} while True: row = data.fetchone() if row is None: break else: existing_actions[row['name'].value()] = row['action_id'] data.close() actions = [ attr[7:] for attr in dir(module) if attr.startswith('action_') and callable(getattr(module, attr)) ] default_actions = [a[0] for a in self._DEFAULT_ACTIONS] # Order default actions first and in the order of self._DEFAULT_ACTIONS. actions.sort(key=lambda a: str(default_actions.index(a)) if a in default_actions else a) descriptions = [action_descr(module, action) for action in actions] from pytis.form import run_dialog, CheckListDialog result = run_dialog( CheckListDialog, title=_("Nalezené akce"), message=_("Zaškrtněte akce, které chcete zpřístupnit webovým " "uživatelům:"), items=[(a in existing_actions, a, d) for a, d in zip(actions, descriptions)], columns=(_("Action"), _("Description"))) if result is not None: # TODO: Use a transaction. Respect existing actions. for i, action in enumerate(actions): if result[i]: description_value = pd.Value(pd.String(), descriptions[i] or None) try: key = existing_actions[action] except KeyError: rowdata = [('mod_id', record['mod_id']), ('name', pd.Value(pd.String(), action)), ('description', description_value)] data.insert(pd.Row(rowdata)) else: data.update( (key, ), pd.Row((('description', description_value), )))
def _authorized(self, req, action=None): return req.check_roles( wiking.module('Application').authorized_roles(req, self, action=action))