Project

General

Profile

Download (34.9 KB) Statistics
| Branch: | Tag: | Revision:

root / extra / modules / root.ptl @ e3bbea04

1
from quixote import get_publisher, get_response, get_request, redirect, get_session
2
from quixote.directory import Directory
3
from quixote.html import htmltext
4
from quixote.util import StaticDirectory
5

    
6
import os
7
import re
8
import urlparse
9

    
10
try:
11
    import lasso
12
except ImportError:
13
    pass
14

    
15
import wcs
16
import wcs.root
17
import qommon
18
from qommon import get_cfg, get_logger
19
from qommon import template
20
from qommon import errors
21
from qommon.form import *
22
from qommon import logger
23
from wcs.roles import logged_users_role
24

    
25
from qommon import emails
26
from qommon.sms import SMS
27
from wcs.categories import Category
28
from wcs.formdef import FormDef, status_labels
29
from qommon.tokens import Token
30
from qommon.admin.emails import EmailsDirectory
31
from qommon.admin.texts import TextsDirectory
32

    
33
from links import Link
34
from announces import Announce, AnnounceSubscription
35
from myspace import MyspaceDirectory
36
from agenda import AgendaDirectory
37
from events import Event, get_default_event_tags
38

    
39
import admin
40

    
41
import wcs.forms.root
42
from wcs.workflows import Workflow
43

    
44
from saml2 import Saml2Directory
45

    
46
OldRootDirectory = wcs.root.RootDirectory
47

    
48
import qommon.ident.password
49
import qommon.ident.idp
50

    
51

    
52
class FormsRootDirectory(wcs.forms.root.RootDirectory):
53

    
54
    def user_forms [html] (self, user_forms):
55
        base_url = get_publisher().get_root_url()
56

    
57
        draft = [x for x in user_forms if x.status == 'draft']
58
        if draft:
59
            '<h3 id="drafts">%s</h3>' % _('Your Current Drafts')
60
            '<ul>'
61
            for f in draft:
62
                '<li><a href="%s%s%s/%s">%s</a></li>' % (base_url, 
63
                    f.formdef.category.url_name,
64
                    f.formdef.url_name, f.id, f.formdef.name)
65
            '</ul>'
66

    
67

    
68
        # (COMPAT) without workflows
69
        current = [x for x in user_forms if x.status in ('new', 'accepted')]
70
        if current:
71
            '<h3 id="submitted">%s</h3>' % _('Your Current Forms')
72
            '<ul>'
73
            for f in current:
74
                if f.formdef.category_id:
75
                    category_url = f.formdef.category.url_name
76
                else:
77
                    category_url = '.'
78
                '<li><a href="%s%s/%s/%s/">%s</a>, %s, %s: %s</li>' % (
79
                    base_url,
80
                    category_url,
81
                    f.formdef.url_name, f.id, f.formdef.name, 
82
                    misc.localstrftime(f.receipt_time),
83
                    _('status'),
84
                    _(status_labels[f.status]) )
85
            '</ul>'
86
        done = [x for x in user_forms if x.status in ('rejected', 'finished')]
87
        if done:
88
            '<h3 id="done">%s</h3>' % _('Your Old Forms')
89
            '<ul>'
90
            for f in done:
91
                if f.formdef.category_id:
92
                    category_url = f.formdef.category.url_name
93
                else:
94
                    category_url = '.'
95
                '<li><a href="%s%s/%s/%s/">%s</a>, %s, %s: %s</li>' % (
96
                    base_url,
97
                    category_url,
98
                    f.formdef.url_name, f.id, f.formdef.name, 
99
                    misc.localstrftime(f.receipt_time),
100
                    _('status'),
101
                    _(status_labels[f.status]) )
102
            '</ul>'
103

    
104
        # with workflows
105
        workflows = Workflow.select(order_by = 'name')
106
        for workflow in workflows:
107
            # XXX: seperate endpoints from non-endpoints
108
            for status in workflow.possible_status:
109
                fms = [x for x in user_forms if x.status == 'wf-%s' % status.id and \
110
                        x.formdef.workflow_id == workflow.id]
111
                if not fms:
112
                    continue
113
                '<h3>%s</h3>' % _('Your forms with status "%s"') % status.name
114
                '<ul>'
115
                for f in fms:
116
                    if f.formdef.category_id:
117
                        category_url = f.formdef.category.url_name
118
                    else:
119
                        category_url = '.'
120
                    '<li><a href="%s%s/%s/%s/">%s</a>, %s</li>' % (
121
                            base_url,
122
                            category_url,
123
                            f.formdef.url_name, f.id, f.formdef.name, 
124
                            misc.localstrftime(f.receipt_time))
125
                '</ul>'
126

    
127

    
128
class AnnounceDirectory(Directory):
129
    _q_exports = ['', 'edit', 'delete', 'email']
