Projet

Général

Profil

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

root / extra / modules / root.py @ 15327599

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
                if f.formdef.category:
95
                    category_url = '%s' % f.formdef.category.url_name
96
                else:
97
                    category_url = '.'
98
                r += htmltext('<li><a href="%s%s/%s/%s">%s</a>, %s') % (base_url,
99
                    category_url,
100
                    f.formdef.url_name, f.id, f.formdef.name,
101
                    misc.localstrftime(f.receipt_time))
102
                r += htmltext(' (<a href="%s%s/%s/%s?remove-draft">%s</a>)') % (base_url,
103
                    category_url,
104
                    f.formdef.url_name, f.id, _('delete'))
105
                r += htmltext('</li>')
106
            r += htmltext('</ul>')
107

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

    
141

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

    
145
    def __init__(self, announce):
146
        self.announce = announce
147

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

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

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

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

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

    
168

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

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

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

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

    
195
    def rawlist(self):
196
        get_response().filter = None
197
        return self.announces_list()
198

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

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

    
220

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

    
224
        if sms_mode == 'none':
225
            raise errors.TraversalError()
226

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

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

    
245
            if form.get_submit() == 'cancel':
246
                return redirect('subscribe')
247

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

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

    
282
        if mobile:
283
            sub.sms = mobile
284

    
285
        if not get_request().user:
286
            sub.enabled = False
287

    
288
        sub.store()
289

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

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

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

    
318
        if form.get_submit() == 'cancel':
319
            return redirect('..')
320

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

    
341
        return r.getvalue()
342

    
343
    def sms_unsubscribe(self):
344
        sub = self._get_announce_subscription()
345

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

    
350
        form.add_submit('submit', _('Unsubscribe'))
351
        form.add_submit('cancel', _('Cancel'))
352

    
353
        if form.get_submit() == 'cancel':
354
            return redirect('..')
355

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

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

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

    
376
        return r.getvalue()
377

    
378

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

    
384
        r += TextsDirectory.get_html_text('aq-announces-subscription')
385

    
386
        sub = self._get_announce_subscription()
387

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

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

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

    
436
        form.add_submit('cancel', _('Cancel'))
437

    
438
        if form.get_submit() == 'cancel':
439
            return redirect('subscribe')
440

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

    
448
        return r.getvalue()
449

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

    
455
        if get_request().user:
456
            sub.user_id = get_request().user.id
457

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

    
463
        if not get_request().user:
464
            sub.enabled = False
465

    
466
        sub.store()
467

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

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

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

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

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

    
505
        root_url = get_publisher().get_root_url()
506

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

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

    
519
        sub = AnnounceSubscription.get(token.subscription_id)
520

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

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

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

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

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

    
565
        announces = Announce.get_published_announces()
566

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

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

    
578
        return str(feed)
579

    
580
    def email_unsubscribe(self):
581
        sub = self._get_announce_subscription()
582

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

    
587
        form.add_submit('submit', _('Unsubscribe'))
588
        form.add_submit('cancel', _('Cancel'))
589

    
590
        if form.get_submit() == 'cancel':
591
            return redirect('..')
592

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

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

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

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

    
619
        return r.getvalue()
620

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

    
627
        if announce.hidden:
628
            raise errors.TraversalError()
629

    
630
        get_response().breadcrumb.append((str(announce.id), announce.title))
631
        return AnnounceDirectory(announce)
632

    
633
OldRegisterDirectory = wcs.root.RegisterDirectory
634

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

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

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

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

    
655
        return qommon.ident.register(method)
656

    
657
OldLoginDirectory = wcs.root.LoginDirectory
658

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

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

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

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

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

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

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

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

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

    
723
            r += htmltext('</div>')
724

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

    
739
            r += form.render()
740
            r += htmltext('</div>')
741

    
742
            get_request().environ['REQUEST_METHOD'] = 'GET'
743

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

    
751

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

    
758

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

    
764

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

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

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

    
799
    def _q_traverse(self, path):
800
        get_publisher().substitutions.feed(get_session())
801
        get_publisher().substitutions.feed(get_request().user)
802
        get_publisher().substitutions.feed(NamedDataSource)
803

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

    
811
        response = get_response()
812
        if not hasattr(response, 'filter'):
813
            response.filter = {}
814

    
815
        response.filter['auquotidien'] = True
816
        response.filter['gauche'] = self.box_side(path)
817
        response.filter['keywords'] = template.get_current_theme().get('keywords')
818
        get_publisher().substitutions.feed(self)
819

    
820
        response.breadcrumb = [ ('', _('Home')) ]
821

    
822
        if not self.admin:
823
            self.admin = get_publisher().admin_directory_class()
824

    
825
        if not self.backoffice:
826
            self.backoffice = get_publisher().backoffice_directory_class()
827

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

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

    
850
            raise e
851

    
852

    
853
    def _q_lookup(self, component):
854
        if component == 'qo':
855
            dirname = os.path.join(get_publisher().data_dir, 'qommon')
856
            return StaticDirectory(dirname, follow_symlinks = True)
857

    
858
        if component == 'aq':
859
            dirname = os.path.join(get_publisher().data_dir, 'qommon', 'auquotidien')
860
            return StaticDirectory(dirname, follow_symlinks = True)
861

    
862
        # maps /leaflet/ to the directory provided by the libjs-openlayers package
863
        if component == 'leaflet':
864
            return StaticDirectory('/usr/share/javascript/leaflet')
865

    
866
        if component in ('css','images'):
867
            return OldRootDirectory._q_lookup(self, component)
868

    
869
        # is this a category ?
