Projet

Général

Profil

Télécharger (48,8 ko) Statistiques
| Branche: | Tag: | Révision:

root / auquotidien / modules / root.py @ 8b02623d

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

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

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

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

    
17
import wcs
18
import wcs.root
19
import qommon
20
from qommon import _
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() and not x.formdef.is_disabled()]
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
            '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', 'roles',
772
            'api', 'code', 'fargo', 'tryauth', 'auth', 'preview',
773
            ('reload-top', 'reload_top'), 'static',
774
            ('i18n.js', 'i18n_js')]
775

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

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

    
796
    def _q_traverse(self, path):
797
        self.feed_substitution_parts()
798

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

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

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

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

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

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

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

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

    
845
            raise e
846

    
847

    
848
    def _q_lookup(self, component):
849
        # is this a category ?
850
        try:
851
            category = Category.get_by_urlname(component)
852
        except KeyError:
853
            pass
854
        else:
855
            return FormsRootDirectory(category)
856

    
857
        # is this a formdef ?
858
        try:
859
            formdef = FormDef.get_by_urlname(component)
860
        except KeyError:
861
            pass
862
        else:
863
            # if there's no category, or the request is a POST, directly call
864
            # into FormsRootDirectory.
865
            if formdef.category_id is None or get_request().get_method() == 'POST':
866
                get_response().filter['bigdiv'] = 'rub_service'
867
                return FormsRootDirectory()._q_lookup(component)
868

    
869
            # if there is category, let it fall back to raise TraversalError,
870
            # it will get caught in _q_traverse that will redirect it to an
871
            # URL embedding the category
872

    
873
        return None
874

    
875
    def json(self):
876
        return FormsRootDirectory().json()
877

    
878
    def categories(self):
879
        return FormsRootDirectory().categories()
880

    
881
    def _q_index(self):
882
        if get_request().is_json():
883
            return FormsRootDirectory().json()
884

    
885
        root_url = get_publisher().get_root_url()
886
        if get_request().user and get_request().user.anonymous and get_request().user.lasso_dump:
887
            return redirect('%smyspace/new' % root_url)
888

    
889
        redirect_url = get_cfg('misc', {}).get('homepage-redirect-url')
890
        if redirect_url:
891
            return redirect(misc.get_variadic_url(redirect_url,
892
                get_publisher().substitutions.get_context_variables()))
893

    
894
        if get_response().iframe_mode:
895
            # never display home page in an iframe
896
            return redirect('%sservices' % root_url)
897

    
898
        template.html_top()
899
        r = TemplateIO(html=True)
900
        get_response().filter['is_index'] = True
901

    
902
        if not 'auquotidien-welcome-in-services' in get_response().filter.get('keywords', []):
903
            t = TextsDirectory.get_html_text('aq-home-page')
904
            if not t:
905
                if get_request().user:
906
                    t = TextsDirectory.get_html_text('welcome-logged')
907
                else:
908
                    t = TextsDirectory.get_html_text('welcome-unlogged')
909
            if t:
910
                r += htmltext('<div id="home-page-intro">')
911
                r += t
912
                r += htmltext('</div>')
913

    
914
        r += htmltext('<div id="centre">')
915
        r += self.box_services(position='1st')
916
        r += htmltext('</div>')
917
        r += htmltext('<div id="droite">')
918
        r += self.myspace_snippet()
919
        r += self.box_services(position='2nd')
920
        r += self.consultations()
921
        r += self.announces()
922
        r += htmltext('</div>')
923

    
924
        user = get_request().user
925
        if user and user.can_go_in_backoffice():
926
            get_response().filter['backoffice'] = True
927

    
928
        return r.getvalue()
929

    
930
    def services(self):
931
        template.html_top()
932
        get_response().filter['bigdiv'] = 'rub_service'
933
        return self.box_services(level = 2)
934

    
935
    def box_services(self, level=3, position=None):
936
        ## Services
937
        if get_request().user and get_request().user.roles:
938
            accepted_roles = get_request().user.roles
939
        else:
940
            accepted_roles = []
941

    
942
        cats = Category.select(order_by = 'name')
