Projet

Général

Profil

Télécharger (50,6 ko) Statistiques
| Branche: | Tag: | Révision:

root / extra / modules / root.py @ 9c28d897

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

    
6
from wcs.qommon.misc import get_variadic_url, simplify
7

    
8
import os
9
import re
10
import string
11
import urlparse
12

    
13
try:
14
    import lasso
15
except ImportError:
16
    pass
17

    
18
import wcs
19
import wcs.root
20
import qommon
21
from qommon import get_cfg, get_logger
22
from qommon import template
23
from qommon import errors
24
from qommon.form import *
25
from qommon import logger
26
from wcs.roles import logged_users_role
27

    
28
from qommon import emails
29
from qommon.sms import SMS
30
from wcs.categories import Category
31
from wcs.formdef import FormDef
32
from wcs.data_sources import NamedDataSource
33
from qommon.tokens import Token
34
from qommon.admin.emails import EmailsDirectory
35
from qommon.admin.texts import TextsDirectory
36

    
37
from links import Link
38
from announces import Announce, AnnounceSubscription
39
from myspace import MyspaceDirectory
40
from agenda import AgendaDirectory
41
from events import Event, get_default_event_tags
42
from payments import PublicPaymentDirectory
43
from payments_ui import InvoicesDirectory
44

    
45
import admin
46

    
47
import wcs.forms.root
48
from wcs.workflows import Workflow
49
from wcs.forms.preview import PreviewDirectory
50

    
51
from saml2 import Saml2Directory
52

    
53
OldRootDirectory = wcs.root.RootDirectory
54

    
55
import qommon.ident.password
56
import qommon.ident.idp
57

    
58

    
59
def category_get_homepage_position(self):
60
    if hasattr(self, 'homepage_position') and self.homepage_position:
61
        return self.homepage_position
62
    if self.url_name == 'consultations':
63
        return '2nd'
64
    return '1st'
65
Category.get_homepage_position = category_get_homepage_position
66

    
67
def category_get_limit(self):
68
    if hasattr(self, 'limit') and self.limit is not None:
69
        return self.limit
70
    return 7
71
Category.get_limit = category_get_limit
72

    
73
Category.TEXT_ATTRIBUTES = ['name', 'url_name', 'description', 'homepage_position']
74
Category.INT_ATTRIBUTES = ['position', 'limit']
75

    
76

    
77
class FormsRootDirectory(wcs.forms.root.RootDirectory):
78

    
79
    def _q_index(self, *args):
80
        get_response().filter['is_index'] = True
81
        return wcs.forms.root.RootDirectory._q_index(self, *args)
82

    
83
    def user_forms(self, user_forms):
84
        r = TemplateIO(html=True)
85
        base_url = get_publisher().get_root_url()
86

    
87
        draft = [x for x in user_forms if x.is_draft()]
88
        if draft:
89
            r += htmltext('<h4 id="drafts">%s</h4>') % _('My Current Drafts')
90
            r += htmltext('<ul>')
91
            for f in draft:
92
                if f.formdef.category:
93
                    category_url = '%s' % f.formdef.category.url_name
94
                else:
95
                    category_url = '.'
96
                r += htmltext('<li><a href="%s%s/%s/%s">%s</a>, %s') % (base_url,
97
                    category_url,
98
                    f.formdef.url_name, f.id, f.formdef.name,
99
                    misc.localstrftime(f.receipt_time))
100
                r += htmltext(' (<a href="%s%s/%s/%s?remove-draft">%s</a>)') % (base_url,
101
                    category_url,
102
                    f.formdef.url_name, f.id, _('delete'))
103
                r += htmltext('</li>')
104
            r += htmltext('</ul>')
105

    
106
        forms_by_status_name = {}
107
        for f in user_forms:
108
            if f.is_draft():
109
                continue
110
            status = f.get_visible_status()
111
            if status:
112
                status_name = status.name
113
            else:
114
                status_name = None
115
            if status_name in forms_by_status_name:
116
                forms_by_status_name[status_name].append(f)
117
            else:
118
                forms_by_status_name[status_name] = [f]
119
        for status_name in forms_by_status_name:
120
            if status_name:
121
                r += htmltext('<h4>%s</h4>') % _('My forms with status "%s"') % status_name
122
            else:
123
                r += htmltext('<h4>%s</h4>') % _('My forms with an unknown status') % status_name
124
            r += htmltext('<ul>')
125
            forms_by_status_name[status_name].sort(lambda x,y: cmp(x.receipt_time, y.receipt_time))
126
            for f in forms_by_status_name[status_name]:
127
                if f.formdef.category_id:
128
                    category_url = f.formdef.category.url_name
129
                else:
130
                    category_url = '.'
131
                r += htmltext('<li><a href="%s%s/%s/%s/">%s</a>, %s</li>') % (
132
                        base_url,
133
                        category_url,
134
                        f.formdef.url_name, f.id, f.formdef.name, 
135
                        misc.localstrftime(f.receipt_time))
136
            r += htmltext('</ul>')
137
        return r.getvalue()
138

    
139

    
140
class AnnounceDirectory(Directory):
141
    _q_exports = ['', 'edit', 'delete', 'email']
142

    
143
    def __init__(self, announce):
144
        self.announce = announce
145

    
146
    def _q_index(self):
147
        template.html_top(_('Announces to citizens'))
148
        r = TemplateIO(html=True)
149

    
150
        if self.announce.publication_time:
151
            date_heading = '%s - ' % time.strftime(misc.date_format(), self.announce.publication_time)
152
        else:
153
            date_heading = ''
154

    
155
        r += htmltext('<h3>%s%s</h3>') % (date_heading, self.announce.title)
156

    
157
        r += htmltext('<p>')
158
        r += self.announce.text
159
        r += htmltext('</p>')
160

    
161
        r += htmltext('<p>')
162
        r += htmltext('<a href="../">%s</a>') % _('Back')
163
        r += htmltext('</p>')
164
        return r.getvalue()
165

    
166

    
167
class AnnouncesDirectory(Directory):
168
    _q_exports = ['', 'subscribe', 'email', 'atom', 'sms', 'emailconfirm',
169
            'email_unsubscribe', 'sms_unsubscribe', 'smsconfirm', 'rawlist']
170

    
171
    def _q_traverse(self, path):
172
        get_response().breadcrumb.append(('announces/', _('Announces')))
173
        return Directory._q_traverse(self, path)
174

    
175
    def _q_index(self):
176
        template.html_top(_('Announces to citizens'))
177
        r = TemplateIO(html=True)
178
        r += self.announces_list()
179
        r += htmltext('<ul id="announces-links">')
180
        r += htmltext('<li><a href="subscribe">%s</a></li>') % _('Receiving those Announces')
181
        r += htmltext('</ul>')
182
        return r.getvalue()
183

    
184
    def _get_announce_subscription(self):
185
        """ """
186
        sub = None
187
        if get_request().user:
188
            subs = AnnounceSubscription.select(lambda x: x.user_id == get_request().user.id)
189
            if subs:
190
                sub = subs[0]
191
        return sub
192

    
193
    def rawlist(self):
194
        get_response().filter = None
195
        return self.announces_list()
196

    
197
    def announces_list(self):
198
        announces = Announce.get_published_announces()
199
        if not announces:
200
            raise errors.TraversalError()
201

    
202
        # XXX: will need pagination someday
203
        r = TemplateIO(html=True)
204
        for item in announces:
205
            r += htmltext('<div class="announce-item">\n')
206
            r += htmltext('<h4>')
207
            if item.publication_time:
208
                r += time.strftime(misc.date_format(), item.publication_time)
209
                r += ' - '
210
            r += item.title
211
            r += htmltext('</h4>\n')
212
            r += htmltext('<p>\n')
213
            r += item.text
214
            r += htmltext('\n</p>\n')
215
            r += htmltext('</div>\n')
216
        return r.getvalue()
217

    
218

    
219
    def sms(self):
220
        sms_mode = get_cfg('sms', {}).get('mode', 'none')
221

    
222
        if sms_mode == 'none':
223
            raise errors.TraversalError()
224

    
225
        get_response().breadcrumb.append(('sms', _('SMS')))
226
        template.html_top(_('Receiving announces by SMS'))
227
        r = TemplateIO(html=True)
228

    
229
        if sms_mode == 'demo':
230
            r += TextsDirectory.get_html_text('aq-sms-demo')
231
        else:
232
            announces_cfg = get_cfg('announces',{})
233
            mobile_mask = announces_cfg.get('mobile_mask')
234
            if mobile_mask:
235
                mobile_mask = ' (' + mobile_mask + ')'
236
            else:
237
                mobile_mask = ''
238
            form = Form(enctype='multipart/form-data')
239
            form.add(StringWidget, 'mobile', title = _('Mobile number %s') % mobile_mask, size=12, required=True)
240
            form.add_submit('submit', _('Subscribe'))
241
            form.add_submit('cancel', _('Cancel'))
242

    
243
            if form.get_submit() == 'cancel':
244
                return redirect('subscribe')
245

    
246
            if form.is_submitted() and not form.has_errors():
247
                s = self.sms_submit(form)
248
                if s == False:
249
                    r += form.render()
250
                else:
251
                    return redirect("smsconfirm")
252
            else:
253
                r += form.render()
254
        return r.getvalue()
255

    
256
    def sms_submit(self, form):
257
        mobile = form.get_widget("mobile").parse()
258
        # clean the string, remove any extra character
259
        mobile = re.sub('[^0-9+]','',mobile)
260
        # if a mask was set, validate
261
        announces_cfg = get_cfg('announces',{})
262
        mobile_mask = announces_cfg.get('mobile_mask')
263
        if mobile_mask:
264
            mobile_regexp = re.sub('X','[0-9]', mobile_mask) + '$'
265
            if not re.match(mobile_regexp, mobile):
266
                form.set_error("mobile", _("Phone number invalid ! It must match ") + mobile_mask)
267
                return False
268
        if mobile.startswith('00'):
269
            mobile = '+' + mobile[2:]
270
        else:
271
            # Default to france international prefix
272
            if not mobile.startswith('+'):
273
                mobile = re.sub("^0", "+33", mobile)
274
        sub = self._get_announce_subscription()
275
        if not sub:
276
            sub = AnnounceSubscription()
277
        if get_request().user:
278
            sub.user_id = get_request().user.id
279

    
280
        if mobile:
281
            sub.sms = mobile
282

    
283
        if not get_request().user:
284
            sub.enabled = False
285

    
286
        sub.store()
287

    
288
        # Asking sms confirmation
289
        token = Token(3 * 86400, 4, string.digits)
290
        token.type = 'announces-subscription-confirmation'
291
        token.subscription_id = sub.id
292
        token.store()
293

    
294
        message = _("Confirmation code : %s") % str(token.id)
295
        sms_cfg = get_cfg('sms', {})
296
        sender = sms_cfg.get('sender', 'AuQuotidien')[:11]
297
        mode = sms_cfg.get('mode', 'none')
298
        sms = SMS.get_sms_class(mode)
299
        try:
300
            sms.send(sender, [mobile], message)
301
        except errors.SMSError, e:
302
            get_logger().error(e)
303
            form.set_error("mobile", _("Send SMS confirmation failed"))
304
            sub.remove("sms")
305
            return False
306

    
307
    def smsconfirm(self):
308
        template.html_top(_('Receiving announces by SMS confirmation'))
309
        r = TemplateIO(html=True)
310
        r += htmltext("<p>%s</p>") % _("You will receive a confirmation code by SMS.")
311
        form = Form(enctype='multipart/form-data')
312
        form.add(StringWidget, 'code', title = _('Confirmation code (4 characters)'), size=12, required=True)
313
        form.add_submit('submit', _('Subscribe'))
314
        form.add_submit('cancel', _('Cancel'))
315

    
316
        if form.get_submit() == 'cancel':
317
            return redirect('..')
318

    
319
        if form.is_submitted() and not form.has_errors():
320
            token = None
321
            id = form.get_widget("code").parse()
322
            try:
323
                token = Token.get(id)
324
            except KeyError:
325
                form.set_error("code",  _('Invalid confirmation code.'))
326
            else:
327
                if token.type != 'announces-subscription-confirmation':
328
                    form.set_error("code",  _('Invalid confirmation code.'))
329
                else:
330
                    sub = AnnounceSubscription.get(token.subscription_id)
331
                    token.remove_self()
332
                    sub.enabled_sms = True
333
                    sub.store()
334
                    return redirect('.')
335
            r += form.render()
336
        else:
337
            r += form.render()
338

    
339
        return r.getvalue()
340

    
341
    def sms_unsubscribe(self):
342
        sub = self._get_announce_subscription()
343

    
344
        form = Form(enctype='multipart/form-data')
345
        if not sub:
346
            return redirect('..')
347

    
348
        form.add_submit('submit', _('Unsubscribe'))
349
        form.add_submit('cancel', _('Cancel'))
350

    
351
        if form.get_submit() == 'cancel':
352
            return redirect('..')
353

    
354
        get_response().breadcrumb.append(('sms', _('SMS Unsubscription')))
355
        template.html_top()
356
        r = TemplateIO(html=True)
357

    
358
        if form.is_submitted() and not form.has_errors():
359
            if sub:
360
                sub.remove("sms")
361

    
362
            root_url = get_publisher().get_root_url()
363
            r += htmltext('<p>')
364
            r += _('You have been unsubscribed from announces')
365
            r += htmltext('</p>')
366
            if not get_response().iframe_mode:
367
                r += htmltext('<a href="%s">%s</a>') % (root_url, _('Back Home'))
368
        else:
369
            r += htmltext('<p>')
370
            r += _('Do you want to stop receiving announces by sms ?')