130

    
131
    def __init__(self, announce):
132
        self.announce = announce
133

    
134
    def _q_index [html] (self):
135
        template.html_top(_('Announces to citizens'))
136

    
137
        if self.announce.publication_time:
138
            date_heading = '%s - ' % time.strftime(misc.date_format(), self.announce.publication_time)
139
        else:
140
            date_heading = ''
141

    
142
        '<h3>%s%s</h3>' % (date_heading, self.announce.title)
143

    
144
        '<p>'
145
        self.announce.text
146
        '</p>'
147

    
148
        '<p>'
149
        '<a href="../">%s</a>' % _('Back')
150
        '</p>'
151

    
152

    
153
class AnnouncesDirectory(Directory):
154
    _q_exports = ['', 'subscribe', 'email', 'atom', 'sms', 'emailconfirm',
155
            'email_unsubscribe', 'sms_unsubscribe', 'smsconfirm', 'rawlist']
156

    
157
    
158
    def _q_traverse(self, path):
159
        get_response().breadcrumb.append(('announces/', _('Announces')))
160
        return Directory._q_traverse(self, path)
161

    
162
    def _q_index [html] (self):
163
        template.html_top(_('Announces to citizens'))
164
        self.announces_list()
165
        '<ul id="announces-links">'
166
        '<li><a href="subscribe">%s</a></li>' % _('Receiving those Announces')
167
        '</ul>'
168

    
169
    def _get_announce_subscription(self):
170
        """ """
171
        sub = None
172
        if get_request().user:
173
            subs = AnnounceSubscription.select(lambda x: x.user_id == get_request().user.id)
174
            if subs:
175
                sub = subs[0]
176
        return sub
177

    
178
    def rawlist [html] (self):
179
        self.announces_list()
180
        get_response().filter = None
181

    
182
    def announces_list [html] (self):
183
        announces = Announce.get_published_announces()
184
        if not announces:
185
            raise errors.TraversalError()
186

    
187
        # XXX: will need pagination someday
188
        for item in announces:
189
            '<div class="announce-item">\n'
190
            '<h4>'
191
            if item.publication_time:
192
                time.strftime(misc.date_format(), item.publication_time)
193
                ' - '
194
            item.title
195
            '</h4>\n'
196
            '<p>\n'
197
            item.text
198
            '\n</p>\n'
199
            '</div>\n'
200

    
201

    
202
    def sms [html] (self):
203
        sms_mode = get_cfg('sms', {}).get('mode', 'none')
204

    
205
        if sms_mode == 'none':
206
            raise errors.TraversalError()
207

    
208
        get_response().breadcrumb.append(('sms', _('SMS')))
209
        template.html_top(_('Receiving announces by SMS'))
210

    
211
        if sms_mode == 'demo':
212
            TextsDirectory.get_html_text('aq-sms-demo')
213
        elif sms_mode == 'mobyt':
214
            form = Form(enctype='multipart/form-data')
215
            form.add(StringWidget, 'mobile', title = _('Mobile number 06XXXXXXXX'), size=12, required=True)
216
            form.add_submit('submit', _('Subscribe'))
217
            form.add_submit('cancel', _('Cancel'))
218

    
219
            if form.get_submit() == 'cancel':
220
                return redirect('subscribe')
221

    
222
            if form.is_submitted() and not form.has_errors():
223
                s = self.sms_submit(form)
224
                if s == False:
225
                    form.render()
226
                else:
227
                    return redirect("smsconfirm")
228
            else:
229
                form.render()
230

    
231
    def sms_submit(self, form):
232
        mobile = form.get_widget("mobile").parse()
233
        if len(mobile) != 10 or not re.search("06[0-9]{8}", mobile):
234
            form.set_error("mobile", "Phone number invalid !")
235
            return False
236
        mobile = re.sub("^0", "+33", mobile)
237
        sub = self._get_announce_subscription()
238
        if not sub:
239
            sub = AnnounceSubscription()
240
        if get_request().user:
241
            sub.user_id = get_request().user.id
242

    
243
        if mobile:
244
            sub.sms = mobile
245

    
246
        if not get_request().user:
247
            sub.enabled = False
248

    
249
        sub.store()
250

    
251
        # Asking sms confirmation
252
        token = Token(3 * 86400, 4)
253
        token.type = 'announces-subscription-confirmation'
254
        token.subscription_id = sub.id
255
        token.store()
256

    
257
        message = _("Announce subscription confirmation code : %s" % token.id)
258
        sms_cfg = get_cfg('sms', {})
259
        sms = SMS()
260
        try:
261
            sms.send([mobile], message, sms_cfg.get('sender', 'auquotidien'))
262
        except errors.SMSError, e:
263
            get_logger().error(e)
