265 lines
9.8 KiB
Python
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
|