Projet

Général

Profil

Télécharger (28 ko) Statistiques
| Branche: | Tag: | Révision:

root / extra / modules / myspace.py @ aeab44dc

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 qommon import template
14
from qommon.form import *
15
from qommon import get_cfg, get_logger
16
from qommon import errors
17
from wcs.api import get_user_from_api_query_string
18

    
19
import qommon.ident.password
20
from qommon.ident.password_accounts import PasswordAccount
21

    
22
from qommon.admin.texts import TextsDirectory
23

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

    
28
from announces import AnnounceSubscription
29
from strongbox import StrongboxItem, StrongboxType
30
from payments import Invoice, Regie, is_payment_supported
31

    
32
class MyInvoicesDirectory(Directory):
33
    _q_exports = ['']
34

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

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

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

    
50
        r += get_session().display_message()
51

    
52
        invoices = []
53
        invoices.extend(Invoice.get_with_indexed_value(
54
            str('user_id'), str(user.id)))
55
        try:
56
            invoices.extend(Invoice.get_with_indexed_value(
57
                str('user_hash'), str(user.hash)))
58
        except AttributeError:
59
            pass
60

    
61
        def cmp_invoice(a, b):
62
            t = cmp(a.regie_id, b.regie_id)
63
            if t != 0:
64
                return t
65
            return -cmp(a.date, b.date)
66

    
67
        invoices.sort(cmp_invoice)
68

    
69
        last_regie_id = None
70
        unpaid = False
71
        for invoice in invoices:
72
            if invoice.regie_id != last_regie_id:
73
                if last_regie_id:
74
                    r += htmltext('</ul>')
75
                    if unpaid:
76
                        r += htmltext('<input type="submit" value="%s"/>') % _('Pay Selected Invoices')
77
                    r += htmltext('</form>')
78
                last_regie_id = invoice.regie_id
79
                r += htmltext('<h3>%s</h3>') % Regie.get(last_regie_id).label
80
                unpaid = False
81
                r += htmltext('<form action="%s/invoices/multiple">' % get_publisher().get_frontoffice_url())
82
                r += htmltext('<ul>')
83

    
84
            r += htmltext('<li>')
85
            if not (invoice.paid or invoice.canceled):
86
                r += htmltext('<input type="checkbox" name="invoice" value="%s"/>' % invoice.id)
87
                unpaid = True
88
            r += misc.localstrftime(invoice.date)
89
            r += ' - '
90
            r += '%s' % invoice.subject
91
            r += ' - '
92
            r += '%s' % invoice.amount
93
            r += htmltext(' &euro;')
94
            r += ' - '
95
            button = '<span class="paybutton">%s</span>' % _('Pay')
96
            if invoice.canceled:
97
                r += _('canceled on %s') % misc.localstrftime(invoice.canceled_date)
98
                r += ' - '
99
                button = _('Details')
100
            if invoice.paid:
101
                r += _('paid on %s') % misc.localstrftime(invoice.paid_date)
102
                r += ' - '
103
                button = _('Details')
104
            r += htmltext('<a href="%s/invoices/%s">%s</a>' % (get_publisher().get_frontoffice_url(),
105
                    invoice.id, button))
106
            r += htmltext('</li>')
107

    
108
        if last_regie_id:
109
            r += htmltext('</ul>')
110
            if unpaid:
111
                r += htmltext('<input type="submit" value="%s"/>') % _('Pay Selected Invoices')
112
            r += htmltext('</form>')
113

    
114
        return r.getvalue()
115

    
116

    
117
class StrongboxDirectory(Directory):
118
    _q_exports = ['', 'add', 'download', 'remove', 'pick', 'validate']
119

    
120
    def _q_traverse(self, path):
121
        if not get_cfg('misc', {}).get('aq-strongbox'):
122
            raise errors.TraversalError()
123
        get_response().breadcrumb.append(('strongbox/', _('Strongbox')))
124
        return Directory._q_traverse(self, path)
125

    
126
    def get_form(self):
127
        types = [(x.id, x.label) for x in StrongboxType.select()]