264
            form.set_error("mobile", _("Send SMS confirmation failed"))
265
            sub.remove("sms")
266
            return False
267

    
268
    def smsconfirm [html] (self):
269
        template.html_top(_('Receiving announces by SMS confirmation'))
270
        "<p>%s</p>" % _("You will receive a confirmation code by SMS.")
271
        form = Form(enctype='multipart/form-data')
272
        form.add(StringWidget, 'code', title = _('Confirmation code (4 characters)'), size=12, required=True)
273
        form.add_submit('submit', _('Subscribe'))
274
        form.add_submit('cancel', _('Cancel'))
275

    
276
        if form.is_submitted() and not form.has_errors():
277
            token = None
278
            id = form.get_widget("code").parse()
279
            try:
280
                token = Token.get(id)
281
            except KeyError:
282
                form.set_error("code",  _('Invalid confirmation code.'))
283

    
284
            if token and token.type != 'announces-subscription-confirmation':
285
                form.set_error("code",  _('Invalid confirmation code.'))
286
            else:
287
                sub = AnnounceSubscription.get(token.subscription_id)
288
                token.remove_self()
289
                sub.enabled_sms = True
290
                sub.store()
291
                return redirect('.')
292
            form.render()
293
        else:
294
            form.render()
295

    
296
    def sms_unsubscribe [html] (self):
297
        sub = self._get_announce_subscription()
298

    
299
        form = Form(enctype='multipart/form-data')
300
        if not sub:
301
            return redirect('..')
302

    
303
        form.add_submit('submit', _('Unsubscribe'))
304
        form.add_submit('cancel', _('Cancel'))
305

    
306
        if form.get_submit() == 'cancel':
307
            return redirect('..')
308

    
309
        get_response().breadcrumb.append(('sms', _('SMS Unsubscription')))
310
        template.html_top()
311

    
312
        if form.is_submitted() and not form.has_errors():
313
            if sub:
314
                sub.remove("sms")
315

    
316
            def sms_unsub_ok [html] ():
317
                root_url = get_publisher().get_root_url()
318
                '<p>'
319
                _('You have been unsubscribed from announces')
320
                '</p>'
321
                '<a href="%s">%s</a>' % (root_url, _('Back Home'))
322

    
323
            return sms_unsub_ok()
324

    
325
        else:
326
            '<p>'
327
            _('Do you want to stop receiving announces by sms ?')
328
            '</p>'
329
            form.render()
330

    
331

    
332
    def subscribe [html] (self):
333
        get_response().breadcrumb.append(('subscribe', _('Subscription')))
334
        template.html_top(_('Receiving Announces'))
335

    
336
        TextsDirectory.get_html_text('aq-announces-subscription')
337

    
338
        sub = self._get_announce_subscription()
339

    
340
        '<ul id="announce-modes">'
341
        if sub and sub.email:
342
            ' <li>'
343
            '<span id="par_mail">%s</span>' % _('Email (currently subscribed)')
344
            ' <a href="email_unsubscribe" rel="popup">%s</a></li>' % _('Unsubscribe')
345
        else:
346
            ' <li><a href="email" id="par_mail" rel="popup">%s</a></li>' % _('Email')
347
        if sub and sub.sms:
348
            ' <li>'
349
            if sub.enabled_sms:
350
                '<span id="par_sms">%s</span>' % _('SMS %s (currently subscribed)' % sub.sms)
351
            else:
352
                '<span id="par_sms">%s</span>' % _('SMS %s (currently not confirmed)' % sub.sms)
353
                ' <a href="smsconfirm" rel="popup">%s</a> ' % _('Confirmation')
354
            ' <a href="sms_unsubscribe" rel="popup">%s</a></li>' % _('Unsubscribe')
355
        elif get_cfg('sms', {}).get('mode', 'none') != 'none':
356
            ' <li><a href="sms" id="par_sms">%s</a></li>' % _('SMS')
357
        ' <li><a class="feed-link" href="atom" id="par_rss">%s</a>' % _('Feed')
358
        '</ul>'
359

    
360

    
361
    def email [html] (self):
362
        get_response().breadcrumb.append(('email', _('Email Subscription')))
363
        template.html_top(_('Receiving Announces by email'))
364

    
365
        form = Form(enctype='multipart/form-data')
366
        if get_request().user:
367
            if get_request().user.email:
368
                '<p>'
369
                _('You are logged in and your email is %s, ok to subscribe ?') % \
370
                    get_request().user.email
371
                '</p>'
372
                form.add_submit('submit', _('Subscribe'))
373
            else:
374
                '<p>'
375
                _("You are logged in but there is no email address in your profile.")
376
                '</p>'
377
                form.add(EmailWidget, 'email', title = _('Email'), required = True)
378
                form.add_submit('submit', _('Subscribe'))
