Projet

Général

Profil

Télécharger (14,5 ko) Statistiques
| Branche: | Tag: | Révision:

root / auquotidien / modules / myspace.py @ a9ee9454

1
try:
2
    import lasso
3
except ImportError:
4
    pass
5

    
6
import json
7

    
8
from quixote import get_publisher, get_request, redirect, get_response, get_session_manager, get_session
9
from quixote.directory import AccessControlled, Directory
10
from quixote.html import TemplateIO, htmltext
11
from quixote.util import StaticFile, FileStream
12

    
13
from wcs.qommon import _
14
from wcs.qommon import template
15
from wcs.qommon.form import *
16
from wcs.qommon import get_cfg, get_logger
17
from wcs.qommon import errors
18
from wcs.api import get_user_from_api_query_string
19

    
20
import wcs.qommon.ident.password
21
from wcs.qommon.ident.password_accounts import PasswordAccount
22

    
23
from wcs.qommon.admin.texts import TextsDirectory
24

    
25
from wcs.formdef import FormDef
26
import wcs.myspace
27

    
28
from .payments import Invoice, Regie, is_payment_supported
29

    
30
class MyInvoicesDirectory(Directory):
31
    _q_exports = ['']
32

    
33
    def _q_traverse(self, path):
34
        if not is_payment_supported():
35
            raise errors.TraversalError()
36
        get_response().breadcrumb.append(('invoices/', _('Invoices')))
37
        return Directory._q_traverse(self, path)
38

    
39
    def _q_index(self):
40
        user = get_request().user
41
        if not user or user.anonymous:
42
            raise errors.AccessUnauthorizedError()
43

    
44
        template.html_top(_('Invoices'))
45
        r = TemplateIO(html=True)
46
        r += TextsDirectory.get_html_text('aq-myspace-invoice')
47

    
48
        r += get_session().display_message()
49

    
50
        invoices = []
51
        invoices.extend(Invoice.get_with_indexed_value(
52
            str('user_id'), str(user.id)))
53
        invoices.sort(key=lambda x: (x.regie_id, -x.date))
54

    
55
        last_regie_id = None
56
        unpaid = False
57
        for invoice in invoices:
58
            if invoice.regie_id != last_regie_id:
59
                if last_regie_id:
60
                    r += htmltext('</ul>')
61
                    if unpaid:
62
                        r += htmltext('<input type="submit" value="%s"/>') % _('Pay Selected Invoices')
63
                    r += htmltext('</form>')
64
                last_regie_id = invoice.regie_id
65
                r += htmltext('<h3>%s</h3>') % Regie.get(last_regie_id).label
66
                unpaid = False
67
                r += htmltext('<form action="%s/invoices/multiple">' % get_publisher().get_frontoffice_url())
68
                r += htmltext('<ul>')
69

    
70
            r += htmltext('<li>')
71
            if not (invoice.paid or invoice.canceled):
72
                r += htmltext('<input type="checkbox" name="invoice" value="%s"/>' % invoice.id)
73
                unpaid = True
74
            r += misc.localstrftime(invoice.date)
75
            r += ' - '
76
            r += '%s' % invoice.subject
77
            r += ' - '
78
            r += '%s' % invoice.amount
79
            r += htmltext(' &euro;')
80
            r += ' - '
81
            button = '<span class="paybutton">%s</span>' % _('Pay')
82
            if invoice.canceled:
83
                r += _('canceled on %s') % misc.localstrftime(invoice.canceled_date)
84
                r += ' - '
85
                button = _('Details')
86
            if invoice.paid:
87
                r += _('paid on %s') % misc.localstrftime(invoice.paid_date)
88
                r += ' - '
89
                button = _('Details')
90
            r += htmltext('<a href="%s/invoices/%s">%s</a>' % (get_publisher().get_frontoffice_url(),
91
                    invoice.id, button))
92
            r += htmltext('</li>')
93

    
94
        if last_regie_id:
95
            r += htmltext('</ul>')
96
            if unpaid:
97
                r += htmltext('<input type="submit" value="%s"/>') % _('Pay Selected Invoices')
98
            r += htmltext('</form>')
99

    
100
        return r.getvalue()
101

    
102

    
103
class JsonDirectory(Directory):
104
    '''Export of several lists in json, related to the current user or the
105
       SAMLv2 NameID we'd get in the URL'''
106

    
107
    _q_exports = ['forms']
108

    
109
    user = None
110

    
111
    def _q_traverse(self, path):
112
        self.user = get_user_from_api_query_string() or get_request().user
113
        if not self.user:
114
            raise errors.AccessUnauthorizedError()
115
        return Directory._q_traverse(self, path)
116

    
117
    def forms(self):
118
        formdefs = FormDef.select(order_by='name', ignore_errors=True)
119
        user_forms = []
120
        for formdef in formdefs:
121
            user_forms.extend(formdef.data_class().get_with_indexed_value(
122
                        'user_id', self.user.id))
123
        user_forms.sort(key=lambda x: x.receipt_time)
124

    
125
        get_response().set_content_type('application/json')
126

    
127

    
128
        forms_output = []
129
        for form in user_forms:
130
            visible_status = form.get_visible_status(user=self.user)
131
            # skip drafts and hidden forms
132
            if not visible_status:
133
                continue
134
            name = form.formdef.name
135
            id = form.get_display_id()
136
            status = visible_status.name
137
            title = _('%(name)s #%(id)s (%(status)s)') % {
138
                    'name': name,
139
                    'id': id,
140
                    'status': status
141
            }
142
            url = form.get_url()
143
            d = { 'title': title, 'url': url }
144
            d.update(form.get_substitution_variables(minimal=True))
145
            forms_output.append(d)
146
        return json.dumps(forms_output, cls=misc.JSONEncoder)
147

    
148

    
149
class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
150
    _q_exports = ['', 'profile', 'new', 'password', 'remove', 'drafts', 'forms',
151
            'invoices', 'json']
152

    
153
    invoices = MyInvoicesDirectory()
154
    json = JsonDirectory()
155

    
156
    def _q_traverse(self, path):
157
        get_response().filter['bigdiv'] = 'profile'
158
        get_response().breadcrumb.append(('myspace/', _('My Space')))
159

    
160
        # Migrate custom text settings
161
        texts_cfg = get_cfg('texts', {})
162
        if 'text-aq-top-of-profile' in texts_cfg and (
163
                        not 'text-top-of-profile' in texts_cfg):
164
            texts_cfg['text-top-of-profile'] = texts_cfg['text-aq-top-of-profile']
165
            del texts_cfg['text-aq-top-of-profile']
166
            get_publisher().write_cfg()
167

    
168
        return Directory._q_traverse(self, path)
169

    
170

    
171
    def _q_index(self):
172
        user = get_request().user
173
        if not user:
174
            raise errors.AccessUnauthorizedError()
175
        template.html_top(_('My Space'))
176
        r = TemplateIO(html=True)
177
        if user.anonymous:
178
            return redirect('new')
179

    
180
        user_formdef = user.get_formdef()
181

    
182
        user_forms = []
183
        if user:
184
            formdefs = FormDef.select(order_by='name', ignore_errors=True)
185
            user_forms = []
186
            for formdef in formdefs:
187
                user_forms.extend(formdef.data_class().get_with_indexed_value(
188
                            'user_id', user.id))
189
            user_forms.sort(key=lambda x: x.receipt_time)
190

    
191
        profile_links = []
192
        if not get_cfg('sp', {}).get('idp-manage-user-attributes', False):
193
            if user_formdef:
194
                profile_links.append('<a href="#my-profile">%s</a>' % _('My Profile'))
195
        if user_forms:
196
            profile_links.append('<a href="#my-forms">%s</a>' % _('My Forms'))
197
        if is_payment_supported():
198
            profile_links.append('<a href="invoices/">%s</a>' % _('My Invoices'))
199

    
200
        root_url = get_publisher().get_root_url()