128
        form = Form(action='add', enctype='multipart/form-data')
129
        form.add(StringWidget, 'description', title=_('Description'), size=60)
130
        form.add(FileWidget, 'file', title=_('File'), required=True)
131
        form.add(SingleSelectWidget, 'type_id', title=_('Document Type'),
132
                 options = [(None, _('Not specified'))] + types)
133
        form.add(DateWidget, 'date_time', title = _('Document Date'))
134
        form.add_submit('submit', _('Upload'))
135
        return form
136

    
137
    def _q_index(self):
138
        template.html_top(_('Strongbox'))
139
        r = TemplateIO(html=True)
140

    
141
        # TODO: a paragraph of explanations here could be useful
142

    
143
        sffiles = StrongboxItem.get_with_indexed_value(
144
                        str('user_id'), str(get_request().user.id))
145
        if sffiles:
146
            r += htmltext('<table id="strongbox-items">')
147
            r += htmltext('<tr><th></th><th>%s</th><th>%s</th><th></th></tr>') % (
148
                _('Type'), _('Expiration'))
149
        else:
150
            r += htmltext('<p>')
151
            r += _('There is currently nothing in your strongbox.')
152
            r += htmltext('</p>')
153
        has_items_to_validate = False
154
        for i, sffile in enumerate(sffiles):
155
            expired = False
156
            if not sffile.validated_time:
157
                has_items_to_validate = True
158
                continue
159
            if sffile.expiration_time and sffile.expiration_time < time.localtime():
160
                expired = True
161
            if i%2:
162
                classnames = ['odd']
163
            else:
164
                classnames = ['even']
165
            if expired:
166
                classnames.append('expired')
167
            r += htmltext('<tr class="%s">') % ' '.join(classnames)
168
            r += htmltext('<td class="label">')
169
            r += sffile.get_display_name()
170
            r += htmltext('</td>')
171
            if sffile.type_id:
172
                r += htmltext('<td class="type">%s</td>') % StrongboxType.get(sffile.type_id).label
173
            else:
174
                r += htmltext('<td class="type">-</td>')
175
            if sffile.expiration_time:
176
                r += htmltext('<td class="expiration">%s') % strftime(misc.date_format(), sffile.expiration_time)
177
                if expired:
178
                    r += ' (%s)' % _('expired')
179
                r += htmltext('</td>')
180
            else:
181
                r += htmltext('<td class="expiration">-</td>')
182
            r += htmltext('<td class="actions">')
183
            r += htmltext(' [<a href="download?id=%s">%s</a>] ') % (sffile.id, _('download'))
184
            r += htmltext('[<a rel="popup" href="remove?id=%s">%s</a>] ') % (sffile.id, _('remove'))
185
            r += htmltext('</td>')
186
            r += htmltext('</tr>')
187

    
188
        if has_items_to_validate:
189
            r += htmltext('<tr><td colspan="4"><h3>%s</h3></td></tr>') % _('Proposed Items')
190
            for sffile in sffiles:
191
                if sffile.validated_time:
192
                    continue
193
                if sffile.expiration_time and sffile.expiration_time < time.localtime():
194
                    expired = True
195
                if i%2:
196
                    classnames = ['odd']
197
                else:
198
                    classnames = ['even']
199
                if expired:
200
                    classnames.append('expired')
201
                r += htmltext('<tr class="%s">') % ' '.join(classnames)
202

    
203
                r += htmltext('<td class="label">')
204
                r += sffile.get_display_name()
205
                r += htmltext('</td>')
206
                if sffile.type_id:
207
                    r += htmltext('<td class="type">%s</td>') % StrongboxType.get(sffile.type_id).label
208
                else:
209
                    r += htmltext('<td class="type">-</td>')
210

    
211
                if sffile.expiration_time:
212
                    r += htmltext('<td class="expiration">%s') % strftime(misc.date_format(), sffile.expiration_time)
213
                    if expired:
214
                        r += ' (%s)' % _('expired')
215
                    r += htmltext('</td>')
216
                else:
217
                    r += htmltext('<td class="expiration">-</td>')
218
                r += htmltext('<td class="actions">')