379
                form.add_submit('submit-remember', _('Subscribe and add this email to my profile'))
380
        else:
381
            '<p>'
382
            _('FIXME will only be used for this purpose etc.')
383
            '</p>'
384
            form.add(EmailWidget, 'email', title = _('Email'), required = True)
385
            form.add_submit('submit', _('Subscribe'))
386
        
387
        form.add_submit('cancel', _('Cancel'))
388

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

    
392
        if form.is_submitted() and not form.has_errors():
393
            s = self.email_submit(form)
394
            if s is not False:
395
                return s
396
        else:
397
            form.render()
398

    
399
    def email_submit(self, form):
400
        sub = self._get_announce_subscription()
401
        if not sub:
402
            sub = AnnounceSubscription()
403

    
404
        if get_request().user:
405
            sub.user_id = get_request().user.id
406

    
407
        if form.get_widget('email'):
408
            sub.email = form.get_widget('email').parse()
409
        elif get_request().user.email:
410
            sub.email = get_request().user.email
411

    
412
        if not get_request().user:
413
            sub.enabled = False
414

    
415
        sub.store()
416

    
417
        if get_request().user:
418
            def email_submit_ok [html] ():
419
                root_url = get_publisher().get_root_url()
420
                '<p>'
421
                _('You have been subscribed to the announces.')
422
                '</p>'
423
                '<a href="%s">%s</a>' % (root_url, _('Back Home'))
424

    
425
            return email_submit_ok()
426

    
427
        # asking email confirmation before subscribing someone
428
        token = Token(3 * 86400)
429
        token.type = 'announces-subscription-confirmation'
430
        token.subscription_id = sub.id
431
        token.store()
432
        data = {
433
            'confirm_url': get_request().get_url() + 'confirm?t=%s&a=cfm' % token.id,
434
            'cancel_url': get_request().get_url() + 'confirm?t=%s&a=cxl' % token.id,
435
            'time': misc.localstrftime(time.localtime(token.expiration)),
436
        }
437

    
438
        emails.custom_ezt_email('announces-subscription-confirmation',
439
                data, sub.email, exclude_current_user = False)
440

    
441
        def email_submit_ok [html] ():
442
            root_url = get_publisher().get_root_url()
443
            '<p>'
444
            _('You have been sent an email for confirmation')
445
            '</p>'
446
            '<a href="%s">%s</a>' % (root_url, _('Back Home'))
447

    
448
        return email_submit_ok()
449

    
450
    def emailconfirm(self):
451
        tokenv = get_request().form.get('t')
452
        action = get_request().form.get('a')
453

    
454
        root_url = get_publisher().get_root_url()
455

    
456
        try:
457
            token = Token.get(tokenv)
458
        except KeyError:
459
            return template.error_page(
460
                    _('The token you submitted does not exist, has expired, or has been cancelled.'),
461
                    continue_to = (root_url, _('home page')))
462

    
463
        if token.type != 'announces-subscription-confirmation':
464
            return template.error_page(
465
                    _('The token you submitted is not appropriate for the requested task.'),
466
                    continue_to = (root_url, _('home page')))
467

    
468
        sub = AnnounceSubscription.get(token.subscription_id)
469

    
470
        if action == 'cxl':
471
            def cancel [html]():
472
                root_url = get_publisher().get_root_url()
473
                template.html_top(_('Email Subscription'))
474
                '<h1>%s</h1>' % _('Request Cancelled')
475
                '<p>%s</p>' % _('The request for subscription has been cancelled.')
476
                '<p>'
477
                htmltext(_('Continue to <a href="%s">home page</a>') % root_url)
478
                '</p>'
479
            token.remove_self()
480
            sub.remove_self()
481
            return cancel()
482

    
483
        if action == 'cfm':
484
            token.remove_self()
485
            sub.enabled = True
486
            sub.store()
487
            def sub [html] ():
488
                root_url = get_publisher().get_root_url()
489
                template.html_top(_('Email Subscription'))
490
                '<h1>%s</h1>' % _('Subscription Confirmation')
491
                '<p>%s</p>' % _('Your subscription to announces is now effective.')
492
                '<p>'
493
                htmltext(_('Continue to <a href="%s">home page</a>') % root_url)
494
                '</p>'
495
            return sub()
496

    
497

    
498
    def atom [plain] (self):
499
        response = get_response()
500
        response.set_content_type('application/atom+xml')
501

    
502
        from pyatom import pyatom
503
        xmldoc = pyatom.XMLDoc()
504
        feed = pyatom.Feed()
505
        xmldoc.root_element = feed
506
        feed.title = get_cfg('misc', {}).get('sitename', 'Au Quotidien')
507
        feed.id = get_request().get_url()
508

    
509
        author_email = get_cfg('emails', {}).get('reply_to')
