Projet

Général

Profil

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

root / extra / modules / root.py @ 78e14232

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
                    # 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_id:
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
        if component == 'qo':
850
            dirname = os.path.join(get_publisher().data_dir, 'qommon')
851
            return StaticDirectory(dirname, follow_symlinks = True)
852

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

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

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

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

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

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

    
888
        return None
889

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

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

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

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

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

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

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

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

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

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

    
943
        return r.getvalue()
944

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

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

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

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

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

    
976
        if not t:
977
            return
978

    
979
        r = TemplateIO(html=True)
980

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

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

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

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

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

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

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

    
1043
            if not formdefs and not formdefs_advertise:
1044
                continue
1045

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

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

    
1081
        return r.getvalue()
1082

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

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

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

    
1120
        r += self.links()
1121

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

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

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

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

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

    
1159
        return None
1160

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

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

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

    
1195
        Link.sort_by_position(links)
1196

    
1197
        r = TemplateIO(html=True)
1198

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

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

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

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

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

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

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

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

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

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

    
1296

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

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

    
1310

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

    
1320
[confirm_url]
1321

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

    
1325
[cancel_url]
1326

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

    
1331

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

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

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

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