371
            r += htmltext('</p>')
372
            r += form.render()
373

    
374
        return r.getvalue()
375

    
376

    
377
    def subscribe(self):
378
        get_response().breadcrumb.append(('subscribe', _('Subscription')))
379
        template.html_top(_('Receiving Announces'))
380
        r = TemplateIO(html=True)
381

    
382
        r += TextsDirectory.get_html_text('aq-announces-subscription')
383

    
384
        sub = self._get_announce_subscription()
385

    
386
        r += htmltext('<ul id="announce-modes">')
387
        if sub and sub.email:
388
            r += htmltext(' <li>')
389
            r += htmltext('<span id="par_mail">%s</span>') % _('Email (currently subscribed)')
390
            r += htmltext(' <a href="email_unsubscribe" rel="popup">%s</a></li>') % _('Unsubscribe')
391
        else:
392
            r += htmltext(' <li><a href="email" id="par_mail" rel="popup">%s</a></li>') % _('Email')
393
        if sub and sub.sms:
394
            r += htmltext(' <li>')
395
            if sub.enabled_sms:
396
                r += htmltext('<span id="par_sms">%s</span>') % _('SMS %s (currently subscribed)') % sub.sms
397
            else:
398
                r += htmltext('<span id="par_sms">%s</span>') % _('SMS %s (currently not confirmed)') % sub.sms
399
                r += htmltext(' <a href="smsconfirm" rel="popup">%s</a> ') % _('Confirmation')
400
            r += htmltext(' <a href="sms_unsubscribe" rel="popup">%s</a></li>') % _('Unsubscribe')
401
        elif get_cfg('sms', {}).get('mode', 'none') != 'none':
402
            r += htmltext(' <li><a href="sms" id="par_sms">%s</a></li>') % _('SMS')
403
        r += htmltext(' <li><a class="feed-link" href="atom" id="par_rss">%s</a>') % _('Feed')
404
        r += htmltext('</ul>')
405
        return r.getvalue()
406

    
407
    def email(self):
408
        get_response().breadcrumb.append(('email', _('Email Subscription')))
409
        template.html_top(_('Receiving Announces by email'))
410
        r = TemplateIO(html=True)
411

    
412
        form = Form(enctype='multipart/form-data')
413
        if get_request().user:
414
            if get_request().user.email:
415
                r += htmltext('<p>')
416
                r += _('You are logged in and your email is %s, ok to subscribe ?') % \
417
                        get_request().user.email
418
                r += htmltext('</p>')
419
                form.add_submit('submit', _('Subscribe'))
420
            else:
421
                r += htmltext('<p>')
422
                r += _("You are logged in but there is no email address in your profile.")
423
                r += htmltext('</p>')
424
                form.add(EmailWidget, 'email', title = _('Email'), required = True)
425
                form.add_submit('submit', _('Subscribe'))
426
                form.add_submit('submit-remember', _('Subscribe and add this email to my profile'))
427
        else:
428
            r += htmltext('<p>')
429
            r += _('FIXME will only be used for this purpose etc.')
430
            r += htmltext('</p>')
431
            form.add(EmailWidget, 'email', title = _('Email'), required = True)
432
            form.add_submit('submit', _('Subscribe'))
433

    
434
        form.add_submit('cancel', _('Cancel'))
435

    
436
        if form.get_submit() == 'cancel':
437
            return redirect('subscribe')
438

    
439
        if form.is_submitted() and not form.has_errors():
440
            s = self.email_submit(form)
441
            if s is not False:
442
                return s
443
        else:
444
            r += form.render()
445

    
446
        return r.getvalue()
447

    
448
    def email_submit(self, form):
449
        sub = self._get_announce_subscription()
450
        if not sub:
451
            sub = AnnounceSubscription()
452

    
453
        if get_request().user:
454
            sub.user_id = get_request().user.id
455

    
456
        if form.get_widget('email'):
457
            sub.email = form.get_widget('email').parse()
458
        elif get_request().user.email:
459
            sub.email = get_request().user.email
460

    
461
        if not get_request().user:
462
            sub.enabled = False
463

    
464
        sub.store()
465

    
466
        if get_request().user:
467
            r = TemplateIO(html=True)
468
            root_url = get_publisher().get_root_url()
469
            r += htmltext('<p>')
470
            r += _('You have been subscribed to the announces.')
471
            r += htmltext('</p>')
472
            if not get_response().iframe_mode:
473
                r += htmltext('<a href="%s">%s</a>') % (root_url, _('Back Home'))
474
            return r.getvalue()
475

    
476
        # asking email confirmation before subscribing someone
477
        token = Token(3 * 86400)
478
        token.type = 'announces-subscription-confirmation'
479
        token.subscription_id = sub.id
480
        token.store()
481
        data = {
482
            'confirm_url': get_request().get_url() + 'confirm?t=%s&a=cfm' % token.id,
483
            'cancel_url': get_request().get_url() + 'confirm?t=%s&a=cxl' % token.id,
484
            'time': misc.localstrftime(time.localtime(token.expiration)),
485
        }
486

    
487
        emails.custom_ezt_email('announces-subscription-confirmation',
488
                data, sub.email, exclude_current_user = False)
489

    
490
        r = TemplateIO(html=True)
491
        root_url = get_publisher().get_root_url()
492
        r += htmltext('<p>')
493
        r += _('You have been sent an email for confirmation')
494
        r += htmltext('</p>')
495
        if not get_response().iframe_mode:
496
            r += htmltext('<a href="%s">%s</a>') % (root_url, _('Back Home'))
497
        return r.getvalue()
498

    
499
    def emailconfirm(self):
500
        tokenv = get_request().form.get('t')
501
        action = get_request().form.get('a')
502

    
503
        root_url = get_publisher().get_root_url()
504

    
505
        try:
506
            token = Token.get(tokenv)
507
        except KeyError:
508
            return template.error_page(
509
                    _('The token you submitted does not exist, has expired, or has been cancelled.'),
510
                    continue_to = (root_url, _('home page')))
511

    
512
        if token.type != 'announces-subscription-confirmation':
513
            return template.error_page(
514
                    _('The token you submitted is not appropriate for the requested task.'),
515
                    continue_to = (root_url, _('home page')))
516

    
517
        sub = AnnounceSubscription.get(token.subscription_id)
518

    
519
        if action == 'cxl':
520
            r = TemplateIO(html=True)
521
            root_url = get_publisher().get_root_url()
522
            template.html_top(_('Email Subscription'))
523
            r += htmltext('<h1>%s</h1>') % _('Request Cancelled')
524
            r += htmltext('<p>%s</p>') % _('The request for subscription has been cancelled.')
525
            r += htmltext('<p>')
526
            r += htmltext(_('Continue to <a href="%s">home page</a>') % root_url)
527
            r += htmltext('</p>')
528
            token.remove_self()
529
            sub.remove_self()
530
            return r.getvalue()