510
        if not author_email:
511
            author_email = get_cfg('emails', {}).get('from')
512
        if author_email:
513
            feed.authors.append(pyatom.Author(author_email))
514

    
515
        announces = Announce.get_published_announces()
516

    
517
        if announces and announces[0].modification_time:
518
            feed.updated = misc.format_time(announces[0].modification_time,
519
                        '%(year)s-%(month)02d-%(day)02dT%(hour)02d:%(minute)02d:%(second)02dZ',
520
                        gmtime = True)
521
        feed.links.append(pyatom.Link(get_request().get_url(1) + '/'))
522

    
523
        for item in announces:
524
            entry = item.get_atom_entry()
525
            if entry:
526
                feed.entries.append(entry)
527

    
528
        str(feed)
529

    
530
    def email_unsubscribe [html] (self):
531
        sub = self._get_announce_subscription()
532

    
533
        form = Form(enctype='multipart/form-data')
534
        if not sub:
535
            form.add(EmailWidget, 'email', title = _('Email'), required = True)
536

    
537
        form.add_submit('submit', _('Unsubscribe'))
538
        form.add_submit('cancel', _('Cancel'))
539

    
540
        if form.get_submit() == 'cancel':
541
            return redirect('..')
542

    
543
        get_response().breadcrumb.append(('email', _('Email Unsubscription')))
544
        template.html_top()
545

    
546
        if form.is_submitted() and not form.has_errors():
547
            if sub:
548
                sub.remove("email")
549
            else:
550
                email = form.get_widget('email').parse()
551
                for s in AnnounceSubscription.select():
552
                    if s.email == email:
553
                        s.remove("email")
554

    
555
            def email_unsub_ok [html] ():
556
                root_url = get_publisher().get_root_url()
557
                '<p>'
558
                _('You have been unsubscribed from announces')
559
                '</p>'
560
                '<a href="%s">%s</a>' % (root_url, _('Back Home'))
561

    
562
            return email_unsub_ok()
563

    
564
        else:
565
            '<p>'
566
            _('Do you want to stop receiving announces by email?')
567
            '</p>'
568
            form.render()
569

    
570
    def _q_lookup(self, component):
571
        try:
572
            announce = Announce.get(component)
573
        except KeyError:
574
            raise errors.TraversalError()
575

    
576
        if announce.hidden:
577
            raise errors.TraversalError()
578

    
579
        get_response().breadcrumb.append((str(announce.id), announce.title))
580
        return AnnounceDirectory(announce)
581

    
582
OldRegisterDirectory = wcs.root.RegisterDirectory
583

    
584
class AlternateRegisterDirectory(OldRegisterDirectory):
585
    def _q_traverse(self, path):
586
        get_response().filter['bigdiv'] = 'new_member'
587
        return OldRegisterDirectory._q_traverse(self, path)
588

    
589
    def _q_index [html] (self):
590
        get_logger().info('register')
591
        ident_methods = get_cfg('identification', {}).get('methods', [])
592

    
593
        if len(ident_methods) == 0:
594
            idps = get_cfg('idp', {})
595
            if len(idps) == 0:
596
                return template.error_page(_('Authentication subsystem is not yet configured.'))
597
            ident_methods = ['idp'] # fallback to old behaviour; liberty.
598

    
599
        if len(ident_methods) == 1:
600
            method = ident_methods[0]
601
        else:
602
            method = 'password'
603
            return qommon.ident.register(method)
604

    
605
        if method == 'idp':
606
            root_url = get_publisher().get_root_url()
607
            return redirect('%slogin' % root_url)
608

    
609
        return OldRegisterDirectory._q_index(self)
610

    
611
OldLoginDirectory = wcs.root.LoginDirectory
612

    
613
class AlternateLoginDirectory(OldLoginDirectory):
614
    def _q_traverse(self, path):
615
        get_response().filter['bigdiv'] = 'member'
616
        return OldLoginDirectory._q_traverse(self, path)
617

    
618
    def _q_index [html] (self):
619
        get_logger().info('login')
620
        ident_methods = get_cfg('identification', {}).get('methods', [])
621

    
622
        if len(ident_methods) > 1 and 'idp' in ident_methods:
623
            # if there is more than one identification method, and there is a
624
            # possibility of SSO, if we got there as a consequence of an access
625
            # unauthorized url on admin/ or backoffice/, then idp auth method
626
            # is chosen forcefully.
627
            after_url = get_session().after_url
628
            if after_url:
629
                root_url = get_publisher().get_root_url()
630
                after_path = urlparse.urlparse(after_url)[2]
631
                after_path = after_path[len(root_url):]
632
                if after_path.startswith(str('admin')) or \
633
                        after_path.startswith(str('backoffice')):
634
                    ident_methods = ['idp']
635

    
636
        # don't display authentication system choice