201
        if user.can_go_in_backoffice():
202
            profile_links.append('<a href="%sbackoffice/">%s</a>' % (root_url, _('Back office')))
203
        if user.is_admin:
204
            profile_links.append('<a href="%sadmin/">%s</a>' % (root_url, _('Admin')))
205

    
206
        if profile_links:
207
            r += htmltext('<p id="profile-links">')
208
            r += htmltext(' - '.join(profile_links))
209
            r += htmltext('</p>')
210

    
211
        if not get_cfg('sp', {}).get('idp-manage-user-attributes', False):
212
            if user_formdef:
213
                r += self._my_profile(user_formdef, user)
214

    
215
            r += self._index_buttons(user_formdef)
216

    
217
            try:
218
                x = PasswordAccount.get_on_index(get_request().user.id, str('user_id'))
219
            except KeyError:
220
                pass
221
            else:
222
                r += htmltext('<p>')
223
                r += _('You can delete your account freely from the services portal. '
224
                       'This action is irreversible; it will destruct your personal '
225
                       'datas and destruct the access to your request history.')
226
                r += htmltext(' <strong><a href="remove" rel="popup">%s</a></strong>.') % _('Delete My Account')
227
                r += htmltext('</p>')
228

    
229
        if user_forms:
230
            r += htmltext('<h3 id="my-forms">%s</h3>') % _('My Forms')
231
            from . import root
232
            r += root.FormsRootDirectory().user_forms(user_forms)
233

    
234
        return r.getvalue()
235

    
236
    def _my_profile(self, user_formdef, user):
237
        r = TemplateIO(html=True)
238
        r += htmltext('<h3 id="my-profile">%s</h3>') % _('My Profile')
239

    
240
        r += TextsDirectory.get_html_text('top-of-profile')
241

    
242
        if user.form_data:
243
            r += htmltext('<ul>')
244
            for field in user_formdef.fields:
245
                if not hasattr(field, str('get_view_value')):
246
                    continue
247
                value = user.form_data.get(field.id)
248
                r += htmltext('<li>')
249
                r += field.label
250
                r += ' : '
251
                if value:
252
                    r += field.get_view_value(value)
253
                r += htmltext('</li>')
254
            r += htmltext('</ul>')
255
        else:
256
            r += htmltext('<p>%s</p>') % _('Empty profile')
257
        return r.getvalue()
258

    
259
    def _index_buttons(self, form_data):
260
        r = TemplateIO(html=True)
261
        passwords_cfg = get_cfg('passwords', {})
262
        ident_method = get_cfg('identification', {}).get('methods', ['idp'])[0]
263
        if get_session().lasso_session_dump:
264
            ident_method = 'idp'
265

    
266
        if form_data and ident_method != 'idp':
267
            r += htmltext('<p class="command"><a href="profile" rel="popup">%s</a></p>') % _('Edit My Profile')
268

    
269
        if ident_method == 'password' and passwords_cfg.get('can_change', False):
270
            r += htmltext('<p class="command"><a href="password" rel="popup">%s</a></p>') % _('Change My Password')
271

    
272
        return r.getvalue()
273

    
274
    def profile(self):
275
        user = get_request().user
276
        if not user or user.anonymous:
277
            raise errors.AccessUnauthorizedError()
278

    
279
        form = Form(enctype = 'multipart/form-data')
280
        formdef = user.get_formdef()
281
        formdef.add_fields_to_form(form, form_data = user.form_data)
282

    
283
        form.add_submit('submit', _('Apply Changes'))
284
        form.add_submit('cancel', _('Cancel'))
285

    
286
        if form.get_submit() == 'cancel':
287
            return redirect('.')
288

    
289
        if form.is_submitted() and not form.has_errors():
290
            self.profile_submit(form, formdef)
291
            return redirect('.')
292

    
293
        template.html_top(_('Edit Profile'))
294
        return form.render()
295

    
296
    def profile_submit(self, form, formdef):
297
        user = get_request().user
298
        data = formdef.get_data(form)