943
        cats = [x for x in cats if x.url_name != 'consultations']
944
        Category.sort_by_position(cats)
945

    
946
        all_formdefs = FormDef.select(lambda x: not x.is_disabled() or x.disabled_redirection,
947
                order_by = 'name')
948
        if get_response().page_template_key == 'mobile':
949
            # if we are in 'mobile' mode, and some formdefs have a 'mobile'
950
            # keyword, we limit the display to those
951
            if any((x for x in all_formdefs if x.keywords and 'mobile' in x.keywords)):
952
                all_formdefs = [x for x in all_formdefs if x.keywords and 'mobile' in x.keywords]
953

    
954
        if position:
955
            t = self.display_list_of_formdefs(
956
                            [x for x in cats if x.get_homepage_position() == position],
957
                            all_formdefs, accepted_roles)
958
        else:
959
            t = self.display_list_of_formdefs(cats, all_formdefs, accepted_roles)
960

    
961
        if not t:
962
            return
963

    
964
        r = TemplateIO(html=True)
965

    
966
        if position == '2nd':
967
            r += htmltext('<div id="services-2nd">')
968
        else:
969
            r += htmltext('<div id="services">')
970
        if level == 2:
971
            r += htmltext('<h2>%s</h2>') % _('Services')
972
        else:
973
            r += htmltext('<h3>%s</h3>') % _('Services')
974

    
975
        if get_response().iframe_mode:
976
            if get_request().user:
977
                message = TextsDirectory.get_html_text('welcome-logged')
978
            else:
979
                message = TextsDirectory.get_html_text('welcome-unlogged')
980

    
981
            if message:
982
                r += htmltext('<div id="welcome-message">')
983
                r += message
984
                r += htmltext('</div>')
985
        elif 'auquotidien-welcome-in-services' in get_response().filter.get('keywords', []):
986
            homepage_text = TextsDirectory.get_html_text('aq-home-page')
987
            if homepage_text:
988
                r += htmltext('<div id="home-page-intro">')
989
                r += homepage_text
990
                r += htmltext('</div>')
991

    
992
        r += htmltext('<ul>')
993
        r += t
994
        r += htmltext('</ul>')
995

    
996
        r += htmltext('</div>')
997
        return r.getvalue()
998

    
999
    def display_list_of_formdefs(self, cats, all_formdefs, accepted_roles):
1000
        r = TemplateIO(html=True)
1001
        for category in cats:
1002
            if category.url_name == 'consultations':
1003
                self.consultations_category = category
1004
                continue
1005
            formdefs = [x for x in all_formdefs if str(x.category_id) == str(category.id)]
1006
            formdefs_advertise = []
1007

    
1008
            for formdef in formdefs[:]:
1009
                if formdef.is_disabled(): # is a redirection
1010
                    continue
1011
                if not formdef.roles:
1012
                    continue
1013
                if not get_request().user:
1014
                    if formdef.always_advertise:
1015
                        formdefs_advertise.append(formdef)
1016
                    formdefs.remove(formdef)
1017
                    continue
1018
                if logged_users_role().id in formdef.roles:
1019
                    continue
1020
                for q in accepted_roles:
1021
                    if q in formdef.roles:
1022
                        break
1023
                else:
1024
                    if formdef.always_advertise:
1025
                        formdefs_advertise.append(formdef)
1026
                    formdefs.remove(formdef)
1027

    
1028
            if not formdefs and not formdefs_advertise:
1029
                continue
1030

    
1031
            keywords = {}
1032
            for formdef in formdefs:
1033
                for keyword in formdef.keywords_list:
1034
                    keywords[keyword] = True
1035

    
1036
            r += htmltext('<li id="category-%s" data-keywords="%s">') % (
1037
                    category.url_name, ' '.join(keywords))
1038
            r += htmltext('<strong>')
1039
            r += htmltext('<a href="%s/">') % category.url_name
1040
            r += category.name
1041
            r += htmltext('</a></strong>\n')
1042
            r += category.get_description_html_text()
1043
            r += htmltext('<ul>')
1044
            limit = category.get_limit()