637
        if len(ident_methods) == 1:
638
            method = ident_methods[0]
639
            try:
640
                return qommon.ident.login(method)
641
            except KeyError:
642
                get_logger().error('failed to login with method %s' % method)
643
                return errors.TraversalError()
644

    
645
        if sorted(ident_methods) == ['idp', 'password']:
646
            get_response().breadcrumb.append(('login', _('Login')))
647
            identities_cfg = get_cfg('identities', {})
648
            form = Form(enctype = 'multipart/form-data', id = 'login-form', use_tokens = False)
649
            if identities_cfg.get('email-as-username', False):
650
                form.add(StringWidget, 'username', title = _('Email'), size=25, required=True)
651
            else:
652
                form.add(StringWidget, 'username', title = _('Username'), size=25, required=True)
653
            form.add(PasswordWidget, 'password', title = _('Password'), size=25, required=True)
654
            form.add_submit('submit', _('Connect'))
655
            if form.is_submitted() and not form.has_errors():
656
                tmp = qommon.ident.password.MethodDirectory().login_submit(form)
657
                if not form.has_errors():
658
                    return tmp
659

    
660
            '<div id="login-password">'
661
            get_session().display_message()
662
            form.render()
663

    
664
            base_url = get_publisher().get_root_url()
665
            '<p><a href="%sident/password/forgotten">%s</a></p>' % (
666
                    base_url, _('Forgotten password ?'))
667

    
668
            '</div>'
669

    
670
            # XXX: this part only supports a single IdP
671
            '<div id="login-sso">'
672
            TextsDirectory.get_html_text('aq-sso-text')
673
            form = Form(enctype='multipart/form-data',
674
                    action = '%sident/idp/login' % base_url)
675
            form.add_hidden('method', 'idp')
676
            for kidp, idp in get_cfg('idp', {}).items():
677
                p = lasso.Provider(lasso.PROVIDER_ROLE_IDP,
678
                        misc.get_abs_path(idp['metadata']),
679
                        misc.get_abs_path(idp.get('publickey')), None)
680
                form.add_hidden('idp', p.providerId)
681
                break
682
            form.add_submit('submit', _('Connect'))
683
            
684
            form.render()
685
            '</div>'
686

    
687
            get_request().environ['REQUEST_METHOD'] = 'GET'
688

    
689
            """<script type="text/javascript">
690
              document.getElementById('login-form')['username'].focus();
691
            </script>"""
692

    
693
        else:
694
            return OldLoginDirectory._q_index(self)
695

    
696

    
697
class AlternateRootDirectory(OldRootDirectory):
698
    _q_exports = ['', 'admin', 'backoffice', 'forms', 'login', 'logout',
699
            'liberty', 'token', 'saml', 'register', 'ident', 'afterjobs',
700
            ('informations-editeur', 'informations_editeur'), 'index2',
701
            ('announces', 'announces_dir'),
702
            'accessibility', 'contact', 'help',
703
            'myspace', 'services', 'agenda',
704
            'themes']
705

    
706
    admin = admin.AdminRootDirectory()
707
    announces_dir = AnnouncesDirectory()
708
    register = AlternateRegisterDirectory()
709
    login = AlternateLoginDirectory()
710
    myspace = MyspaceDirectory()
711
    agenda = AgendaDirectory()
712
    saml = Saml2Directory()
713

    
714
    def _q_traverse(self, path):
715
        session = get_session()
716
        if session:
717
            get_request().user = session.get_user()
718
        else:
719
            get_request().user = None
720

    
721
        response = get_response()
722
        if not hasattr(response, 'filter'):
723
            response.filter = {}
724
        response.filter['gauche'] = self.box_side(path)
725
        response.breadcrumb = [ ('', _('Home')) ]
726

    
727
        if not self.admin:
728
            self.admin = get_publisher().admin_directory_class()
729

    
730
        if not self.backoffice:
731
            self.backoffice = get_publisher().backoffice_directory_class()
732

    
733
        try:
734
            return Directory._q_traverse(self, path)
735
        except errors.TraversalError, e:
736
            try:
737
                f = FormDef.get_by_urlname(path[0])
738
            except KeyError:
739
                pass
740
            else:
741
                base_url = get_publisher().get_root_url()
742
                uri_rest = get_request().environ.get('REQUEST_URI')
743
                if uri_rest.startswith(base_url):
744
                    uri_rest = uri_rest[len(base_url):]
745
                return redirect('%s%s/%s' % (base_url, f.category.url_name, uri_rest))
746

    
747
            raise e
748

    
749

    
750

    
751
    def _q_lookup(self, component):
752
        if component == 'qo':
753
            dirname = os.path.join(get_publisher().data_dir, 'qommon')
754
            return StaticDirectory(dirname, follow_symlinks = True)