870
        try:
871
            category = Category.get_by_urlname(component)
872
        except KeyError:
873
            pass
874
        else:
875
            return FormsRootDirectory(category)
876

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

    
889
            # if there is category, let it fall back to raise TraversalError,
890
            # it will get caught in _q_traverse that will redirect it to an
891
            # URL embedding the category
892

    
893
        return None
894

    
895
    def json(self):
896
        return FormsRootDirectory().json()
897

    
898
    def categories(self):
899
        return FormsRootDirectory().categories()
900

    
901
    def _q_index(self):
902
        if get_request().is_json():
903
            return FormsRootDirectory().json()
904

    
905
        root_url = get_publisher().get_root_url()
906
        if get_request().user and get_request().user.anonymous and get_request().user.lasso_dump:
907
            return redirect('%smyspace/new' % root_url)
908

    
909
        redirect_url = get_cfg('misc', {}).get('homepage-redirect-url')
910
        if redirect_url:
911
            return redirect(misc.get_variadic_url(redirect_url,
912
                get_publisher().substitutions.get_context_variables()))
913

    
914
        if get_response().iframe_mode:
915
            # never display home page in an iframe
916
            return redirect('%sservices' % root_url)
917

    
918
        template.html_top()
919
        r = TemplateIO(html=True)
920
        get_response().filter['is_index'] = True
921

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

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

    
944
        user = get_request().user
945
        if user and user.can_go_in_backoffice():
946
            get_response().filter['backoffice'] = True
947

    
948
        return r.getvalue()
949

    
950
    def services(self):
951
        template.html_top()
952
        get_response().filter['bigdiv'] = 'rub_service'
953
        return self.box_services(level = 2)
954

    
955
    def box_services(self, level=3, position=None):
956
        ## Services
957
        if get_request().user and get_request().user.roles:
958
            accepted_roles = get_request().user.roles
959
        else:
960
            accepted_roles = []
961

    
962
        cats = Category.select(order_by = 'name')
963
        cats = [x for x in cats if x.url_name != 'consultations']
964
        Category.sort_by_position(cats)
965

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

    
974
        if position:
975
            t = self.display_list_of_formdefs(
976
                            [x for x in cats if x.get_homepage_position() == position],
977
                            all_formdefs, accepted_roles)
978
        else:
979
            t = self.display_list_of_formdefs(cats, all_formdefs, accepted_roles)
980

    
981
        if not t:
982
            return
983

    
984
        r = TemplateIO(html=True)
985

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

    
995
        if get_response().iframe_mode:
996
            if get_request().user:
997
                message = TextsDirectory.get_html_text('welcome-logged')
998
            else:
999
                message = TextsDirectory.get_html_text('welcome-unlogged')
1000

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

    
1012
        r += htmltext('<ul>')
1013
        r += t
1014
        r += htmltext('</ul>')
1015

    
1016
        r += htmltext('</div>')
1017
        return r.getvalue()
1018

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

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

    
1048
            if not formdefs and not formdefs_advertise:
1049
                continue
1050

    
1051
            keywords = {}
1052
            for formdef in formdefs:
1053
                for keyword in formdef.keywords_list:
1054
                    keywords[keyword] = True
1055

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

    
1086
        return r.getvalue()
1087

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

    
1114
    def box_side(self, path):
1115
        r = TemplateIO(html=True)
1116
        root_url = get_publisher().get_root_url()
1117

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

    
1125
        r += self.links()
1126

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

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

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

    
1152
                r += htmltext('<p>')
1153
                r += htmltext('  <a href="%sagenda/filter">%s</a>') % (root_url, _('Advanced Filter'))
1154
                r += htmltext('</p>')
1155

    
1156
        v = r.getvalue()
1157
        if v:
1158
            r = TemplateIO(html=True)
1159
            r += htmltext('<div id="sidebox">')
1160
            r += v
1161
            r += htmltext('</div>')
1162
            return r.getvalue()
1163

    
1164
        return None
1165

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

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

    
1195
    def links(self):
1196
        links = Link.select()
1197
        if not links:
1198
            return ''
1199

    
1200
        Link.sort_by_position(links)
1201

    
1202
        r = TemplateIO(html=True)
1203

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

    
1230
    def announces(self):
1231
        announces = Announce.get_published_announces()
1232
        if not announces:
1233
            return
1234

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

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

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

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

    
1284
    def informations_editeur(self):
1285
        get_response().filter['bigdiv'] = 'info'
1286
        return self.page_view('aq-editor-info', _('Editor Informations'),
1287
                urlname = 'informations_editeur')
1288

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

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

    
1297
    def help(self):
1298
        get_response().filter['bigdiv'] = 'help'
1299
        return self.page_view('aq-help', _('Help'))
1300

    
1301

    
1302
from qommon.publisher import get_publisher_class
1303
get_publisher_class().root_directory_class = AlternateRootDirectory
1304
get_publisher_class().after_login_url = 'myspace/'
1305
get_publisher_class().use_sms_feature = True
1306

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

    
1315

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

    
1325
[confirm_url]
1326

    
1327
If you are not the person who made this request, or you wish to cancel
1328
this request, visit the following link:
1329

    
1330
[cancel_url]
1331

    
1332
If you do nothing, the request will lapse after 3 days (precisely on
1333
[time]).
1334
"""))
1335

    
1336

    
1337
TextsDirectory.register('aq-announces-subscription',
1338
        N_('Text on announces subscription page'),
1339
        default = N_('''\
1340
<p>
1341
FIXME
1342
'</p>'''))
1343

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

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

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