|
1 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
3 # |
|
4 # This file is part of CubicWeb. |
|
5 # |
|
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
7 # terms of the GNU Lesser General Public License as published by the Free |
|
8 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
9 # any later version. |
|
10 # |
|
11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT |
|
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
14 # details. |
|
15 # |
|
16 # You should have received a copy of the GNU Lesser General Public License along |
|
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
1 """abstract controller classe for CubicWeb web client |
18 """abstract controller classe for CubicWeb web client |
2 |
19 |
3 |
20 |
4 :organization: Logilab |
|
5 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
|
6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
7 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
|
8 """ |
21 """ |
9 __docformat__ = "restructuredtext en" |
22 __docformat__ = "restructuredtext en" |
|
23 |
|
24 from logilab.mtconverter import xml_escape |
10 |
25 |
11 from cubicweb.selectors import yes |
26 from cubicweb.selectors import yes |
12 from cubicweb.appobject import AppObject |
27 from cubicweb.appobject import AppObject |
13 from cubicweb.web import LOGGER, Redirect, RequestError |
28 from cubicweb.web import LOGGER, Redirect, RequestError |
14 |
29 |
77 pp = self._cw.vreg['components'].select_or_none('magicsearch', self._cw) |
92 pp = self._cw.vreg['components'].select_or_none('magicsearch', self._cw) |
78 if pp is not None: |
93 if pp is not None: |
79 self.cw_rset = pp.process_query(rql) |
94 self.cw_rset = pp.process_query(rql) |
80 return self.cw_rset |
95 return self.cw_rset |
81 |
96 |
82 def check_expected_params(self, params): |
|
83 """check that the given list of parameters are specified in the form |
|
84 dictionary |
|
85 """ |
|
86 missing = [] |
|
87 for param in params: |
|
88 if not self._cw.form.get(param): |
|
89 missing.append(param) |
|
90 if missing: |
|
91 raise RequestError('missing required parameter(s): %s' |
|
92 % ','.join(missing)) |
|
93 |
|
94 |
|
95 def notify_edited(self, entity): |
97 def notify_edited(self, entity): |
96 """called by edit_entity() to notify which entity is edited""" |
98 """called by edit_entity() to notify which entity is edited""" |
97 # NOTE: we can't use entity.rest_path() at this point because |
99 # NOTE: we can't use entity.rest_path() at this point because |
98 # rest_path() could rely on schema constraints (such as a required |
100 # rest_path() could rely on schema constraints (such as a required |
99 # relation) that might not be satisfied yet (in case of creations) |
101 # relation) that might not be satisfied yet (in case of creations) |
100 if not self._edited_entity: |
102 if not self._edited_entity: |
101 self._edited_entity = entity |
103 self._edited_entity = entity |
102 |
104 |
103 # XXX move to EditController (only customer) |
|
104 def delete_entities(self, eidtypes): |
|
105 """delete entities from the repository""" |
|
106 redirect_info = set() |
|
107 eidtypes = tuple(eidtypes) |
|
108 for eid, etype in eidtypes: |
|
109 entity = self._cw.entity_from_eid(eid, etype) |
|
110 path, params = entity.after_deletion_path() |
|
111 redirect_info.add( (path, tuple(params.iteritems())) ) |
|
112 entity.delete() |
|
113 if len(redirect_info) > 1: |
|
114 # In the face of ambiguity, refuse the temptation to guess. |
|
115 self._after_deletion_path = 'view', () |
|
116 else: |
|
117 self._after_deletion_path = iter(redirect_info).next() |
|
118 if len(eidtypes) > 1: |
|
119 self._cw.set_message(self._cw._('entities deleted')) |
|
120 else: |
|
121 self._cw.set_message(self._cw._('entity deleted')) |
|
122 |
|
123 def validate_cache(self, view): |
105 def validate_cache(self, view): |
124 view.set_http_cache_headers() |
106 view.set_http_cache_headers() |
125 self._cw.validate_cache() |
107 self._cw.validate_cache() |
126 |
108 |
127 # XXX is that used AT ALL ? |
|
128 def reset(self): |
109 def reset(self): |
129 """reset form parameters and redirect to a view determinated by given |
110 """reset form parameters and redirect to a view determinated by given |
130 parameters |
111 parameters |
131 """ |
112 """ |
132 newparams = {} |
113 newparams = {} |
133 # sets message if needed |
114 # sets message if needed |
134 if self._cw.message: |
115 if self._cw.message: |
135 newparams['__message'] = self._cw.message |
116 newparams['_cwmsgid'] = self._cw.set_redirect_message(self._cw.message) |
136 if self._cw.form.has_key('__action_apply'): |
117 if self._cw.form.has_key('__action_apply'): |
137 self._return_to_edition_view(newparams) |
118 self._return_to_edition_view(newparams) |
138 if self._cw.form.has_key('__action_cancel'): |
119 if self._cw.form.has_key('__action_cancel'): |
139 self._return_to_lastpage(newparams) |
120 self._return_to_lastpage(newparams) |
140 else: |
121 else: |
141 self._return_to_original_view(newparams) |
122 self._return_to_original_view(newparams) |
142 |
123 |
143 |
|
144 # XXX is that used AT ALL ? |
|
145 def _return_to_original_view(self, newparams): |
124 def _return_to_original_view(self, newparams): |
146 """validate-button case""" |
125 """validate-button case""" |
147 # transforms __redirect[*] parameters into regular form parameters |
126 # transforms __redirect[*] parameters into regular form parameters |
148 newparams.update(redirect_params(self._cw.form)) |
127 newparams.update(redirect_params(self._cw.form)) |
149 # find out if we have some explicit `rql` needs |
128 # find out if we have some explicit `rql` needs |
154 path = 'view' |
133 path = 'view' |
155 newparams['rql'] = rql |
134 newparams['rql'] = rql |
156 elif '__redirectpath' in self._cw.form: |
135 elif '__redirectpath' in self._cw.form: |
157 # if redirect path was explicitly specified in the form, use it |
136 # if redirect path was explicitly specified in the form, use it |
158 path = self._cw.form['__redirectpath'] |
137 path = self._cw.form['__redirectpath'] |
159 if self._edited_entity and path != self._edited_entity.rest_path(): |
138 if (self._edited_entity and path != self._edited_entity.rest_path() |
160 # XXX may be here on modification? if yes the message should be |
139 and '_cwmsgid' in newparams): |
161 # modified where __createdpath is detected (cw.web.request) |
140 # XXX may be here on modification? |
162 newparams['__createdpath'] = self._edited_entity.rest_path() |
141 msg = u'(<a href="%s">%s</a>)' % ( |
|
142 xml_escape(self._edited_entity.absolute_url()), |
|
143 self._cw._('click here to see created entity')) |
|
144 self._cw.append_to_redirect_message(msg) |
163 elif self._after_deletion_path: |
145 elif self._after_deletion_path: |
164 # else it should have been set during form processing |
146 # else it should have been set during form processing |
165 path, params = self._after_deletion_path |
147 path, params = self._after_deletion_path |
166 params = dict(params) # params given as tuple |
148 params = dict(params) # params given as tuple |
167 params.update(newparams) |
149 params.update(newparams) |
168 newparams = params |
150 newparams = params |
169 elif self._edited_entity: |
151 elif self._edited_entity: |
|
152 # clear caches in case some attribute participating to the rest path |
|
153 # has been modified |
|
154 self._edited_entity.clear_all_caches() |
170 path = self._edited_entity.rest_path() |
155 path = self._edited_entity.rest_path() |
171 else: |
156 else: |
172 path = 'view' |
157 path = 'view' |
173 url = self._cw.build_url(path, **newparams) |
158 url = self._cw.build_url(path, **newparams) |
174 url = append_url_params(url, self._cw.form.get('__redirectparams')) |
159 url = append_url_params(url, self._cw.form.get('__redirectparams')) |
175 raise Redirect(url) |
160 raise Redirect(url) |
176 |
161 |
177 # XXX is that used AT ALL ? |
|
178 def _return_to_edition_view(self, newparams): |
162 def _return_to_edition_view(self, newparams): |
179 """apply-button case""" |
163 """apply-button case""" |
180 form = self._cw.form |
164 form = self._cw.form |
181 if self._edited_entity: |
165 if self._edited_entity: |
182 path = self._edited_entity.rest_path() |
166 path = self._edited_entity.rest_path() |
184 # else, fallback on the old `view?rql=...` url form |
168 # else, fallback on the old `view?rql=...` url form |
185 elif 'rql' in self._cw.form: |
169 elif 'rql' in self._cw.form: |
186 path = 'view' |
170 path = 'view' |
187 newparams['rql'] = form['rql'] |
171 newparams['rql'] = form['rql'] |
188 else: |
172 else: |
189 self.warning("the edited data seems inconsistent") |
173 self.warning('the edited data seems inconsistent') |
190 path = 'view' |
174 path = 'view' |
191 # pick up the correction edition view |
175 # pick up the correction edition view |
192 if form.get('__form_id'): |
176 if form.get('__form_id'): |
193 newparams['vid'] = form['__form_id'] |
177 newparams['vid'] = form['__form_id'] |
194 # re-insert copy redirection parameters |
178 # re-insert copy redirection parameters |
196 if redirectparam in form: |
180 if redirectparam in form: |
197 newparams[redirectparam] = form[redirectparam] |
181 newparams[redirectparam] = form[redirectparam] |
198 raise Redirect(self._cw.build_url(path, **newparams)) |
182 raise Redirect(self._cw.build_url(path, **newparams)) |
199 |
183 |
200 |
184 |
201 # XXX is that used AT ALL ? |
|
202 def _return_to_lastpage(self, newparams): |
185 def _return_to_lastpage(self, newparams): |
203 """cancel-button case: in this case we are always expecting to go back |
186 """cancel-button case: in this case we are always expecting to go back |
204 where we came from, and this is not easy. Currently we suppose that |
187 where we came from, and this is not easy. Currently we suppose that |
205 __redirectpath is specifying that place if found, else we look in the |
188 __redirectpath is specifying that place if found, else we look in the |
206 request breadcrumbs for the last visited page. |
189 request breadcrumbs for the last visited page. |