299

    
300
        user.set_attributes_from_formdata(data)
301
        user.form_data = data
302

    
303
        user.store()
304

    
305
    def password(self):
306
        ident_method = get_cfg('identification', {}).get('methods', ['idp'])[0]
307
        if ident_method != 'password':
308
            raise errors.TraversalError()
309

    
310
        user = get_request().user
311
        if not user or user.anonymous:
312
            raise errors.AccessUnauthorizedError()
313

    
314
        form = Form(enctype = 'multipart/form-data')
315
        form.add(PasswordWidget, 'new_password', title = _('New Password'),
316
                required=True)
317
        form.add(PasswordWidget, 'new2_password', title = _('New Password (confirm)'),
318
                required=True) 
319

    
320
        form.add_submit('submit', _('Change Password'))
321
        form.add_submit('cancel', _('Cancel'))
322

    
323
        if form.get_submit() == 'cancel':
324
            return redirect('.')
325

    
326
        if form.is_submitted() and not form.has_errors():
327
            wcs.qommon.ident.password.check_password(form, 'new_password')
328
            new_password = form.get_widget('new_password').parse()
329
            new2_password = form.get_widget('new2_password').parse()
330
            if new_password != new2_password:
331
                form.set_error('new2_password', _('Passwords do not match'))
332

    
333
        if form.is_submitted() and not form.has_errors():
334
            self.submit_password(new_password)
335
            return redirect('.')
336

    
337
        template.html_top(_('Change Password'))
338
        return form.render()
339

    
340
    def submit_password(self, new_password):
341
        passwords_cfg = get_cfg('passwords', {})
342
        account = PasswordAccount.get(get_session().username)
343
        account.hashing_algo = passwords_cfg.get('hashing_algo')
344
        account.set_password(new_password)
345
        account.store()
346

    
347
    def new(self):
348
        if not get_request().user or not get_request().user.anonymous:
349
            raise errors.AccessUnauthorizedError()
350

    
351
        form = Form(enctype = 'multipart/form-data')
352
        formdef = get_publisher().user_class.get_formdef()
353
        if formdef:
354
            formdef.add_fields_to_form(form)
355
        else:
356
            get_logger().error('missing user formdef (in myspace/new)')
357

    
358
        form.add_submit('submit', _('Register'))
359

    
360
        if form.is_submitted() and not form.has_errors():
361
            user = get_publisher().user_class()
362
            data = formdef.get_data(form)
363
            user.set_attributes_from_formdata(data)
364
            user.name_identifiers = get_request().user.name_identifiers
365
            user.lasso_dump = get_request().user.lasso_dump
366
            user.set_attributes_from_formdata(data)
367
            user.form_data = data
368
            user.store()
369
            get_session().set_user(user.id)
370
            root_url = get_publisher().get_root_url()
371
            return redirect('%smyspace' % root_url)
372

    
373
        template.html_top(_('Welcome'))
374
        return form.render()
375

    
376

    
377
    def remove(self):
378
        user = get_request().user
379
        if not user or user.anonymous:
380
            raise errors.AccessUnauthorizedError()
381

    
382
        form = Form(enctype = 'multipart/form-data')
383
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
384
                        'Are you really sure you want to remove your account?')))
385
        form.add_submit('submit', _('Remove my account'))
386
        form.add_submit('cancel', _('Cancel'))
387

    
388
        if form.get_submit() == 'cancel':
389
            return redirect('.')
390

    
391
        if form.is_submitted() and not form.has_errors():
392
            user = get_request().user
393
            account = PasswordAccount.get_on_index(user.id, str('user_id'))
394
            get_session_manager().expire_session() 
395
            account.remove_self()
396
            return redirect(get_publisher().get_root_url())
397

    
398
        template.html_top(_('Removing Account'))
399
        return form.render()
400

    
401

    
402
TextsDirectory.register('aq-myspace-invoice',
403
        N_('Message on top of invoices page'),
404
        category = N_('Invoices'))
405

    
(13-13/18)