531

    
532
        if action == 'cfm':
533
            token.remove_self()
534
            sub.enabled = True
535
            sub.store()
536
            r = TemplateIO(html=True)
537
            root_url = get_publisher().get_root_url()
538
            template.html_top(_('Email Subscription'))
539
            r += htmltext('<h1>%s</h1>') % _('Subscription Confirmation')
540
            r += htmltext('<p>%s</p>') % _('Your subscription to announces is now effective.')
541
            r += htmltext('<p>')
542
            r += htmltext(_('Continue to <a href="%s">home page</a>') % root_url)
543
            r += htmltext('</p>')
544
            return r.getvalue()
545

    
546
    def atom(self):
547
        response = get_response()
548
        response.set_content_type('application/atom+xml')
549

    
550
        from pyatom import pyatom
551
        xmldoc = pyatom.XMLDoc()
552
        feed = pyatom.Feed()
553
        xmldoc.root_element = feed
554
        feed.title = get_cfg('misc', {}).get('sitename') or 'Publik'
555
        feed.id = get_request().get_url()
556

    
557
        author_email = get_cfg('emails', {}).get('reply_to')
558
        if not author_email:
559
            author_email = get_cfg('emails', {}).get('from')
560
        if author_email:
561
            feed.authors.append(pyatom.Author(author_email))
562

    
563
        announces = Announce.get_published_announces()
564

    
565
        if announces and announces[0].modification_time:
566
            feed.updated = misc.format_time(announces[0].modification_time,
567
                        '%(year)s-%(month)02d-%(day)02dT%(hour)02d:%(minute)02d:%(second)02dZ',
568
                        gmtime = True)
569
        feed.links.append(pyatom.Link(get_request().get_url(1) + '/'))
570

    
571
        for item in announces:
572
            entry = item.get_atom_entry()
573
            if entry:
574
                feed.entries.append(entry)
575

    
576
        return str(feed)
577

    
578
    def email_unsubscribe(self):
579
        sub = self._get_announce_subscription()
580

    
581
        form = Form(enctype='multipart/form-data')
582
        if not sub:
583
            form.add(EmailWidget, 'email', title = _('Email'), required = True)
584

    
585
        form.add_submit('submit', _('Unsubscribe'))
586
        form.add_submit('cancel', _('Cancel'))
587

    
588
        if form.get_submit() == 'cancel':
589
            return redirect('..')
590

    
591
        get_response().breadcrumb.append(('email', _('Email Unsubscription')))
592
        template.html_top()
593
        r = TemplateIO(html=True)
594

    
595
        if form.is_submitted() and not form.has_errors():
596
            if sub:
597
                sub.remove("email")
598
            else:
599
                email = form.get_widget('email').parse()
600
                for s in AnnounceSubscription.select():
601
                    if s.email == email:
602
                        s.remove("email")
603

    
604
            root_url = get_publisher().get_root_url()
605
            r += htmltext('<p>')
606
            r += _('You have been unsubscribed from announces')
607
            r += htmltext('</p>')
608
            if not get_response().iframe_mode:
609
                r += htmltext('<a href="%s">%s</a>') % (root_url, _('Back Home'))
610

    
611
        else:
612
            r += htmltext('<p>')
613
            r += _('Do you want to stop receiving announces by email?')
614
            r += htmltext('</p>')
615
            r += form.render()
616

    
617
        return r.getvalue()
618

    
619
    def _q_lookup(self, component):
620
        try:
621
            announce = Announce.get(component)
622
        except KeyError:
623
            raise errors.TraversalError()
624

    
625
        if announce.hidden:
626
            raise errors.TraversalError()
627

    
628
        get_response().breadcrumb.append((str(announce.id), announce.title))
629
        return AnnounceDirectory(announce)
630

    
631
OldRegisterDirectory = wcs.root.RegisterDirectory
632

    
633
class AlternateRegisterDirectory(OldRegisterDirectory):
634
    def _q_traverse(self, path):
635
        get_response().filter['bigdiv'] = 'new_member'
636
        return OldRegisterDirectory._q_traverse(self, path)
637

    
638
    def _q_index(self):
639
        get_logger().info('register')
640
        ident_methods = get_cfg('identification', {}).get('methods', [])
641

    
642
        if len(ident_methods) == 0:
643
            idps = get_cfg('idp', {})
644
            if len(idps) == 0:
645
                return template.error_page(_('Authentication subsystem is not yet configured.'))
646
            ident_methods = ['idp'] # fallback to old behaviour; saml.
647

    
648
        if len(ident_methods) == 1:
649
            method = ident_methods[0]
650
        else:
651
            method = 'password'
652

    
653
        return qommon.ident.register(method)
654

    
655
OldLoginDirectory = wcs.root.LoginDirectory
656

    
657
class AlternateLoginDirectory(OldLoginDirectory):
658
    def _q_traverse(self, path):
659
        get_response().filter['bigdiv'] = 'member'
660
        return OldLoginDirectory._q_traverse(self, path)
661

    
662
    def _q_index(self):
663
        get_logger().info('login')
664
        ident_methods = get_cfg('identification', {}).get('methods', [])
665

    
666
        if get_request().form.get('ReturnUrl'):
667
            get_request().form['next'] = get_request().form.pop('ReturnUrl')
668

    
669
        if 'IsPassive' in get_request().form and 'idp' in ident_methods:
670
            # if isPassive is given in query parameters, we restrict ourselves
671
            # to saml login.
672
            ident_methods = ['idp']
673

    
674
        if len(ident_methods) > 1 and 'idp' in ident_methods:
675
            # if there is more than one identification method, and there is a
676
            # possibility of SSO, if we got there as a consequence of an access
677
            # unauthorized url on admin/ or backoffice/, then idp auth method
678
            # is chosen forcefully.
679
            after_url = get_request().form.get('next')
680
            if after_url:
681
                root_url = get_publisher().get_root_url()
682
                after_path = urlparse.urlparse(after_url)[2]
683
                after_path = after_path[len(root_url):]
684
                if after_path.startswith(str('admin')) or \
685
                        after_path.startswith(str('backoffice')):
686
                    ident_methods = ['idp']
687

    
688
        # don't display authentication system choice
689
        if len(ident_methods) == 1:
690
            method = ident_methods[0]
691
            try:
692
                return qommon.ident.login(method)
693
            except KeyError:
694
                get_logger().error('failed to login with method %s' % method)
695
                return errors.TraversalError()
696

    
697
        if sorted(ident_methods) == ['idp', 'password']:
698
            r = TemplateIO(html=True)
699
            get_response().breadcrumb.append(('login', _('Login')))
700
            identities_cfg = get_cfg('identities', {})
701
            form = Form(enctype = 'multipart/form-data', id = 'login-form', use_tokens = False)
702
            if identities_cfg.get('email-as-username', False):
703
                form.add(StringWidget, 'username', title = _('Email'), size=25, required=True)
704
            else:
705
                form.add(StringWidget, 'username', title = _('Username'), size=25, required=True)
706
            form.add(PasswordWidget, 'password', title = _('Password'), size=25, required=True)
707
            form.add_submit('submit', _('Connect'))
708
            if form.is_submitted() and not form.has_errors():
709
                tmp = qommon.ident.password.MethodDirectory().login_submit(form)
710
                if not form.has_errors():
711
                    return tmp
712

    
713
            r += htmltext('<div id="login-password">')
714
            r += get_session().display_message()
715
            r += form.render()
716

    
717
            base_url = get_publisher().get_root_url()
718
            r += htmltext('<p><a href="%sident/password/forgotten">%s</a></p>') % (
719
                    base_url, _('Forgotten password ?'))
720

    
721
            r += htmltext('</div>')
722

    
723
            # XXX: this part only supports a single IdP
724
            r += htmltext('<div id="login-sso">')
725
            r += TextsDirectory.get_html_text('aq-sso-text')
726
            form = Form(enctype='multipart/form-data',
727
                    action = '%sident/idp/login' % base_url)
728
            form.add_hidden('method', 'idp')
729
            for kidp, idp in get_cfg('idp', {}).items():
730
                p = lasso.Provider(lasso.PROVIDER_ROLE_IDP,
731
                        misc.get_abs_path(idp['metadata']),
732
                        misc.get_abs_path(idp.get('publickey')), None)
733
                form.add_hidden('idp', p.providerId)
734
                break
735
            form.add_submit('submit', _('Connect'))
736

    
737
            r += form.render()
738
            r += htmltext('</div>')
739

    
740
            get_request().environ['REQUEST_METHOD'] = 'GET'
741

    
742
            r += htmltext("""<script type="text/javascript">
743
              document.getElementById('login-form')['username'].focus();
744
            </script>""")
745
            return r.getvalue()
746
        else:
747
            return OldLoginDirectory._q_index(self)
748

    
749

    
750
OldIdentDirectory = wcs.root.IdentDirectory
751
class AlternateIdentDirectory(OldIdentDirectory):
752
    def _q_traverse(self, path):
753
        get_response().filter['bigdiv'] = 'member'
754
        return OldIdentDirectory._q_traverse(self, path)
755

    
756

    
757
class AlternatePreviewDirectory(PreviewDirectory):
758
    def _q_traverse(self, path):
759
        get_response().filter['bigdiv'] = 'rub_service'
760
        return super(AlternatePreviewDirectory, self)._q_traverse(path)
761

    
762

    
763
class AlternateRootDirectory(OldRootDirectory):
764
    _q_exports = ['', 'admin', 'backoffice', 'forms', 'login', 'logout',
765
            'token', 'saml', 'register', 'ident', 'afterjobs',
766
            ('informations-editeur', 'informations_editeur'),
767
            ('announces', 'announces_dir'),
768
            'accessibility', 'contact', 'help',
769
            'myspace', 'services', 'agenda', 'categories', 'user',
770
            ('tmp-upload', 'tmp_upload'), 'json', '__version__',
771
            'themes', 'pages', 'payment', 'invoices', 'accesscode', 'roles',
772
            'api', 'code', 'fargo', 'tryauth', 'auth', 'preview',
773
            ('reload-top', 'reload_top')]
774

    
775
    admin = admin.AdminRootDirectory()
776
    announces_dir = AnnouncesDirectory()
777
    register = AlternateRegisterDirectory()
778
    login = AlternateLoginDirectory()
779
    ident = AlternateIdentDirectory()
780
    myspace = MyspaceDirectory()
781
    agenda = AgendaDirectory()
782
    saml = Saml2Directory()
783
    payment = PublicPaymentDirectory()
784
    invoices = InvoicesDirectory()
785
    code = wcs.forms.root.TrackingCodesDirectory()
786
    preview = AlternatePreviewDirectory()
787

    
788
    def get_substitution_variables(self):
789
        d = {}
790
        def print_links(fd):
791
            fd.write(str(self.links()))
792
        d['links'] = print_links
793
        return d
794

    
795
    def _q_traverse(self, path):
796
        get_publisher().substitutions.feed(get_session())
797
        get_publisher().substitutions.feed(get_request().user)
798
        get_publisher().substitutions.feed(NamedDataSource)
799

    
800
        # set app_label to Publik if none was specified (this is used in
801
        # backoffice header top line)
802
        if not get_publisher().get_site_option('app_label'):
803
            if not get_publisher().site_options.has_section('options'):
804
                get_publisher().site_options.add_section('options')
805
            get_publisher().site_options.set('options', 'app_label', 'Publik')
806

    
807
        response = get_response()
808
        if not hasattr(response, 'filter'):
809
            response.filter = {}
810

    
811
        response.filter['auquotidien'] = True
812
        response.filter['gauche'] = self.box_side(path)
813
        response.filter['keywords'] = template.get_current_theme().get('keywords')
814
        get_publisher().substitutions.feed(self)
815

    
816
        response.breadcrumb = [ ('', _('Home')) ]
817

    
818
        if not self.admin:
819
            self.admin = get_publisher().admin_directory_class()
820

    
821
        if not self.backoffice:
822
            self.backoffice = get_publisher().backoffice_directory_class()
823

    
824
        try:
825
            return Directory._q_traverse(self, path)
826
        except errors.TraversalError, e:
827
            try:
828
                f = FormDef.get_by_urlname(path[0])
829
            except KeyError:
830
                pass
831
            else:
832
                base_url = get_publisher().get_root_url()
833

    
834
                uri_rest = get_request().environ.get('REQUEST_URI')
835
                if not uri_rest:
836
                    # REQUEST_URI doesn't exist when using internal HTTP server
837
                    # (--http)
838
                    uri_rest = get_request().get_path()
839
                    if get_request().get_query():
840
                        uri_rest += '?' + get_request().get_query()
841
                if uri_rest.startswith(base_url):
842
                    uri_rest = uri_rest[len(base_url):]
843
                if f.category:
844
                    return redirect('%s%s/%s' % (base_url, f.category.url_name, uri_rest))
845

    
846
            raise e
847

    
848

    
849
    def _q_lookup(self, component):
850
        if component == 'qo':
851
            dirname = os.path.join(get_publisher().data_dir, 'qommon')
852
            return StaticDirectory(dirname, follow_symlinks = True)
853

    
854
        if component == 'aq':
855
            dirname = os.path.join(get_publisher().data_dir, 'qommon', 'auquotidien')
856
            return StaticDirectory(dirname, follow_symlinks = True)
857

    
858
        # maps /leaflet/ to the directory provided by the libjs-openlayers package
859
        if component == 'leaflet':
860
            return StaticDirectory('/usr/share/javascript/leaflet')
861

    
862
        if component in ('css','images'):
863
            return OldRootDirectory._q_lookup(self, component)
864

    
865
        # is this a category ?
866
        try:
867
            category = Category.get_by_urlname(component)
868
        except KeyError:
869
            pass
870
        else:
871
            return FormsRootDirectory(category)
872

    
873
        # is this a formdef ?
874
        try:
875
            formdef = FormDef.get_by_urlname(component)
876
        except KeyError:
877
            pass
878
        else:
879
            # if there's no category, or the request is a POST, directly call
880
            # into FormsRootDirectory.
881
            if formdef.category_id is None or get_request().get_method() == 'POST':
882
                get_response().filter['bigdiv'] = 'rub_service'
883
                return FormsRootDirectory()._q_lookup(component)
884

    
885
            # if there is category, let it fall back to raise TraversalError,
886
            # it will get caught in _q_traverse that will redirect it to an
887
            # URL embedding the category
888

    
889
        return None
890

    
891
    def json(self):
892
        return FormsRootDirectory().json()
893

    
894
    def categories(self):
895
        return FormsRootDirectory().categories()
896

    
897
    def _q_index(self):
898
        if get_request().is_json():
899
            return FormsRootDirectory().json()
900

    
901
        root_url = get_publisher().get_root_url()
902
        if get_request().user and get_request().user.anonymous and get_request().user.lasso_dump:
903
            return redirect('%smyspace/new' % root_url)
904

    
905
        redirect_url = get_cfg('misc', {}).get('homepage-redirect-url')
906
        if redirect_url:
907
            return redirect(misc.get_variadic_url(redirect_url,
908
                get_publisher().substitutions.get_context_variables()))
909

    
910
        if get_response().iframe_mode:
911
            # never display home page in an iframe
912
            return redirect('%sservices' % root_url)
913

    
914
        template.html_top()
915
        r = TemplateIO(html=True)
916
        get_response().filter['is_index'] = True
917

    
918
        if not 'auquotidien-welcome-in-services' in get_response().filter.get('keywords', []):
919
            t = TextsDirectory.get_html_text('aq-home-page')
920
            if not t:
921
                if get_request().user:
922
                    t = TextsDirectory.get_html_text('welcome-logged')
923
                else:
924
                    t = TextsDirectory.get_html_text('welcome-unlogged')
925
            if t:
926
                r += htmltext('<div id="home-page-intro">')
927
                r += t
928
                r += htmltext('</div>')
929

    
930
        r += htmltext('<div id="centre">')
931
        r += self.box_services(position='1st')
932
        r += htmltext('</div>')
933
        r += htmltext('<div id="droite">')
934
        r += self.myspace_snippet()
935
        r += self.box_services(position='2nd')
936
        r += self.consultations()
937
        r += self.announces()
938
        r += htmltext('</div>')
939

    
940
        user = get_request().user
941
        if user and user.can_go_in_backoffice():
942
            get_response().filter['backoffice'] = True
943

    
944
        return r.getvalue()
945

    
946
    def services(self):
947
        template.html_top()
948
        get_response().filter['bigdiv'] = 'rub_service'
949
        return self.box_services(level = 2)
950

    
951
    def box_services(self, level=3, position=None):
952
        ## Services
953
        if get_request().user and get_request().user.roles:
954
            accepted_roles = get_request().user.roles
955
        else:
956
            accepted_roles = []
957

    
958
        cats = Category.select(order_by = 'name')
959
        cats = [x for x in cats if x.url_name != 'consultations']
960
        Category.sort_by_position(cats)
961

    
962
        all_formdefs = FormDef.select(lambda x: not x.is_disabled() or x.disabled_redirection,
963
                order_by = 'name')
964
        if get_response().page_template_key == 'mobile':
965
            # if we are in 'mobile' mode, and some formdefs have a 'mobile'
966
            # keyword, we limit the display to those
967
            if any((x for x in all_formdefs if x.keywords and 'mobile' in x.keywords)):
968
                all_formdefs = [x for x in all_formdefs if x.keywords and 'mobile' in x.keywords]
969

    
970
        if position:
971
            t = self.display_list_of_formdefs(
972
                            [x for x in cats if x.get_homepage_position() == position],
973
                            all_formdefs, accepted_roles)
974
        else:
975
            t = self.display_list_of_formdefs(cats, all_formdefs, accepted_roles)
976

    
977
        if not t:
978
            return
979

    
980
        r = TemplateIO(html=True)
981

    
982
        if position == '2nd':
983
            r += htmltext('<div id="services-2nd">')
984
        else:
985
            r += htmltext('<div id="services">')
986
        if level == 2:
987
            r += htmltext('<h2>%s</h2>') % _('Services')
988
        else:
989
            r += htmltext('<h3>%s</h3>') % _('Services')
990

    
991
        if get_response().iframe_mode:
992
            if get_request().user:
993
                message = TextsDirectory.get_html_text('welcome-logged')
994
            else:
995
                message = TextsDirectory.get_html_text('welcome-unlogged')
996

    
997
            if message:
998
                r += htmltext('<div id="welcome-message">')
999
                r += message
1000
                r += htmltext('</div>')
1001
        elif 'auquotidien-welcome-in-services' in get_response().filter.get('keywords', []):
1002
            homepage_text = TextsDirectory.get_html_text('aq-home-page')
1003
            if homepage_text:
1004
                r += htmltext('<div id="home-page-intro">')
1005
                r += homepage_text
1006
                r += htmltext('</div>')
1007

    
1008
        r += htmltext('<ul>')
1009
        r += t
1010
        r += htmltext('</ul>')
1011

    
1012
        r += htmltext('</div>')
1013
        return r.getvalue()
1014

    
1015
    def display_list_of_formdefs(self, cats, all_formdefs, accepted_roles):
1016
        r = TemplateIO(html=True)
1017
        for category in cats:
1018
            if category.url_name == 'consultations':
1019
                self.consultations_category = category
1020
                continue
1021
            formdefs = [x for x in all_formdefs if str(x.category_id) == str(category.id)]
1022
            formdefs_advertise = []
1023

    
1024
            for formdef in formdefs[:]:
1025
                if formdef.is_disabled(): # is a redirection
1026
                    continue
1027
                if not formdef.roles:
1028
                    continue
1029
                if not get_request().user:
1030
                    if formdef.always_advertise:
1031
                        formdefs_advertise.append(formdef)
1032
                    formdefs.remove(formdef)
1033
                    continue
1034
                if logged_users_role().id in formdef.roles:
1035
                    continue
1036
                for q in accepted_roles:
1037
                    if q in formdef.roles:
1038
                        break
1039
                else:
1040
                    if formdef.always_advertise:
1041
                        formdefs_advertise.append(formdef)
1042
                    formdefs.remove(formdef)
1043

    
1044
            if not formdefs and not formdefs_advertise:
1045
                continue
1046

    
1047
            keywords = {}
1048
            for formdef in formdefs:
1049
                for keyword in formdef.keywords_list:
1050
                    keywords[keyword] = True
