diff --git a/auquotidien/auquotidien.py b/auquotidien/auquotidien.py index 9a5384f..1ff3f10 100644 --- a/auquotidien/auquotidien.py +++ b/auquotidien/auquotidien.py @@ -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'), +] diff --git a/auquotidien/modules/abelium_domino_workflow.py b/auquotidien/modules/abelium_domino_workflow.py index 40737c7..7b301c1 100644 --- a/auquotidien/modules/abelium_domino_workflow.py +++ b/auquotidien/modules/abelium_domino_workflow.py @@ -1,4 +1,5 @@ from wcs.workflows import WorkflowStatusItem + class AbeliumDominoRegisterFamilyWorkflowStatusItem(WorkflowStatusItem): key = 'abelium-domino-register-family' diff --git a/auquotidien/modules/admin.py b/auquotidien/modules/admin.py index 050f18d..6d2a986 100644 --- a/auquotidien/modules/admin.py +++ b/auquotidien/modules/admin.py @@ -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 diff --git a/auquotidien/modules/backoffice.py b/auquotidien/modules/backoffice.py index c4f3659..6367c53 100644 --- a/auquotidien/modules/backoffice.py +++ b/auquotidien/modules/backoffice.py @@ -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 diff --git a/auquotidien/modules/categories_admin.py b/auquotidien/modules/categories_admin.py index 0a6d559..1e81cb6 100644 --- a/auquotidien/modules/categories_admin.py +++ b/auquotidien/modules/categories_admin.py @@ -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('
') - 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(' %s.') % _('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(' %s.') % _( + 'Delete My Account' + ) r += htmltext('
') if user_forms: r += htmltext('%s
' % _( - 'Are you really sure you want to remove your account?'))) + form = Form(enctype='multipart/form-data') + form.widgets.append( + HtmlWidget('%s
' % _('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')) diff --git a/auquotidien/modules/payments.py b/auquotidien/modules/payments.py index 3026ef0..ad94c81 100644 --- a/auquotidien/modules/payments.py +++ b/auquotidien/modules/payments.py @@ -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 %(id)s: %(subject)s - %(amount)s €'), - 'pay': N_('Invoice %(id)s is paid with transaction number %(transaction_order_id)s'), + 'pay': N_( + 'Invoice %(id)s is paid with transaction number %(transaction_order_id)s' + ), 'cancel': N_('Cancel Invoice %(id)s'), - 'try': N_('Try paying invoice %(id)s with transaction number %(transaction_order_id)s'), + 'try': N_( + 'Try paying invoice %(id)s 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('' % self.action + \ - _(INVOICE_EVO_VIEW[self.action]) % vars + '
') + return htmltext( + '' % self.action + _(INVOICE_EVO_VIEW[self.action]) % vars + '
' + ) 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('') - r += htmltext('') - 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('You can also use your identity provider to connect. -
''')) +''' + ), +) -TextsDirectory.register('aq-home-page', N_('Home Page'), wysiwyg = True) +TextsDirectory.register('aq-home-page', N_('Home Page'), wysiwyg=True) diff --git a/auquotidien/modules/saml2.py b/auquotidien/modules/saml2.py index b670eb9..b63ef0a 100644 --- a/auquotidien/modules/saml2.py +++ b/auquotidien/modules/saml2.py @@ -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: diff --git a/auquotidien/modules/template.py b/auquotidien/modules/template.py index 2a1bdd0..e59a5d3 100644 --- a/auquotidien/modules/template.py +++ b/auquotidien/modules/template.py @@ -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('