1045
            for formdef in formdefs[:limit]:
1046
                r += htmltext('<li data-keywords="%s">') % ' '.join(formdef.keywords_list)
1047
                classes = []
1048
                if formdef.is_disabled() and formdef.disabled_redirection:
1049
                    classes.append('redirection')
1050
                r += htmltext('<a class="%s" href="%s/%s/">%s</a>') % (
1051
                        ' '.join(classes), category.url_name, formdef.url_name, formdef.name)
1052
                r += htmltext('</li>\n')
1053
            if len(formdefs) < limit:
1054
                for formdef in formdefs_advertise[:limit-len(formdefs)]:
1055
                    r += htmltext('<li class="required-authentication">')
1056
                    r += htmltext('<a href="%s/%s/">%s</a>') % (category.url_name, formdef.url_name, formdef.name)
1057
                    r += htmltext('<span> (%s)</span>') % _('authentication required')
1058
                    r += htmltext('</li>\n')
1059
            if (len(formdefs)+len(formdefs_advertise)) > limit:
1060
                r += htmltext('<li class="all-forms"><a href="%s/" title="%s">%s</a></li>') % (category.url_name,
1061
                        _('Access to all forms of the "%s" category') % category.name,
1062
                        _('Access to all forms in this category'))
1063
            r += htmltext('</ul>')
1064
            r += htmltext('</li>\n')
1065

    
1066
        return r.getvalue()
1067

    
1068
    def consultations(self):
1069
        cats = [x for x in Category.select() if x.url_name == 'consultations']
1070
        if not cats:
1071
            return
1072
        consultations_category = cats[0]
1073
        formdefs = FormDef.select(lambda x: (
1074
                    str(x.category_id) == str(consultations_category.id) and
1075
                        (not x.is_disabled() or x.disabled_redirection)),
1076
                    order_by = 'name')
1077
        if not formdefs:
1078
            return
1079
        ## Consultations
1080
        r = TemplateIO(html=True)
1081
        r += htmltext('<div id="consultations">')
1082
        r += htmltext('<h3>%s</h3>') % _('Consultations')
1083
        r += consultations_category.get_description_html_text()
1084
        r += htmltext('<ul>')
1085
        for formdef in formdefs:
1086
            r += htmltext('<li>')
1087
            r += htmltext('<a href="%s/%s/">%s</a>') % (consultations_category.url_name,
1088
                formdef.url_name, formdef.name)
1089
            r += htmltext('</li>')
1090
        r += htmltext('</ul>')
1091
        r += htmltext('</div>')
1092
        return r.getvalue()
1093

    
1094
    def box_side(self, path):
1095
        r = TemplateIO(html=True)
1096
        root_url = get_publisher().get_root_url()
1097

    
1098
        if self.has_anonymous_access_codes() and path == [''] and (
1099
                'include-tracking-code-form' in get_response().filter.get('keywords', [])):
1100
            r += htmltext('<form id="follow-form" action="%scode/load">') % root_url
1101
            r += htmltext('<h3>%s</h3>') % _('Tracking code')
1102
            r += htmltext('<input size="12" name="code" placeholder="%s"/>') % _('ex: RPQDFVCD')
1103
            r += htmltext('<input type="submit" value="%s"/>') % _('Load')
1104
            r += htmltext('</form>')
1105

    
1106
        r += self.links()
1107

    
1108
        cats = Category.select(order_by = 'name')
1109
        cats = [x for x in cats if x.url_name != 'consultations' and x.get_homepage_position() == 'side']
1110
        Category.sort_by_position(cats)
1111
        if cats:
1112
            r += htmltext('<div id="side-services">')
1113
            r += htmltext('<h3>%s</h3>') % _('Services')
1114
            r += htmltext('<ul>')
1115
            for cat in cats:
1116
                r += htmltext('<li><a href="%s/">%s</a></li>') % (cat.url_name, cat.name)
1117
            r += htmltext('</ul>')
1118
            r += htmltext('</div>')
1119

    
1120
        if Event.keys(): # if there are events, add a link to the agenda
1121
            tags = get_cfg('misc', {}).get('event_tags')
