wcs/wcs/backoffice/root.py

265 lines
9.8 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2010 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import time
from quixote import get_session, get_publisher, get_request, get_response, redirect
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext
from qommon.backoffice import BackofficeRootDirectory
from qommon.backoffice.menu import html_top
from qommon import misc, get_logger, get_cfg
from qommon import errors
from qommon.form import *
from wcs.formdef import FormDef
from wcs.roles import Role
import wcs.admin.bounces
import wcs.admin.categories
import wcs.admin.forms
import wcs.admin.logger
import wcs.admin.roles
import wcs.admin.settings
import wcs.admin.users
import wcs.admin.workflows
from . import management
class RootDirectory(BackofficeRootDirectory):
_q_exports = ['', 'pending', 'statistics', ('menu.json', 'menu_json')]
bounces = wcs.admin.bounces.BouncesDirectory()
categories = wcs.admin.categories.CategoriesDirectory()
forms = wcs.admin.forms.FormsDirectory()
logger = wcs.admin.logger.LoggerDirectory()
roles = wcs.admin.roles.RolesDirectory()
settings = wcs.admin.settings.SettingsDirectory()
users = wcs.admin.users.UsersDirectory()
workflows = wcs.admin.workflows.WorkflowsDirectory()
management = management.ManagementDirectory()
menu_items = [
('management/', N_('Management')),
('forms/', N_('Forms Workshop')),
('workflows/', N_('Workflows Workshop')),
('users/', N_('Users')),
('roles/', N_('Roles')),
('categories/', N_('Categories')),
('logger/', N_('Logs'), logger.is_visible),
('bounces/', N_('Bounces'), bounces.is_visible),
('settings/', N_('Settings')),
]
def _q_traverse(self, path):
get_response().add_javascript(['jquery.js'])
return super(RootDirectory, self)._q_traverse(path)
@classmethod
def is_accessible(cls, subdirectory):
# check a backoffice directory is accessible to the current user
if getattr(get_response(), 'filter', {}) and get_response().filter.get('admin_for_all'):
# if admin for all is set, access is granted to everything
return True
if not get_request().user:
if get_publisher().user_class.count() == 0:
# setting up the site, access is granted to settings and users
# sections
return subdirectory in ('settings', 'users')
return False
user_roles = set(get_request().user.roles or [])
authorised_roles = set(get_cfg('admin-permissions', {}).get(subdirectory) or [])
if authorised_roles:
# access is governed by roles set in the settings panel
return user_roles.intersection(authorised_roles)
# for some subdirectories, the user needs to be part of a role allowed
# to go in the backoffice
if subdirectory in ('management',):
return get_request().user.can_go_in_backoffice()
# for the other directories, an extra level is required, the user needs
# to be marked as admin
return get_request().user.can_go_in_admin()
def check_admin_for_all(self):
admin_for_all_file_path = os.path.join(get_publisher().app_dir, 'ADMIN_FOR_ALL')
if not os.path.exists(os.path.join(admin_for_all_file_path)):
return False
admin_for_all_contents = open(admin_for_all_file_path).read()
if not admin_for_all_contents:
# empty file, access is granted to everybody
return True
if get_request().get_environ('REMOTE_ADDR', '') in admin_for_all_contents.splitlines():
# if the file is not empty it should contain the list of authorized
# IP addresses.
return True
return False
def _q_access(self):
get_response().breadcrumb.append( ('backoffice/', _('Back Office')) )
req = get_request()
if self.check_admin_for_all():
get_response().filter['admin_for_all'] = True
return
if get_publisher().user_class.count() > 0:
user = req.user
if not user:
raise errors.AccessUnauthorizedError(
public_msg = _('Access to backoffice is restricted to authorized persons only. '\
'Please login.'))
if not user.can_go_in_backoffice():
raise errors.AccessForbiddenError()
get_response().filter['in_backoffice'] = True
def get_intro_text(self):
return _('''Welcome.''')
def generate_header_menu(self, selected=None):
s = ['<ul id="menu">\n']
for menu_item in self.get_menu_items():
if not 'icon' in menu_item:
continue
if menu_item.get('slug') == selected:
s.append('<li class="active">')
else:
s.append('<li>')
s.append('<a href="%(url)s">%(label)s</a></li>\n' % menu_item)
s.append('</ul>\n')
return ''.join(s)
def _q_index(self):
html_top('/')
r = TemplateIO(html=True)
r += htmltext('<div class="bo-block"><p>%s</p></div>') % self.get_intro_text()
menu_items = self.get_menu_items()
r += htmltext('<ul class="apps">')
for menu_item in menu_items:
if not 'icon' in menu_item:
continue
r += htmltext('<li class="zone-%(icon)s"><a href="%(url)s">%(label)s</a></li>') % menu_item
for menu_item in menu_items:
if 'icon' in menu_item:
continue
r += htmltext('<li class="zone-no-icon"><a href="%(url)s">%(label)s</a></li>') % menu_item
r += htmltext('</ul>')
r += htmltext('<br class="clear">')
r += htmltext('<p id="for-more-info"></p>')
get_response().filter['sidebar'] = str(self.get_sidebar())
return r.getvalue()
def get_sidebar(self):
from qommon.admin.menu import get_vc_version
from wcs.admin.root import gpl
r = TemplateIO(html=True)
r += htmltext('<div class="bo-block">')
r += htmltext('<ul id="sidebar-actions">')
r += htmltext('<li><a href="management/statistics">%s</a></li>') % _('Global statistics')
r += htmltext('</ul>')
r += htmltext('</div>')
version = get_vc_version()
if version:
r += htmltext('<div class="bo-block"><p class="version-info">')
r += _('Version:')
r += ' '
r += version
r += htmltext('</p></div>')
r += htmltext('<div class="bo-block">')
r += gpl()
r += htmltext('</div>')
return r.getvalue()
def menu_json(self):
get_response().set_content_type('application/json')
if get_request().get_environ('HTTP_ORIGIN'):
get_response().set_header('Access-Control-Allow-Origin',
get_request().get_environ('HTTP_ORIGIN'))
get_response().set_header('Access-Control-Allow-Credentials', 'true')
get_response().set_header('Access-Control-Allow-Headers', 'x-requested-with')
menu_items = []
backoffice_url = get_publisher().get_backoffice_url()
return json.dumps(self.get_menu_items())
def pending(self):
# kept as a redirection for compatibility with possible bookmarks
return redirect('.')
def statistics(self):
return redirect('management/statistics')
def _q_lookup(self, component):
if component in [str(x[0]).strip('/') for x in self.menu_items]:
if not self.is_accessible(component):
raise errors.AccessForbiddenError()
return getattr(self, component)
if FormDef.has_key(component):
# keep compatibility with previous versions, redirect from legacy
# URL to new ones under management/
return redirect('management/%s/' % component)
return super(RootDirectory, self)._q_lookup(component)
def get_menu_items(self):
if not get_request().user:
# this could happen if admin-for-all is set, or if it's the first
# user connecting.
user_roles = set()
else:
user_roles = set(get_request().user.roles or [])
menu_items = []
backoffice_url = get_publisher().get_backoffice_url()
if not backoffice_url.endswith('/'):
backoffice_url += '/'
for item in self.menu_items:
if len(item) == 2:
item = list(item) + [None]
k, v, display_function = item
slug = k.strip(str('/'))
if not slug:
continue
if display_function and not display_function(slug):
continue
if not self.is_accessible(slug):
continue
if callable(v):
label = v()
else:
label = _(v)
menu_items.append({
'label': label,
'slug': slug,
'url': backoffice_url + k})
if slug in ('home', 'forms', 'workflows', 'users', 'roles',
'categories', 'settings', 'management'):
menu_items[-1]['icon'] = k.strip('/')
return menu_items