219
                r += htmltext(' [<a href="download?id=%s">%s</a>] ') % (sffile.id, _('download'))
220
                r += htmltext(' [<a href="validate?id=%s">%s</a>] ') % (sffile.id, _('validate'))
221
                r += htmltext(' [<a href="remove?id=%s">%s</a>] ') % (sffile.id, _('reject'))
222
                r += htmltext('</td>')
223
                r += htmltext('</tr>')
224
        if sffiles:
225
            r += htmltext('</table>')
226

    
227
        r += htmltext('<h3>%s</h3>') % _('Add a file to the strongbox')
228
        form = self.get_form()
229
        r += form.render()
230
        return r.getvalue()
231

    
232
    def add(self):
233
        form = self.get_form()
234
        if not form.is_submitted():
235
            if get_request().form.get('mode') == 'pick':
236
                return redirect('pick')
237
            else:
238
                return redirect('.')
239

    
240
        sffile = StrongboxItem()
241
        sffile.user_id = get_request().user.id
242
        sffile.description = form.get_widget('description').parse()
243
        sffile.validated_time = time.localtime()
244
        sffile.type_id = form.get_widget('type_id').parse()
245
        v = form.get_widget('date_time').parse()
246
        sffile.set_expiration_time_from_date(v)
247
        sffile.store()
248
        sffile.set_file(form.get_widget('file').parse())
249
        sffile.store()
250
        if get_request().form.get('mode') == 'pick':
251
            return redirect('pick')
252
        else:
253
            return redirect('.')
254

    
255
    def download(self):
256
        id = get_request().form.get('id')
257
        if not id:
258
            raise errors.TraversalError()
259
        try:
260
            sffile = StrongboxItem.get(id)
261
        except KeyError:
262
            raise errors.TraversalError()
263
        if str(sffile.user_id) != str(get_request().user.id):
264
            raise errors.TraversalError()
265

    
266
        filename = sffile.file.filename
267
        fd = file(filename)
268
        size = os.path.getsize(filename)
269
        response = get_response()
270
        response.set_content_type('application/octet-stream')
271
        response.set_header('content-disposition', 'attachment; filename="%s"' % sffile.file.base_filename)
272
        return FileStream(fd, size)
273

    
274
    def validate(self):
275
        id = get_request().form.get('id')
276
        if not id:
277
            raise errors.TraversalError()
278
        try:
279
            sffile = StrongboxItem.get(id)
280
        except KeyError:
281
            raise errors.TraversalError()
282
        if str(sffile.user_id) != str(get_request().user.id):
283
            raise errors.TraversalError()
284
        sffile.validated_time = time.time()
285
        sffile.store()
286
        return redirect('.')
287

    
288
    def remove(self):
289
        id = get_request().form.get('id')
290
        if not id:
291
            raise errors.TraversalError()
292
        try:
293
            sffile = StrongboxItem.get(id)
294
        except KeyError:
295
            raise errors.TraversalError()
296
        if str(sffile.user_id) != str(get_request().user.id):
297
            raise errors.TraversalError()
298

    
299
        r = TemplateIO(html=True)
300
        form = Form(enctype='multipart/form-data')
301
        form.add_hidden('id', get_request().form.get('id'))
302
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
303
                        'You are about to irrevocably delete this item from your strongbox.')))
304
        form.add_submit('submit', _('Submit'))
305
        form.add_submit('cancel', _('Cancel'))
306
        if form.get_submit() == 'cancel':
307
            return redirect('.')
308
        if not form.is_submitted() or form.has_errors():
309
            if sffile.type_id:
310
                r += htmltext('<h2>%s</h2>') % _('Deleting %(filetype)s: %(filename)s') % {
311
                        'filetype': StrongboxType.get(sffile.type_id).label,
312
                        'filename': sffile.get_display_name()
313
                    }
314
            else:
315
                r += htmltext('<h2>%s</h2>') % _('Deleting %(filename)s') % {'filename': sffile.get_display_name()}
316
            r += form.render()
317
            return r.getvalue()
318
        else:
319
            sffile.remove_self()