1122
            if not tags:
1123
                tags = get_default_event_tags()
1124
            r += htmltext('<h3 id="agenda-link"><a href="%sagenda/">%s</a></h3>') % (root_url, _('Agenda'))
1125

    
1126
            if path and path[0] == 'agenda':
1127
                r += htmltext('<p class="tags">')
1128
                for tag in tags:
1129
                    r += htmltext('<a href="%sagenda/tag/%s">%s</a> ') % (root_url, tag, tag)
1130
                r += htmltext('</p>')
1131
                r += self.agenda.display_remote_calendars()
1132

    
1133
                r += htmltext('<p>')
1134
                r += htmltext('  <a href="%sagenda/filter">%s</a>') % (root_url, _('Advanced Filter'))
1135
                r += htmltext('</p>')
1136

    
1137
        v = r.getvalue()
1138
        if v:
1139
            r = TemplateIO(html=True)
1140
            r += htmltext('<div id="sidebox">')
1141
            r += v
1142
            r += htmltext('</div>')
1143
            return r.getvalue()
1144

    
1145
        return None
1146

    
1147
    def has_anonymous_access_codes(self):
1148
        return any((x for x in FormDef.select() if x.enable_tracking_codes))
1149

    
1150
    def links(self):
1151
        links = Link.select()
1152
        if not links:
1153
            return ''
1154

    
1155
        Link.sort_by_position(links)
1156

    
1157
        r = TemplateIO(html=True)
1158

    
1159
        r += htmltext('<div id="links">')
1160
        if links[0].url:
1161
            # first link has an URL, so it's not a title, so we display a
1162
            # generic title
1163
            r += htmltext('<h3>%s</h3>') % _('Useful links')
1164
        has_ul = False
1165
        vars = get_publisher().substitutions.get_context_variables()
1166
        for link in links:
1167
            if not link.url:
1168
                # acting title
1169
                if has_ul:
1170
                    r += htmltext('</ul>')
1171
                r += htmltext('<h3>%s</h3>') % link.title
1172
                r += htmltext('<ul>')
1173
                has_ul = True
1174
            else:
1175
                if not has_ul:
1176
                    r += htmltext('<ul>')
1177
                    has_ul = True
1178
                r += htmltext('<li class="link-%s"><a href="%s">%s</a></li>') % (
1179
                        simplify(link.title), get_variadic_url(link.url, vars), link.title)
1180
        if has_ul:
1181
            r += htmltext('</ul>')
1182
        r += htmltext('</div>')
1183
        return r.getvalue()
1184

    
1185
    def announces(self):
1186
        announces = Announce.get_published_announces()
1187
        if not announces:
1188
            return
1189

    
1190
        r = TemplateIO(html=True)
1191
        r += htmltext('<div id="announces">')
1192
        r += htmltext('<h3>%s</h3>') % _('Announces to citizens')
1193
        for item in announces[:3]:
1194
            r += htmltext('<div class="announce-item">')
1195
            r += htmltext('<h4>')
1196
            if item.publication_time:
1197
                r += time.strftime(misc.date_format(), item.publication_time)
1198
                r += ' - '
1199
            r += item.title
1200
            r += htmltext('</h4>')
1201
            r += htmltext('<p>')
1202
            r += item.text
1203
            r += htmltext('</p>')
1204
            r += htmltext('</div>')
1205

    
1206
        r += htmltext('<ul id="announces-links">')
1207
        r += htmltext('<li><a href="announces/subscribe">%s</a></li>') % _('Receiving those Announces')
1208
        r += htmltext('<li><a href="announces/">%s</a></li>') % _('Previous Announces')
1209
        r += htmltext('</ul>')
1210
        r += htmltext('</div>')
1211
        return r.getvalue()
1212

    
1213
    def myspace_snippet(self):
1214
        r = TemplateIO(html=True)
1215
        r += htmltext('<div id="myspace">')
1216
        r += htmltext('<h3>%s</h3>') % _('My Space')
1217
        r += htmltext('<ul>')
1218
        if get_request().user and not get_request().user.anonymous:
1219
            r += htmltext('  <li><a href="myspace/" id="member">%s</a></li>') % _('Access to your personal space')
1220
            r += htmltext('  <li><a href="logout" id="logout">%s</a></li>') % _('Logout')
1221
        else:
1222
            r += htmltext('  <li><a href="register/" id="inscr">%s</a></li>') % _('Registration')
1223
            r += htmltext('  <li><a href="login/" id="login">%s</a></li>') % _('Login')
1224
        r += htmltext('</ul>')
1225
        r += htmltext('</div>')
1226
        return r.getvalue()
1227

    
1228
    def page_view(self, key, title, urlname = None):
1229
        if not urlname:
1230
            urlname = key[3:].replace(str('_'), str('-'))
1231
        get_response().breadcrumb.append((urlname, title))
1232
        template.html_top(title)
1233
        r = TemplateIO(html=True)
1234
        r += htmltext('<div class="article">')
1235
        r += htmltext(TextsDirectory.get_html_text(key))
1236
        r += htmltext('</div>')
1237
        return r.getvalue()
1238

    
1239
    def informations_editeur(self):
1240
        get_response().filter['bigdiv'] = 'info'
1241
        return self.page_view('aq-editor-info', _('Editor Informations'),
1242
                urlname = 'informations_editeur')
1243

    
1244
    def accessibility(self):
1245
        get_response().filter['bigdiv'] = 'accessibility'
1246
        return self.page_view('aq-accessibility', _('Accessibility Statement'))
1247

    
1248
    def contact(self):
1249
        get_response().filter['bigdiv'] = 'contact'
1250
        return self.page_view('aq-contact', _('Contact'))
1251

    
1252
    def help(self):
1253
        get_response().filter['bigdiv'] = 'help'
1254
        return self.page_view('aq-help', _('Help'))
1255

    
1256

    
1257
from qommon.publisher import get_publisher_class
1258
get_publisher_class().root_directory_class = AlternateRootDirectory
1259
get_publisher_class().after_login_url = 'myspace/'
1260
get_publisher_class().use_sms_feature = True
1261

    
1262
# help links
1263
get_publisher_class().backoffice_help_url = {
1264
    'fr': 'https://doc-publik.entrouvert.com/',
1265
}
1266

    
1267

    
1268
EmailsDirectory.register('announces-subscription-confirmation',
1269
        N_('Confirmation of Announces Subscription'),
1270
        N_('Available variables: change_url, cancel_url, time, sitename'),
1271
        default_subject = N_('Announce Subscription Request'),
1272
        default_body = N_("""\
1273
You have (or someone impersonating you has) requested to subscribe to
1274
announces from [sitename].  To confirm this request, visit the
1275
following link:
1276

    
1277
[confirm_url]
1278

    
1279
If you are not the person who made this request, or you wish to cancel
1280
this request, visit the following link:
1281

    
1282
[cancel_url]
1283

    
1284
If you do nothing, the request will lapse after 3 days (precisely on
1285
[time]).
1286
"""))
1287

    
1288

    
1289
TextsDirectory.register('aq-announces-subscription',
1290
        N_('Text on announces subscription page'),
1291
        default = N_('''\
1292
<p>
1293
FIXME
1294
'</p>'''))
1295

    
1296
TextsDirectory.register('aq-sms-demo',
1297
        N_('Text when subscribing to announces SMS and configured as demo'),
1298
        default = N_('''
1299
<p>
1300
Receiving announces by SMS is not possible in this demo
1301
</p>'''))
1302

    
1303
TextsDirectory.register('aq-editor-info', N_('Editor Informations'))
1304
TextsDirectory.register('aq-accessibility', N_('Accessibility Statement'))
1305
TextsDirectory.register('aq-contact', N_('Contact Information'))
1306
TextsDirectory.register('aq-help', N_('Help'))
1307
TextsDirectory.register('aq-sso-text',  N_('Connecting with Identity Provider'),
1308
        default = N_('''<h3>Connecting with Identity Provider</h3>
1309
<p>You can also use your identity provider to connect.
1310
</p>'''))
1311

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