755

    
756
        # is this a category ?
757
        try:
758
            category = Category.get_by_urlname(component)
759
        except KeyError:
760
            pass
761
        else:
762
            return FormsRootDirectory(category)
763

    
764
        return None
765

    
766

    
767
    def _q_index [html] (self):
768
        root_url = get_publisher().get_root_url()
769
        if get_request().user and get_request().user.anonymous and get_request().user.lasso_dump:
770
            return redirect('%smyspace/new' % root_url)
771

    
772
        if get_response().iframe_mode:
773
            # never display home page in an iframe
774
            return redirect('%sservices' % root_url)
775

    
776
        template.html_top()
777

    
778
        t = TextsDirectory.get_html_text('aq-home-page')
779
        if t:
780
            '<div id="home-page-intro">'
781
            t
782
            '</div>'
783

    
784

    
785
        '<div id="centre">'
786
        self.box_services()
787
        '</div>'
788
        '<div id="droite">'
789
        self.consultations()
790
        self.announces()
791
        if get_request().user and not get_request().user.anonymous:
792
            self.myspace_snippet()
793
        '</div>'
794

    
795
    def services [html] (self):
796
        template.html_top()
797
        get_response().filter['bigdiv'] = 'rub_service'
798
        self.box_services(level = 2)
799

    
800
    def box_services [html] (self, level = 3):
801
        ## Services
802
        '<div id="services">'
803
        if level == 2:
804
            '<h2>%s</h2>' % _('Services')
805
        else:
806
            '<h3>%s</h3>' % _('Services')
807

    
808
        if get_request().user and get_request().user.roles:
809
            accepted_roles = get_request().user.roles
810
        else:
811
            accepted_roles = []
812

    
813
        self.consultations_category = None
814
        '<ul>'
815
        cats = Category.select(order_by = 'name')
816
        Category.sort_by_position(cats)
817

    
818
        all_formdefs = FormDef.select(lambda x: not x.disabled, order_by = 'name')
819

    
820
        for category in cats:
821
            if category.url_name == 'consultations':
822
                self.consultations_category = category
823
                continue
824
            formdefs = [x for x in all_formdefs if x.category_id == category.id]
825

    
826
            for formdef in formdefs[:]:
827
                if not formdef.roles:
828
                    continue
829
                if not get_request().user:
830
                    formdefs.remove(formdef)
831
                    continue
832
                if logged_users_role().id in formdef.roles:
833
                    continue
834
                for q in accepted_roles:
835
                    if q in formdef.roles:
836
                        break
837
                else:
838
                    formdefs.remove(formdef)
839

    
840
            if not formdefs:
841
                continue
842

    
843
            '<li>'
844
            '<strong>'
845
            '<a href="%s/">' % category.url_name
846
            category.name
847
            '</a></strong>\n'
848
            '<ul>'
849
            for formdef in formdefs[:3]:
850
                '<li>'
851
                '<a href="%s/%s/">%s</a>' % (category.url_name, formdef.url_name, formdef.name)
852
                '</li>\n'
853
            if len(formdefs) > 3:
854
                '<li class="all-forms"><a href="%s/">%s</a></li>' % (category.url_name,
855
                        _('Access to all forms in this category'))
856
            '</ul>'
857
            '</li>\n'
858
        '</ul>'
859
        '</div>'
860

    
861
    def consultations [html] (self):
862
        if not self.consultations_category:
863
            return
864
        ## Consultations
865
        '<div id="consultations">'
866
        '<h3>%s</h3>' % _('Consultations')
867
        formdefs = FormDef.select(lambda x: (
868
                    x.category_id == self.consultations_category.id and not x.disabled),
869
                    order_by = 'name')
870
        '<ul>'
871
        for formdef in formdefs:
872
            '<li>'
873
            '<a href="%s/%s/">%s</a>' % (
874
                    self.consultations_category.url_name, formdef.url_name, formdef.name)
875
            '</li>'
876
        '</ul>'
877
        '</div>'
878

    
879
    def box_side [html] (self, path):
880
        '<div id="sidebox">'
881
        self.links()
882
        if Event.keys(): # if there are events, add a link to the agenda
883
            tags = get_cfg('misc', {}).get('event_tags')
884
            if not tags:
885
                tags = get_default_event_tags()
886
            root_url = get_publisher().get_root_url()
887
            '<h3 id="agenda-link"><a href="%sagenda/">%s</a></h3>' % (root_url, _('Agenda'))
888
            '<p class="tags">'
889
            for tag in tags:
890
                '<a href="%sagenda/tag/%s">%s</a> ' % (root_url, tag, tag)
891
            '</p>'
892
            if path and path[0] == 'agenda':
893
                self.agenda.display_remote_calendars()
894

    
895
        '</div>'
