Projet

Général

Profil

Télécharger (49,9 ko) Statistiques
| Branche: | Tag: | Révision:

root / extra / modules / root.py @ b255cad1

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
import msp_ui
59
import fargo_ui
60

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

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

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

    
78

    
79
class FormsRootDirectory(wcs.forms.root.RootDirectory):
80

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

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

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

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

    
137

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

    
141
    def __init__(self, announce):
142
        self.announce = announce
143

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

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

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

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

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

    
164

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

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

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

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

    
191
    def rawlist(self):
192
        get_response().filter = None
193
        return self.announces_list()
194

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

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

    
216

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

    
220
        if sms_mode == 'none':
221
            raise errors.TraversalError()
222

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

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

    
241
            if form.get_submit() == 'cancel':
242
                return redirect('subscribe')
243

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

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

    
278
        if mobile:
279
            sub.sms = mobile
280

    
281
        if not get_request().user:
282
            sub.enabled = False
283

    
284
        sub.store()
285

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

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

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

    
314
        if form.get_submit() == 'cancel':
315
            return redirect('..')
316

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

    
337
        return r.getvalue()
338

    
339
    def sms_unsubscribe(self):
340
        sub = self._get_announce_subscription()
341

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

    
346
        form.add_submit('submit', _('Unsubscribe'))
347
        form.add_submit('cancel', _('Cancel'))
348

    
349
        if form.get_submit() == 'cancel':
350
            return redirect('..')
351

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

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

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

    
372
        return r.getvalue()
373

    
374

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

    
380
        r += TextsDirectory.get_html_text('aq-announces-subscription')
381

    
382
        sub = self._get_announce_subscription()
383

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

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

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

    
432
        form.add_submit('cancel', _('Cancel'))
433

    
434
        if form.get_submit() == 'cancel':
435
            return redirect('subscribe')
436

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

    
444
        return r.getvalue()
445

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

    
451
        if get_request().user:
452
            sub.user_id = get_request().user.id
453

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

    
459
        if not get_request().user:
460
            sub.enabled = False
461

    
462
        sub.store()
463

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

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

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

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

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

    
501
        root_url = get_publisher().get_root_url()
502

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

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

    
515
        sub = AnnounceSubscription.get(token.subscription_id)
516

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

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

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

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

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

    
561
        announces = Announce.get_published_announces()
562

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

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

    
574
        return str(feed)
575

    
576
    def email_unsubscribe(self):
577
        sub = self._get_announce_subscription()
578

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

    
583
        form.add_submit('submit', _('Unsubscribe'))
584
        form.add_submit('cancel', _('Cancel'))
585

    
586
        if form.get_submit() == 'cancel':
587
            return redirect('..')
588

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

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

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

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

    
615
        return r.getvalue()
616

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

    
623
        if announce.hidden:
624
            raise errors.TraversalError()
625

    
626
        get_response().breadcrumb.append((str(announce.id), announce.title))
627
        return AnnounceDirectory(announce)
628

    
629
OldRegisterDirectory = wcs.root.RegisterDirectory
630

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

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

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

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

    
651
        return qommon.ident.register(method)
652

    
653
OldLoginDirectory = wcs.root.LoginDirectory
654

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

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

    
664
        if get_request().form.get('ReturnUrl'):
665
            get_session().after_url = get_request().form.get('ReturnUrl')
666

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

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

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

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

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

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

    
719
            r += htmltext('</div>')
720

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

    
735
            r += form.render()
736
            r += htmltext('</div>')
737

    
738
            get_request().environ['REQUEST_METHOD'] = 'GET'
739

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

    
747

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

    
754

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

    
760

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

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

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

    
794
    def _q_traverse(self, path):
795
        get_publisher().substitutions.feed(get_session())
796
        get_publisher().substitutions.feed(get_request().user)
797
        get_publisher().substitutions.feed(NamedDataSource)
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
                    uri_rest = get_request().get_path()
836
                if uri_rest.startswith(base_url):
837
                    uri_rest = uri_rest[len(base_url):]
