34 def jsonize(func): |
34 def jsonize(func): |
35 """decorator to sets correct content_type and calls `simplejson.dumps` on |
35 """decorator to sets correct content_type and calls `simplejson.dumps` on |
36 results |
36 results |
37 """ |
37 """ |
38 def wrapper(self, *args, **kwargs): |
38 def wrapper(self, *args, **kwargs): |
39 self.req.set_content_type('application/json') |
39 self._cw.set_content_type('application/json') |
40 return json_dumps(func(self, *args, **kwargs)) |
40 return json_dumps(func(self, *args, **kwargs)) |
41 wrapper.__name__ = func.__name__ |
41 wrapper.__name__ = func.__name__ |
42 return wrapper |
42 return wrapper |
43 |
43 |
44 def xhtmlize(func): |
44 def xhtmlize(func): |
45 """decorator to sets correct content_type and calls `xmlize` on results""" |
45 """decorator to sets correct content_type and calls `xmlize` on results""" |
46 def wrapper(self, *args, **kwargs): |
46 def wrapper(self, *args, **kwargs): |
47 self.req.set_content_type(self.req.html_content_type()) |
47 self._cw.set_content_type(self._cw.html_content_type()) |
48 result = func(self, *args, **kwargs) |
48 result = func(self, *args, **kwargs) |
49 return ''.join((self.req.document_surrounding_div(), result.strip(), |
49 return ''.join((self._cw.document_surrounding_div(), result.strip(), |
50 u'</div>')) |
50 u'</div>')) |
51 wrapper.__name__ = func.__name__ |
51 wrapper.__name__ = func.__name__ |
52 return wrapper |
52 return wrapper |
53 |
53 |
54 def check_pageid(func): |
54 def check_pageid(func): |
55 """decorator which checks the given pageid is found in the |
55 """decorator which checks the given pageid is found in the |
56 user's session data |
56 user's session data |
57 """ |
57 """ |
58 def wrapper(self, *args, **kwargs): |
58 def wrapper(self, *args, **kwargs): |
59 data = self.req.get_session_data(self.req.pageid) |
59 data = self._cw.get_session_data(self._cw.pageid) |
60 if data is None: |
60 if data is None: |
61 raise RemoteCallFailed(self.req._('pageid-not-found')) |
61 raise RemoteCallFailed(self._cw._('pageid-not-found')) |
62 return func(self, *args, **kwargs) |
62 return func(self, *args, **kwargs) |
63 return wrapper |
63 return wrapper |
64 |
64 |
65 |
65 |
66 class LoginController(Controller): |
66 class LoginController(Controller): |
67 __regid__ = 'login' |
67 __regid__ = 'login' |
68 |
68 |
69 def publish(self, rset=None): |
69 def publish(self, rset=None): |
70 """log in the instance""" |
70 """log in the instance""" |
71 if self.config['auth-mode'] == 'http': |
71 if self._cw.config['auth-mode'] == 'http': |
72 # HTTP authentication |
72 # HTTP authentication |
73 raise ExplicitLogin() |
73 raise ExplicitLogin() |
74 else: |
74 else: |
75 # Cookie authentication |
75 # Cookie authentication |
76 return self.appli.need_login_content(self.req) |
76 return self.appli.need_login_content(self._cw) |
77 |
77 |
78 |
78 |
79 class LogoutController(Controller): |
79 class LogoutController(Controller): |
80 __regid__ = 'logout' |
80 __regid__ = 'logout' |
81 |
81 |
82 def publish(self, rset=None): |
82 def publish(self, rset=None): |
83 """logout from the instance""" |
83 """logout from the instance""" |
84 return self.appli.session_handler.logout(self.req) |
84 return self.appli.session_handler.logout(self._cw) |
85 |
85 |
86 |
86 |
87 class ViewController(Controller): |
87 class ViewController(Controller): |
88 """standard entry point : |
88 """standard entry point : |
89 - build result set |
89 - build result set |
114 except Redirect: # propagate redirect that might occur in method() |
114 except Redirect: # propagate redirect that might occur in method() |
115 raise |
115 raise |
116 except Exception, ex: |
116 except Exception, ex: |
117 self.exception('while handling __method') |
117 self.exception('while handling __method') |
118 req.set_message(req._("error while handling __method: %s") % req._(ex)) |
118 req.set_message(req._("error while handling __method: %s") % req._(ex)) |
119 vid = req.form.get('vid') or vid_from_rset(req, rset, self.schema) |
119 vid = req.form.get('vid') or vid_from_rset(req, rset, self._cw.schema) |
120 try: |
120 try: |
121 view = self.vreg['views'].select(vid, req, rset=rset) |
121 view = self._cw.vreg['views'].select(vid, req, rset=rset) |
122 except ObjectNotFound: |
122 except ObjectNotFound: |
123 self.warning("the view %s could not be found", vid) |
123 self.warning("the view %s could not be found", vid) |
124 req.set_message(req._("The view %s could not be found") % vid) |
124 req.set_message(req._("The view %s could not be found") % vid) |
125 vid = vid_from_rset(req, rset, self.schema) |
125 vid = vid_from_rset(req, rset, self._cw.schema) |
126 view = self.vreg['views'].select(vid, req, rset=rset) |
126 view = self._cw.vreg['views'].select(vid, req, rset=rset) |
127 except NoSelectableObject: |
127 except NoSelectableObject: |
128 if rset: |
128 if rset: |
129 req.set_message(req._("The view %s can not be applied to this query") % vid) |
129 req.set_message(req._("The view %s can not be applied to this query") % vid) |
130 else: |
130 else: |
131 req.set_message(req._("You have no access to this view or it can not " |
131 req.set_message(req._("You have no access to this view or it can not " |
132 "be used to display the current data.")) |
132 "be used to display the current data.")) |
133 self.warning("the view %s can not be applied to this query", vid) |
133 self.warning("the view %s can not be applied to this query", vid) |
134 vid = vid_from_rset(req, rset, self.schema) |
134 vid = vid_from_rset(req, rset, self._cw.schema) |
135 view = self.vreg['views'].select(vid, req, rset=rset) |
135 view = self._cw.vreg['views'].select(vid, req, rset=rset) |
136 return view, rset |
136 return view, rset |
137 |
137 |
138 def add_to_breadcrumbs(self, view): |
138 def add_to_breadcrumbs(self, view): |
139 # update breadcrumps **before** validating cache, unless the view |
139 # update breadcrumps **before** validating cache, unless the view |
140 # specifies explicitly it should not be added to breadcrumb or the |
140 # specifies explicitly it should not be added to breadcrumb or the |
141 # view is a binary view |
141 # view is a binary view |
142 if view.add_to_breadcrumbs and not view.binary: |
142 if view.add_to_breadcrumbs and not view.binary: |
143 self.req.update_breadcrumbs() |
143 self._cw.update_breadcrumbs() |
144 |
144 |
145 def validate_cache(self, view): |
145 def validate_cache(self, view): |
146 view.set_http_cache_headers() |
146 view.set_http_cache_headers() |
147 self.req.validate_cache() |
147 self._cw.validate_cache() |
148 |
148 |
149 def execute_linkto(self, eid=None): |
149 def execute_linkto(self, eid=None): |
150 """XXX __linkto parameter may cause security issue |
150 """XXX __linkto parameter may cause security issue |
151 |
151 |
152 defined here since custom application controller inheriting from this |
152 defined here since custom application controller inheriting from this |
153 one use this method? |
153 one use this method? |
154 """ |
154 """ |
155 req = self.req |
155 req = self._cw |
156 if not '__linkto' in req.form: |
156 if not '__linkto' in req.form: |
157 return |
157 return |
158 if eid is None: |
158 if eid is None: |
159 eid = typed_eid(req.form['eid']) |
159 eid = typed_eid(req.form['eid']) |
160 for linkto in req.list_form_param('__linkto', pop=True): |
160 for linkto in req.list_form_param('__linkto', pop=True): |
209 |
209 |
210 class FormValidatorController(Controller): |
210 class FormValidatorController(Controller): |
211 __regid__ = 'validateform' |
211 __regid__ = 'validateform' |
212 |
212 |
213 def response(self, domid, status, args, entity): |
213 def response(self, domid, status, args, entity): |
214 callback = str(self.req.form.get('__onsuccess', 'null')) |
214 callback = str(self._cw.form.get('__onsuccess', 'null')) |
215 errback = str(self.req.form.get('__onfailure', 'null')) |
215 errback = str(self._cw.form.get('__onfailure', 'null')) |
216 cbargs = str(self.req.form.get('__cbargs', 'null')) |
216 cbargs = str(self._cw.form.get('__cbargs', 'null')) |
217 self.req.set_content_type('text/html') |
217 self._cw.set_content_type('text/html') |
218 jsargs = simplejson.dumps((status, args, entity), cls=CubicWebJsonEncoder) |
218 jsargs = simplejson.dumps((status, args, entity), cls=CubicWebJsonEncoder) |
219 return """<script type="text/javascript"> |
219 return """<script type="text/javascript"> |
220 wp = window.parent; |
220 wp = window.parent; |
221 window.parent.handleFormValidationResponse('%s', %s, %s, %s, %s); |
221 window.parent.handleFormValidationResponse('%s', %s, %s, %s, %s); |
222 </script>""" % (domid, callback, errback, jsargs, cbargs) |
222 </script>""" % (domid, callback, errback, jsargs, cbargs) |
223 |
223 |
224 def publish(self, rset=None): |
224 def publish(self, rset=None): |
225 self.req.json_request = True |
225 self._cw.json_request = True |
226 # XXX unclear why we have a separated controller here vs |
226 # XXX unclear why we have a separated controller here vs |
227 # js_validate_form on the json controller |
227 # js_validate_form on the json controller |
228 status, args, entity = _validate_form(self.req, self.vreg) |
228 status, args, entity = _validate_form(self._cw, self._cw.vreg) |
229 domid = self.req.form.get('__domid', 'entityForm').encode( |
229 domid = self._cw.form.get('__domid', 'entityForm').encode( |
230 self.req.encoding) |
230 self._cw.encoding) |
231 return self.response(domid, status, args, entity) |
231 return self.response(domid, status, args, entity) |
232 |
232 |
233 |
233 |
234 class JSonController(Controller): |
234 class JSonController(Controller): |
235 __regid__ = 'json' |
235 __regid__ = 'json' |
331 return stream.getvalue() |
331 return stream.getvalue() |
332 |
332 |
333 @xhtmlize |
333 @xhtmlize |
334 def js_view(self): |
334 def js_view(self): |
335 # XXX try to use the page-content template |
335 # XXX try to use the page-content template |
336 req = self.req |
336 req = self._cw |
337 rql = req.form.get('rql') |
337 rql = req.form.get('rql') |
338 if rql: |
338 if rql: |
339 rset = self._exec(rql) |
339 rset = self._exec(rql) |
340 else: |
340 else: |
341 rset = None |
341 rset = None |
342 vid = req.form.get('vid') or vid_from_rset(req, rset, self.schema) |
342 vid = req.form.get('vid') or vid_from_rset(req, rset, self._cw.schema) |
343 try: |
343 try: |
344 view = self.vreg['views'].select(vid, req, rset=rset) |
344 view = self._cw.vreg['views'].select(vid, req, rset=rset) |
345 except NoSelectableObject: |
345 except NoSelectableObject: |
346 vid = req.form.get('fallbackvid', 'noresult') |
346 vid = req.form.get('fallbackvid', 'noresult') |
347 view = self.vreg['views'].select(vid, req, rset=rset) |
347 view = self._cw.vreg['views'].select(vid, req, rset=rset) |
348 return self._call_view(view) |
348 return self._call_view(view) |
349 |
349 |
350 @xhtmlize |
350 @xhtmlize |
351 def js_prop_widget(self, propkey, varname, tabindex=None): |
351 def js_prop_widget(self, propkey, varname, tabindex=None): |
352 """specific method for CWProperty handling""" |
352 """specific method for CWProperty handling""" |
353 entity = self.vreg['etypes'].etype_class('CWProperty')(self.req) |
353 entity = self._cw.vreg['etypes'].etype_class('CWProperty')(self._cw) |
354 entity.eid = varname |
354 entity.eid = varname |
355 entity['pkey'] = propkey |
355 entity['pkey'] = propkey |
356 form = self.vreg['forms'].select('edition', self.req, entity=entity) |
356 form = self._cw.vreg['forms'].select('edition', self._cw, entity=entity) |
357 form.form_build_context() |
357 form.form_build_context() |
358 vfield = form.field_by_name('value') |
358 vfield = form.field_by_name('value') |
359 renderer = FormRenderer(self.req) |
359 renderer = FormRenderer(self._cw) |
360 return vfield.render(form, renderer, tabindex=tabindex) \ |
360 return vfield.render(form, renderer, tabindex=tabindex) \ |
361 + renderer.render_help(form, vfield) |
361 + renderer.render_help(form, vfield) |
362 |
362 |
363 @xhtmlize |
363 @xhtmlize |
364 def js_component(self, compid, rql, registry='components', extraargs=None): |
364 def js_component(self, compid, rql, registry='components', extraargs=None): |
365 if rql: |
365 if rql: |
366 rset = self._exec(rql) |
366 rset = self._exec(rql) |
367 else: |
367 else: |
368 rset = None |
368 rset = None |
369 comp = self.vreg[registry].select(compid, self.req, rset=rset) |
369 comp = self._cw.vreg[registry].select(compid, self._cw, rset=rset) |
370 if extraargs is None: |
370 if extraargs is None: |
371 extraargs = {} |
371 extraargs = {} |
372 else: # we receive unicode keys which is not supported by the **syntax |
372 else: # we receive unicode keys which is not supported by the **syntax |
373 extraargs = dict((str(key), value) |
373 extraargs = dict((str(key), value) |
374 for key, value in extraargs.items()) |
374 for key, value in extraargs.items()) |
376 return comp.render(**extraargs) |
376 return comp.render(**extraargs) |
377 |
377 |
378 @check_pageid |
378 @check_pageid |
379 @xhtmlize |
379 @xhtmlize |
380 def js_inline_creation_form(self, peid, ttype, rtype, role, i18nctx): |
380 def js_inline_creation_form(self, peid, ttype, rtype, role, i18nctx): |
381 view = self.vreg['views'].select('inline-creation', self.req, |
381 view = self._cw.vreg['views'].select('inline-creation', self._cw, |
382 etype=ttype, peid=peid, rtype=rtype, |
382 etype=ttype, peid=peid, rtype=rtype, |
383 role=role) |
383 role=role) |
384 return self._call_view(view, etype=ttype, peid=peid, |
384 return self._call_view(view, etype=ttype, peid=peid, |
385 rtype=rtype, role=role, i18nctx=i18nctx) |
385 rtype=rtype, role=role, i18nctx=i18nctx) |
386 |
386 |
387 @jsonize |
387 @jsonize |
388 def js_validate_form(self, action, names, values): |
388 def js_validate_form(self, action, names, values): |
389 return self.validate_form(action, names, values) |
389 return self.validate_form(action, names, values) |
390 |
390 |
391 def validate_form(self, action, names, values): |
391 def validate_form(self, action, names, values): |
392 self.req.form = self._rebuild_posted_form(names, values, action) |
392 self._cw.form = self._rebuild_posted_form(names, values, action) |
393 return _validate_form(self.req, self.vreg) |
393 return _validate_form(self._cw, self._cw.vreg) |
394 |
394 |
395 @jsonize |
395 @jsonize |
396 def js_edit_field(self, action, names, values, rtype, eid, default): |
396 def js_edit_field(self, action, names, values, rtype, eid, default): |
397 success, args, _ = self.validate_form(action, names, values) |
397 success, args, _ = self.validate_form(action, names, values) |
398 if success: |
398 if success: |
399 # Any X,N where we don't seem to use N is an optimisation |
399 # Any X,N where we don't seem to use N is an optimisation |
400 # printable_value won't need to query N again |
400 # printable_value won't need to query N again |
401 rset = self.req.execute('Any X,N WHERE X eid %%(x)s, X %s N' % rtype, |
401 rset = self._cw.execute('Any X,N WHERE X eid %%(x)s, X %s N' % rtype, |
402 {'x': eid}, 'x') |
402 {'x': eid}, 'x') |
403 entity = rset.get_entity(0, 0) |
403 entity = rset.get_entity(0, 0) |
404 value = entity.printable_value(rtype) or default |
404 value = entity.printable_value(rtype) or default |
405 return (success, args, value) |
405 return (success, args, value) |
406 else: |
406 else: |
407 return (success, args, None) |
407 return (success, args, None) |
408 |
408 |
409 @jsonize |
409 @jsonize |
410 def js_reledit_form(self, eid, rtype, role, default, lzone): |
410 def js_reledit_form(self, eid, rtype, role, default, lzone): |
411 """XXX we should get rid of this and use loadxhtml""" |
411 """XXX we should get rid of this and use loadxhtml""" |
412 entity = self.req.entity_from_eid(eid) |
412 entity = self._cw.entity_from_eid(eid) |
413 return entity.view('reledit', rtype=rtype, role=role, |
413 return entity.view('reledit', rtype=rtype, role=role, |
414 default=default, landing_zone=lzone) |
414 default=default, landing_zone=lzone) |
415 |
415 |
416 @jsonize |
416 @jsonize |
417 def js_i18n(self, msgids): |
417 def js_i18n(self, msgids): |
418 """returns the translation of `msgid`""" |
418 """returns the translation of `msgid`""" |
419 return [self.req._(msgid) for msgid in msgids] |
419 return [self._cw._(msgid) for msgid in msgids] |
420 |
420 |
421 @jsonize |
421 @jsonize |
422 def js_format_date(self, strdate): |
422 def js_format_date(self, strdate): |
423 """returns the formatted date for `msgid`""" |
423 """returns the formatted date for `msgid`""" |
424 date = strptime(strdate, '%Y-%m-%d %H:%M:%S') |
424 date = strptime(strdate, '%Y-%m-%d %H:%M:%S') |
425 return self.format_date(date) |
425 return self.format_date(date) |
426 |
426 |
427 @jsonize |
427 @jsonize |
428 def js_external_resource(self, resource): |
428 def js_external_resource(self, resource): |
429 """returns the URL of the external resource named `resource`""" |
429 """returns the URL of the external resource named `resource`""" |
430 return self.req.external_resource(resource) |
430 return self._cw.external_resource(resource) |
431 |
431 |
432 @check_pageid |
432 @check_pageid |
433 @jsonize |
433 @jsonize |
434 def js_user_callback(self, cbname): |
434 def js_user_callback(self, cbname): |
435 page_data = self.req.get_session_data(self.req.pageid, {}) |
435 page_data = self._cw.get_session_data(self._cw.pageid, {}) |
436 try: |
436 try: |
437 cb = page_data[cbname] |
437 cb = page_data[cbname] |
438 except KeyError: |
438 except KeyError: |
439 return None |
439 return None |
440 return cb(self.req) |
440 return cb(self._cw) |
441 |
441 |
442 if HAS_SEARCH_RESTRICTION: |
442 if HAS_SEARCH_RESTRICTION: |
443 @jsonize |
443 @jsonize |
444 def js_filter_build_rql(self, names, values): |
444 def js_filter_build_rql(self, names, values): |
445 form = self._rebuild_posted_form(names, values) |
445 form = self._rebuild_posted_form(names, values) |
446 self.req.form = form |
446 self._cw.form = form |
447 builder = FilterRQLBuilder(self.req) |
447 builder = FilterRQLBuilder(self._cw) |
448 return builder.build_rql() |
448 return builder.build_rql() |
449 |
449 |
450 @jsonize |
450 @jsonize |
451 def js_filter_select_content(self, facetids, rql): |
451 def js_filter_select_content(self, facetids, rql): |
452 rqlst = self.vreg.parse(self.req, rql) # XXX Union unsupported yet |
452 rqlst = self._cw.vreg.parse(self._cw, rql) # XXX Union unsupported yet |
453 mainvar = prepare_facets_rqlst(rqlst)[0] |
453 mainvar = prepare_facets_rqlst(rqlst)[0] |
454 update_map = {} |
454 update_map = {} |
455 for facetid in facetids: |
455 for facetid in facetids: |
456 facet = get_facet(self.req, facetid, rqlst.children[0], mainvar) |
456 facet = get_facet(self._cw, facetid, rqlst.children[0], mainvar) |
457 update_map[facetid] = facet.possible_values() |
457 update_map[facetid] = facet.possible_values() |
458 return update_map |
458 return update_map |
459 |
459 |
460 def js_unregister_user_callback(self, cbname): |
460 def js_unregister_user_callback(self, cbname): |
461 self.req.unregister_callback(self.req.pageid, cbname) |
461 self._cw.unregister_callback(self._cw.pageid, cbname) |
462 |
462 |
463 def js_unload_page_data(self): |
463 def js_unload_page_data(self): |
464 self.req.del_session_data(self.req.pageid) |
464 self._cw.del_session_data(self._cw.pageid) |
465 |
465 |
466 def js_cancel_edition(self, errorurl): |
466 def js_cancel_edition(self, errorurl): |
467 """cancelling edition from javascript |
467 """cancelling edition from javascript |
468 |
468 |
469 We need to clear associated req's data : |
469 We need to clear associated req's data : |
470 - errorurl |
470 - errorurl |
471 - pending insertions / deletions |
471 - pending insertions / deletions |
472 """ |
472 """ |
473 self.req.cancel_edition(errorurl) |
473 self._cw.cancel_edition(errorurl) |
474 |
474 |
475 def js_delete_bookmark(self, beid): |
475 def js_delete_bookmark(self, beid): |
476 rql = 'DELETE B bookmarked_by U WHERE B eid %(b)s, U eid %(u)s' |
476 rql = 'DELETE B bookmarked_by U WHERE B eid %(b)s, U eid %(u)s' |
477 self.req.execute(rql, {'b': typed_eid(beid), 'u' : self.req.user.eid}) |
477 self._cw.execute(rql, {'b': typed_eid(beid), 'u' : self._cw.user.eid}) |
478 |
478 |
479 def js_node_clicked(self, treeid, nodeeid): |
479 def js_node_clicked(self, treeid, nodeeid): |
480 """add/remove eid in treestate cookie""" |
480 """add/remove eid in treestate cookie""" |
481 from cubicweb.web.views.treeview import treecookiename |
481 from cubicweb.web.views.treeview import treecookiename |
482 cookies = self.req.get_cookie() |
482 cookies = self._cw.get_cookie() |
483 statename = treecookiename(treeid) |
483 statename = treecookiename(treeid) |
484 treestate = cookies.get(statename) |
484 treestate = cookies.get(statename) |
485 if treestate is None: |
485 if treestate is None: |
486 cookies[statename] = nodeeid |
486 cookies[statename] = nodeeid |
487 self.req.set_cookie(cookies, statename) |
487 self._cw.set_cookie(cookies, statename) |
488 else: |
488 else: |
489 marked = set(filter(None, treestate.value.split(';'))) |
489 marked = set(filter(None, treestate.value.split(';'))) |
490 if nodeeid in marked: |
490 if nodeeid in marked: |
491 marked.remove(nodeeid) |
491 marked.remove(nodeeid) |
492 else: |
492 else: |
493 marked.add(nodeeid) |
493 marked.add(nodeeid) |
494 cookies[statename] = ';'.join(marked) |
494 cookies[statename] = ';'.join(marked) |
495 self.req.set_cookie(cookies, statename) |
495 self._cw.set_cookie(cookies, statename) |
496 |
496 |
497 def js_set_cookie(self, cookiename, cookievalue): |
497 def js_set_cookie(self, cookiename, cookievalue): |
498 # XXX we should consider jQuery.Cookie |
498 # XXX we should consider jQuery.Cookie |
499 cookiename, cookievalue = str(cookiename), str(cookievalue) |
499 cookiename, cookievalue = str(cookiename), str(cookievalue) |
500 cookies = self.req.get_cookie() |
500 cookies = self._cw.get_cookie() |
501 cookies[cookiename] = cookievalue |
501 cookies[cookiename] = cookievalue |
502 self.req.set_cookie(cookies, cookiename) |
502 self._cw.set_cookie(cookies, cookiename) |
503 |
503 |
504 # relations edition stuff ################################################## |
504 # relations edition stuff ################################################## |
505 |
505 |
506 def _add_pending(self, eidfrom, rel, eidto, kind): |
506 def _add_pending(self, eidfrom, rel, eidto, kind): |
507 key = 'pending_%s' % kind |
507 key = 'pending_%s' % kind |
508 pendings = self.req.get_session_data(key, set()) |
508 pendings = self._cw.get_session_data(key, set()) |
509 pendings.add( (typed_eid(eidfrom), rel, typed_eid(eidto)) ) |
509 pendings.add( (typed_eid(eidfrom), rel, typed_eid(eidto)) ) |
510 self.req.set_session_data(key, pendings) |
510 self._cw.set_session_data(key, pendings) |
511 |
511 |
512 def _remove_pending(self, eidfrom, rel, eidto, kind): |
512 def _remove_pending(self, eidfrom, rel, eidto, kind): |
513 key = 'pending_%s' % kind |
513 key = 'pending_%s' % kind |
514 pendings = self.req.get_session_data(key) |
514 pendings = self._cw.get_session_data(key) |
515 pendings.remove( (typed_eid(eidfrom), rel, typed_eid(eidto)) ) |
515 pendings.remove( (typed_eid(eidfrom), rel, typed_eid(eidto)) ) |
516 self.req.set_session_data(key, pendings) |
516 self._cw.set_session_data(key, pendings) |
517 |
517 |
518 def js_remove_pending_insert(self, (eidfrom, rel, eidto)): |
518 def js_remove_pending_insert(self, (eidfrom, rel, eidto)): |
519 self._remove_pending(eidfrom, rel, eidto, 'insert') |
519 self._remove_pending(eidfrom, rel, eidto, 'insert') |
520 |
520 |
521 def js_add_pending_inserts(self, tripletlist): |
521 def js_add_pending_inserts(self, tripletlist): |
542 __regid__ = 'sendmail' |
542 __regid__ = 'sendmail' |
543 __select__ = match_user_groups('managers', 'users') |
543 __select__ = match_user_groups('managers', 'users') |
544 |
544 |
545 def recipients(self): |
545 def recipients(self): |
546 """returns an iterator on email's recipients as entities""" |
546 """returns an iterator on email's recipients as entities""" |
547 eids = self.req.form['recipient'] |
547 eids = self._cw.form['recipient'] |
548 # make sure we have a list even though only one recipient was specified |
548 # make sure we have a list even though only one recipient was specified |
549 if isinstance(eids, basestring): |
549 if isinstance(eids, basestring): |
550 eids = (eids,) |
550 eids = (eids,) |
551 rql = 'Any X WHERE X eid in (%s)' % (','.join(eids)) |
551 rql = 'Any X WHERE X eid in (%s)' % (','.join(eids)) |
552 rset = self.req.execute(rql) |
552 rset = self._cw.execute(rql) |
553 for entity in rset.entities(): |
553 for entity in rset.entities(): |
554 entity.complete() # XXX really? |
554 entity.complete() # XXX really? |
555 yield entity |
555 yield entity |
556 |
556 |
557 @property |
557 @property |
558 @cached |
558 @cached |
559 def smtp(self): |
559 def smtp(self): |
560 mailhost, port = self.config['smtp-host'], self.config['smtp-port'] |
560 mailhost, port = self._cw.config['smtp-host'], self._cw.config['smtp-port'] |
561 try: |
561 try: |
562 return SMTP(mailhost, port) |
562 return SMTP(mailhost, port) |
563 except Exception, ex: |
563 except Exception, ex: |
564 self.exception("can't connect to smtp server %s:%s (%s)", |
564 self.exception("can't connect to smtp server %s:%s (%s)", |
565 mailhost, port, ex) |
565 mailhost, port, ex) |
566 url = self.build_url(__message=self.req._('could not connect to the SMTP server')) |
566 url = self.build_url(__message=self._cw._('could not connect to the SMTP server')) |
567 raise Redirect(url) |
567 raise Redirect(url) |
568 |
568 |
569 def sendmail(self, recipient, subject, body): |
569 def sendmail(self, recipient, subject, body): |
570 helo_addr = '%s <%s>' % (self.config['sender-name'], |
570 helo_addr = '%s <%s>' % (self._cw.config['sender-name'], |
571 self.config['sender-addr']) |
571 self._cw.config['sender-addr']) |
572 msg = format_mail({'email' : self.req.user.get_email(), |
572 msg = format_mail({'email' : self._cw.user.get_email(), |
573 'name' : self.req.user.dc_title(),}, |
573 'name' : self._cw.user.dc_title(),}, |
574 [recipient], body, subject) |
574 [recipient], body, subject) |
575 self.smtp.sendmail(helo_addr, [recipient], msg.as_string()) |
575 self.smtp.sendmail(helo_addr, [recipient], msg.as_string()) |
576 |
576 |
577 def publish(self, rset=None): |
577 def publish(self, rset=None): |
578 # XXX this allows users with access to an cubicweb instance to use it as |
578 # XXX this allows users with access to an cubicweb instance to use it as |
579 # a mail relay |
579 # a mail relay |
580 body = self.req.form['mailbody'] |
580 body = self._cw.form['mailbody'] |
581 subject = self.req.form['subject'] |
581 subject = self._cw.form['subject'] |
582 for recipient in self.recipients(): |
582 for recipient in self.recipients(): |
583 text = body % recipient.as_email_context() |
583 text = body % recipient.as_email_context() |
584 self.sendmail(recipient.get_email(), subject, text) |
584 self.sendmail(recipient.get_email(), subject, text) |
585 # breadcrumbs = self.req.get_session_data('breadcrumbs', None) |
585 # breadcrumbs = self._cw.get_session_data('breadcrumbs', None) |
586 url = self.build_url(__message=self.req._('emails successfully sent')) |
586 url = self.build_url(__message=self._cw._('emails successfully sent')) |
587 raise Redirect(url) |
587 raise Redirect(url) |
588 |
588 |
589 |
589 |
590 class MailBugReportController(SendMailController): |
590 class MailBugReportController(SendMailController): |
591 __regid__ = 'reportbug' |
591 __regid__ = 'reportbug' |
592 __select__ = yes() |
592 __select__ = yes() |
593 |
593 |
594 def publish(self, rset=None): |
594 def publish(self, rset=None): |
595 body = self.req.form['description'] |
595 body = self._cw.form['description'] |
596 self.sendmail(self.config['submit-mail'], _('%s error report') % self.config.appid, body) |
596 self.sendmail(self._cw.config['submit-mail'], _('%s error report') % self._cw.config.appid, body) |
597 url = self.build_url(__message=self.req._('bug report sent')) |
597 url = self.build_url(__message=self._cw._('bug report sent')) |
598 raise Redirect(url) |
598 raise Redirect(url) |
599 |
599 |