896

    
897

    
898
    def links [html] (self):
899
        links = Link.select()
900
        if not links:
901
            return
902

    
903
        Link.sort_by_position(links)
904

    
905
        '<div id="links">'
906
        '<h3>%s</h3>' % _('Useful links')
907
        '<ul>'
908
        for link in links:
909
            '<li><a href="%s">%s</a></li>' % (link.url, link.title)
910
        '</ul>'
911
        '</div>'
912

    
913

    
914
    def announces [html] (self):
915
        announces = Announce.get_published_announces()
916
        if not announces:
917
            return
918

    
919
        '<div id="announces">'
920
        '<h3>%s</h3>' % _('Announces to citizens')
921
        for item in announces[:3]:
922
            '<div class="announce-item">'
923
            '<h4>'
924
            if item.publication_time:
925
                time.strftime(misc.date_format(), item.publication_time)
926
                ' - '
927
            item.title
928
            '</h4>'
929
            '<p>'
930
            item.text
931
            '</p>'
932
            '</div>'
933

    
934
        '<ul id="announces-links">'
935
        '<li><a href="announces/subscribe">%s</a></li>' % _('Receiving those Announces')
936
        '<li><a href="announces/">%s</a></li>' % _('Previous Announces')
937
        '</ul>'
938
        '</div>'
939

    
940
    def myspace_snippet [html] (self):
941
        '<div id="myspace">'
942
        '<h3>%s</h3>' % _('My Space')
943
        '<ul>'
944
        '  <li><a href="myspace/">%s</a></li>' % _('Access to your personal space')
945
        '</ul>'
946
        '</div>'
947

    
948

    
949
    def page_view [html] (self, key, title, urlname = None):
950
        if not urlname:
951
            urlname = key[3:].replace(str('_'), str('-'))
952
        get_response().breadcrumb.append((urlname, title))
953
        template.html_top(title)
954
        '<div class="article">'
955
        htmltext(TextsDirectory.get_html_text(key))
956
        '</div>'
957

    
958
    def informations_editeur [html] (self):
959
        get_response().filter['bigdiv'] = 'info'
960
        return self.page_view('aq-editor-info', _('Editor Informations'),
961
                urlname = 'informations_editeur')
962

    
963
    def accessibility(self):
964
        get_response().filter['bigdiv'] = 'accessibility'
965
        return self.page_view('aq-accessibility', _('Accessibility Statement'))
966

    
967
    def contact(self):
968
        get_response().filter['bigdiv'] = 'contact'
969
        return self.page_view('aq-contact', _('Contact'))
970

    
971
    def help(self):
972
        get_response().filter['bigdiv'] = 'help'
973
        return self.page_view('aq-help', _('Help'))
974

    
975

    
976
from qommon.publisher import get_publisher_class
977
get_publisher_class().root_directory_class = AlternateRootDirectory
978
get_publisher_class().after_login_url = 'myspace/'
979

    
980

    
981
EmailsDirectory.register('announces-subscription-confirmation',
982
        N_('Confirmation of Announces Subscription'),
983
        N_('Available variables: change_url, cancel_url, time, sitename'),
984
        default_subject = N_('Announce Subscription Request'),
985
        default_body = N_("""\
986
You have (or someone impersonating you has) requested to subscribe to
987
announces from [sitename].  To confirm this request, visit the
988
following link:
989

    
990
[confirm_url]
991

    
992
If you are not the person who made this request, or you wish to cancel
993
this request, visit the following link:
994

    
995
[cancel_url]
996

    
997
If you do nothing, the request will lapse after 3 days (precisely on
998
[time]).
999
"""))
1000

    
1001

    
1002
TextsDirectory.register('aq-announces-subscription',
1003
        N_('Text on announces subscription page'),
1004
        default = N_('''\
1005
<p>
1006
FIXME
1007
'</p>'''))
1008

    
1009
TextsDirectory.register('aq-sms-demo',
1010
        N_('Text when subscribing to announces SMS and configured as demo'),
1011
        default = N_('''
1012
<p>
1013
Receiving announces by SMS is not possible in this demo
1014
</p>'''))
1015

    
1016
TextsDirectory.register('aq-editor-info', N_('Editor Informations'))
1017
TextsDirectory.register('aq-accessibility', N_('Accessibility Statement'))
1018
TextsDirectory.register('aq-contact', N_('Contact Information'))
1019
TextsDirectory.register('aq-help', N_('Help'))
1020
TextsDirectory.register('aq-sso-text',  N_('Connecting with Identity Provider'),
1021
        default = N_('''<h3>Connecting with Identity Provider</h3>
1022
<p>You can also use your identity provider to connect.
1023
</p>'''))
1024

    
1025
TextsDirectory.register('aq-home-page', N_('Home Page'), wysiwyg = True)
(13-13/15)