author | Sylvain Thénault <sylvain.thenault@logilab.fr> |
Fri, 21 Aug 2009 15:03:00 +0200 | |
branch | stable |
changeset 2960 | 1c6eafc68586 |
parent 2870 | e3a5b7c3f767 |
child 2880 | bfc8e1831290 |
child 3144 | a5deac822a13 |
permissions | -rw-r--r-- |
0 | 1 |
# -*- coding: utf-8 -*- |
2 |
"""Set of base controllers, which are directly plugged into the application |
|
3 |
object to handle publication. |
|
4 |
||
5 |
||
6 |
:organization: Logilab |
|
1977
606923dff11b
big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1889
diff
changeset
|
7 |
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
0 | 8 |
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
1977
606923dff11b
big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1889
diff
changeset
|
9 |
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
0 | 10 |
""" |
11 |
__docformat__ = "restructuredtext en" |
|
12 |
||
13 |
from smtplib import SMTP |
|
14 |
||
15 |
import simplejson |
|
16 |
||
17 |
from logilab.common.decorators import cached |
|
18 |
||
945
912b604f0e42
missing import
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
882
diff
changeset
|
19 |
from cubicweb import NoSelectableObject, ValidationError, ObjectNotFound, typed_eid |
1016
26387b836099
use datetime instead of mx.DateTime
sylvain.thenault@logilab.fr
parents:
945
diff
changeset
|
20 |
from cubicweb.utils import strptime |
692
800592b8d39b
replace deprecated cubicweb.common.selectors by its new module path (cubicweb.selectors)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
644
diff
changeset
|
21 |
from cubicweb.selectors import yes, match_user_groups |
1838
d4cbcc15c01c
work-around for #343301 (display garbage in non xhtml browsers)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1798
diff
changeset
|
22 |
from cubicweb.view import STRICT_DOCTYPE, STRICT_DOCTYPE_NOEXT |
0 | 23 |
from cubicweb.common.mail import format_mail |
1635
866563e2d0fc
don't depends on simplejson outside web/
sylvain.thenault@logilab.fr
parents:
1560
diff
changeset
|
24 |
from cubicweb.web import ExplicitLogin, Redirect, RemoteCallFailed, json_dumps |
0 | 25 |
from cubicweb.web.controller import Controller |
26 |
from cubicweb.web.views import vid_from_rset |
|
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
27 |
from cubicweb.web.views.formrenderers import FormRenderer |
0 | 28 |
try: |
29 |
from cubicweb.web.facet import (FilterRQLBuilder, get_facet, |
|
408
a8814ff6824e
reactivate tests and fix bug triggering removal of undesired relation (eg type restriction) in some cases
sylvain.thenault@logilab.fr
parents:
353
diff
changeset
|
30 |
prepare_facets_rqlst) |
0 | 31 |
HAS_SEARCH_RESTRICTION = True |
32 |
except ImportError: # gae |
|
33 |
HAS_SEARCH_RESTRICTION = False |
|
1419 | 34 |
|
35 |
def jsonize(func): |
|
36 |
"""decorator to sets correct content_type and calls `simplejson.dumps` on |
|
37 |
results |
|
38 |
""" |
|
39 |
def wrapper(self, *args, **kwargs): |
|
40 |
self.req.set_content_type('application/json') |
|
1635
866563e2d0fc
don't depends on simplejson outside web/
sylvain.thenault@logilab.fr
parents:
1560
diff
changeset
|
41 |
return json_dumps(func(self, *args, **kwargs)) |
1527
c8ca1782e252
controller fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1467
diff
changeset
|
42 |
wrapper.__name__ = func.__name__ |
1419 | 43 |
return wrapper |
44 |
||
45 |
def xhtmlize(func): |
|
46 |
"""decorator to sets correct content_type and calls `xmlize` on results""" |
|
47 |
def wrapper(self, *args, **kwargs): |
|
48 |
self.req.set_content_type(self.req.html_content_type()) |
|
49 |
result = func(self, *args, **kwargs) |
|
2559
46859078c866
[R xhtml] remove xhtml_wrap* function, use instead a single req.document_surrounding_div method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2557
diff
changeset
|
50 |
return ''.join((self.req.document_surrounding_div(), result.strip(), |
46859078c866
[R xhtml] remove xhtml_wrap* function, use instead a single req.document_surrounding_div method
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2557
diff
changeset
|
51 |
u'</div>')) |
1527
c8ca1782e252
controller fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1467
diff
changeset
|
52 |
wrapper.__name__ = func.__name__ |
1419 | 53 |
return wrapper |
54 |
||
55 |
def check_pageid(func): |
|
56 |
"""decorator which checks the given pageid is found in the |
|
57 |
user's session data |
|
58 |
""" |
|
59 |
def wrapper(self, *args, **kwargs): |
|
60 |
data = self.req.get_session_data(self.req.pageid) |
|
61 |
if data is None: |
|
62 |
raise RemoteCallFailed(self.req._('pageid-not-found')) |
|
63 |
return func(self, *args, **kwargs) |
|
64 |
return wrapper |
|
65 |
||
66 |
||
0 | 67 |
class LoginController(Controller): |
68 |
id = 'login' |
|
69 |
||
70 |
def publish(self, rset=None): |
|
2476
1294a6bdf3bf
application -> instance where it makes sense
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2458
diff
changeset
|
71 |
"""log in the instance""" |
0 | 72 |
if self.config['auth-mode'] == 'http': |
73 |
# HTTP authentication |
|
74 |
raise ExplicitLogin() |
|
75 |
else: |
|
76 |
# Cookie authentication |
|
77 |
return self.appli.need_login_content(self.req) |
|
78 |
||
1419 | 79 |
|
0 | 80 |
class LogoutController(Controller): |
81 |
id = 'logout' |
|
1419 | 82 |
|
0 | 83 |
def publish(self, rset=None): |
2476
1294a6bdf3bf
application -> instance where it makes sense
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2458
diff
changeset
|
84 |
"""logout from the instance""" |
0 | 85 |
return self.appli.session_handler.logout(self.req) |
86 |
||
87 |
||
88 |
class ViewController(Controller): |
|
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
89 |
"""standard entry point : |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
90 |
- build result set |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
91 |
- select and call main template |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
92 |
""" |
0 | 93 |
id = 'view' |
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
94 |
template = 'main-template' |
1419 | 95 |
|
0 | 96 |
def publish(self, rset=None): |
97 |
"""publish a request, returning an encoded string""" |
|
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
98 |
view, rset = self._select_view_and_rset(rset) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
99 |
self.add_to_breadcrumbs(view) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
100 |
self.validate_cache(view) |
882
75488a2a875e
fix ui.main-template property handling
sylvain.thenault@logilab.fr
parents:
823
diff
changeset
|
101 |
template = self.appli.main_template_id(self.req) |
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
102 |
return self.vreg['views'].main_template(self.req, template, |
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
103 |
rset=rset, view=view) |
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
104 |
|
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
105 |
def _select_view_and_rset(self, rset): |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
106 |
req = self.req |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
107 |
if rset is None and not hasattr(req, '_rql_processed'): |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
108 |
req._rql_processed = True |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
109 |
rset = self.process_rql(req.form.get('rql')) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
110 |
if rset and rset.rowcount == 1 and '__method' in req.form: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
111 |
entity = rset.get_entity(0, 0) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
112 |
try: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
113 |
method = getattr(entity, req.form.pop('__method')) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
114 |
method() |
1827
93840d187f26
allow the __method() hook to raise a Redirect exception
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1798
diff
changeset
|
115 |
except Redirect: # propagate redirect that might occur in method() |
93840d187f26
allow the __method() hook to raise a Redirect exception
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1798
diff
changeset
|
116 |
raise |
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
117 |
except Exception, ex: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
118 |
self.exception('while handling __method') |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
119 |
req.set_message(req._("error while handling __method: %s") % req._(ex)) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
120 |
vid = req.form.get('vid') or vid_from_rset(req, rset, self.schema) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
121 |
try: |
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
122 |
view = self.vreg['views'].select(vid, req, rset=rset) |
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
123 |
except ObjectNotFound: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
124 |
self.warning("the view %s could not be found", vid) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
125 |
req.set_message(req._("The view %s could not be found") % vid) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
126 |
vid = vid_from_rset(req, rset, self.schema) |
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
127 |
view = self.vreg['views'].select(vid, req, rset=rset) |
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
128 |
except NoSelectableObject: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
129 |
if rset: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
130 |
req.set_message(req._("The view %s can not be applied to this query") % vid) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
131 |
else: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
132 |
req.set_message(req._("You have no access to this view or it's not applyable to current data")) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
133 |
self.warning("the view %s can not be applied to this query", vid) |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
134 |
vid = vid_from_rset(req, rset, self.schema) |
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
135 |
view = self.vreg['views'].select(vid, req, rset=rset) |
823
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
136 |
return view, rset |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
137 |
|
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
138 |
def add_to_breadcrumbs(self, view): |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
139 |
# update breadcrumps **before** validating cache, unless the view |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
140 |
# specifies explicitly it should not be added to breadcrumb or the |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
141 |
# view is a binary view |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
142 |
if view.add_to_breadcrumbs and not view.binary: |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
143 |
self.req.update_breadcrumbs() |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
144 |
|
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
145 |
def validate_cache(self, view): |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
146 |
view.set_http_cache_headers() |
cb8ccbef8fa5
main template refactoring
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
808
diff
changeset
|
147 |
self.req.validate_cache() |
0 | 148 |
|
149 |
def execute_linkto(self, eid=None): |
|
150 |
"""XXX __linkto parameter may cause security issue |
|
151 |
||
152 |
defined here since custom application controller inheriting from this |
|
153 |
one use this method? |
|
154 |
""" |
|
155 |
req = self.req |
|
156 |
if not '__linkto' in req.form: |
|
157 |
return |
|
158 |
if eid is None: |
|
159 |
eid = typed_eid(req.form['eid']) |
|
160 |
for linkto in req.list_form_param('__linkto', pop=True): |
|
161 |
rtype, eids, target = linkto.split(':') |
|
162 |
assert target in ('subject', 'object') |
|
163 |
eids = eids.split('_') |
|
164 |
if target == 'subject': |
|
165 |
rql = 'SET X %s Y WHERE X eid %%(x)s, Y eid %%(y)s' % rtype |
|
166 |
else: |
|
167 |
rql = 'SET Y %s X WHERE X eid %%(x)s, Y eid %%(y)s' % rtype |
|
168 |
for teid in eids: |
|
1419 | 169 |
req.execute(rql, {'x': eid, 'y': typed_eid(teid)}, ('x', 'y')) |
0 | 170 |
|
171 |
||
2240
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
172 |
def _validation_error(req, ex): |
2293 | 173 |
req.cnx.rollback() |
2240
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
174 |
forminfo = req.get_session_data(req.form.get('__errorurl'), pop=True) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
175 |
foreid = ex.entity |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
176 |
eidmap = req.data.get('eidmap', {}) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
177 |
for var, eid in eidmap.items(): |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
178 |
if foreid == eid: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
179 |
foreid = var |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
180 |
break |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
181 |
return (foreid, ex.errors) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
182 |
|
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
183 |
def _validate_form(req, vreg): |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
184 |
# XXX should use the `RemoteCallFailed` mechanism |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
185 |
try: |
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
186 |
ctrl = vreg['controllers'].select('edit', req=req) |
2240
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
187 |
except NoSelectableObject: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
188 |
return (False, {None: req._('not authorized')}) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
189 |
try: |
2255
c346af0727ca
more generic way to detect json requests (not yet perfect though)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2240
diff
changeset
|
190 |
ctrl.publish(None) |
2240
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
191 |
except ValidationError, ex: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
192 |
return (False, _validation_error(req, ex)) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
193 |
except Redirect, ex: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
194 |
try: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
195 |
req.cnx.commit() # ValidationError may be raise on commit |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
196 |
except ValidationError, ex: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
197 |
return (False, _validation_error(req, ex)) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
198 |
else: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
199 |
return (True, ex.location) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
200 |
except Exception, ex: |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
201 |
req.cnx.rollback() |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
202 |
req.exception('unexpected error while validating form') |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
203 |
return (False, req._(str(ex).decode('utf-8'))) |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
204 |
return (False, '???') |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
205 |
|
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
206 |
|
0 | 207 |
class FormValidatorController(Controller): |
208 |
id = 'validateform' |
|
209 |
||
2557
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
210 |
def response(self, domid, status, args): |
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
211 |
self.req.set_content_type('text/html') |
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
212 |
jsargs = simplejson.dumps( (status, args) ) |
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
213 |
return """<script type="text/javascript"> |
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
214 |
window.parent.handleFormValidationResponse('%s', null, null, %s); |
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
215 |
</script>""" % (domid, jsargs) |
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
216 |
|
0 | 217 |
def publish(self, rset=None): |
2255
c346af0727ca
more generic way to detect json requests (not yet perfect though)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2240
diff
changeset
|
218 |
self.req.json_request = True |
2240
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
219 |
# XXX unclear why we have a separated controller here vs |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
220 |
# js_validate_form on the json controller |
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
221 |
status, args = _validate_form(self.req, self.vreg) |
2045
bf0643d4ef36
add __domid hidden input in forms so that we can validate more than one form per page
Florent <florent@secondweb.fr>
parents:
1996
diff
changeset
|
222 |
domid = self.req.form.get('__domid', 'entityForm').encode( |
bf0643d4ef36
add __domid hidden input in forms so that we can validate more than one form per page
Florent <florent@secondweb.fr>
parents:
1996
diff
changeset
|
223 |
self.req.encoding) |
2557
200985d3258d
make it easy to change response of FormValidatorController
Florent <florent@secondweb.fr>
parents:
2555
diff
changeset
|
224 |
return self.response(domid, status, args) |
0 | 225 |
|
226 |
||
227 |
class JSonController(Controller): |
|
228 |
id = 'json' |
|
229 |
||
230 |
def publish(self, rset=None): |
|
1419 | 231 |
"""call js_* methods. Expected form keys: |
232 |
||
233 |
:fname: the method name without the js_ prefix |
|
234 |
:args: arguments list (json) |
|
235 |
||
236 |
note: it's the responsability of js_* methods to set the correct |
|
237 |
response content type |
|
238 |
""" |
|
2255
c346af0727ca
more generic way to detect json requests (not yet perfect though)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2240
diff
changeset
|
239 |
self.req.json_request = True |
0 | 240 |
self.req.pageid = self.req.form.get('pageid') |
1419 | 241 |
try: |
2079
aff0950c54c4
proper error when fname isn't specified
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2045
diff
changeset
|
242 |
fname = self.req.form['fname'] |
1419 | 243 |
func = getattr(self, 'js_%s' % fname) |
2079
aff0950c54c4
proper error when fname isn't specified
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2045
diff
changeset
|
244 |
except KeyError: |
aff0950c54c4
proper error when fname isn't specified
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2045
diff
changeset
|
245 |
raise RemoteCallFailed('no method specified') |
1419 | 246 |
except AttributeError: |
247 |
raise RemoteCallFailed('no %s method' % fname) |
|
248 |
# no <arg> attribute means the callback takes no argument |
|
249 |
args = self.req.form.get('arg', ()) |
|
250 |
if not isinstance(args, (list, tuple)): |
|
251 |
args = (args,) |
|
252 |
args = [simplejson.loads(arg) for arg in args] |
|
0 | 253 |
try: |
1419 | 254 |
result = func(*args) |
255 |
except RemoteCallFailed: |
|
256 |
raise |
|
257 |
except Exception, ex: |
|
2058
7ef12c03447c
nicer vreg api, try to make rset an optional named argument in select and derivated (including selectors)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2045
diff
changeset
|
258 |
import traceback |
7ef12c03447c
nicer vreg api, try to make rset an optional named argument in select and derivated (including selectors)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2045
diff
changeset
|
259 |
traceback.print_exc() |
1419 | 260 |
self.exception('an exception occured while calling js_%s(%s): %s', |
261 |
fname, args, ex) |
|
262 |
raise RemoteCallFailed(repr(ex)) |
|
263 |
if result is None: |
|
264 |
return '' |
|
265 |
# get unicode on @htmlize methods, encoded string on @jsonize methods |
|
266 |
elif isinstance(result, unicode): |
|
267 |
return result.encode(self.req.encoding) |
|
268 |
return result |
|
269 |
||
270 |
def _rebuild_posted_form(self, names, values, action=None): |
|
271 |
form = {} |
|
272 |
for name, value in zip(names, values): |
|
273 |
# remove possible __action_xxx inputs |
|
274 |
if name.startswith('__action'): |
|
275 |
continue |
|
276 |
# form.setdefault(name, []).append(value) |
|
277 |
if name in form: |
|
278 |
curvalue = form[name] |
|
279 |
if isinstance(curvalue, list): |
|
280 |
curvalue.append(value) |
|
281 |
else: |
|
282 |
form[name] = [curvalue, value] |
|
283 |
else: |
|
284 |
form[name] = value |
|
285 |
# simulate click on __action_%s button to help the controller |
|
286 |
if action: |
|
287 |
form['__action_%s' % action] = u'whatever' |
|
288 |
return form |
|
0 | 289 |
|
290 |
def _exec(self, rql, args=None, eidkey=None, rocheck=True): |
|
291 |
"""json mode: execute RQL and return resultset as json""" |
|
292 |
if rocheck: |
|
293 |
self.ensure_ro_rql(rql) |
|
294 |
try: |
|
295 |
return self.req.execute(rql, args, eidkey) |
|
296 |
except Exception, ex: |
|
297 |
self.exception("error in _exec(rql=%s): %s", rql, ex) |
|
298 |
return None |
|
299 |
return None |
|
300 |
||
2852
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
301 |
def _call_view(self, view, **kwargs): |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
302 |
req = self.req |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
303 |
divid = req.form.get('divid', 'pageContent') |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
304 |
# we need to call pagination before with the stream set |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
305 |
stream = view.set_stream() |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
306 |
if req.form.get('paginate'): |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
307 |
if divid == 'pageContent': |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
308 |
# mimick main template behaviour |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
309 |
stream.write(u'<div id="pageContent">') |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
310 |
vtitle = self.req.form.get('vtitle') |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
311 |
if vtitle: |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
312 |
stream.write(u'<h1 class="vtitle">%s</h1>\n' % vtitle) |
2870
e3a5b7c3f767
use view.paginate
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2862
diff
changeset
|
313 |
view.paginate() |
2852
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
314 |
if divid == 'pageContent': |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
315 |
stream.write(u'<div id="contentmain">') |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
316 |
view.render(**kwargs) |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
317 |
extresources = req.html_headers.getvalue(skiphead=True) |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
318 |
if extresources: |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
319 |
stream.write(u'<div class="ajaxHtmlHead">\n') # XXX use a widget ? |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
320 |
stream.write(extresources) |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
321 |
stream.write(u'</div>\n') |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
322 |
if req.form.get('paginate') and divid == 'pageContent': |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
323 |
stream.write(u'</div></div>') |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
324 |
return stream.getvalue() |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
325 |
|
1419 | 326 |
@xhtmlize |
327 |
def js_view(self): |
|
643
616191014b8b
[jsoncontroller] reorganize _html_exec (used by replacePageChunk) to output required css and js scripts
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
603
diff
changeset
|
328 |
# XXX try to use the page-content template |
0 | 329 |
req = self.req |
330 |
rql = req.form.get('rql') |
|
1419 | 331 |
if rql: |
0 | 332 |
rset = self._exec(rql) |
1419 | 333 |
else: |
334 |
rset = None |
|
0 | 335 |
vid = req.form.get('vid') or vid_from_rset(req, rset, self.schema) |
336 |
try: |
|
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
337 |
view = self.vreg['views'].select(vid, req, rset=rset) |
0 | 338 |
except NoSelectableObject: |
339 |
vid = req.form.get('fallbackvid', 'noresult') |
|
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
340 |
view = self.vreg['views'].select(vid, req, rset=rset) |
2852
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
341 |
return self._call_view(view) |
0 | 342 |
|
1419 | 343 |
@xhtmlize |
344 |
def js_prop_widget(self, propkey, varname, tabindex=None): |
|
345 |
"""specific method for CWProperty handling""" |
|
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
346 |
entity = self.vreg['etypes'].etype_class('CWProperty')(self.req) |
1419 | 347 |
entity.eid = varname |
348 |
entity['pkey'] = propkey |
|
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
349 |
form = self.vreg['forms'].select('edition', self.req, entity=entity) |
1419 | 350 |
form.form_build_context() |
351 |
vfield = form.field_by_name('value') |
|
1995
ec95eaa2b711
turn renderers into appobjects
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
352 |
renderer = FormRenderer(self.req) |
1419 | 353 |
return vfield.render(form, renderer, tabindex=tabindex) \ |
354 |
+ renderer.render_help(form, vfield) |
|
0 | 355 |
|
1419 | 356 |
@xhtmlize |
357 |
def js_component(self, compid, rql, registry='components', extraargs=None): |
|
358 |
if rql: |
|
359 |
rset = self._exec(rql) |
|
360 |
else: |
|
361 |
rset = None |
|
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
362 |
comp = self.vreg[registry].select(compid, self.req, rset=rset) |
1419 | 363 |
if extraargs is None: |
364 |
extraargs = {} |
|
365 |
else: # we receive unicode keys which is not supported by the **syntax |
|
366 |
extraargs = dict((str(key), value) |
|
367 |
for key, value in extraargs.items()) |
|
368 |
extraargs = extraargs or {} |
|
1723 | 369 |
return comp.render(**extraargs) |
1419 | 370 |
|
371 |
@check_pageid |
|
372 |
@xhtmlize |
|
373 |
def js_inline_creation_form(self, peid, ttype, rtype, role): |
|
2650
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
374 |
view = self.vreg['views'].select('inline-creation', self.req, |
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
375 |
etype=ttype, peid=peid, rtype=rtype, |
18aec79ec3a3
R [vreg] important refactoring of the vregistry, moving behaviour to end dictionnary (and so leaving room for more flexibility ; keep bw compat ; update api usage in cw
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2559
diff
changeset
|
376 |
role=role) |
2852
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
377 |
return self._call_view(view, etype=ttype, peid=peid, |
858b33162e9d
[ajax] allow inlineCreationForms to add their own JS / CSS
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
2681
diff
changeset
|
378 |
rtype=rtype, role=role) |
1419 | 379 |
|
380 |
@jsonize |
|
0 | 381 |
def js_validate_form(self, action, names, values): |
1527
c8ca1782e252
controller fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1467
diff
changeset
|
382 |
return self.validate_form(action, names, values) |
c8ca1782e252
controller fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1467
diff
changeset
|
383 |
|
c8ca1782e252
controller fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1467
diff
changeset
|
384 |
def validate_form(self, action, names, values): |
0 | 385 |
self.req.form = self._rebuild_posted_form(names, values, action) |
2240
ff84892900ac
factorize form validation code, fix pb with validation error in inlined forms during creation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2079
diff
changeset
|
386 |
return _validate_form(self.req, self.vreg) |
0 | 387 |
|
1419 | 388 |
@jsonize |
2345
16e3d0e47ee6
[reledit] there is nothing to escape, also cleanup lzone for attributes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
2330
diff
changeset
|
389 |
def js_edit_field(self, action, names, values, rtype, eid, default): |
1527
c8ca1782e252
controller fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1467
diff
changeset
|
390 |
success, args = self.validate_form(action, names, values) |
0 | 391 |
if success: |
1560
7dd2a81b8bc8
[basecontrollers] add edit_relation next to edit_field, misc notes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1527
diff
changeset
|
392 |
# Any X,N where we don't seem to use N is an optimisation |
7dd2a81b8bc8
[basecontrollers] add edit_relation next to edit_field, misc notes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1527
diff
changeset
|
393 |
# printable_value won't need to query N again |
0 | 394 |
rset = self.req.execute('Any X,N WHERE X eid %%(x)s, X %s N' % rtype, |
395 |
{'x': eid}, 'x') |
|
396 |
entity = rset.get_entity(0, 0) |
|
2330
8c70ca715fe9
[reledit] have a link-free landing zone for mouse-clicks (closes #343544)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
2312
diff
changeset
|
397 |
value = entity.printable_value(rtype) or default |
2345
16e3d0e47ee6
[reledit] there is nothing to escape, also cleanup lzone for attributes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
2330
diff
changeset
|
398 |
return (success, args, value) |
0 | 399 |
else: |
400 |
return (success, args, None) |
|
1419 | 401 |
|
1560
7dd2a81b8bc8
[basecontrollers] add edit_relation next to edit_field, misc notes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1527
diff
changeset
|
402 |
@jsonize |
2382
c1dcb5aef4b4
[reledit] simplify a bit more
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
2371
diff
changeset
|
403 |
def js_reledit_form(self, eid, rtype, role, default, lzone): |
c1dcb5aef4b4
[reledit] simplify a bit more
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
2371
diff
changeset
|
404 |
"""XXX we should get rid of this and use loadxhtml""" |
2680
66472d85d548
[R] use req.entity_from_eid
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2650
diff
changeset
|
405 |
entity = self.req.entity_from_eid(eid) |
2371
76bf522c27be
[reledit] simplify, fixing #344545
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
2345
diff
changeset
|
406 |
return entity.view('reledit', rtype=rtype, role=role, |
2382
c1dcb5aef4b4
[reledit] simplify a bit more
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
2371
diff
changeset
|
407 |
default=default, landing_zone=lzone) |
1759
61d026ced19f
preliminary support for inline edition of relations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1736
diff
changeset
|
408 |
|
61d026ced19f
preliminary support for inline edition of relations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1736
diff
changeset
|
409 |
@jsonize |
0 | 410 |
def js_i18n(self, msgids): |
411 |
"""returns the translation of `msgid`""" |
|
412 |
return [self.req._(msgid) for msgid in msgids] |
|
413 |
||
1419 | 414 |
@jsonize |
0 | 415 |
def js_format_date(self, strdate): |
416 |
"""returns the formatted date for `msgid`""" |
|
1380 | 417 |
date = strptime(strdate, '%Y-%m-%d %H:%M:%S') |
0 | 418 |
return self.format_date(date) |
419 |
||
1419 | 420 |
@jsonize |
0 | 421 |
def js_external_resource(self, resource): |
422 |
"""returns the URL of the external resource named `resource`""" |
|
423 |
return self.req.external_resource(resource) |
|
424 |
||
425 |
@check_pageid |
|
1419 | 426 |
@jsonize |
0 | 427 |
def js_user_callback(self, cbname): |
428 |
page_data = self.req.get_session_data(self.req.pageid, {}) |
|
429 |
try: |
|
430 |
cb = page_data[cbname] |
|
431 |
except KeyError: |
|
432 |
return None |
|
433 |
return cb(self.req) |
|
434 |
||
435 |
if HAS_SEARCH_RESTRICTION: |
|
1419 | 436 |
@jsonize |
0 | 437 |
def js_filter_build_rql(self, names, values): |
438 |
form = self._rebuild_posted_form(names, values) |
|
439 |
self.req.form = form |
|
440 |
builder = FilterRQLBuilder(self.req) |
|
441 |
return builder.build_rql() |
|
442 |
||
1419 | 443 |
@jsonize |
0 | 444 |
def js_filter_select_content(self, facetids, rql): |
445 |
rqlst = self.vreg.parse(self.req, rql) # XXX Union unsupported yet |
|
446 |
mainvar = prepare_facets_rqlst(rqlst)[0] |
|
447 |
update_map = {} |
|
448 |
for facetid in facetids: |
|
449 |
facet = get_facet(self.req, facetid, rqlst.children[0], mainvar) |
|
450 |
update_map[facetid] = facet.possible_values() |
|
451 |
return update_map |
|
452 |
||
1419 | 453 |
def js_unregister_user_callback(self, cbname): |
454 |
self.req.unregister_callback(self.req.pageid, cbname) |
|
455 |
||
456 |
def js_unload_page_data(self): |
|
457 |
self.req.del_session_data(self.req.pageid) |
|
458 |
||
459 |
def js_cancel_edition(self, errorurl): |
|
460 |
"""cancelling edition from javascript |
|
461 |
||
462 |
We need to clear associated req's data : |
|
463 |
- errorurl |
|
464 |
- pending insertions / deletions |
|
465 |
""" |
|
466 |
self.req.cancel_edition(errorurl) |
|
467 |
||
0 | 468 |
def js_delete_bookmark(self, beid): |
1419 | 469 |
rql = 'DELETE B bookmarked_by U WHERE B eid %(b)s, U eid %(u)s' |
470 |
self.req.execute(rql, {'b': typed_eid(beid), 'u' : self.req.user.eid}) |
|
471 |
||
1844
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
472 |
def js_node_clicked(self, treeid, nodeeid): |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
473 |
"""add/remove eid in treestate cookie""" |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
474 |
from cubicweb.web.views.treeview import treecookiename |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
475 |
cookies = self.req.get_cookie() |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
476 |
statename = treecookiename(treeid) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
477 |
treestate = cookies.get(statename) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
478 |
if treestate is None: |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
479 |
cookies[statename] = nodeeid |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
480 |
self.req.set_cookie(cookies, statename) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
481 |
else: |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
482 |
marked = set(filter(None, treestate.value.split(';'))) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
483 |
if nodeeid in marked: |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
484 |
marked.remove(nodeeid) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
485 |
else: |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
486 |
marked.add(nodeeid) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
487 |
cookies[statename] = ';'.join(marked) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
488 |
self.req.set_cookie(cookies, statename) |
ec51bf1b8be3
avoid monkeypatching JsonController in cw, to avoid _potential_ load order problems
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
1839
diff
changeset
|
489 |
|
1419 | 490 |
def js_set_cookie(self, cookiename, cookievalue): |
491 |
# XXX we should consider jQuery.Cookie |
|
492 |
cookiename, cookievalue = str(cookiename), str(cookievalue) |
|
493 |
cookies = self.req.get_cookie() |
|
494 |
cookies[cookiename] = cookievalue |
|
495 |
self.req.set_cookie(cookies, cookiename) |
|
496 |
||
497 |
# relations edition stuff ################################################## |
|
0 | 498 |
|
499 |
def _add_pending(self, eidfrom, rel, eidto, kind): |
|
500 |
key = 'pending_%s' % kind |
|
501 |
pendings = self.req.get_session_data(key, set()) |
|
502 |
pendings.add( (typed_eid(eidfrom), rel, typed_eid(eidto)) ) |
|
503 |
self.req.set_session_data(key, pendings) |
|
504 |
||
505 |
def _remove_pending(self, eidfrom, rel, eidto, kind): |
|
1419 | 506 |
key = 'pending_%s' % kind |
1713
d817f23439ba
bix a bug: correct the sended parameter 'no need for id in the string parameter name'
Graziella Toutoungis <graziella.toutoungis@logilab.fr>
parents:
1635
diff
changeset
|
507 |
pendings = self.req.get_session_data(key) |
d817f23439ba
bix a bug: correct the sended parameter 'no need for id in the string parameter name'
Graziella Toutoungis <graziella.toutoungis@logilab.fr>
parents:
1635
diff
changeset
|
508 |
pendings.remove( (typed_eid(eidfrom), rel, typed_eid(eidto)) ) |
d817f23439ba
bix a bug: correct the sended parameter 'no need for id in the string parameter name'
Graziella Toutoungis <graziella.toutoungis@logilab.fr>
parents:
1635
diff
changeset
|
509 |
self.req.set_session_data(key, pendings) |
0 | 510 |
|
1419 | 511 |
def js_remove_pending_insert(self, (eidfrom, rel, eidto)): |
512 |
self._remove_pending(eidfrom, rel, eidto, 'insert') |
|
513 |
||
514 |
def js_add_pending_inserts(self, tripletlist): |
|
515 |
for eidfrom, rel, eidto in tripletlist: |
|
516 |
self._add_pending(eidfrom, rel, eidto, 'insert') |
|
517 |
||
518 |
def js_remove_pending_delete(self, (eidfrom, rel, eidto)): |
|
519 |
self._remove_pending(eidfrom, rel, eidto, 'delete') |
|
520 |
||
521 |
def js_add_pending_delete(self, (eidfrom, rel, eidto)): |
|
522 |
self._add_pending(eidfrom, rel, eidto, 'delete') |
|
523 |
||
524 |
# XXX specific code. Kill me and my AddComboBox friend |
|
525 |
@jsonize |
|
0 | 526 |
def js_add_and_link_new_entity(self, etype_to, rel, eid_to, etype_from, value_from): |
527 |
# create a new entity |
|
528 |
eid_from = self.req.execute('INSERT %s T : T name "%s"' % ( etype_from, value_from ))[0][0] |
|
529 |
# link the new entity to the main entity |
|
530 |
rql = 'SET F %(rel)s T WHERE F eid %(eid_to)s, T eid %(eid_from)s' % {'rel' : rel, 'eid_to' : eid_to, 'eid_from' : eid_from} |
|
531 |
return eid_from |
|
603
18c6c31bbaf4
[controllers] a set_cookie method
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
581
diff
changeset
|
532 |
|
18c6c31bbaf4
[controllers] a set_cookie method
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents:
581
diff
changeset
|
533 |
|
0 | 534 |
class SendMailController(Controller): |
535 |
id = 'sendmail' |
|
742
99115e029dca
replaced most of __selectors__ assignments with __select__
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
692
diff
changeset
|
536 |
__select__ = match_user_groups('managers', 'users') |
0 | 537 |
|
538 |
def recipients(self): |
|
539 |
"""returns an iterator on email's recipients as entities""" |
|
540 |
eids = self.req.form['recipient'] |
|
541 |
# make sure we have a list even though only one recipient was specified |
|
542 |
if isinstance(eids, basestring): |
|
543 |
eids = (eids,) |
|
544 |
rql = 'Any X WHERE X eid in (%s)' % (','.join(eids)) |
|
545 |
rset = self.req.execute(rql) |
|
546 |
for entity in rset.entities(): |
|
547 |
entity.complete() # XXX really? |
|
548 |
yield entity |
|
549 |
||
550 |
@property |
|
551 |
@cached |
|
552 |
def smtp(self): |
|
553 |
mailhost, port = self.config['smtp-host'], self.config['smtp-port'] |
|
554 |
try: |
|
555 |
return SMTP(mailhost, port) |
|
556 |
except Exception, ex: |
|
557 |
self.exception("can't connect to smtp server %s:%s (%s)", |
|
558 |
mailhost, port, ex) |
|
559 |
url = self.build_url(__message=self.req._('could not connect to the SMTP server')) |
|
560 |
raise Redirect(url) |
|
561 |
||
562 |
def sendmail(self, recipient, subject, body): |
|
563 |
helo_addr = '%s <%s>' % (self.config['sender-name'], |
|
564 |
self.config['sender-addr']) |
|
565 |
msg = format_mail({'email' : self.req.user.get_email(), |
|
566 |
'name' : self.req.user.dc_title(),}, |
|
567 |
[recipient], body, subject) |
|
1419 | 568 |
self.smtp.sendmail(helo_addr, [recipient], msg.as_string()) |
0 | 569 |
|
570 |
def publish(self, rset=None): |
|
2476
1294a6bdf3bf
application -> instance where it makes sense
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2458
diff
changeset
|
571 |
# XXX this allows users with access to an cubicweb instance to use it as |
1294a6bdf3bf
application -> instance where it makes sense
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2458
diff
changeset
|
572 |
# a mail relay |
0 | 573 |
body = self.req.form['mailbody'] |
1467
972517be96dc
sendmail form should now work as before
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1419
diff
changeset
|
574 |
subject = self.req.form['subject'] |
0 | 575 |
for recipient in self.recipients(): |
576 |
text = body % recipient.as_email_context() |
|
577 |
self.sendmail(recipient.get_email(), subject, text) |
|
578 |
# breadcrumbs = self.req.get_session_data('breadcrumbs', None) |
|
579 |
url = self.build_url(__message=self.req._('emails successfully sent')) |
|
580 |
raise Redirect(url) |
|
581 |
||
582 |
||
583 |
class MailBugReportController(SendMailController): |
|
584 |
id = 'reportbug' |
|
742
99115e029dca
replaced most of __selectors__ assignments with __select__
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
692
diff
changeset
|
585 |
__select__ = yes() |
0 | 586 |
|
587 |
def publish(self, rset=None): |
|
588 |
body = self.req.form['description'] |
|
589 |
self.sendmail(self.config['submit-mail'], _('%s error report') % self.config.appid, body) |
|
590 |
url = self.build_url(__message=self.req._('bug report sent')) |
|
591 |
raise Redirect(url) |
|
1419 | 592 |