838
                if f.category_id:
839
                    return redirect('%s%s/%s' % (base_url, f.category.url_name, uri_rest))
840

    
841
            raise e
842

    
843

    
844
    def _q_lookup(self, component):
845
        if component == 'qo':
846
            dirname = os.path.join(get_publisher().data_dir, 'qommon')
847
            return StaticDirectory(dirname, follow_symlinks = True)
848

    
849
        if component == 'aq':
850
            dirname = os.path.join(get_publisher().data_dir, 'qommon', 'auquotidien')
851
            return StaticDirectory(dirname, follow_symlinks = True)
852

    
853
        # maps /leaflet/ to the directory provided by the libjs-openlayers package
854
        if component == 'leaflet':
855
            return StaticDirectory('/usr/share/javascript/leaflet')
856

    
857
        if component in ('css','images'):
858
            return OldRootDirectory._q_lookup(self, component)
859

    
860
        # is this a category ?
861
        try:
862
            category = Category.get_by_urlname(component)
863
        except KeyError:
864
            pass
865
        else:
866
            return FormsRootDirectory(category)
867

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

    
880
            # if there is category, let it fall back to raise TraversalError,
881
            # it will get caught in _q_traverse that will redirect it to an
882
            # URL embedding the category
883

    
884
        return None
885

    
886
    def json(self):
887
        return FormsRootDirectory().json()
888

    
889
    def categories(self):
890
        return FormsRootDirectory().categories()
891

    
892
    def _q_index(self):
893
        if get_request().is_json():
894
            return FormsRootDirectory().json()
895

    
896
        root_url = get_publisher().get_root_url()
897
        if get_request().user and get_request().user.anonymous and get_request().user.lasso_dump:
898
            return redirect('%smyspace/new' % root_url)
899

    
900
        if get_response().iframe_mode:
901
            # never display home page in an iframe
902
            return redirect('%sservices' % root_url)
903

    
904
        template.html_top()
905
        r = TemplateIO(html=True)
906
        get_response().filter['is_index'] = True
907

    
908
        if not 'auquotidien-welcome-in-services' in get_response().filter.get('keywords', []):
909
            t = TextsDirectory.get_html_text('aq-home-page')
910
            if not t:
911
                if get_request().user:
912
                    t = TextsDirectory.get_html_text('welcome-logged')
913
                else:
914
                    t = TextsDirectory.get_html_text('welcome-unlogged')
915
            if t:
916
                r += htmltext('<div id="home-page-intro">')
917
                r += t
918
                r += htmltext('</div>')
919

    
920
        r += htmltext('<div id="centre">')
921
        r += self.box_services(position='1st')
922
        r += htmltext('</div>')
923
        r += htmltext('<div id="droite">')
924
        r += self.myspace_snippet()
925
        r += self.box_services(position='2nd')
926
        r += self.consultations()
927
        r += self.announces()
928
        r += htmltext('</div>')
929

    
930
        user = get_request().user
931
        if user and user.can_go_in_backoffice():
932
            get_response().filter['backoffice'] = True
933

    
934
        return r.getvalue()
935

    
936
    def services(self):
937
        template.html_top()
938
        get_response().filter['bigdiv'] = 'rub_service'
939
        return self.box_services(level = 2)
940

    
941
    def box_services(self, level=3, position=None):
942
        ## Services
943
        if get_request().user and get_request().user.roles:
944
            accepted_roles = get_request().user.roles
945
        else:
946
            accepted_roles = []
947

    
948
        cats = Category.select(order_by = 'name')
949
        cats = [x for x in cats if x.url_name != 'consultations']
950
        Category.sort_by_position(cats)
951

    
952
        all_formdefs = FormDef.select(lambda x: not x.is_disabled() or x.disabled_redirection,
953
                order_by = 'name')
954
        if get_response().page_template_key == 'mobile':
955
            # if we are in 'mobile' mode, and some formdefs have a 'mobile'
956
            # keyword, we limit the display to those
957
            if any((x for x in all_formdefs if x.keywords and 'mobile' in x.keywords)):
