trivial: apply black
This commit is contained in:
parent
1fd2171ea2
commit
2663e08e2d
|
@ -27,9 +27,17 @@ rdb.register_menu_item('payments/', _('Payments'))
|
|||
rdb.register_directory('settings', admin.SettingsDirectory())
|
||||
|
||||
import wcs.admin.forms
|
||||
|
||||
wcs.admin.forms.FormsDirectory.categories = categories_admin.CategoriesDirectory()
|
||||
|
||||
import wcs.categories
|
||||
wcs.categories.Category.XML_NODES = [('name', 'str'), ('url_name', 'str'),
|
||||
('description', 'str'), ('position', 'int'),
|
||||
('homepage_position', 'str'), ('redirect_url', 'str'), ('limit', 'int')]
|
||||
|
||||
wcs.categories.Category.XML_NODES = [
|
||||
('name', 'str'),
|
||||
('url_name', 'str'),
|
||||
('description', 'str'),
|
||||
('position', 'int'),
|
||||
('homepage_position', 'str'),
|
||||
('redirect_url', 'str'),
|
||||
('limit', 'int'),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from wcs.workflows import WorkflowStatusItem
|
||||
|
||||
|
||||
class AbeliumDominoRegisterFamilyWorkflowStatusItem(WorkflowStatusItem):
|
||||
key = 'abelium-domino-register-family'
|
||||
|
|
|
@ -36,13 +36,21 @@ class PanelDirectory(Directory):
|
|||
def permissions(self):
|
||||
permissions_cfg = get_cfg('aq-permissions', {})
|
||||
form = Form(enctype='multipart/form-data')
|
||||
form.add(SingleSelectWidget, 'forms', title = _('Admin role for forms'),
|
||||
value = permissions_cfg.get('forms', None),
|
||||
options = [(None, _('Nobody'), None)] + get_user_roles())
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'forms',
|
||||
title=_('Admin role for forms'),
|
||||
value=permissions_cfg.get('forms', None),
|
||||
options=[(None, _('Nobody'), None)] + get_user_roles(),
|
||||
)
|
||||
if get_publisher().has_site_option('auquotidien-payments'):
|
||||
form.add(SingleSelectWidget, 'payments', title = _('Admin role for payments'),
|
||||
value = permissions_cfg.get('payments', None),
|
||||
options = [(None, _('Nobody'), None)] + get_user_roles())
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'payments',
|
||||
title=_('Admin role for payments'),
|
||||
value=permissions_cfg.get('payments', None),
|
||||
options=[(None, _('Nobody'), None)] + get_user_roles(),
|
||||
)
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
|
||||
|
@ -58,6 +66,7 @@ class PanelDirectory(Directory):
|
|||
return r.getvalue()
|
||||
else:
|
||||
from wcs.admin.settings import cfg_submit
|
||||
|
||||
cfg_submit(form, 'aq-permissions', ('forms', 'payments'))
|
||||
return redirect('..')
|
||||
|
||||
|
@ -83,4 +92,5 @@ class SettingsDirectory(wcs.admin.settings.SettingsDirectory):
|
|||
return PanelDirectory()
|
||||
return super(SettingsDirectory, self)._q_lookup(component)
|
||||
|
||||
|
||||
from . import categories_admin
|
||||
|
|
|
@ -17,6 +17,7 @@ from wcs.qommon.form import *
|
|||
|
||||
CURRENT_USER = object()
|
||||
|
||||
|
||||
def check_visibility(target, user=CURRENT_USER):
|
||||
if not get_publisher().has_site_option('auquotidien-%s' % target):
|
||||
# option not explicitely enabled, -> off.
|
||||
|
@ -48,4 +49,5 @@ class BackofficeRootDirectory(wcs.backoffice.root.RootDirectory):
|
|||
def home(self):
|
||||
return redirect('management/')
|
||||
|
||||
|
||||
get_publisher_class().backoffice_directory_class = BackofficeRootDirectory
|
||||
|
|
|
@ -26,6 +26,7 @@ from wcs.qommon.backoffice.menu import html_top
|
|||
from wcs.qommon.admin.menu import command_icon, error_page
|
||||
import wcs.admin.categories
|
||||
|
||||
|
||||
class CategoryUI:
|
||||
def __init__(self, category):
|
||||
self.category = category
|
||||
|
@ -34,28 +35,47 @@ class CategoryUI:
|
|||
|
||||
def get_form(self):
|
||||
form = Form(enctype='multipart/form-data')
|
||||
form.add(StringWidget, 'name', title = _('Category Name'), required = True, size=30,
|
||||
value = self.category.name)
|
||||
form.add(TextWidget, 'description', title = _('Description'), cols = 80, rows = 10,
|
||||
value = self.category.description)
|
||||
form.add(
|
||||
StringWidget, 'name', title=_('Category Name'), required=True, size=30, value=self.category.name
|
||||
)
|
||||
form.add(
|
||||
TextWidget,
|
||||
'description',
|
||||
title=_('Description'),
|
||||
cols=80,
|
||||
rows=10,
|
||||
value=self.category.description,
|
||||
)
|
||||
|
||||
homepage_redirect_url = get_cfg('misc', {}).get('homepage-redirect-url')
|
||||
if not homepage_redirect_url:
|
||||
form.add(SingleSelectWidget, 'homepage_position',
|
||||
title=_('Position on homepage'),
|
||||
value=self.category.get_homepage_position(),
|
||||
options = [('1st', _('First Column')),
|
||||
('2nd', _('Second Column')),
|
||||
('side', _('Sidebar')),
|
||||
('none', _('None'))])
|
||||
form.add(IntWidget, 'limit',
|
||||
title=_('Limit number of items displayed on homepage'),
|
||||
value=self.category.get_limit())
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'homepage_position',
|
||||
title=_('Position on homepage'),
|
||||
value=self.category.get_homepage_position(),
|
||||
options=[
|
||||
('1st', _('First Column')),
|
||||
('2nd', _('Second Column')),
|
||||
('side', _('Sidebar')),
|
||||
('none', _('None')),
|
||||
],
|
||||
)
|
||||
form.add(
|
||||
IntWidget,
|
||||
'limit',
|
||||
title=_('Limit number of items displayed on homepage'),
|
||||
value=self.category.get_limit(),
|
||||
)
|
||||
|
||||
form.add(StringWidget, 'redirect_url', size=32,
|
||||
title=_('URL Redirection'),
|
||||
hint=_('If set, redirect the site category page to the given URL.'),
|
||||
value=self.category.redirect_url)
|
||||
form.add(
|
||||
StringWidget,
|
||||
'redirect_url',
|
||||
size=32,
|
||||
title=_('URL Redirection'),
|
||||
hint=_('If set, redirect the site category page to the given URL.'),
|
||||
value=self.category.redirect_url,
|
||||
)
|
||||
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
|
@ -66,7 +86,7 @@ class CategoryUI:
|
|||
self.category.name = form.get_widget('name').parse()
|
||||
category = self.category
|
||||
else:
|
||||
category = Category(name = form.get_widget('name').parse())
|
||||
category = Category(name=form.get_widget('name').parse())
|
||||
|
||||
name = form.get_widget('name').parse()
|
||||
category_names = [x.name for x in Category.select() if x.id != category.id]
|
||||
|
@ -85,7 +105,6 @@ class CategoryUI:
|
|||
category.store()
|
||||
|
||||
|
||||
|
||||
class CategoryPage(wcs.admin.categories.CategoryPage):
|
||||
def __init__(self, component):
|
||||
self.category = Category.get(component)
|
||||
|
@ -97,7 +116,7 @@ class CategoriesDirectory(wcs.admin.categories.CategoriesDirectory):
|
|||
label = N_('Categories')
|
||||
|
||||
def new(self):
|
||||
get_response().breadcrumb.append( ('new', _('New')) )
|
||||
get_response().breadcrumb.append(('new', _('New')))
|
||||
category_ui = CategoryUI(None)
|
||||
form = category_ui.get_form()
|
||||
if form.get_widget('cancel').parse():
|
||||
|
@ -111,7 +130,7 @@ class CategoriesDirectory(wcs.admin.categories.CategoriesDirectory):
|
|||
else:
|
||||
return redirect('.')
|
||||
|
||||
html_top('categories', title = _('New Category'))
|
||||
html_top('categories', title=_('New Category'))
|
||||
r = TemplateIO(html=True)
|
||||
r += htmltext('<h2>%s</h2>') % _('New Category')
|
||||
r += form.render()
|
||||
|
|
|
@ -2,6 +2,7 @@ class AppointmentPart(object):
|
|||
def view(self):
|
||||
return ''
|
||||
|
||||
|
||||
class AppointmentErrorPart(object):
|
||||
def view(self):
|
||||
return ''
|
||||
|
|
|
@ -17,6 +17,7 @@ from wcs.qommon import emails
|
|||
|
||||
OldFormPage = wcs.forms.root.FormPage
|
||||
|
||||
|
||||
class AlternateFormPage(OldFormPage):
|
||||
def __call__(self):
|
||||
# Fix missing trailing slash; lose query string on purpose.
|
||||
|
@ -31,6 +32,7 @@ class AlternateFormPage(OldFormPage):
|
|||
get_response().filter['steps'] = form_side_html
|
||||
return
|
||||
|
||||
|
||||
wcs.forms.root.FormPage = AlternateFormPage
|
||||
wcs.forms.root.PublicFormStatusPage.form_page_class = AlternateFormPage
|
||||
wcs.forms.preview.PreviewFormPage.__bases__ = (AlternateFormPage,)
|
||||
|
@ -38,9 +40,11 @@ wcs.forms.preview.PreviewFormPage.__bases__ = (AlternateFormPage,)
|
|||
|
||||
OldFormsRootDirectory = wcs.forms.root.RootDirectory
|
||||
|
||||
|
||||
class AlternateFormsRootDirectory(OldFormsRootDirectory):
|
||||
def form_list(self, *args, **kwargs):
|
||||
form_list = OldFormsRootDirectory.form_list(self, *args, **kwargs)
|
||||
return htmltext(str(form_list).replace('h2>', 'h3>'))
|
||||
|
||||
|
||||
wcs.forms.root.RootDirectory = AlternateFormsRootDirectory
|
||||
|
|
|
@ -28,6 +28,7 @@ import wcs.myspace
|
|||
|
||||
from .payments import Invoice, Regie, is_payment_supported
|
||||
|
||||
|
||||
class MyInvoicesDirectory(Directory):
|
||||
_q_exports = ['']
|
||||
|
||||
|
@ -49,8 +50,7 @@ class MyInvoicesDirectory(Directory):
|
|||
r += get_session().display_message()
|
||||
|
||||
invoices = []
|
||||
invoices.extend(Invoice.get_with_indexed_value(
|
||||
str('user_id'), str(user.id)))
|
||||
invoices.extend(Invoice.get_with_indexed_value(str('user_id'), str(user.id)))
|
||||
invoices.sort(key=lambda x: (str(x.regie_id), -x.date.toordinal()))
|
||||
|
||||
last_regie_id = None
|
||||
|
@ -88,8 +88,10 @@ class MyInvoicesDirectory(Directory):
|
|||
r += _('paid on %s') % misc.localstrftime(invoice.paid_date)
|
||||
r += ' - '
|
||||
button = _('Details')
|
||||
r += htmltext('<a href="%s/invoices/%s">%s</a>' % (get_publisher().get_frontoffice_url(),
|
||||
invoice.id, button))
|
||||
r += htmltext(
|
||||
'<a href="%s/invoices/%s">%s</a>'
|
||||
% (get_publisher().get_frontoffice_url(), invoice.id, button)
|
||||
)
|
||||
r += htmltext('</li>')
|
||||
|
||||
if last_regie_id:
|
||||
|
@ -102,8 +104,8 @@ class MyInvoicesDirectory(Directory):
|
|||
|
||||
|
||||
class JsonDirectory(Directory):
|
||||
'''Export of several lists in json, related to the current user or the
|
||||
SAMLv2 NameID we'd get in the URL'''
|
||||
"""Export of several lists in json, related to the current user or the
|
||||
SAMLv2 NameID we'd get in the URL"""
|
||||
|
||||
_q_exports = ['forms']
|
||||
|
||||
|
@ -119,14 +121,12 @@ class JsonDirectory(Directory):
|
|||
formdefs = FormDef.select(order_by='name', ignore_errors=True)
|
||||
user_forms = []
|
||||
for formdef in formdefs:
|
||||
user_forms.extend(formdef.data_class().get_with_indexed_value(
|
||||
'user_id', self.user.id))
|
||||
user_forms.extend(formdef.data_class().get_with_indexed_value('user_id', self.user.id))
|
||||
epoch = time.localtime(1970)
|
||||
user_forms.sort(key=lambda x: x.receipt_time or epoch)
|
||||
|
||||
get_response().set_content_type('application/json')
|
||||
|
||||
|
||||
forms_output = []
|
||||
for form in user_forms:
|
||||
visible_status = form.get_visible_status(user=self.user)
|
||||
|
@ -136,21 +136,16 @@ class JsonDirectory(Directory):
|
|||
name = form.formdef.name
|
||||
id = form.get_display_id()
|
||||
status = visible_status.name
|
||||
title = _('%(name)s #%(id)s (%(status)s)') % {
|
||||
'name': name,
|
||||
'id': id,
|
||||
'status': status
|
||||
}
|
||||
title = _('%(name)s #%(id)s (%(status)s)') % {'name': name, 'id': id, 'status': status}
|
||||
url = form.get_url()
|
||||
d = { 'title': title, 'url': url }
|
||||
d = {'title': title, 'url': url}
|
||||
d.update(form.get_substitution_variables(minimal=True))
|
||||
forms_output.append(d)
|
||||
return json.dumps(forms_output, cls=misc.JSONEncoder)
|
||||
|
||||
|
||||
class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
||||
_q_exports = ['', 'profile', 'new', 'password', 'remove', 'drafts', 'forms',
|
||||
'invoices', 'json']
|
||||
_q_exports = ['', 'profile', 'new', 'password', 'remove', 'drafts', 'forms', 'invoices', 'json']
|
||||
|
||||
invoices = MyInvoicesDirectory()
|
||||
json = JsonDirectory()
|
||||
|
@ -161,15 +156,13 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
|
||||
# Migrate custom text settings
|
||||
texts_cfg = get_cfg('texts', {})
|
||||
if 'text-aq-top-of-profile' in texts_cfg and (
|
||||
not 'text-top-of-profile' in texts_cfg):
|
||||
if 'text-aq-top-of-profile' in texts_cfg and (not 'text-top-of-profile' in texts_cfg):
|
||||
texts_cfg['text-top-of-profile'] = texts_cfg['text-aq-top-of-profile']
|
||||
del texts_cfg['text-aq-top-of-profile']
|
||||
get_publisher().write_cfg()
|
||||
|
||||
return Directory._q_traverse(self, path)
|
||||
|
||||
|
||||
def _q_index(self):
|
||||
user = get_request().user
|
||||
if not user:
|
||||
|
@ -186,8 +179,7 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
formdefs = FormDef.select(order_by='name', ignore_errors=True)
|
||||
user_forms = []
|
||||
for formdef in formdefs:
|
||||
user_forms.extend(formdef.data_class().get_with_indexed_value(
|
||||
'user_id', user.id))
|
||||
user_forms.extend(formdef.data_class().get_with_indexed_value('user_id', user.id))
|
||||
epoch = time.localtime(1970)
|
||||
user_forms.sort(key=lambda x: x.receipt_time or epoch)
|
||||
|
||||
|
@ -223,15 +215,20 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
pass
|
||||
else:
|
||||
r += htmltext('<p>')
|
||||
r += _('You can delete your account freely from the services portal. '
|
||||
'This action is irreversible; it will destruct your personal '
|
||||
'datas and destruct the access to your request history.')
|
||||
r += htmltext(' <strong><a href="remove" rel="popup">%s</a></strong>.') % _('Delete My Account')
|
||||
r += _(
|
||||
'You can delete your account freely from the services portal. '
|
||||
'This action is irreversible; it will destruct your personal '
|
||||
'datas and destruct the access to your request history.'
|
||||
)
|
||||
r += htmltext(' <strong><a href="remove" rel="popup">%s</a></strong>.') % _(
|
||||
'Delete My Account'
|
||||
)
|
||||
r += htmltext('</p>')
|
||||
|
||||
if user_forms:
|
||||
r += htmltext('<h3 id="my-forms">%s</h3>') % _('My Forms')
|
||||
from . import root
|
||||
|
||||
r += root.FormsRootDirectory().user_forms(user_forms)
|
||||
|
||||
return r.getvalue()
|
||||
|
@ -267,10 +264,14 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
ident_method = 'idp'
|
||||
|
||||
if form_data and ident_method != 'idp':
|
||||
r += htmltext('<p class="command"><a href="profile" rel="popup">%s</a></p>') % _('Edit My Profile')
|
||||
r += htmltext('<p class="command"><a href="profile" rel="popup">%s</a></p>') % _(
|
||||
'Edit My Profile'
|
||||
)
|
||||
|
||||
if ident_method == 'password' and passwords_cfg.get('can_change', False):
|
||||
r += htmltext('<p class="command"><a href="password" rel="popup">%s</a></p>') % _('Change My Password')
|
||||
r += htmltext('<p class="command"><a href="password" rel="popup">%s</a></p>') % _(
|
||||
'Change My Password'
|
||||
)
|
||||
|
||||
return r.getvalue()
|
||||
|
||||
|
@ -279,9 +280,9 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
if not user or user.anonymous:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
|
||||
form = Form(enctype = 'multipart/form-data')
|
||||
form = Form(enctype='multipart/form-data')
|
||||
formdef = user.get_formdef()
|
||||
formdef.add_fields_to_form(form, form_data = user.form_data)
|
||||
formdef.add_fields_to_form(form, form_data=user.form_data)
|
||||
|
||||
form.add_submit('submit', _('Apply Changes'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
|
@ -314,11 +315,9 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
if not user or user.anonymous:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
|
||||
form = Form(enctype = 'multipart/form-data')
|
||||
form.add(PasswordWidget, 'new_password', title = _('New Password'),
|
||||
required=True)
|
||||
form.add(PasswordWidget, 'new2_password', title = _('New Password (confirm)'),
|
||||
required=True)
|
||||
form = Form(enctype='multipart/form-data')
|
||||
form.add(PasswordWidget, 'new_password', title=_('New Password'), required=True)
|
||||
form.add(PasswordWidget, 'new2_password', title=_('New Password (confirm)'), required=True)
|
||||
|
||||
form.add_submit('submit', _('Change Password'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
|
@ -351,7 +350,7 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
if not get_request().user or not get_request().user.anonymous:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
|
||||
form = Form(enctype = 'multipart/form-data')
|
||||
form = Form(enctype='multipart/form-data')
|
||||
formdef = get_publisher().user_class.get_formdef()
|
||||
if formdef:
|
||||
formdef.add_fields_to_form(form)
|
||||
|
@ -376,15 +375,15 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
template.html_top(_('Welcome'))
|
||||
return form.render()
|
||||
|
||||
|
||||
def remove(self):
|
||||
user = get_request().user
|
||||
if not user or user.anonymous:
|
||||
raise errors.AccessUnauthorizedError()
|
||||
|
||||
form = Form(enctype = 'multipart/form-data')
|
||||
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
|
||||
'Are you really sure you want to remove your account?')))
|
||||
form = Form(enctype='multipart/form-data')
|
||||
form.widgets.append(
|
||||
HtmlWidget('<p>%s</p>' % _('Are you really sure you want to remove your account?'))
|
||||
)
|
||||
form.add_submit('submit', _('Remove my account'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
|
||||
|
@ -394,7 +393,7 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
if form.is_submitted() and not form.has_errors():
|
||||
user = get_request().user
|
||||
account = PasswordAccount.get_on_index(user.id, str('user_id'))
|
||||
get_session_manager().expire_session()
|
||||
get_session_manager().expire_session()
|
||||
account.remove_self()
|
||||
return redirect(get_publisher().get_root_url())
|
||||
|
||||
|
@ -402,7 +401,4 @@ class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
|
|||
return form.render()
|
||||
|
||||
|
||||
TextsDirectory.register('aq-myspace-invoice',
|
||||
N_('Message on top of invoices page'),
|
||||
category = N_('Invoices'))
|
||||
|
||||
TextsDirectory.register('aq-myspace-invoice', N_('Message on top of invoices page'), category=N_('Invoices'))
|
||||
|
|
|
@ -8,8 +8,7 @@ from decimal import Decimal
|
|||
|
||||
from django.utils.six.moves.urllib import parse as urllib
|
||||
|
||||
from quixote import (redirect, get_publisher, get_request, get_session,
|
||||
get_response)
|
||||
from quixote import redirect, get_publisher, get_request, get_session, get_response
|
||||
from quixote.directory import Directory
|
||||
from quixote.html import TemplateIO, htmltext
|
||||
|
||||
|
@ -26,14 +25,14 @@ from wcs.qommon import _, N_
|
|||
from wcs.qommon import force_str
|
||||
from wcs.qommon import errors, get_logger, get_cfg, emails
|
||||
from wcs.qommon.storage import StorableObject
|
||||
from wcs.qommon.form import htmltext, StringWidget, TextWidget, SingleSelectWidget, \
|
||||
WidgetDict
|
||||
from wcs.qommon.form import htmltext, StringWidget, TextWidget, SingleSelectWidget, WidgetDict
|
||||
from wcs.qommon.misc import simplify
|
||||
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.formdata import Evolution
|
||||
from wcs.workflows import WorkflowStatusItem, register_item_class, template_on_formdata
|
||||
|
||||
|
||||
def is_payment_supported():
|
||||
if not eopayment:
|
||||
return False
|
||||
|
@ -49,8 +48,7 @@ class Regie(StorableObject):
|
|||
service_options = None
|
||||
|
||||
def get_payment_object(self):
|
||||
return eopayment.Payment(kind=self.service,
|
||||
options=self.service_options)
|
||||
return eopayment.Payment(kind=self.service, options=self.service_options)
|
||||
|
||||
|
||||
class Invoice(StorableObject):
|
||||
|
@ -97,12 +95,14 @@ class Invoice(StorableObject):
|
|||
r = random.SystemRandom()
|
||||
self.fresh = True
|
||||
while True:
|
||||
id = '-'.join([
|
||||
dt.now().strftime('%Y%m%d'),
|
||||
'r%s' % (self.regie_id or 'x'),
|
||||
'f%s' % (self.formdef_id or 'x'),
|
||||
''.join([r.choice(string.digits) for x in range(5)])
|
||||
])
|
||||
id = '-'.join(
|
||||
[
|
||||
dt.now().strftime('%Y%m%d'),
|
||||
'r%s' % (self.regie_id or 'x'),
|
||||
'f%s' % (self.formdef_id or 'x'),
|
||||
''.join([r.choice(string.digits) for x in range(5)]),
|
||||
]
|
||||
)
|
||||
crc = '%0.2d' % (hashlib.md5(id.encode('utf-8')).digest()[0] % 100)
|
||||
id = id + '-' + crc
|
||||
if not self.has_key(id):
|
||||
|
@ -119,6 +119,7 @@ class Invoice(StorableObject):
|
|||
return int(id[-2:]) == (hashlib.md5(id[:-3].encode('utf-8')).digest()[0] % 100)
|
||||
except:
|
||||
return False
|
||||
|
||||
check_crc = classmethod(check_crc)
|
||||
|
||||
def pay(self):
|
||||
|
@ -150,11 +151,16 @@ class Invoice(StorableObject):
|
|||
|
||||
INVOICE_EVO_VIEW = {
|
||||
'create': N_('Create Invoice <a href="%(url)s">%(id)s</a>: %(subject)s - %(amount)s €'),
|
||||
'pay': N_('Invoice <a href="%(url)s">%(id)s</a> is paid with transaction number %(transaction_order_id)s'),
|
||||
'pay': N_(
|
||||
'Invoice <a href="%(url)s">%(id)s</a> is paid with transaction number %(transaction_order_id)s'
|
||||
),
|
||||
'cancel': N_('Cancel Invoice <a href="%(url)s">%(id)s</a>'),
|
||||
'try': N_('Try paying invoice <a href="%(url)s">%(id)s</a> with transaction number %(transaction_order_id)s'),
|
||||
'try': N_(
|
||||
'Try paying invoice <a href="%(url)s">%(id)s</a> with transaction number %(transaction_order_id)s'
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class InvoiceEvolutionPart:
|
||||
action = None
|
||||
id = None
|
||||
|
@ -180,8 +186,9 @@ class InvoiceEvolutionPart:
|
|||
return ''
|
||||
if self.transaction:
|
||||
vars['transaction_order_id'] = self.transaction.order_id
|
||||
return htmltext('<p class="invoice-%s">' % self.action + \
|
||||
_(INVOICE_EVO_VIEW[self.action]) % vars + '</p>')
|
||||
return htmltext(
|
||||
'<p class="invoice-%s">' % self.action + _(INVOICE_EVO_VIEW[self.action]) % vars + '</p>'
|
||||
)
|
||||
|
||||
|
||||
class Transaction(StorableObject):
|
||||
|
@ -206,8 +213,10 @@ class Transaction(StorableObject):
|
|||
id = ''.join([r.choice(string.digits) for x in range(16)])
|
||||
if not cls.has_key(id):
|
||||
return id
|
||||
|
||||
get_new_id = classmethod(get_new_id)
|
||||
|
||||
|
||||
class PaymentWorkflowStatusItem(WorkflowStatusItem):
|
||||
description = N_('Payment Creation')
|
||||
key = 'payment'
|
||||
|
@ -224,6 +233,7 @@ class PaymentWorkflowStatusItem(WorkflowStatusItem):
|
|||
|
||||
def is_available(self, workflow=None):
|
||||
return is_payment_supported()
|
||||
|
||||
is_available = classmethod(is_available)
|
||||
|
||||
def render_as_line(self):
|
||||
|
@ -236,38 +246,49 @@ class PaymentWorkflowStatusItem(WorkflowStatusItem):
|
|||
return _('Payable (not completed)')
|
||||
|
||||
def get_parameters(self):
|
||||
return ('subject', 'details', 'amount', 'regie_id', 'next_status',
|
||||
'request_kwargs')
|
||||
return ('subject', 'details', 'amount', 'regie_id', 'next_status', 'request_kwargs')
|
||||
|
||||
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
|
||||
if 'subject' in parameters:
|
||||
form.add(StringWidget, '%ssubject' % prefix, title=_('Subject'),
|
||||
value=self.subject, size=40)
|
||||
form.add(StringWidget, '%ssubject' % prefix, title=_('Subject'), value=self.subject, size=40)
|
||||
if 'details' in parameters:
|
||||
form.add(TextWidget, '%sdetails' % prefix, title=_('Details'),
|
||||
value=self.details, cols=80, rows=10)
|
||||
form.add(
|
||||
TextWidget, '%sdetails' % prefix, title=_('Details'), value=self.details, cols=80, rows=10
|
||||
)
|
||||
if 'amount' in parameters:
|
||||
form.add(StringWidget, '%samount' % prefix, title=_('Amount'), value=self.amount)
|
||||
if 'regie_id' in parameters:
|
||||
form.add(SingleSelectWidget, '%sregie_id' % prefix,
|
||||
title=_('Regie'), value=self.regie_id,
|
||||
options = [(None, '---')] + [(x.id, x.label) for x in Regie.select()])
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'%sregie_id' % prefix,
|
||||
title=_('Regie'),
|
||||
value=self.regie_id,
|
||||
options=[(None, '---')] + [(x.id, x.label) for x in Regie.select()],
|
||||
)
|
||||
if 'next_status' in parameters:
|
||||
form.add(SingleSelectWidget, '%snext_status' % prefix,
|
||||
title=_('Status after validation'), value = self.next_status,
|
||||
hint=_('Used only if the current status of the form does not contain any "Payment Validation" item'),
|
||||
options = [(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status])
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'%snext_status' % prefix,
|
||||
title=_('Status after validation'),
|
||||
value=self.next_status,
|
||||
hint=_(
|
||||
'Used only if the current status of the form does not contain any "Payment Validation" item'
|
||||
),
|
||||
options=[(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status],
|
||||
)
|
||||
if 'request_kwargs' in parameters:
|
||||
keys = ['name', 'email', 'address', 'phone', 'info1', 'info2', 'info3']
|
||||
hint = ''
|
||||
hint +=_('If the value starts by = it will be '
|
||||
'interpreted as a Python expression.')
|
||||
hint += _('If the value starts by = it will be ' 'interpreted as a Python expression.')
|
||||
hint += ' '
|
||||
hint += _('Standard keys are: %s.') % (', '.join(keys))
|
||||
form.add(WidgetDict, 'request_kwargs',
|
||||
form.add(
|
||||
WidgetDict,
|
||||
'request_kwargs',
|
||||
title=_('Parameters for the payment system'),
|
||||
hint=hint,
|
||||
value = self.request_kwargs)
|
||||
value=self.request_kwargs,
|
||||
)
|
||||
|
||||
def perform(self, formdata):
|
||||
invoice = Invoice(regie_id=self.regie_id, formdef_id=formdata.formdef.id)
|
||||
|
@ -278,8 +299,9 @@ class PaymentWorkflowStatusItem(WorkflowStatusItem):
|
|||
invoice.subject = template_on_formdata(formdata, self.compute(self.subject))
|
||||
else:
|
||||
invoice.subject = _('%(form_name)s #%(formdata_id)s') % {
|
||||
'form_name': formdata.formdef.name,
|
||||
'formdata_id': formdata.id }
|
||||
'form_name': formdata.formdef.name,
|
||||
'formdata_id': formdata.id,
|
||||
}
|
||||
invoice.details = template_on_formdata(formdata, self.compute(self.details))
|
||||
invoice.amount = Decimal(self.compute(self.amount))
|
||||
invoice.date = dt.now()
|
||||
|
@ -300,8 +322,10 @@ class PaymentWorkflowStatusItem(WorkflowStatusItem):
|
|||
# redirect the user to "my invoices"
|
||||
return get_publisher().get_frontoffice_url() + '/myspace/invoices/'
|
||||
|
||||
|
||||
register_item_class(PaymentWorkflowStatusItem)
|
||||
|
||||
|
||||
class PaymentCancelWorkflowStatusItem(WorkflowStatusItem):
|
||||
description = N_('Payment Cancel')
|
||||
key = 'payment-cancel'
|
||||
|
@ -313,6 +337,7 @@ class PaymentCancelWorkflowStatusItem(WorkflowStatusItem):
|
|||
|
||||
def is_available(self, workflow=None):
|
||||
return is_payment_supported()
|
||||
|
||||
is_available = classmethod(is_available)
|
||||
|
||||
def render_as_line(self):
|
||||
|
@ -332,13 +357,16 @@ class PaymentCancelWorkflowStatusItem(WorkflowStatusItem):
|
|||
|
||||
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
|
||||
if 'reason' in parameters:
|
||||
form.add(StringWidget, '%sreason' % prefix, title=_('Reason'),
|
||||
value=self.reason, size=40)
|
||||
form.add(StringWidget, '%sreason' % prefix, title=_('Reason'), value=self.reason, size=40)
|
||||
if 'regie_id' in parameters:
|
||||
form.add(SingleSelectWidget, '%sregie_id' % prefix,
|
||||
title=_('Regie'), value=self.regie_id,
|
||||
options = [(None, '---'), ('_all', _('All Regies'))] + \
|
||||
[(x.id, x.label) for x in Regie.select()])
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'%sregie_id' % prefix,
|
||||
title=_('Regie'),
|
||||
value=self.regie_id,
|
||||
options=[(None, '---'), ('_all', _('All Regies'))]
|
||||
+ [(x.id, x.label) for x in Regie.select()],
|
||||
)
|
||||
|
||||
def perform(self, formdata):
|
||||
invoices_id = []
|
||||
|
@ -356,8 +384,9 @@ class PaymentCancelWorkflowStatusItem(WorkflowStatusItem):
|
|||
# security filter: check user
|
||||
invoices = [i for i in invoices if i.user_id == formdata.user_id]
|
||||
# security filter: check formdata & formdef
|
||||
invoices = [i for i in invoices if (i.formdata_id == formdata.id) \
|
||||
and (i.formdef_id == formdata.formdef.id)]
|
||||
invoices = [
|
||||
i for i in invoices if (i.formdata_id == formdata.id) and (i.formdef_id == formdata.formdef.id)
|
||||
]
|
||||
evo = Evolution()
|
||||
evo.time = time.localtime()
|
||||
for invoice in invoices:
|
||||
|
@ -370,6 +399,7 @@ class PaymentCancelWorkflowStatusItem(WorkflowStatusItem):
|
|||
formdata.store()
|
||||
return get_publisher().get_frontoffice_url() + '/myspace/invoices/'
|
||||
|
||||
|
||||
register_item_class(PaymentCancelWorkflowStatusItem)
|
||||
|
||||
|
||||
|
@ -377,8 +407,8 @@ def request_payment(invoice_ids, url, add_regie=True):
|
|||
for invoice_id in invoice_ids:
|
||||
if not Invoice.check_crc(invoice_id):
|
||||
raise errors.QueryError()
|
||||
invoices = [ Invoice.get(invoice_id) for invoice_id in invoice_ids ]
|
||||
invoices = [ i for i in invoices if not (i.paid or i.canceled) ]
|
||||
invoices = [Invoice.get(invoice_id) for invoice_id in invoice_ids]
|
||||
invoices = [i for i in invoices if not (i.paid or i.canceled)]
|
||||
regie_ids = set([invoice.regie_id for invoice in invoices])
|
||||
# Do not apply if more than one regie is used or no invoice is not paid or canceled
|
||||
if len(invoices) == 0 or len(regie_ids) != 1:
|
||||
|
@ -420,8 +450,7 @@ def request_payment(invoice_ids, url, add_regie=True):
|
|||
evo = Evolution()
|
||||
evo.time = time.localtime()
|
||||
evo.status = formdata.status
|
||||
evo.add_part(InvoiceEvolutionPart('try', invoice,
|
||||
transaction=transaction))
|
||||
evo.add_part(InvoiceEvolutionPart('try', invoice, transaction=transaction))
|
||||
if not formdata.evolution:
|
||||
formdata.evolution = []
|
||||
formdata.evolution.append(evo)
|
||||
|
@ -434,15 +463,20 @@ def request_payment(invoice_ids, url, add_regie=True):
|
|||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def return_eopayment_form(form):
|
||||
r = TemplateIO(html=True)
|
||||
r += htmltext('<html><body onload="document.payform.submit()">')
|
||||
r += htmltext('<form action="%s" method="%s" name="payform">') % (force_str(form.url), force_str(form.method))
|
||||
r += htmltext('<form action="%s" method="%s" name="payform">') % (
|
||||
force_str(form.url),
|
||||
force_str(form.method),
|
||||
)
|
||||
for field in form.fields:
|
||||
r += htmltext('<input type="%s" name="%s" value="%s"/>') % (
|
||||
force_str(field['type']),
|
||||
force_str(field['name']),
|
||||
force_str(field['value']))
|
||||
force_str(field['type']),
|
||||
force_str(field['name']),
|
||||
force_str(field['value']),
|
||||
)
|
||||
r += htmltext('<input type="submit" name="submit" value="%s"/>') % _('Pay')
|
||||
r += htmltext('</body></html>')
|
||||
return r.getvalue()
|
||||
|
@ -458,6 +492,7 @@ class PaymentValidationWorkflowStatusItem(WorkflowStatusItem):
|
|||
|
||||
def is_available(self, workflow=None):
|
||||
return is_payment_supported()
|
||||
|
||||
is_available = classmethod(is_available)
|
||||
|
||||
def render_as_line(self):
|
||||
|
@ -468,9 +503,14 @@ class PaymentValidationWorkflowStatusItem(WorkflowStatusItem):
|
|||
|
||||
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
|
||||
if 'next_status' in parameters:
|
||||
form.add(SingleSelectWidget, '%snext_status' % prefix,
|
||||
title=_('Status once validated'), value = self.next_status,
|
||||
options = [(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status])
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'%snext_status' % prefix,
|
||||
title=_('Status once validated'),
|
||||
value=self.next_status,
|
||||
options=[(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status],
|
||||
)
|
||||
|
||||
|
||||
register_item_class(PaymentValidationWorkflowStatusItem)
|
||||
|
||||
|
@ -507,8 +547,10 @@ class PublicPaymentRegieBackDirectory(Directory):
|
|||
transaction.bank_data = bank_data
|
||||
transaction.store()
|
||||
if payment_response.signed and payment_response.is_paid() and commit:
|
||||
logger.info('transaction %s successful, bankd_id:%s bank_data:%s' % (
|
||||
order_id, payment_response.transaction_id, bank_data))
|
||||
logger.info(
|
||||
'transaction %s successful, bankd_id:%s bank_data:%s'
|
||||
% (order_id, payment_response.transaction_id, bank_data)
|
||||
)
|
||||
|
||||
for invoice_id in transaction.invoice_ids:
|
||||
# all invoices are now paid
|
||||
|
@ -530,8 +572,7 @@ class PublicPaymentRegieBackDirectory(Directory):
|
|||
evo = Evolution()
|
||||
evo.time = time.localtime()
|
||||
evo.status = formdata.status
|
||||
evo.add_part(InvoiceEvolutionPart('pay', invoice,
|
||||
transaction=transaction))
|
||||
evo.add_part(InvoiceEvolutionPart('pay', invoice, transaction=transaction))
|
||||
if not formdata.evolution:
|
||||
formdata.evolution = []
|
||||
formdata.evolution.append(evo)
|
||||
|
@ -540,11 +581,9 @@ class PublicPaymentRegieBackDirectory(Directory):
|
|||
formdata.perform_workflow()
|
||||
|
||||
elif payment_response.is_error() and commit:
|
||||
logger.info('transaction %s finished with failure, bank_data:%s' % (
|
||||
order_id, bank_data))
|
||||
logger.info('transaction %s finished with failure, bank_data:%s' % (order_id, bank_data))
|
||||
elif commit:
|
||||
logger.info('transaction %s is in intermediate state, bank_data:%s' % (
|
||||
order_id, bank_data))
|
||||
logger.info('transaction %s is in intermediate state, bank_data:%s' % (order_id, bank_data))
|
||||
if payment_response.return_content != None and self.asynchronous:
|
||||
get_response().set_content_type('text/plain')
|
||||
return payment_response.return_content
|
||||
|
@ -560,6 +599,7 @@ class PublicPaymentRegieBackDirectory(Directory):
|
|||
url += '/myspace/invoices/'
|
||||
return redirect(url)
|
||||
|
||||
|
||||
class PublicPaymentDirectory(Directory):
|
||||
_q_exports = ['init', 'back', 'back_asynchronous']
|
||||
|
||||
|
@ -579,23 +619,26 @@ class PublicPaymentDirectory(Directory):
|
|||
|
||||
return request_payment(invoice_ids, url)
|
||||
|
||||
|
||||
def notify_new_invoice(invoice):
|
||||
notify_invoice(invoice, 'payment-new-invoice-email')
|
||||
|
||||
|
||||
def notify_paid_invoice(invoice):
|
||||
notify_invoice(invoice, 'payment-invoice-paid-email')
|
||||
|
||||
|
||||
def notify_canceled_invoice(invoice):
|
||||
notify_invoice(invoice, 'payment-invoice-canceled-email')
|
||||
|
||||
|
||||
def notify_invoice(invoice, template):
|
||||
user = invoice.get_user()
|
||||
assert user is not None
|
||||
regie = Regie.get(id=invoice.regie_id)
|
||||
emails.custom_template_email(template, {
|
||||
'user': user,
|
||||
'invoice': invoice,
|
||||
'regie': regie,
|
||||
'invoice_url': invoice.payment_url()
|
||||
}, user.email, fire_and_forget = True)
|
||||
|
||||
emails.custom_template_email(
|
||||
template,
|
||||
{'user': user, 'invoice': invoice, 'regie': regie, 'invoice_url': invoice.payment_url()},
|
||||
user.email,
|
||||
fire_and_forget=True,
|
||||
)
|
||||
|
|
|
@ -19,14 +19,14 @@ from wcs.qommon.admin.emails import EmailsDirectory
|
|||
from wcs.qommon.backoffice.menu import html_top
|
||||
from wcs.qommon import get_cfg
|
||||
|
||||
from .payments import (eopayment, Regie, is_payment_supported, Invoice,
|
||||
Transaction, notify_paid_invoice)
|
||||
from .payments import eopayment, Regie, is_payment_supported, Invoice, Transaction, notify_paid_invoice
|
||||
|
||||
from wcs.qommon.admin.texts import TextsDirectory
|
||||
|
||||
if not set:
|
||||
from sets import Set as set
|
||||
|
||||
|
||||
def invoice_as_html(invoice):
|
||||
r = TemplateIO(html=True)
|
||||
r += htmltext('<div id="invoice">')
|
||||
|
@ -40,16 +40,20 @@ def invoice_as_html(invoice):
|
|||
r += '\nTransaction:\n'
|
||||
r += pprint.pformat(transaction.__dict__)
|
||||
r += htmltext('\n-->')
|
||||
if invoice.formdef_id and invoice.formdata_id and \
|
||||
get_session().user == invoice.user_id:
|
||||
if invoice.formdef_id and invoice.formdata_id and get_session().user == invoice.user_id:
|
||||
formdef = FormDef.get(invoice.formdef_id)
|
||||
if formdef:
|
||||
formdata = formdef.data_class().get(invoice.formdata_id, ignore_errors=True)
|
||||
if formdata:
|
||||
name = _('%(form_name)s #%(formdata_id)s') % {
|
||||
'form_name': formdata.formdef.name,
|
||||
'formdata_id': formdata.id }
|
||||
r += htmltext('<p class="from">%s <a href="%s">%s</a></p>') % (_('From:'), formdata.get_url(), name)
|
||||
'form_name': formdata.formdef.name,
|
||||
'formdata_id': formdata.id,
|
||||
}
|
||||
r += htmltext('<p class="from">%s <a href="%s">%s</a></p>') % (
|
||||
_('From:'),
|
||||
formdata.get_url(),
|
||||
name,
|
||||
)
|
||||
r += htmltext('<p class="regie">%s</p>') % _('Regie: %s') % Regie.get(invoice.regie_id).label
|
||||
r += htmltext('<p class="date">%s</p>') % _('Created on: %s') % misc.localstrftime(invoice.date)
|
||||
if invoice.details:
|
||||
|
@ -114,7 +118,9 @@ class InvoicesDirectory(Directory):
|
|||
if len(regies_id) == 1:
|
||||
r += htmltext('<p class="command">')
|
||||
r += htmltext('<a href="%s/payment/init?invoice_ids=%s">') % (
|
||||
get_publisher().get_frontoffice_url(), component)
|
||||
get_publisher().get_frontoffice_url(),
|
||||
component,
|
||||
)
|
||||
if len(invoice_ids) > 1:
|
||||
r += _('Pay Selected Invoices')
|
||||
else:
|
||||
|
@ -136,7 +142,7 @@ class RegieDirectory(Directory):
|
|||
self.regie = regie
|
||||
|
||||
def _q_index(self):
|
||||
html_top('payments', title = _('Regie: %s') % self.regie.label)
|
||||
html_top('payments', title=_('Regie: %s') % self.regie.label)
|
||||
r = TemplateIO(html=True)
|
||||
get_response().filter['sidebar'] = self.get_sidebar()
|
||||
r += htmltext('<h2>%s</h2>') % _('Regie: %s') % self.regie.label
|
||||
|
@ -182,26 +188,31 @@ class RegieDirectory(Directory):
|
|||
self.submit(form)
|
||||
return redirect('..')
|
||||
|
||||
html_top('payments', title = _('Edit Regie: %s') % self.regie.label)
|
||||
html_top('payments', title=_('Edit Regie: %s') % self.regie.label)
|
||||
r = TemplateIO(html=True)
|
||||
r += htmltext('<h2>%s</h2>') % _('Edit Regie: %s') % self.regie.label
|
||||
r += form.render()
|
||||
return r.getvalue()
|
||||
|
||||
|
||||
def form(self):
|
||||
form = Form(enctype='multipart/form-data')
|
||||
form.add(StringWidget, 'label', title=_('Label'), required=True,
|
||||
value=self.regie.label)
|
||||
form.add(TextWidget, 'description', title=_('Description'),
|
||||
value=self.regie.description, rows=5, cols=60)
|
||||
form.add(SingleSelectWidget, 'service', title=_('Banking Service'),
|
||||
value=self.regie.service, required=True,
|
||||
options = [
|
||||
('dummy', _('Dummy (for tests)')),
|
||||
('sips', 'SIPS'),
|
||||
('systempayv2', 'systempay (Banque Populaire)'),
|
||||
('spplus', _('SP+ (Caisse d\'epargne)'))])
|
||||
form.add(StringWidget, 'label', title=_('Label'), required=True, value=self.regie.label)
|
||||
form.add(
|
||||
TextWidget, 'description', title=_('Description'), value=self.regie.description, rows=5, cols=60
|
||||
)
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'service',
|
||||
title=_('Banking Service'),
|
||||
value=self.regie.service,
|
||||
required=True,
|
||||
options=[
|
||||
('dummy', _('Dummy (for tests)')),
|
||||
('sips', 'SIPS'),
|
||||
('systempayv2', 'systempay (Banque Populaire)'),
|
||||
('spplus', _('SP+ (Caisse d\'epargne)')),
|
||||
],
|
||||
)
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
return form
|
||||
|
@ -215,8 +226,7 @@ class RegieDirectory(Directory):
|
|||
|
||||
def delete(self):
|
||||
form = Form(enctype='multipart/form-data')
|
||||
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
|
||||
'You are about to irrevocably delete this regie.')))
|
||||
form.widgets.append(HtmlWidget('<p>%s</p>' % _('You are about to irrevocably delete this regie.')))
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
if form.get_submit() == 'cancel':
|
||||
|
@ -224,7 +234,7 @@ class RegieDirectory(Directory):
|
|||
if not form.is_submitted() or form.has_errors():
|
||||
get_response().breadcrumb.append(('delete', _('Delete')))
|
||||
r = TemplateIO(html=True)
|
||||
html_top('payments', title = _('Delete Regie'))
|
||||
html_top('payments', title=_('Delete Regie'))
|
||||
r += htmltext('<h2>%s</h2>') % _('Deleting Regie: %s') % self.regie.label
|
||||
r += form.render()
|
||||
return r.getvalue()
|
||||
|
@ -267,11 +277,9 @@ class RegieDirectory(Directory):
|
|||
kwargs['cols'] = 80
|
||||
kwargs['rows'] = 5
|
||||
if 'type' not in infos or infos['type'] is str:
|
||||
form.add(widget, name, title=_(title),
|
||||
value=service_options.get(name), **kwargs)
|
||||
form.add(widget, name, title=_(title), value=service_options.get(name), **kwargs)
|
||||
elif infos['type'] is bool:
|
||||
form.add(CheckboxWidget, name, title=title,
|
||||
value=service_options.get(name), **kwargs)
|
||||
form.add(CheckboxWidget, name, title=title, value=service_options.get(name), **kwargs)
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
return form
|
||||
|
@ -297,7 +305,7 @@ class RegieDirectory(Directory):
|
|||
return redirect('.')
|
||||
|
||||
if form.is_submitted() and not form.has_errors():
|
||||
if self.submit_options(form, module):
|
||||
if self.submit_options(form, module):
|
||||
return redirect('..')
|
||||
|
||||
html_top('payments', title=_('Edit Service Options'))
|
||||
|
@ -360,8 +368,7 @@ class RegieDirectory(Directory):
|
|||
|
||||
def get_invoices(self):
|
||||
sort_by = self.get_sort_by()
|
||||
invoices = list(Invoice.get_with_indexed_value('regie_id', self.regie.id,
|
||||
ignore_errors=True))
|
||||
invoices = list(Invoice.get_with_indexed_value('regie_id', self.regie.id, ignore_errors=True))
|
||||
if 'date' in sort_by:
|
||||
reverse = True
|
||||
key = lambda i: getattr(i, sort_by) or datetime.datetime.now()
|
||||
|
@ -372,31 +379,35 @@ class RegieDirectory(Directory):
|
|||
return invoices
|
||||
|
||||
def unpay(self, request, invoice):
|
||||
get_logger().info(_('manually set unpaid invoice %(invoice_id)s in regie %(regie)s')
|
||||
% dict(invoice_id=invoice.id, regie=self.regie.id))
|
||||
get_logger().info(
|
||||
_('manually set unpaid invoice %(invoice_id)s in regie %(regie)s')
|
||||
% dict(invoice_id=invoice.id, regie=self.regie.id)
|
||||
)
|
||||
transaction = Transaction()
|
||||
transaction.invoice_ids = [ invoice.id ]
|
||||
transaction.invoice_ids = [invoice.id]
|
||||
transaction.order_id = 'Manual action'
|
||||
transaction.start = datetime.datetime.now()
|
||||
transaction.end = transaction.start
|
||||
transaction.bank_data = {
|
||||
'action': 'Set unpaid',
|
||||
'by': request.user.get_display_name() + ' (%s)' % request.user.id
|
||||
transaction.bank_data = {
|
||||
'action': 'Set unpaid',
|
||||
'by': request.user.get_display_name() + ' (%s)' % request.user.id,
|
||||
}
|
||||
transaction.store()
|
||||
invoice.unpay()
|
||||
|
||||
def pay(self, request, invoice):
|
||||
get_logger().info(_('manually set paid invoice %(invoice_id)s in regie %(regie)s')
|
||||
% dict(invoice_id=invoice.id, regie=self.regie.id))
|
||||
get_logger().info(
|
||||
_('manually set paid invoice %(invoice_id)s in regie %(regie)s')
|
||||
% dict(invoice_id=invoice.id, regie=self.regie.id)
|
||||
)
|
||||
transaction = Transaction()
|
||||
transaction.invoice_ids = [ invoice.id ]
|
||||
transaction.invoice_ids = [invoice.id]
|
||||
transaction.order_id = 'Manual action'
|
||||
transaction.start = datetime.datetime.now()
|
||||
transaction.end = transaction.start
|
||||
transaction.bank_data = {
|
||||
'action': 'Set paid',
|
||||
'by': request.user.get_display_name() + ' (%s)' % request.user.id
|
||||
transaction.bank_data = {
|
||||
'action': 'Set paid',
|
||||
'by': request.user.get_display_name() + ' (%s)' % request.user.id,
|
||||
}
|
||||
transaction.store()
|
||||
invoice.pay()
|
||||
|
@ -430,7 +441,7 @@ class RegieDirectory(Directory):
|
|||
r += htmltext('</tr>')
|
||||
r += htmltext('</thead>')
|
||||
invoices = self.get_invoices()
|
||||
for invoice in invoices[offset:offset+self.PAGINATION]:
|
||||
for invoice in invoices[offset : offset + self.PAGINATION]:
|
||||
r += htmltext('<tbody class="invoice-rows">')
|
||||
r += htmltext('<tr class="invoice-row"><td>')
|
||||
r += misc.localstrftime(invoice.date)
|
||||
|
@ -456,8 +467,7 @@ class RegieDirectory(Directory):
|
|||
r += htmltext('</form>')
|
||||
|
||||
r += htmltext('</td></tr>')
|
||||
transactions = list(Transaction.get_with_indexed_value('invoice_ids',
|
||||
invoice.id))
|
||||
transactions = list(Transaction.get_with_indexed_value('invoice_ids', invoice.id))
|
||||
for transaction in sorted(transactions, key=lambda x: x.start):
|
||||
r += htmltext('<tr>')
|
||||
r += htmltext('<td></td>')
|
||||
|
@ -473,11 +483,9 @@ class RegieDirectory(Directory):
|
|||
r += htmltext('</tbody>')
|
||||
r += htmltext('</tbody></table>')
|
||||
if offset != 0:
|
||||
r += htmltext('<a href="?offset=%d>%s</a> ') % (
|
||||
max(0, offset-self.PAGINATION), _('Previous'))
|
||||
r += htmltext('<a href="?offset=%d>%s</a> ') % (max(0, offset - self.PAGINATION), _('Previous'))
|
||||
if offset + self.PAGINATION < len(invoices):
|
||||
r += htmltext('<a href="?offset=%d>%s</a> ') % (
|
||||
max(0, offset-self.PAGINATION), _('Previous'))
|
||||
r += htmltext('<a href="?offset=%d>%s</a> ') % (max(0, offset - self.PAGINATION), _('Previous'))
|
||||
return r.getvalue()
|
||||
|
||||
|
||||
|
@ -503,7 +511,7 @@ class RegiesDirectory(Directory):
|
|||
return redirect('%s/' % regie_ui.regie.id)
|
||||
|
||||
get_response().breadcrumb.append(('new', _('New Regie')))
|
||||
html_top('payments', title = _('New Regie'))
|
||||
html_top('payments', title=_('New Regie'))
|
||||
r = TemplateIO(html=True)
|
||||
r += htmltext('<h2>%s</h2>') % _('New Regie')
|
||||
r += form.render()
|
||||
|
@ -526,6 +534,7 @@ class PaymentsDirectory(AccessControlled, Directory):
|
|||
|
||||
def is_accessible(self, user):
|
||||
from .backoffice import check_visibility
|
||||
|
||||
return check_visibility('payments', user)
|
||||
|
||||
def _q_access(self):
|
||||
|
@ -535,8 +544,8 @@ class PaymentsDirectory(AccessControlled, Directory):
|
|||
|
||||
if not self.is_accessible(user):
|
||||
raise errors.AccessForbiddenError(
|
||||
public_msg = _('You are not allowed to access Payments Management'),
|
||||
location_hint = 'backoffice')
|
||||
public_msg=_('You are not allowed to access Payments Management'), location_hint='backoffice'
|
||||
)
|
||||
|
||||
get_response().breadcrumb.append(('payments/', _('Payments')))
|
||||
|
||||
|
@ -573,33 +582,43 @@ class PaymentsDirectory(AccessControlled, Directory):
|
|||
return r.getvalue()
|
||||
|
||||
|
||||
TextsDirectory.register('aq-invoice',
|
||||
N_('Message on top of an invoice'),
|
||||
category = N_('Invoices'))
|
||||
TextsDirectory.register('aq-invoice', N_('Message on top of an invoice'), category=N_('Invoices'))
|
||||
|
||||
EmailsDirectory.register('payment-new-invoice-email',
|
||||
N_('New invoice'),
|
||||
N_('Available variables: user, regie, invoice, invoice_url'),
|
||||
category = N_('Invoices'),
|
||||
default_subject = N_('New invoice'),
|
||||
default_body = N_('''
|
||||
EmailsDirectory.register(
|
||||
'payment-new-invoice-email',
|
||||
N_('New invoice'),
|
||||
N_('Available variables: user, regie, invoice, invoice_url'),
|
||||
category=N_('Invoices'),
|
||||
default_subject=N_('New invoice'),
|
||||
default_body=N_(
|
||||
'''
|
||||
A new invoice is available at [invoice_url].
|
||||
'''))
|
||||
'''
|
||||
),
|
||||
)
|
||||
|
||||
EmailsDirectory.register('payment-invoice-paid-email',
|
||||
N_('Paid invoice'),
|
||||
N_('Available variables: user, regie, invoice, invoice_url'),
|
||||
category = N_('Invoices'),
|
||||
default_subject = N_('Paid invoice'),
|
||||
default_body = N_('''
|
||||
EmailsDirectory.register(
|
||||
'payment-invoice-paid-email',
|
||||
N_('Paid invoice'),
|
||||
N_('Available variables: user, regie, invoice, invoice_url'),
|
||||
category=N_('Invoices'),
|
||||
default_subject=N_('Paid invoice'),
|
||||
default_body=N_(
|
||||
'''
|
||||
The invoice [invoice_url] has been paid.
|
||||
'''))
|
||||
'''
|
||||
),
|
||||
)
|
||||
|
||||
EmailsDirectory.register('payment-invoice-canceled-email',
|
||||
N_('Canceled invoice'),
|
||||
N_('Available variables: user, regie, invoice, invoice_url'),
|
||||
category = N_('Invoices'),
|
||||
default_subject = N_('Canceled invoice'),
|
||||
default_body = N_('''
|
||||
EmailsDirectory.register(
|
||||
'payment-invoice-canceled-email',
|
||||
N_('Canceled invoice'),
|
||||
N_('Available variables: user, regie, invoice, invoice_url'),
|
||||
category=N_('Invoices'),
|
||||
default_subject=N_('Canceled invoice'),
|
||||
default_body=N_(
|
||||
'''
|
||||
The invoice [invoice.id] has been canceled.
|
||||
'''))
|
||||
'''
|
||||
),
|
||||
)
|
||||
|
|
|
@ -62,12 +62,17 @@ def category_get_homepage_position(self):
|
|||
if self.url_name == 'consultations':
|
||||
return '2nd'
|
||||
return '1st'
|
||||
|
||||
|
||||
Category.get_homepage_position = category_get_homepage_position
|
||||
|
||||
|
||||
def category_get_limit(self):
|
||||
if hasattr(self, 'limit') and self.limit is not None:
|
||||
return self.limit
|
||||
return 7
|
||||
|
||||
|
||||
Category.get_limit = category_get_limit
|
||||
|
||||
Category.TEXT_ATTRIBUTES = ['name', 'url_name', 'description', 'homepage_position']
|
||||
|
@ -75,6 +80,7 @@ Category.INT_ATTRIBUTES = ['position', 'limit']
|
|||
|
||||
OldRegisterDirectory = wcs.root.RegisterDirectory
|
||||
|
||||
|
||||
class AlternateRegisterDirectory(OldRegisterDirectory):
|
||||
def _q_traverse(self, path):
|
||||
get_response().filter['bigdiv'] = 'new_member'
|
||||
|
@ -88,7 +94,7 @@ class AlternateRegisterDirectory(OldRegisterDirectory):
|
|||
idps = get_cfg('idp', {})
|
||||
if len(idps) == 0:
|
||||
return template.error_page(_('Authentication subsystem is not yet configured.'))
|
||||
ident_methods = ['idp'] # fallback to old behaviour; saml.
|
||||
ident_methods = ['idp'] # fallback to old behaviour; saml.
|
||||
|
||||
if len(ident_methods) == 1:
|
||||
method = ident_methods[0]
|
||||
|
@ -97,8 +103,10 @@ class AlternateRegisterDirectory(OldRegisterDirectory):
|
|||
|
||||
return wcs.qommon.ident.register(method)
|
||||
|
||||
|
||||
OldLoginDirectory = wcs.root.LoginDirectory
|
||||
|
||||
|
||||
class AlternateLoginDirectory(OldLoginDirectory):
|
||||
def _q_traverse(self, path):
|
||||
get_response().filter['bigdiv'] = 'member'
|
||||
|
@ -125,9 +133,8 @@ class AlternateLoginDirectory(OldLoginDirectory):
|
|||
if after_url:
|
||||
root_url = get_publisher().get_root_url()
|
||||
after_path = urlparse.urlparse(after_url)[2]
|
||||
after_path = after_path[len(root_url):]
|
||||
if after_path.startswith(str('admin')) or \
|
||||
after_path.startswith(str('backoffice')):
|
||||
after_path = after_path[len(root_url) :]
|
||||
if after_path.startswith(str('admin')) or after_path.startswith(str('backoffice')):
|
||||
ident_methods = ['idp']
|
||||
|
||||
# don't display authentication system choice
|
||||
|
@ -143,12 +150,12 @@ class AlternateLoginDirectory(OldLoginDirectory):
|
|||
r = TemplateIO(html=True)
|
||||
get_response().breadcrumb.append(('login', _('Login')))
|
||||
identities_cfg = get_cfg('identities', {})
|
||||
form = Form(enctype = 'multipart/form-data', id = 'login-form', use_tokens = False)
|
||||
form = Form(enctype='multipart/form-data', id='login-form', use_tokens=False)
|
||||
if identities_cfg.get('email-as-username', False):
|
||||
form.add(StringWidget, 'username', title = _('Email'), size=25, required=True)
|
||||
form.add(StringWidget, 'username', title=_('Email'), size=25, required=True)
|
||||
else:
|
||||
form.add(StringWidget, 'username', title = _('Username'), size=25, required=True)
|
||||
form.add(PasswordWidget, 'password', title = _('Password'), size=25, required=True)
|
||||
form.add(StringWidget, 'username', title=_('Username'), size=25, required=True)
|
||||
form.add(PasswordWidget, 'password', title=_('Password'), size=25, required=True)
|
||||
form.add_submit('submit', _('Connect'))
|
||||
if form.is_submitted() and not form.has_errors():
|
||||
tmp = wcs.qommon.ident.password.MethodDirectory().login_submit(form)
|
||||
|
@ -161,20 +168,24 @@ class AlternateLoginDirectory(OldLoginDirectory):
|
|||
|
||||
base_url = get_publisher().get_root_url()
|
||||
r += htmltext('<p><a href="%sident/password/forgotten">%s</a></p>') % (
|
||||
base_url, _('Forgotten password ?'))
|
||||
base_url,
|
||||
_('Forgotten password ?'),
|
||||
)
|
||||
|
||||
r += htmltext('</div>')
|
||||
|
||||
# XXX: this part only supports a single IdP
|
||||
r += htmltext('<div id="login-sso">')
|
||||
r += TextsDirectory.get_html_text('aq-sso-text')
|
||||
form = Form(enctype='multipart/form-data',
|
||||
action = '%sident/idp/login' % base_url)
|
||||
form = Form(enctype='multipart/form-data', action='%sident/idp/login' % base_url)
|
||||
form.add_hidden('method', 'idp')
|
||||
for kidp, idp in get_cfg('idp', {}).items():
|
||||
p = lasso.Provider(lasso.PROVIDER_ROLE_IDP,
|
||||
misc.get_abs_path(idp['metadata']),
|
||||
misc.get_abs_path(idp.get('publickey')), None)
|
||||
p = lasso.Provider(
|
||||
lasso.PROVIDER_ROLE_IDP,
|
||||
misc.get_abs_path(idp['metadata']),
|
||||
misc.get_abs_path(idp.get('publickey')),
|
||||
None,
|
||||
)
|
||||
form.add_hidden('idp', p.providerId)
|
||||
break
|
||||
form.add_submit('submit', _('Connect'))
|
||||
|
@ -184,15 +195,19 @@ class AlternateLoginDirectory(OldLoginDirectory):
|
|||
|
||||
get_request().environ['REQUEST_METHOD'] = 'GET'
|
||||
|
||||
r += htmltext("""<script type="text/javascript">
|
||||
r += htmltext(
|
||||
"""<script type="text/javascript">
|
||||
document.getElementById('login-form')['username'].focus();
|
||||
</script>""")
|
||||
</script>"""
|
||||
)
|
||||
return r.getvalue()
|
||||
else:
|
||||
return OldLoginDirectory._q_index(self)
|
||||
|
||||
|
||||
OldIdentDirectory = wcs.root.IdentDirectory
|
||||
|
||||
|
||||
class AlternateIdentDirectory(OldIdentDirectory):
|
||||
def _q_traverse(self, path):
|
||||
get_response().filter['bigdiv'] = 'member'
|
||||
|
@ -206,15 +221,41 @@ class AlternatePreviewDirectory(PreviewDirectory):
|
|||
|
||||
|
||||
class AlternateRootDirectory(OldRootDirectory):
|
||||
_q_exports = ['', 'admin', 'backoffice', 'forms', 'login', 'logout',
|
||||
'saml', 'register', 'ident', 'afterjobs',
|
||||
('informations-editeur', 'informations_editeur'),
|
||||
'myspace', 'services', 'categories', 'user',
|
||||
('tmp-upload', 'tmp_upload'), 'json', '__version__',
|
||||
'themes', 'pages', 'payment', 'invoices', 'roles',
|
||||
'api', 'code', 'fargo', 'tryauth', 'auth', 'preview',
|
||||
('reload-top', 'reload_top'), 'static',
|
||||
('i18n.js', 'i18n_js'), 'actions',]
|
||||
_q_exports = [
|
||||
'',
|
||||
'admin',
|
||||
'backoffice',
|
||||
'forms',
|
||||
'login',
|
||||
'logout',
|
||||
'saml',
|
||||
'register',
|
||||
'ident',
|
||||
'afterjobs',
|
||||
('informations-editeur', 'informations_editeur'),
|
||||
'myspace',
|
||||
'services',
|
||||
'categories',
|
||||
'user',
|
||||
('tmp-upload', 'tmp_upload'),
|
||||
'json',
|
||||
'__version__',
|
||||
'themes',
|
||||
'pages',
|
||||
'payment',
|
||||
'invoices',
|
||||
'roles',
|
||||
'api',
|
||||
'code',
|
||||
'fargo',
|
||||
'tryauth',
|
||||
'auth',
|
||||
'preview',
|
||||
('reload-top', 'reload_top'),
|
||||
'static',
|
||||
('i18n.js', 'i18n_js'),
|
||||
'actions',
|
||||
]
|
||||
|
||||
register = AlternateRegisterDirectory()
|
||||
login = AlternateLoginDirectory()
|
||||
|
@ -250,7 +291,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
response.filter['keywords'] = template.get_current_theme().get('keywords')
|
||||
get_publisher().substitutions.feed(self)
|
||||
|
||||
response.breadcrumb = [ ('', _('Home')) ]
|
||||
response.breadcrumb = [('', _('Home'))]
|
||||
|
||||
if not self.admin:
|
||||
self.admin = get_publisher().admin_directory_class()
|
||||
|
@ -279,7 +320,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
if get_request().get_query():
|
||||
uri_rest += '?' + get_request().get_query()
|
||||
if uri_rest.startswith(base_url):
|
||||
uri_rest = uri_rest[len(base_url):]
|
||||
uri_rest = uri_rest[len(base_url) :]
|
||||
if f.category:
|
||||
if f.category.url_name == f.url_name:
|
||||
return FormsRootDirectory(f.category)._q_traverse(path[1:])
|
||||
|
@ -298,7 +339,6 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
|
||||
raise e
|
||||
|
||||
|
||||
def _q_lookup(self, component):
|
||||
# is this a category ?
|
||||
try:
|
||||
|
@ -316,8 +356,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
# if the form has no category, or the request is a POST, or the
|
||||
# slug matches both a category and a formdef, directly call
|
||||
# into FormsRootDirectory.
|
||||
if formdef.category_id is None or get_request().get_method() == 'POST' or (
|
||||
formdef and category):
|
||||
if formdef.category_id is None or get_request().get_method() == 'POST' or (formdef and category):
|
||||
get_response().filter['bigdiv'] = 'rub_service'
|
||||
return FormsRootDirectory()._q_lookup(component)
|
||||
|
||||
|
@ -347,8 +386,9 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
|
||||
redirect_url = get_cfg('misc', {}).get('homepage-redirect-url')
|
||||
if redirect_url:
|
||||
return redirect(misc.get_variadic_url(redirect_url,
|
||||
get_publisher().substitutions.get_context_variables()))
|
||||
return redirect(
|
||||
misc.get_variadic_url(redirect_url, get_publisher().substitutions.get_context_variables())
|
||||
)
|
||||
|
||||
template.html_top()
|
||||
r = TemplateIO(html=True)
|
||||
|
@ -384,7 +424,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
def services(self):
|
||||
template.html_top()
|
||||
get_response().filter['bigdiv'] = 'rub_service'
|
||||
return self.box_services(level = 2)
|
||||
return self.box_services(level=2)
|
||||
|
||||
def box_services(self, level=3, position=None):
|
||||
## Services
|
||||
|
@ -393,17 +433,18 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
else:
|
||||
accepted_roles = []
|
||||
|
||||
cats = Category.select(order_by = 'name')
|
||||
cats = Category.select(order_by='name')
|
||||
cats = [x for x in cats if x.url_name != 'consultations']
|
||||
Category.sort_by_position(cats)
|
||||
|
||||
all_formdefs = FormDef.select(lambda x: not x.is_disabled() or x.disabled_redirection,
|
||||
order_by = 'name')
|
||||
all_formdefs = FormDef.select(
|
||||
lambda x: not x.is_disabled() or x.disabled_redirection, order_by='name'
|
||||
)
|
||||
|
||||
if position:
|
||||
t = self.display_list_of_formdefs(
|
||||
[x for x in cats if x.get_homepage_position() == position],
|
||||
all_formdefs, accepted_roles)
|
||||
[x for x in cats if x.get_homepage_position() == position], all_formdefs, accepted_roles
|
||||
)
|
||||
else:
|
||||
t = self.display_list_of_formdefs(cats, all_formdefs, accepted_roles)
|
||||
|
||||
|
@ -445,7 +486,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
formdefs_advertise = []
|
||||
|
||||
for formdef in formdefs[:]:
|
||||
if formdef.is_disabled(): # is a redirection
|
||||
if formdef.is_disabled(): # is a redirection
|
||||
continue
|
||||
if not formdef.roles:
|
||||
continue
|
||||
|
@ -473,7 +514,9 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
keywords[keyword] = True
|
||||
|
||||
r += htmltext('<li id="category-%s" data-keywords="%s">') % (
|
||||
category.url_name, ' '.join(keywords))
|
||||
category.url_name,
|
||||
' '.join(keywords),
|
||||
)
|
||||
r += htmltext('<strong>')
|
||||
r += htmltext('<a href="%s/">') % category.url_name
|
||||
r += category.name
|
||||
|
@ -487,18 +530,28 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
if formdef.is_disabled() and formdef.disabled_redirection:
|
||||
classes.append('redirection')
|
||||
r += htmltext('<a class="%s" href="%s/%s/">%s</a>') % (
|
||||
' '.join(classes), category.url_name, formdef.url_name, formdef.name)
|
||||
' '.join(classes),
|
||||
category.url_name,
|
||||
formdef.url_name,
|
||||
formdef.name,
|
||||
)
|
||||
r += htmltext('</li>\n')
|
||||
if len(formdefs) < limit:
|
||||
for formdef in formdefs_advertise[:limit-len(formdefs)]:
|
||||
for formdef in formdefs_advertise[: limit - len(formdefs)]:
|
||||
r += htmltext('<li class="required-authentication">')
|
||||
r += htmltext('<a href="%s/%s/">%s</a>') % (category.url_name, formdef.url_name, formdef.name)
|
||||
r += htmltext('<a href="%s/%s/">%s</a>') % (
|
||||
category.url_name,
|
||||
formdef.url_name,
|
||||
formdef.name,
|
||||
)
|
||||
r += htmltext('<span> (%s)</span>') % _('authentication required')
|
||||
r += htmltext('</li>\n')
|
||||
if (len(formdefs)+len(formdefs_advertise)) > limit:
|
||||
r += htmltext('<li class="all-forms"><a href="%s/" title="%s">%s</a></li>') % (category.url_name,
|
||||
_('Access to all forms of the "%s" category') % category.name,
|
||||
_('Access to all forms in this category'))
|
||||
if (len(formdefs) + len(formdefs_advertise)) > limit:
|
||||
r += htmltext('<li class="all-forms"><a href="%s/" title="%s">%s</a></li>') % (
|
||||
category.url_name,
|
||||
_('Access to all forms of the "%s" category') % category.name,
|
||||
_('Access to all forms in this category'),
|
||||
)
|
||||
r += htmltext('</ul>')
|
||||
r += htmltext('</li>\n')
|
||||
|
||||
|
@ -509,10 +562,13 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
if not cats:
|
||||
return
|
||||
consultations_category = cats[0]
|
||||
formdefs = FormDef.select(lambda x: (
|
||||
str(x.category_id) == str(consultations_category.id) and
|
||||
(not x.is_disabled() or x.disabled_redirection)),
|
||||
order_by = 'name')
|
||||
formdefs = FormDef.select(
|
||||
lambda x: (
|
||||
str(x.category_id) == str(consultations_category.id)
|
||||
and (not x.is_disabled() or x.disabled_redirection)
|
||||
),
|
||||
order_by='name',
|
||||
)
|
||||
if not formdefs:
|
||||
return
|
||||
## Consultations
|
||||
|
@ -523,8 +579,11 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
r += htmltext('<ul>')
|
||||
for formdef in formdefs:
|
||||
r += htmltext('<li>')
|
||||
r += htmltext('<a href="%s/%s/">%s</a>') % (consultations_category.url_name,
|
||||
formdef.url_name, formdef.name)
|
||||
r += htmltext('<a href="%s/%s/">%s</a>') % (
|
||||
consultations_category.url_name,
|
||||
formdef.url_name,
|
||||
formdef.name,
|
||||
)
|
||||
r += htmltext('</li>')
|
||||
r += htmltext('</ul>')
|
||||
r += htmltext('</div>')
|
||||
|
@ -534,16 +593,18 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
r = TemplateIO(html=True)
|
||||
root_url = get_publisher().get_root_url()
|
||||
|
||||
if (path == [''] and
|
||||
'include-tracking-code-form' in get_response().filter.get('keywords', []) and
|
||||
self.has_anonymous_access_codes()):
|
||||
if (
|
||||
path == ['']
|
||||
and 'include-tracking-code-form' in get_response().filter.get('keywords', [])
|
||||
and self.has_anonymous_access_codes()
|
||||
):
|
||||
r += htmltext('<form id="follow-form" action="%scode/load">') % root_url
|
||||
r += htmltext('<h3>%s</h3>') % _('Tracking code')
|
||||
r += htmltext('<input size="12" name="code" placeholder="%s"/>') % _('ex: RPQDFVCD')
|
||||
r += htmltext('<input type="submit" value="%s"/>') % _('Load')
|
||||
r += htmltext('</form>')
|
||||
|
||||
cats = Category.select(order_by = 'name')
|
||||
cats = Category.select(order_by='name')
|
||||
cats = [x for x in cats if x.url_name != 'consultations' and x.get_homepage_position() == 'side']
|
||||
Category.sort_by_position(cats)
|
||||
if cats:
|
||||
|
@ -574,7 +635,9 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
r += htmltext('<h3>%s</h3>') % _('My Space')
|
||||
r += htmltext('<ul>')
|
||||
if get_request().user and not get_request().user.anonymous:
|
||||
r += htmltext(' <li><a href="myspace/" id="member">%s</a></li>') % _('Access to your personal space')
|
||||
r += htmltext(' <li><a href="myspace/" id="member">%s</a></li>') % _(
|
||||
'Access to your personal space'
|
||||
)
|
||||
r += htmltext(' <li><a href="logout" id="logout">%s</a></li>') % _('Logout')
|
||||
else:
|
||||
r += htmltext(' <li><a href="register/" id="inscr">%s</a></li>') % _('Registration')
|
||||
|
@ -583,7 +646,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
r += htmltext('</div>')
|
||||
return r.getvalue()
|
||||
|
||||
def page_view(self, key, title, urlname = None):
|
||||
def page_view(self, key, title, urlname=None):
|
||||
if not urlname:
|
||||
urlname = key[3:].replace(str('_'), str('-'))
|
||||
get_response().breadcrumb.append((urlname, title))
|
||||
|
@ -596,8 +659,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
|
||||
def informations_editeur(self):
|
||||
get_response().filter['bigdiv'] = 'info'
|
||||
return self.page_view('aq-editor-info', _('Editor Informations'),
|
||||
urlname = 'informations_editeur')
|
||||
return self.page_view('aq-editor-info', _('Editor Informations'), urlname='informations_editeur')
|
||||
|
||||
def accessibility(self):
|
||||
get_response().filter['bigdiv'] = 'accessibility'
|
||||
|
@ -613,6 +675,7 @@ class AlternateRootDirectory(OldRootDirectory):
|
|||
|
||||
|
||||
from qommon.publisher import get_publisher_class
|
||||
|
||||
get_publisher_class().root_directory_class = AlternateRootDirectory
|
||||
get_publisher_class().after_login_url = 'myspace/'
|
||||
get_publisher_class().use_sms_feature = True
|
||||
|
@ -622,9 +685,14 @@ TextsDirectory.register('aq-editor-info', N_('Editor Informations'))
|
|||
TextsDirectory.register('aq-accessibility', N_('Accessibility Statement'))
|
||||
TextsDirectory.register('aq-contact', N_('Contact Information'))
|
||||
TextsDirectory.register('aq-help', N_('Help'))
|
||||
TextsDirectory.register('aq-sso-text', N_('Connecting with Identity Provider'),
|
||||
default = N_('''<h3>Connecting with Identity Provider</h3>
|
||||
TextsDirectory.register(
|
||||
'aq-sso-text',
|
||||
N_('Connecting with Identity Provider'),
|
||||
default=N_(
|
||||
'''<h3>Connecting with Identity Provider</h3>
|
||||
<p>You can also use your identity provider to connect.
|
||||
</p>'''))
|
||||
</p>'''
|
||||
),
|
||||
)
|
||||
|
||||
TextsDirectory.register('aq-home-page', N_('Home Page'), wysiwyg = True)
|
||||
TextsDirectory.register('aq-home-page', N_('Home Page'), wysiwyg=True)
|
||||
|
|
|
@ -9,8 +9,8 @@ import wcs.qommon.saml2
|
|||
|
||||
class Saml2Directory(wcs.qommon.saml2.Saml2Directory):
|
||||
def extract_attributes(self, session, login):
|
||||
'''Separate attributes as two dictionaries: one for last value, one for
|
||||
the list of values.'''
|
||||
"""Separate attributes as two dictionaries: one for last value, one for
|
||||
the list of values."""
|
||||
d = {}
|
||||
m = {}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class Saml2Directory(wcs.qommon.saml2.Saml2Directory):
|
|||
# name field, this only works if there's a single field for the name
|
||||
field_name_values = users_cfg.get('field_name')
|
||||
if field_name_values:
|
||||
if type(field_name_values) is str: # it was a string in previous versions
|
||||
if type(field_name_values) is str: # it was a string in previous versions
|
||||
field_name_values = [field_name_values]
|
||||
if len(field_name_values) == 1:
|
||||
user.form_data[field_name_values[0]] = d.get('cn')
|
||||
|
@ -67,18 +67,81 @@ class Saml2Directory(wcs.qommon.saml2.Saml2Directory):
|
|||
# other fields, matching is done on known LDAP attribute names and
|
||||
# common variable names
|
||||
extra_field_mappings = [
|
||||
('gn', ('firstname', 'prenom')),
|
||||
('givenName', ('firstname', 'prenom')),
|
||||
('surname', ('surname', 'name', 'nom',)),
|
||||
('sn', ('surname', 'name', 'nom',)),
|
||||
('personalTitle', ('personalTitle', 'civilite',)),
|
||||
('l', ('location', 'commune', 'ville',)),
|
||||
('streetAddress', ('streetAddress', 'address', 'adresse', 'street',)),
|
||||
('street', ('streetAddress', 'address', 'adresse', 'street',)),
|
||||
('postalCode', ('postalCode', 'codepostal', 'cp',)),
|
||||
('telephoneNumber', ('telephoneNumber', 'telephonefixe', 'telephone',)),
|
||||
('mobile', ('mobile', 'telephonemobile',)),
|
||||
('faxNumber', ('faxNumber', 'fax')),
|
||||
('gn', ('firstname', 'prenom')),
|
||||
('givenName', ('firstname', 'prenom')),
|
||||
(
|
||||
'surname',
|
||||
(
|
||||
'surname',
|
||||
'name',
|
||||
'nom',
|
||||
),
|
||||
),
|
||||
(
|
||||
'sn',
|
||||
(
|
||||
'surname',
|
||||
'name',
|
||||
'nom',
|
||||
),
|
||||
),
|
||||
(
|
||||
'personalTitle',
|
||||
(
|
||||
'personalTitle',
|
||||
'civilite',
|
||||
),
|
||||
),
|
||||
(
|
||||
'l',
|
||||
(
|
||||
'location',
|
||||
'commune',
|
||||
'ville',
|
||||
),
|
||||
),
|
||||
(
|
||||
'streetAddress',
|
||||
(
|
||||
'streetAddress',
|
||||
'address',
|
||||
'adresse',
|
||||
'street',
|
||||
),
|
||||
),
|
||||
(
|
||||
'street',
|
||||
(
|
||||
'streetAddress',
|
||||
'address',
|
||||
'adresse',
|
||||
'street',
|
||||
),
|
||||
),
|
||||
(
|
||||
'postalCode',
|
||||
(
|
||||
'postalCode',
|
||||
'codepostal',
|
||||
'cp',
|
||||
),
|
||||
),
|
||||
(
|
||||
'telephoneNumber',
|
||||
(
|
||||
'telephoneNumber',
|
||||
'telephonefixe',
|
||||
'telephone',
|
||||
),
|
||||
),
|
||||
(
|
||||
'mobile',
|
||||
(
|
||||
'mobile',
|
||||
'telephonemobile',
|
||||
),
|
||||
),
|
||||
('faxNumber', ('faxNumber', 'fax')),
|
||||
]
|
||||
|
||||
for attribute_key, field_varnames in extra_field_mappings:
|
||||
|
|
|
@ -10,6 +10,7 @@ from wcs.categories import Category
|
|||
wcs_error_page = template.error_page
|
||||
wcs_get_decorate_vars = template.get_decorate_vars
|
||||
|
||||
|
||||
def get_decorate_vars(body, response, generate_breadcrumb=True, template_context=None, **kwargs):
|
||||
if template_context and 'form_side' in template_context:
|
||||
# force rendering as it will put new variables in the context
|
||||
|
@ -30,7 +31,7 @@ def render_response(publisher, body):
|
|||
body = str(body)
|
||||
|
||||
root_url = publisher.get_root_url()
|
||||
wcs_path = publisher.get_request().get_path()[len(root_url):]
|
||||
wcs_path = publisher.get_request().get_path()[len(root_url) :]
|
||||
section = wcs_path.split('/')[0]
|
||||
|
||||
if section in ('backoffice', 'admin'):
|
||||
|
@ -78,6 +79,7 @@ def error_page(*args, **kwargs):
|
|||
get_response().filter['title'] = None
|
||||
return htmltext('<div id="info"><h2>%s</h2>' % title) + error_page + htmltext('</div>')
|
||||
|
||||
|
||||
template.error_page = error_page
|
||||
template.get_decorate_vars = get_decorate_vars
|
||||
get_publisher_class().render_response = render_response
|
||||
|
|
61
setup.py
61
setup.py
|
@ -12,16 +12,17 @@ from setuptools import setup
|
|||
|
||||
|
||||
def get_version():
|
||||
'''Use the VERSION, if absent generates a version with git describe, if not
|
||||
tag exists, take 0.0- and add the length of the commit log.
|
||||
'''
|
||||
"""Use the VERSION, if absent generates a version with git describe, if not
|
||||
tag exists, take 0.0- and add the length of the commit log.
|
||||
"""
|
||||
if os.path.exists('VERSION'):
|
||||
with open('VERSION', 'r') as v:
|
||||
return v.read()
|
||||
if os.path.exists('.git'):
|
||||
p = subprocess.Popen(
|
||||
['git', 'describe', '--dirty=.dirty', '--match=v*'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
result = p.communicate()[0]
|
||||
if p.returncode == 0:
|
||||
|
@ -33,9 +34,7 @@ def get_version():
|
|||
version = result
|
||||
return version
|
||||
else:
|
||||
return '0.0.post%s' % len(
|
||||
subprocess.check_output(
|
||||
['git', 'rev-list', 'HEAD']).splitlines())
|
||||
return '0.0.post%s' % len(subprocess.check_output(['git', 'rev-list', 'HEAD']).splitlines())
|
||||
return '0.0'
|
||||
|
||||
|
||||
|
@ -44,7 +43,7 @@ def data_tree(destdir, sourcedir):
|
|||
r = []
|
||||
for root, dirs, files in os.walk(sourcedir):
|
||||
l = [os.path.join(root, x) for x in files if os.path.splitext(x)[1] in extensions]
|
||||
r.append( (root.replace(sourcedir, destdir, 1), l) )
|
||||
r.append((root.replace(sourcedir, destdir, 1), l))
|
||||
if 'CVS' in dirs:
|
||||
dirs.remove('CVS')
|
||||
if '.svn' in dirs:
|
||||
|
@ -65,6 +64,7 @@ class compile_translations(Command):
|
|||
def run(self):
|
||||
try:
|
||||
from django.core.management import call_command
|
||||
|
||||
for path, dirs, files in os.walk('auquotidien'):
|
||||
if 'locale' not in dirs:
|
||||
continue
|
||||
|
@ -87,7 +87,6 @@ class install_lib(_install_lib):
|
|||
|
||||
|
||||
class eo_sdist(sdist):
|
||||
|
||||
def run(self):
|
||||
print("creating VERSION file")
|
||||
if os.path.exists('VERSION'):
|
||||
|
@ -101,21 +100,31 @@ class eo_sdist(sdist):
|
|||
if os.path.exists('VERSION'):
|
||||
os.remove('VERSION')
|
||||
|
||||
|
||||
setup(
|
||||
name = 'wcs-au-quotidien',
|
||||
version = get_version(),
|
||||
maintainer = 'Frederic Peters',
|
||||
maintainer_email = 'fpeters@entrouvert.com',
|
||||
package_dir = {'auquotidien': 'auquotidien'},
|
||||
packages = ['auquotidien', 'auquotidien.modules'],
|
||||
cmdclass={'build': build,
|
||||
'compile_translations': compile_translations,
|
||||
'install_lib': install_lib,
|
||||
'sdist': eo_sdist},
|
||||
include_package_data=True,
|
||||
data_files = data_tree('share/wcs/texts', 'texts') +\
|
||||
data_tree('share/wcs/themes/auquotidien', 'theme') +\
|
||||
data_tree('share/wcs/themes/', 'data/themes/') + \
|
||||
data_tree('share/auquotidien/apache-errors', 'apache-errors') +\
|
||||
[('share/wcs/', ['au-quotidien-wcs-settings.xml',])]
|
||||
)
|
||||
name='wcs-au-quotidien',
|
||||
version=get_version(),
|
||||
maintainer='Frederic Peters',
|
||||
maintainer_email='fpeters@entrouvert.com',
|
||||
package_dir={'auquotidien': 'auquotidien'},
|
||||
packages=['auquotidien', 'auquotidien.modules'],
|
||||
cmdclass={
|
||||
'build': build,
|
||||
'compile_translations': compile_translations,
|
||||
'install_lib': install_lib,
|
||||
'sdist': eo_sdist,
|
||||
},
|
||||
include_package_data=True,
|
||||
data_files=data_tree('share/wcs/texts', 'texts')
|
||||
+ data_tree('share/wcs/themes/auquotidien', 'theme')
|
||||
+ data_tree('share/wcs/themes/', 'data/themes/')
|
||||
+ data_tree('share/auquotidien/apache-errors', 'apache-errors')
|
||||
+ [
|
||||
(
|
||||
'share/wcs/',
|
||||
[
|
||||
'au-quotidien-wcs-settings.xml',
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
|
@ -23,6 +23,7 @@ from wcs import fields
|
|||
|
||||
from utilities import get_app, login, create_temporary_pub
|
||||
|
||||
|
||||
def setup_module(module):
|
||||
cleanup()
|
||||
|
||||
|
@ -35,6 +36,7 @@ def setup_module(module):
|
|||
pub.cfg['identification'] = {'methods': ['password']}
|
||||
pub.write_cfg()
|
||||
|
||||
|
||||
def create_superuser():
|
||||
global user1
|
||||
if pub.user_class.has_key('admin'):
|
||||
|
@ -56,19 +58,23 @@ def create_superuser():
|
|||
pub.cfg['identification'] = {'methods': ['password']}
|
||||
pub.write_cfg()
|
||||
|
||||
|
||||
def create_role():
|
||||
Role.wipe()
|
||||
role = Role(name='foobar')
|
||||
role.store()
|
||||
return role
|
||||
|
||||
|
||||
def teardown_module(module):
|
||||
shutil.rmtree(pub.APP_DIR)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def empty_siteoptions():
|
||||
open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w').close()
|
||||
|
||||
|
||||
def test_with_superuser():
|
||||
create_superuser()
|
||||
app = login(get_app(pub))
|
||||
|
@ -76,6 +82,7 @@ def test_with_superuser():
|
|||
# this makes sure the extension loaded properly
|
||||
assert '<span id="applabel">Publik</span>' in resp.text
|
||||
|
||||
|
||||
def test_general_admin_permissions():
|
||||
create_superuser()
|
||||
app = login(get_app(pub))
|
||||
|
@ -89,6 +96,7 @@ def test_general_admin_permissions():
|
|||
del pub.cfg['admin-permissions']
|
||||
pub.write_cfg()
|
||||
|
||||
|
||||
def test_aq_permissions_panel(empty_siteoptions):
|
||||
create_superuser()
|
||||
app = login(get_app(pub))
|
||||
|
@ -105,6 +113,7 @@ def test_aq_permissions_panel(empty_siteoptions):
|
|||
assert 'aq/permissions' in resp.text
|
||||
resp = app.get('/backoffice/settings/aq/permissions')
|
||||
|
||||
|
||||
def test_menu_items(empty_siteoptions):
|
||||
create_superuser()
|
||||
role = create_role()
|
||||
|
|
|
@ -18,6 +18,7 @@ from wcs import fields
|
|||
|
||||
from utilities import get_app, login, create_temporary_pub
|
||||
|
||||
|
||||
def setup_module(module):
|
||||
cleanup()
|
||||
|
||||
|
@ -30,6 +31,7 @@ def setup_module(module):
|
|||
pub.cfg['identification'] = {'methods': ['password']}
|
||||
pub.write_cfg()
|
||||
|
||||
|
||||
def create_agent():
|
||||
if pub.user_class.has_key('agent'):
|
||||
return
|
||||
|
@ -48,6 +50,7 @@ def create_agent():
|
|||
|
||||
return user1
|
||||
|
||||
|
||||
def create_role():
|
||||
Role.wipe()
|
||||
role = Role(name='foobar')
|
||||
|
@ -55,9 +58,11 @@ def create_role():
|
|||
role.store()
|
||||
return role
|
||||
|
||||
|
||||
def teardown_module(module):
|
||||
shutil.rmtree(pub.APP_DIR)
|
||||
|
||||
|
||||
def test_with_agent():
|
||||
user = create_agent()
|
||||
app = login(get_app(pub), username='agent', password='agent')
|
||||
|
@ -71,6 +76,7 @@ def test_with_agent():
|
|||
# check user is automatically redirected to management/
|
||||
assert resp.location == 'http://example.net/backoffice/management/'
|
||||
|
||||
|
||||
def test_with_agent_submitter():
|
||||
user = create_agent()
|
||||
role = create_role()
|
||||
|
@ -89,7 +95,7 @@ def test_with_agent_submitter():
|
|||
|
||||
formdef.backoffice_submission_roles = [role.id]
|
||||
formdef.store()
|
||||
resp = app.get('/backoffice/', status=200) # no redirect
|
||||
resp = app.get('/backoffice/', status=200) # no redirect
|
||||
# check the management and submission links are presend twice, once in the
|
||||
# sidebar and once in the page body
|
||||
assert resp.text.count('//example.net/backoffice/management/') == 2
|
||||
|
|
|
@ -6,6 +6,7 @@ from auquotidien.modules import payments
|
|||
|
||||
from utilities import get_app, login, create_temporary_pub
|
||||
|
||||
|
||||
def setup_module(module):
|
||||
cleanup()
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ from wcs import fields
|
|||
|
||||
from utilities import get_app, login, create_temporary_pub
|
||||
|
||||
|
||||
def setup_module(module):
|
||||
cleanup()
|
||||
|
||||
|
@ -30,6 +31,7 @@ def setup_module(module):
|
|||
pub.cfg['identification'] = {'methods': ['password']}
|
||||
pub.write_cfg()
|
||||
|
||||
|
||||
def create_user():
|
||||
if pub.user_class.has_key('user'):
|
||||
return
|
||||
|
@ -48,6 +50,7 @@ def create_user():
|
|||
|
||||
return user1
|
||||
|
||||
|
||||
def create_formdef():
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
|
@ -56,15 +59,18 @@ def create_formdef():
|
|||
formdef.store()
|
||||
return formdef
|
||||
|
||||
|
||||
def teardown_module(module):
|
||||
shutil.rmtree(pub.APP_DIR)
|
||||
|
||||
|
||||
def test_with_user():
|
||||
user = create_user()
|
||||
app = login(get_app(pub), username='user', password='user')
|
||||
resp = app.get('/', status=200)
|
||||
resp = app.get('/myspace/', status=200)
|
||||
|
||||
|
||||
def test_myspace_with_user_forms():
|
||||
user = create_user()
|
||||
formdef = create_formdef()
|
||||
|
|
|
@ -16,12 +16,14 @@ import wcs.middleware
|
|||
|
||||
wcs.middleware.AfterJobsMiddleware.ASYNC = False
|
||||
|
||||
|
||||
def create_temporary_pub():
|
||||
config = ConfigParser.ConfigParser()
|
||||
APP_DIR = tempfile.mkdtemp()
|
||||
compat.CompatWcsPublisher.APP_DIR = APP_DIR
|
||||
compat.CompatWcsPublisher.DATA_DIR = os.path.abspath(
|
||||
os.path.join(os.path.dirname(wcs.__file__), '..', 'data'))
|
||||
os.path.join(os.path.dirname(wcs.__file__), '..', 'data')
|
||||
)
|
||||
compat.CompatWcsPublisher.cronjobs = None
|
||||
config.add_section('extra')
|
||||
config.set('extra', 'auquotidien', os.path.join(os.path.dirname(__file__), '..', 'auquotidien'))
|
||||
|
@ -34,6 +36,7 @@ def create_temporary_pub():
|
|||
os.mkdir(pub.app_dir)
|
||||
return pub
|
||||
|
||||
|
||||
def get_app(pub, https=False):
|
||||
extra_environ = {'HTTP_HOST': 'example.net', 'REMOTE_ADDR': '127.0.0.1'}
|
||||
if https:
|
||||
|
@ -43,6 +46,7 @@ def get_app(pub, https=False):
|
|||
extra_environ['HTTPS'] = 'off'
|
||||
return TestApp(wcs.wsgi.application, extra_environ=extra_environ)
|
||||
|
||||
|
||||
def login(app, username='admin', password='admin'):
|
||||
login_page = app.get('/login/')
|
||||
login_form = login_page.forms['login-form']
|
||||
|
|
Reference in New Issue