1051

    
1052
            r += htmltext('<li id="category-%s" data-keywords="%s">') % (
1053
                    category.url_name, ' '.join(keywords))
1054
            r += htmltext('<strong>')
1055
            r += htmltext('<a href="%s/">') % category.url_name
1056
            r += category.name
1057
            r += htmltext('</a></strong>\n')
1058
            r += category.get_description_html_text()
1059
            r += htmltext('<ul>')
1060
            limit = category.get_limit()
1061
            for formdef in formdefs[:limit]:
1062
                r += htmltext('<li data-keywords="%s">') % ' '.join(formdef.keywords_list)
1063
                classes = []
1064
                if formdef.is_disabled() and formdef.disabled_redirection:
1065
                    classes.append('redirection')
1066
                r += htmltext('<a class="%s" href="%s/%s/">%s</a>') % (
1067
                        ' '.join(classes), category.url_name, formdef.url_name, formdef.name)
1068
                r += htmltext('</li>\n')
1069
            if len(formdefs) < limit:
1070
                for formdef in formdefs_advertise[:limit-len(formdefs)]:
1071
                    r += htmltext('<li class="required-authentication">')
1072
                    r += htmltext('<a href="%s/%s/">%s</a>') % (category.url_name, formdef.url_name, formdef.name)
1073
                    r += htmltext('<span> (%s)</span>') % _('authentication required')
1074
                    r += htmltext('</li>\n')
1075
            if (len(formdefs)+len(formdefs_advertise)) > limit:
1076
                r += htmltext('<li class="all-forms"><a href="%s/" title="%s">%s</a></li>') % (category.url_name,
1077
                        _('Access to all forms of the "%s" category') % category.name,
1078
                        _('Access to all forms in this category'))
1079
            r += htmltext('</ul>')
1080
            r += htmltext('</li>\n')
1081

    
1082
        return r.getvalue()
1083

    
1084
    def consultations(self):
1085
        cats = [x for x in Category.select() if x.url_name == 'consultations']
1086
        if not cats:
1087
            return
1088
        consultations_category = cats[0]
1089
        formdefs = FormDef.select(lambda x: (
1090
                    str(x.category_id) == str(consultations_category.id) and
1091
                        (not x.is_disabled() or x.disabled_redirection)),
1092
                    order_by = 'name')
1093
        if not formdefs:
1094
            return
1095
        ## Consultations
1096
        r = TemplateIO(html=True)
1097
        r += htmltext('<div id="consultations">')
1098
        r += htmltext('<h3>%s</h3>') % _('Consultations')
1099
        r += consultations_category.get_description_html_text()
1100
        r += htmltext('<ul>')
1101
        for formdef in formdefs:
1102
            r += htmltext('<li>')
1103
            r += htmltext('<a href="%s/%s/">%s</a>') % (consultations_category.url_name,
1104
                formdef.url_name, formdef.name)
1105
            r += htmltext('</li>')
1106
        r += htmltext('</ul>')
1107
        r += htmltext('</div>')
1108
        return r.getvalue()
1109

    
1110
    def box_side(self, path):
1111
        r = TemplateIO(html=True)
1112
        root_url = get_publisher().get_root_url()
1113

    
1114
        if self.has_anonymous_access_codes():
1115
            r += htmltext('<form id="follow-form" action="%saccesscode">') % root_url
1116
            r += htmltext('<h3>%s</h3>') % _('Tracking')
1117
            r += htmltext('<label>%s</label> ') % _('Code:')
1118
            r += htmltext('<input name="code" size="10"/>')
1119
            r += htmltext('</form>')
1120

    
1121
        r += self.links()
1122

    
1123
        cats = Category.select(order_by = 'name')
1124
        cats = [x for x in cats if x.url_name != 'consultations' and x.get_homepage_position() == 'side']
1125
        Category.sort_by_position(cats)
1126
        if cats:
1127
            r += htmltext('<div id="side-services">')
1128
            r += htmltext('<h3>%s</h3>') % _('Services')
1129
            r += htmltext('<ul>')
1130
            for cat in cats:
1131
                r += htmltext('<li><a href="%s/">%s</a></li>') % (cat.url_name, cat.name)
1132
            r += htmltext('</ul>')
1133
            r += htmltext('</div>')
1134

    
1135
        if Event.keys(): # if there are events, add a link to the agenda
1136
            tags = get_cfg('misc', {}).get('event_tags')
1137
            if not tags:
1138
                tags = get_default_event_tags()
1139
            r += htmltext('<h3 id="agenda-link"><a href="%sagenda/">%s</a></h3>') % (root_url, _('Agenda'))
1140

    
1141
            if path and path[0] == 'agenda':
1142
                r += htmltext('<p class="tags">')
1143
                for tag in tags:
1144
                    r += htmltext('<a href="%sagenda/tag/%s">%s</a> ') % (root_url, tag, tag)
1145
                r += htmltext('</p>')
1146
                r += self.agenda.display_remote_calendars()
1147

    
1148
                r += htmltext('<p>')
1149
                r += htmltext('  <a href="%sagenda/filter">%s</a>') % (root_url, _('Advanced Filter'))
1150
                r += htmltext('</p>')
1151

    
1152
        v = r.getvalue()
1153
        if v:
1154
            r = TemplateIO(html=True)
1155
            r += htmltext('<div id="sidebox">')
1156
            r += v
1157
            r += htmltext('</div>')
1158
            return r.getvalue()
1159

    
1160
        return None
1161

    
1162
    def has_anonymous_access_codes(self):
1163
        for workflow in Workflow.select():
1164
            for wfstatus in workflow.possible_status:
1165
                for wfitem in wfstatus.items:
1166
                    if wfitem.key == 'create-anonymous-access-code':
1167
                        return True
1168
        return False
1169

    
1170
    def accesscode(self):
1171
        code = get_request().form.get('code')
1172
        if not code:
1173
            return redirect(get_publisher().get_root_url())
1174
        try:
1175
            token = Token.get(code)
1176
        except KeyError:
1177
            return redirect(get_publisher().get_root_url())
1178
        if token.type != 'anonymous-access-code':
1179
            return redirect(get_publisher().get_root_url())
1180
        formdef_urlname, formdata_id = token.formdata_reference
1181
        try:
1182
            formdata = FormDef.get_by_urlname(formdef_urlname).data_class().get(formdata_id)
1183
        except KeyError:
1184
            return redirect(get_publisher().get_root_url())
1185
        session = get_session()
1186
        if not hasattr(session, '_wf_anonymous_access_authorized'):
1187
            session._wf_anonymous_access_authorized = []
1188
        session._wf_anonymous_access_authorized.append(formdata.get_url())
1189
        return redirect(formdata.get_url() + 'access/')
1190

    
1191
    def links(self):
1192
        links = Link.select()
1193
        if not links:
1194
            return ''
1195

    
1196
        Link.sort_by_position(links)
1197

    
1198
        r = TemplateIO(html=True)