958
                all_formdefs = [x for x in all_formdefs if x.keywords and 'mobile' in x.keywords]
959

    
960
        if position:
961
            t = self.display_list_of_formdefs(
962
                            [x for x in cats if x.get_homepage_position() == position],
963
                            all_formdefs, accepted_roles)
964
        else:
965
            t = self.display_list_of_formdefs(cats, all_formdefs, accepted_roles)
966

    
967
        if not t:
968
            return
969

    
970
        r = TemplateIO(html=True)
971

    
972
        if position == '2nd':
973
            r += htmltext('<div id="services-2nd">')
974
        else:
975
            r += htmltext('<div id="services">')
976
        if level == 2:
977
            r += htmltext('<h2>%s</h2>') % _('Services')
978
        else:
979
            r += htmltext('<h3>%s</h3>') % _('Services')
980

    
981
        if get_response().iframe_mode:
982
            if get_request().user:
983
                message = TextsDirectory.get_html_text('welcome-logged')
984
            else:
985
                message = TextsDirectory.get_html_text('welcome-unlogged')
986

    
987
            if message:
988
                r += htmltext('<div id="welcome-message">')
989
                r += message
990
                r += htmltext('</div>')
991
        elif 'auquotidien-welcome-in-services' in get_response().filter.get('keywords', []):
992
            homepage_text = TextsDirectory.get_html_text('aq-home-page')
993
            if homepage_text:
994
                r += htmltext('<div id="home-page-intro">')
995
                r += homepage_text
996
                r += htmltext('</div>')
997

    
998
        r += htmltext('<ul>')
999
        r += t
1000
        r += htmltext('</ul>')
1001

    
1002
        r += htmltext('</div>')
1003
        return r.getvalue()
1004

    
1005
    def display_list_of_formdefs(self, cats, all_formdefs, accepted_roles):
1006
        r = TemplateIO(html=True)
1007
        for category in cats:
1008
            if category.url_name == 'consultations':
1009
                self.consultations_category = category
1010
                continue
1011
            formdefs = [x for x in all_formdefs if str(x.category_id) == str(category.id)]
1012
            formdefs_advertise = []
1013

    
1014
            for formdef in formdefs[:]:
1015
                if formdef.is_disabled(): # is a redirection
1016
                    continue
1017
                if not formdef.roles:
1018
                    continue
1019
                if not get_request().user:
1020
                    if formdef.always_advertise:
1021
                        formdefs_advertise.append(formdef)
1022
                    formdefs.remove(formdef)
1023
                    continue
1024
                if logged_users_role().id in formdef.roles:
1025
                    continue
1026
                for q in accepted_roles:
1027
                    if q in formdef.roles:
1028
                        break
1029
                else:
1030
                    if formdef.always_advertise:
1031
                        formdefs_advertise.append(formdef)
1032
                    formdefs.remove(formdef)
1033

    
1034
            if not formdefs and not formdefs_advertise:
1035
                continue
1036

    
1037
            r += htmltext('<li id="category-%s">') % category.url_name
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>')
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():
1099
            r += htmltext('<form id="follow-form" action="%saccesscode">') % root_url
1100
            r += htmltext('<h3>%s</h3>') % _('Tracking')
1101
            r += htmltext('<label>%s</label> ') % _('Code:')
1102
            r += htmltext('<input name="code" size="10"/>')
1103
            r += htmltext('</form>')
1104

    
1105
        r += self.links()
1106

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

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

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

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

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

    
1144
        return None
1145

    
1146
    def has_anonymous_access_codes(self):
1147
        for workflow in Workflow.select():
1148
            for wfstatus in workflow.possible_status:
1149
                for wfitem in wfstatus.items:
1150
                    if wfitem.key == 'create-anonymous-access-code':
1151
                        return True
1152
        return False
1153

    
1154
    def accesscode(self):
1155
        code = get_request().form.get('code')
1156
        if not code:
1157
            return redirect(get_publisher().get_root_url())
1158
        try:
1159
            token = Token.get(code)
1160
        except KeyError:
1161
            return redirect(get_publisher().get_root_url())
1162
        if token.type != 'anonymous-access-code':
1163
            return redirect(get_publisher().get_root_url())
1164
        formdef_urlname, formdata_id = token.formdata_reference
1165
        try:
1166
            formdata = FormDef.get_by_urlname(formdef_urlname).data_class().get(formdata_id)
1167
        except KeyError:
1168
            return redirect(get_publisher().get_root_url())
1169
        session = get_session()
1170
        if not hasattr(session, '_wf_anonymous_access_authorized'):
1171
            session._wf_anonymous_access_authorized = []
1172
        session._wf_anonymous_access_authorized.append(formdata.get_url())
1173
        return redirect(formdata.get_url() + 'access/')
1174

    
1175
    def links(self):
1176
        links = Link.select()
1177
        if not links:
1178
            return ''
1179

    
1180
        Link.sort_by_position(links)
1181

    
1182
        r = TemplateIO(html=True)
1183

    
1184
        r += htmltext('<div id="links">')
1185
        if links[0].url:
1186
            # first link has an URL, so it's not a title, so we display a
1187
            # generic title
1188
            r += htmltext('<h3>%s</h3>') % _('Useful links')
1189
        has_ul = False
1190
        vars = get_publisher().substitutions.get_context_variables()
1191
        for link in links:
1192
            if not link.url:
1193
                # acting title
1194
                if has_ul:
1195
                    r += htmltext('</ul>')
1196
                r += htmltext('<h3>%s</h3>') % link.title
1197
                r += htmltext('<ul>')
1198
                has_ul = True
1199
            else:
1200
                if not has_ul:
1201
                    r += htmltext('<ul>')
1202
                    has_ul = True
1203
                r += htmltext('<li class="link-%s"><a href="%s">%s</a></li>') % (
1204
                        simplify(link.title), get_variadic_url(link.url, vars), link.title)
1205
        if has_ul:
1206
            r += htmltext('</ul>')
1207
        r += htmltext('</div>')
1208
        return r.getvalue()
1209

    
1210
    def announces(self):
1211
        announces = Announce.get_published_announces()
1212
        if not announces:
1213
            return
1214

    
1215
        r = TemplateIO(html=True)
1216
        r += htmltext('<div id="announces">')
1217
        r += htmltext('<h3>%s</h3>') % _('Announces to citizens')
1218
        for item in announces[:3]:
1219
            r += htmltext('<div class="announce-item">')
1220
            r += htmltext('<h4>')
1221
            if item.publication_time:
1222
                r += time.strftime(misc.date_format(), item.publication_time)
1223
                r += ' - '
1224
            r += item.title
1225
            r += htmltext('</h4>')
1226
            r += htmltext('<p>')
1227
            r += item.text
1228
            r += htmltext('</p>')
1229
            r += htmltext('</div>')
1230

    
1231
        r += htmltext('<ul id="announces-links">')
1232
        r += htmltext('<li><a href="announces/subscribe">%s</a></li>') % _('Receiving those Announces')
1233
        r += htmltext('<li><a href="announces/">%s</a></li>') % _('Previous Announces')
1234
        r += htmltext('</ul>')
1235
        r += htmltext('</div>')
1236
        return r.getvalue()
1237

    
1238
    def myspace_snippet(self):
1239
        r = TemplateIO(html=True)
1240
        r += htmltext('<div id="myspace">')
1241
        r += htmltext('<h3>%s</h3>') % _('My Space')
1242
        r += htmltext('<ul>')
1243
        if get_request().user and not get_request().user.anonymous:
1244
            r += htmltext('  <li><a href="myspace/" id="member">%s</a></li>') % _('Access to your personal space')
1245
            r += htmltext('  <li><a href="logout" id="logout">%s</a></li>') % _('Logout')
1246
        else:
1247
            r += htmltext('  <li><a href="register/" id="inscr">%s</a></li>') % _('Registration')