320
            sffile.remove_file()
321
            return redirect('.')
322

    
323
    def picked_file(self):
324
        get_response().set_content_type('application/json')
325
        sffile = StrongboxItem.get(get_request().form.get('val'))
326
        sffile.file.fp = file(sffile.file.filename)
327
        if sffile.user_id != get_request().user.id:
328
            raise errors.TraversalError()
329
        # XXX: this will copy the file, it would be quite nice if it was
330
        # possible to just make it a symlink to the sffile
331
        token = get_session().add_tempfile(sffile.file)
332
        return json.dumps({'token': token, 'filename': sffile.file.base_filename})
333

    
334
    def pick(self):
335
        if get_request().form.get('select') == 'true':
336
            return self.picked_file()
337
        r = TemplateIO(html=True)
338
        root_url = get_publisher().get_root_url()
339
        sffiles = StrongboxItem.get_with_indexed_value(
340
                        str('user_id'), str(get_request().user.id))
341
        r += htmltext('<h2>%s</h2>') % _('Pick a file')
342

    
343
        if not sffiles:
344
            r += htmltext('<p>')
345
            r += _('You do not have any file in your strongbox at the moment.')
346
            r += htmltext('</p>')
347
            r += htmltext('<div class="buttons">')
348
            r += htmltext('<a href="%smyspace/strongbox/" target="_blank">%s</a>') % (root_url,
349
                _('Open Strongbox Management'))
350
            r += htmltext('</div>')
351
        else:
352
            r += htmltext('<form id="strongbox-pick">')
353
            r += htmltext('<ul>')
354
            for sffile in sffiles:
355
                r += htmltext('<li><label><input type="radio" name="file" value="%s"/>%s</label>') % (
356
                                sffile.id, sffile.get_display_name())
357
                r += htmltext(' [<a href="%smyspace/strongbox/download?id=%s">%s</a>] ') % (
358
                                root_url, sffile.id, _('view'))
359
                r += htmltext('</li>')
360
            r += htmltext('</ul>')
361

    
362
            r += htmltext('<div class="buttons">')
363
            r += htmltext('<input name="cancel" type="button" value="%s"/>') % _('Cancel')
364
            r += ' '
365
            r += htmltext('<input name="pick" type="button" value="%s"/>') % _('Pick')
366
            r += htmltext('</div>')
367
            r += htmltext('</form>')
368
        return r.getvalue()
369

    
370

    
371
class JsonDirectory(Directory):
372
    '''Export of several lists in json, related to the current user or the
373
       SAMLv2 NameID we'd get in the URL'''
374

    
375
    _q_exports = ['forms']
376

    
377
    user = None
378

    
379
    def _q_traverse(self, path):
380
        self.user = get_user_from_api_query_string() or get_request().user
381
        if not self.user:
382
            raise errors.AccessUnauthorizedError()
383
        return Directory._q_traverse(self, path)
384

    
385
    def forms(self):
386
        formdefs = FormDef.select(order_by='name', ignore_errors=True)
387
        user_forms = []
388
        for formdef in formdefs:
389
            user_forms.extend(formdef.data_class().get_with_indexed_value(
390
                        'user_id', self.user.id))
391
            try:
392
                user_forms.extend(formdef.data_class().get_with_indexed_value(
393
                        'user_hash', self.user.hash))
394
            except AttributeError:
395
                pass
396
        user_forms.sort(lambda x,y: cmp(x.receipt_time, y.receipt_time))
397

    
398
        get_response().set_content_type('application/json')
399

    
400

    
401
        forms_output = []
402
        for form in user_forms:
403
            visible_status = form.get_visible_status(user=self.user)
404
            # skip drafts and hidden forms
405
            if not visible_status:
406
                continue
407
            name = form.formdef.name
408
            id = form.get_display_id()
409
            status = visible_status.name
410
            title = _('%(name)s #%(id)s (%(status)s)') % {
411
                    'name': name,
412
                    'id': id,
413
                    'status': status
414
            }
415
            url = form.get_url()
416
            d = { 'title': title, 'url': url }
417
            d.update(form.get_substitution_variables(minimal=True))