1199

    
1200
        r += htmltext('<div id="links">')
1201
        if links[0].url:
1202
            # first link has an URL, so it's not a title, so we display a
1203
            # generic title
1204
            r += htmltext('<h3>%s</h3>') % _('Useful links')
1205
        has_ul = False
1206
        vars = get_publisher().substitutions.get_context_variables()
1207
        for link in links:
1208
            if not link.url:
1209
                # acting title
1210
                if has_ul:
1211
                    r += htmltext('</ul>')
1212
                r += htmltext('<h3>%s</h3>') % link.title
1213
                r += htmltext('<ul>')
1214
                has_ul = True
1215
            else:
1216
                if not has_ul:
1217
                    r += htmltext('<ul>')
1218
                    has_ul = True
1219
                r += htmltext('<li class="link-%s"><a href="%s">%s</a></li>') % (
1220
                        simplify(link.title), get_variadic_url(link.url, vars), link.title)
1221
        if has_ul:
1222
            r += htmltext('</ul>')
1223
        r += htmltext('</div>')
1224
        return r.getvalue()
1225

    
1226
    def announces(self):
1227
        announces = Announce.get_published_announces()
1228
        if not announces:
1229
            return
1230

    
1231
        r = TemplateIO(html=True)
1232
        r += htmltext('<div id="announces">')
1233
        r += htmltext('<h3>%s</h3>') % _('Announces to citizens')
1234
        for item in announces[:3]:
1235
            r += htmltext('<div class="announce-item">')
1236
            r += htmltext('<h4>')
1237
            if item.publication_time:
1238
                r += time.strftime(misc.date_format(), item.publication_time)
1239
                r += ' - '
1240
            r += item.title
1241
            r += htmltext('</h4>')
1242
            r += htmltext('<p>')
1243
            r += item.text
1244
            r += htmltext('</p>')
1245
            r += htmltext('</div>')
1246

    
1247
        r += htmltext('<ul id="announces-links">')
1248
        r += htmltext('<li><a href="announces/subscribe">%s</a></li>') % _('Receiving those Announces')
1249
        r += htmltext('<li><a href="announces/">%s</a></li>') % _('Previous Announces')
1250
        r += htmltext('</ul>')
1251
        r += htmltext('</div>')
1252
        return r.getvalue()
1253

    
1254
    def myspace_snippet(self):
1255
        r = TemplateIO(html=True)
1256
        r += htmltext('<div id="myspace">')
1257
        r += htmltext('<h3>%s</h3>') % _('My Space')
1258
        r += htmltext('<ul>')
1259
        if get_request().user and not get_request().user.anonymous:
1260
            r += htmltext('  <li><a href="myspace/" id="member">%s</a></li>') % _('Access to your personal space')
1261
            r += htmltext('  <li><a href="logout" id="logout">%s</a></li>') % _('Logout')
1262
        else:
1263
            r += htmltext('  <li><a href="register/" id="inscr">%s</a></li>') % _('Registration')
1264
            r += htmltext('  <li><a href="login/" id="login">%s</a></li>') % _('Login')
1265
        r += htmltext('</ul>')
1266
        r += htmltext('</div>')
1267
        return r.getvalue()
1268

    
1269
    def page_view(self, key, title, urlname = None):
1270
        if not urlname:
1271
            urlname = key[3:].replace(str('_'), str('-'))
1272
        get_response().breadcrumb.append((urlname, title))
1273
        template.html_top(title)
1274
        r = TemplateIO(html=True)
1275
        r += htmltext('<div class="article">')
1276
        r += htmltext(TextsDirectory.get_html_text(key))
1277
        r += htmltext('</div>')
1278
        return r.getvalue()
1279

    
1280
    def informations_editeur(self):
1281
        get_response().filter['bigdiv'] = 'info'
1282
        return self.page_view('aq-editor-info', _('Editor Informations'),
1283
                urlname = 'informations_editeur')
1284

    
1285
    def accessibility(self):
1286
        get_response().filter['bigdiv'] = 'accessibility'
1287
        return self.page_view('aq-accessibility', _('Accessibility Statement'))
1288

    
1289
    def contact(self):
1290
        get_response().filter['bigdiv'] = 'contact'
1291
        return self.page_view('aq-contact', _('Contact'))
1292

    
1293
    def help(self):
1294
        get_response().filter['bigdiv'] = 'help'
1295
        return self.page_view('aq-help', _('Help'))
1296

    
1297

    
1298
from qommon.publisher import get_publisher_class
1299
get_publisher_class().root_directory_class = AlternateRootDirectory
1300
get_publisher_class().after_login_url = 'myspace/'
1301
get_publisher_class().use_sms_feature = True
1302

    
1303
# help links
1304
get_publisher_class().backoffice_help_url = {
1305
    'fr': 'https://doc.entrouvert.org/au-quotidien/stable/guide-gestionnaire.html',
1306
}
1307
get_publisher_class().admin_help_url = {
1308
    'fr': 'https://doc.entrouvert.org/auquotidien/dev/',
1309
}
1310

    
1311

    
1312
EmailsDirectory.register('announces-subscription-confirmation',
1313
        N_('Confirmation of Announces Subscription'),
1314
        N_('Available variables: change_url, cancel_url, time, sitename'),
1315
        default_subject = N_('Announce Subscription Request'),
1316
        default_body = N_("""\
1317
You have (or someone impersonating you has) requested to subscribe to
1318
announces from [sitename].  To confirm this request, visit the
1319
following link:
1320

    
1321
[confirm_url]
1322

    
1323
If you are not the person who made this request, or you wish to cancel
1324
this request, visit the following link:
1325

    
1326
[cancel_url]
1327

    
1328
If you do nothing, the request will lapse after 3 days (precisely on
1329
[time]).
1330
"""))
1331

    
1332

    
1333
TextsDirectory.register('aq-announces-subscription',
1334
        N_('Text on announces subscription page'),
1335
        default = N_('''\
1336
<p>
1337
FIXME
1338
'</p>'''))
1339

    
1340
TextsDirectory.register('aq-sms-demo',
1341
        N_('Text when subscribing to announces SMS and configured as demo'),
1342
        default = N_('''
1343
<p>
1344
Receiving announces by SMS is not possible in this demo
1345
</p>'''))
1346

    
1347
TextsDirectory.register('aq-editor-info', N_('Editor Informations'))
1348
TextsDirectory.register('aq-accessibility', N_('Accessibility Statement'))
1349
TextsDirectory.register('aq-contact', N_('Contact Information'))
1350
TextsDirectory.register('aq-help', N_('Help'))
1351
TextsDirectory.register('aq-sso-text',  N_('Connecting with Identity Provider'),
1352
        default = N_('''<h3>Connecting with Identity Provider</h3>
1353
<p>You can also use your identity provider to connect.
1354
</p>'''))
1355

    
1356
TextsDirectory.register('aq-home-page', N_('Home Page'), wysiwyg = True)
(23-23/27)