1248
            r += htmltext('  <li><a href="login/" id="login">%s</a></li>') % _('Login')
1249
        r += htmltext('</ul>')
1250
        r += htmltext('</div>')
1251
        return r.getvalue()
1252

    
1253
    def page_view(self, key, title, urlname = None):
1254
        if not urlname:
1255
            urlname = key[3:].replace(str('_'), str('-'))
1256
        get_response().breadcrumb.append((urlname, title))
1257
        template.html_top(title)
1258
        r = TemplateIO(html=True)
1259
        r += htmltext('<div class="article">')
1260
        r += htmltext(TextsDirectory.get_html_text(key))
1261
        r += htmltext('</div>')
1262
        return r.getvalue()
1263

    
1264
    def informations_editeur(self):
1265
        get_response().filter['bigdiv'] = 'info'
1266
        return self.page_view('aq-editor-info', _('Editor Informations'),
1267
                urlname = 'informations_editeur')
1268

    
1269
    def accessibility(self):
1270
        get_response().filter['bigdiv'] = 'accessibility'
1271
        return self.page_view('aq-accessibility', _('Accessibility Statement'))
1272

    
1273
    def contact(self):
1274
        get_response().filter['bigdiv'] = 'contact'
1275
        return self.page_view('aq-contact', _('Contact'))
1276

    
1277
    def help(self):
1278
        get_response().filter['bigdiv'] = 'help'
1279
        return self.page_view('aq-help', _('Help'))
1280

    
1281

    
1282
from qommon.publisher import get_publisher_class
1283
get_publisher_class().root_directory_class = AlternateRootDirectory
1284
get_publisher_class().after_login_url = 'myspace/'
1285
get_publisher_class().use_sms_feature = True
1286

    
1287
# help links
1288
get_publisher_class().backoffice_help_url = {
1289
    'fr': 'https://doc.entrouvert.org/au-quotidien/stable/guide-gestionnaire.html',
1290
}
1291
get_publisher_class().admin_help_url = {
1292
    'fr': 'https://doc.entrouvert.org/auquotidien/dev/',
1293
}
1294

    
1295

    
1296
EmailsDirectory.register('announces-subscription-confirmation',
1297
        N_('Confirmation of Announces Subscription'),
1298
        N_('Available variables: change_url, cancel_url, time, sitename'),
1299
        default_subject = N_('Announce Subscription Request'),
1300
        default_body = N_("""\
1301
You have (or someone impersonating you has) requested to subscribe to
1302
announces from [sitename].  To confirm this request, visit the
1303
following link:
1304

    
1305
[confirm_url]
1306

    
1307
If you are not the person who made this request, or you wish to cancel
1308
this request, visit the following link:
1309

    
1310
[cancel_url]
1311

    
1312
If you do nothing, the request will lapse after 3 days (precisely on
1313
[time]).
1314
"""))
1315

    
1316

    
1317
TextsDirectory.register('aq-announces-subscription',
1318
        N_('Text on announces subscription page'),
1319
        default = N_('''\
1320
<p>
1321
FIXME
1322
'</p>'''))
1323

    
1324
TextsDirectory.register('aq-sms-demo',
1325
        N_('Text when subscribing to announces SMS and configured as demo'),
1326
        default = N_('''
1327
<p>
1328
Receiving announces by SMS is not possible in this demo
1329
</p>'''))
1330

    
1331
TextsDirectory.register('aq-editor-info', N_('Editor Informations'))
1332
TextsDirectory.register('aq-accessibility', N_('Accessibility Statement'))
1333
TextsDirectory.register('aq-contact', N_('Contact Information'))
1334
TextsDirectory.register('aq-help', N_('Help'))
1335
TextsDirectory.register('aq-sso-text',  N_('Connecting with Identity Provider'),
1336
        default = N_('''<h3>Connecting with Identity Provider</h3>
1337
<p>You can also use your identity provider to connect.
1338
</p>'''))
1339

    
1340
TextsDirectory.register('aq-home-page', N_('Home Page'), wysiwyg = True)
(26-26/30)