418
            forms_output.append(d)
419
        return json.dumps(forms_output)
420

    
421

    
422
class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
423
    _q_exports = ['', 'profile', 'new', 'password', 'remove', 'drafts', 'forms',
424
            'announces', 'strongbox', 'invoices', 'json']
425

    
426
    strongbox = StrongboxDirectory()
427
    invoices = MyInvoicesDirectory()
428
    json = JsonDirectory()
429

    
430
    def _q_traverse(self, path):
431
        get_response().filter['bigdiv'] = 'profile'
432
        get_response().breadcrumb.append(('myspace/', _('My Space')))
433

    
434
        # Migrate custom text settings
435
        texts_cfg = get_cfg('texts', {})
436
        if 'text-aq-top-of-profile' in texts_cfg and (
437
                        not 'text-top-of-profile' in texts_cfg):
438
            texts_cfg['text-top-of-profile'] = texts_cfg['text-aq-top-of-profile']
439
            del texts_cfg['text-aq-top-of-profile']
440
            get_publisher().write_cfg()
441

    
442
        return Directory._q_traverse(self, path)
443

    
444

    
445
    def _q_index(self):
446
        user = get_request().user
447
        if not user:
448
            raise errors.AccessUnauthorizedError()
449
        template.html_top(_('My Space'))
450
        r = TemplateIO(html=True)
451
        if user.anonymous:
452
            return redirect('new')
453

    
454
        user_formdef = user.get_formdef()
455

    
456
        user_forms = []
457
        if user:
458
            formdefs = FormDef.select(order_by='name', ignore_errors=True)
459
            user_forms = []
460
            for formdef in formdefs:
461
                user_forms.extend(formdef.data_class().get_with_indexed_value(
462
                            'user_id', user.id))
463
                try:
464
                    user_forms.extend(formdef.data_class().get_with_indexed_value(
465
                            'user_hash', user.hash))
466
                except AttributeError:
467
                    pass
468
            user_forms.sort(lambda x,y: cmp(x.receipt_time, y.receipt_time))
469

    
470
        profile_links = []
471
        if not get_cfg('sp', {}).get('idp-manage-user-attributes', False):
472
            if user_formdef:
473
                profile_links.append('<a href="#my-profile">%s</a>' % _('My Profile'))
474
        if user_forms:
475
            profile_links.append('<a href="#my-forms">%s</a>' % _('My Forms'))
476
        if get_cfg('misc', {}).get('aq-strongbox'):
477
            profile_links.append('<a href="strongbox/">%s</a>' % _('My Strongbox'))
478
        if is_payment_supported():
479
            profile_links.append('<a href="invoices/">%s</a>' % _('My Invoices'))
480

    
481
        root_url = get_publisher().get_root_url()
482
        if user.can_go_in_backoffice():
483
            profile_links.append('<a href="%sbackoffice/">%s</a>' % (root_url, _('Back office')))
484
        if user.is_admin:
485
            profile_links.append('<a href="%sadmin/">%s</a>' % (root_url, _('Admin')))
486

    
487
        if profile_links:
488
            r += htmltext('<p id="profile-links">')
489
            r += htmltext(' - '.join(profile_links))
490
            r += htmltext('</p>')
491

    
492
        if not get_cfg('sp', {}).get('idp-manage-user-attributes', False):
493
            if user_formdef:
494
                r += self._my_profile(user_formdef, user)
495

    
496
            r += self._index_buttons(user_formdef)
497

    
498
            try:
499
                x = PasswordAccount.get_on_index(get_request().user.id, str('user_id'))
500
            except KeyError:
501
                pass
502
            else:
503
                r += htmltext('<p>')
504
                r += _('You can delete your account freely from the services portal. '
505
                       'This action is irreversible; it will destruct your personal '
506
                       'datas and destruct the access to your request history.')
507
                r += htmltext(' <strong><a href="remove" rel="popup">%s</a></strong>.') % _('Delete My Account')
508
                r += htmltext('</p>')
509

    
510
        options = get_cfg('misc', {}).get('announce_themes')
511
        if options:
512
            try:
513
                subscription = AnnounceSubscription.get_on_index(
514
                        get_request().user.id, str('user_id'))
515
            except KeyError:
516
                pass
517
            else:
518
                r += htmltext('<p class="command"><a href="announces">%s</a></p>') % _(
519
                        'Edit my Subscription to Announces')
520

    
521
        if user_forms:
522
            r += htmltext('<h3 id="my-forms">%s</h3>') % _('My Forms')
523
            r += root.FormsRootDirectory().user_forms(user_forms)
524

    
525
        return r.getvalue()
526

    
527
    def _my_profile(self, user_formdef, user):
528
        r = TemplateIO(html=True)
529
        r += htmltext('<h3 id="my-profile">%s</h3>') % _('My Profile')
530

    
531
        r += TextsDirectory.get_html_text('top-of-profile')
532

    
533
        if user.form_data:
534
            r += htmltext('<ul>')
535
            for field in user_formdef.fields:
536
                if not hasattr(field, str('get_view_value')):
537
                    continue
538
                value = user.form_data.get(field.id)
539
                r += htmltext('<li>')
540
                r += field.label
541
                r += ' : '
542
                if value:
543
                    r += field.get_view_value(value)
544
                r += htmltext('</li>')
545
            r += htmltext('</ul>')
546
        else:
547
            r += htmltext('<p>%s</p>') % _('Empty profile')
548
        return r.getvalue()
549

    
550
    def _index_buttons(self, form_data):
551
        r = TemplateIO(html=True)
552
        passwords_cfg = get_cfg('passwords', {})
553
        ident_method = get_cfg('identification', {}).get('methods', ['idp'])[0]
554
        if get_session().lasso_session_dump:
555
            ident_method = 'idp'
556

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

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

    
563
        return r.getvalue()
564

    
565
    def profile(self):
566
        user = get_request().user
567
        if not user or user.anonymous:
568
            raise errors.AccessUnauthorizedError()
569

    
570
        form = Form(enctype = 'multipart/form-data')
571
        formdef = user.get_formdef()
572
        formdef.add_fields_to_form(form, form_data = user.form_data)
573

    
574
        form.add_submit('submit', _('Apply Changes'))
575
        form.add_submit('cancel', _('Cancel'))
576

    
577
        if form.get_submit() == 'cancel':
578
            return redirect('.')
579

    
580
        if form.is_submitted() and not form.has_errors():
581
            self.profile_submit(form, formdef)
582
            return redirect('.')
583

    
584
        template.html_top(_('Edit Profile'))
585
        return form.render()
586

    
587
    def profile_submit(self, form, formdef):
588
        user = get_request().user
589
        data = formdef.get_data(form)
590

    
591
        user.set_attributes_from_formdata(data)
592
        user.form_data = data
593

    
594
        user.store()
595

    
596
    def password(self):
597
        ident_method = get_cfg('identification', {}).get('methods', ['idp'])[0]
598
        if ident_method != 'password':
599
            raise errors.TraversalError()
600

    
601
        user = get_request().user
602
        if not user or user.anonymous:
603
            raise errors.AccessUnauthorizedError()
604

    
605
        form = Form(enctype = 'multipart/form-data')
606
        form.add(PasswordWidget, 'new_password', title = _('New Password'),
607
                required=True)
608
        form.add(PasswordWidget, 'new2_password', title = _('New Password (confirm)'),
609
                required=True) 
610

    
611
        form.add_submit('submit', _('Change Password'))
612
        form.add_submit('cancel', _('Cancel'))
613

    
614
        if form.get_submit() == 'cancel':
615
            return redirect('.')
616

    
617
        if form.is_submitted() and not form.has_errors():
618
            qommon.ident.password.check_password(form, 'new_password')
619
            new_password = form.get_widget('new_password').parse()
620
            new2_password = form.get_widget('new2_password').parse()
621
            if new_password != new2_password:
622
                form.set_error('new2_password', _('Passwords do not match'))
623

    
624
        if form.is_submitted() and not form.has_errors():
625
            self.submit_password(new_password)
626
            return redirect('.')
627

    
628
        template.html_top(_('Change Password'))
629
        return form.render()
630

    
631
    def submit_password(self, new_password):
632
        passwords_cfg = get_cfg('passwords', {})
633
        account = PasswordAccount.get(get_session().username)
634
        account.hashing_algo = passwords_cfg.get('hashing_algo')
635
        account.set_password(new_password)
636
        account.store()
637

    
638
    def new(self):
639
        if not get_request().user or not get_request().user.anonymous:
640
            raise errors.AccessUnauthorizedError()
641

    
642
        form = Form(enctype = 'multipart/form-data')
643
        formdef = get_publisher().user_class.get_formdef()
644
        if formdef:
645
            formdef.add_fields_to_form(form)
646
        else:
647
            get_logger().error('missing user formdef (in myspace/new)')
648

    
649
        form.add_submit('submit', _('Register'))
650

    
651
        if form.is_submitted() and not form.has_errors():
652
            user = get_publisher().user_class()
653
            data = formdef.get_data(form)
654
            user.set_attributes_from_formdata(data)
655
            user.name_identifiers = get_request().user.name_identifiers
656
            user.lasso_dump = get_request().user.lasso_dump
657
            user.set_attributes_from_formdata(data)
658
            user.form_data = data
659
            user.store()
660
            get_session().set_user(user.id)
661
            root_url = get_publisher().get_root_url()
662
            return redirect('%smyspace' % root_url)
663

    
664
        template.html_top(_('Welcome'))
665
        return form.render()
666

    
667

    
668
    def remove(self):
669
        user = get_request().user
670
        if not user or user.anonymous:
671
            raise errors.AccessUnauthorizedError()
672

    
673
        form = Form(enctype = 'multipart/form-data')
674
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
675
                        'Are you really sure you want to remove your account?')))
676
        form.add_submit('submit', _('Remove my account'))
677
        form.add_submit('cancel', _('Cancel'))
678

    
679
        if form.get_submit() == 'cancel':
680
            return redirect('.')
681

    
682
        if form.is_submitted() and not form.has_errors():
683
            user = get_request().user
684
            account = PasswordAccount.get_on_index(user.id, str('user_id'))
685
            get_session_manager().expire_session() 
686
            account.remove_self()
687
            return redirect(get_publisher().get_root_url())
688

    
689
        template.html_top(_('Removing Account'))
690
        return form.render()
691

    
692
    def announces(self):
693
        options = get_cfg('misc', {}).get('announce_themes')
694
        if not options:
695
            raise errors.TraversalError()
696
        user = get_request().user
697
        if not user or user.anonymous:
698
            raise errors.AccessUnauthorizedError()
699
        subscription = AnnounceSubscription.get_on_index(get_request().user.id, str('user_id'))
700
        if not subscription:
701
            raise errors.TraversalError()
702

    
703
        if subscription.enabled_themes is None:
704
            enabled_themes = options
705
        else:
706
            enabled_themes = subscription.enabled_themes
707

    
708
        form = Form(enctype = 'multipart/form-data')
709
        form.add(CheckboxesWidget, 'themes', title=_('Announce Themes'),
710
                value=enabled_themes, options=[(x, x, x) for x in options],
711
                inline=False, required=False)
712

    
713
        form.add_submit('submit', _('Apply Changes'))
714
        form.add_submit('cancel', _('Cancel'))
715

    
716
        if form.get_submit() == 'cancel':
717
            return redirect('.')
718

    
719
        if form.is_submitted() and not form.has_errors():
720
            chosen_themes = form.get_widget('themes').parse()
721
            if chosen_themes == options:
722
                chosen_themes = None
723
            subscription.enabled_themes = chosen_themes
724
            subscription.store()
725
            return redirect('.')
726

    
727
        template.html_top()
728
        get_response().breadcrumb.append(('announces', _('Announce Subscription')))
729
        return form.render()
730

    
731

    
732
TextsDirectory.register('aq-myspace-invoice',
733
        N_('Message on top of invoices page'),
734
        category = N_('Invoices'))
735

    
(20-20/27)