class PIWSCSVView(CSVMixIn, View): """ Dumps table data in CSV: used by 'jtable-table' view. """ __regid__ = "jtable-table-csv-export" __select__ = yes() title = _("piws csv export") def call(self): """ Display the CSV formated table data. """ qname = self._cw.form["qname"] timepoint = self._cw.form["timepoint"] labels = json.loads(self._cw.form["labels"]) rset = [] for rtype in ANSWERS_RTYPE: rql = ("Any ID, QT, OV Where S is Subject, S code_in_study ID, " "S subject_questionnaire_runs QR, QR questionnaire QU, " "QU name '{0}', QR {1}_answers O, O value OV, " "O in_assessment A, A timepoint '{2}', O question Q, " "Q text QT".format(qname, rtype, timepoint)) rset.extend(self._cw.execute(rql)) table = defaultdict(lambda: OrderedDict.fromkeys(labels, "")) for item in rset: table[item[0]][item[1]] = item[2] for key in table: table[key]["ID"] = key writer = self.csvwriter() writer.writerow(labels) for psc2, data in iter(sorted(table.iteritems())): writer.writerow(data.values())
class EmptyCellView(AnyRsetView): __regid__ = 'empty-cell' __select__ = yes() def call(self, **kwargs): self.w(u' ') cell_call = call
class NeurospinAction(Action): __regid__ = "neurospin" __select__ = yes() category = "footer" order = 2 title = _("NeuroSpin") def url(self): return 'http://i2bm.cea.fr/drf/i2bm/NeuroSpin'
class ImagenLicenseAction(Action): __regid__ = "license" __select__ = yes() category = "footer" order = 3 title = _("License") def url(self): return self._cw.build_url("license")
class ImagenLegalAction(Action): __regid__ = "legal" __select__ = yes() category = "footer" order = 4 title = _("Legal") def url(self): return self._cw.build_url("legal")
class ApplLogo(HeaderComponent): """build the instance logo, usually displayed in the header""" __regid__ = 'logo' __select__ = yes() # no need for a cnx order = -1 context = _('header-left') def render(self, w): w(u'<a id="logo" href="%s"></a>' % self._cw.base_url())
class AnAppobject(object): __registries__ = ('hip', ) __regid__ = 'hop' __select__ = yes() registered = None @classmethod def __registered__(cls, reg): cls.registered = reg
class ImagenAction(Action): __regid__ = "imagen" __select__ = yes() category = "footer" order = 1 title = _("Imagen") def url(self): return 'http://www.imagen-europe.com/'
class PIWSPoweredByAction(Action): __regid__ = "poweredby" __select__ = yes() category = "footer" order = 3 title = _("Powered by NSAp") def url(self): return "https://github.com/neurospin/piws"
class AboutAction(action.Action): __regid__ = 'about' __select__ = yes() category = 'footer' order = 2 title = _('About this site') def url(self): return self._cw.build_url('doc/about')
class PoweredByAction(action.Action): __regid__ = 'poweredby' __select__ = yes() category = 'footer' order = 3 title = _('Powered by CubicWeb') def url(self): return 'http://www.cubicweb.org'
class ViewSchemaAction(action.Action): __regid__ = 'schema' __select__ = yes() title = _('data model schema') order = 30 category = 'manage' def url(self): return self._cw.build_url(self.__regid__)
class HelpAction(action.Action): __regid__ = 'help' __select__ = yes() category = 'footer' order = 0 title = _('Help') def url(self): return self._cw.build_url('doc/main')
class CWSearchEntityFormRenderer(EntityFormRenderer): __select__ = is_instance("CWSearch") & yes() main_form_title = _("Add subset to cart") def render_buttons(self, w, form): for button in form.form_buttons: button.attrs.setdefault("class", button.css_class) if button.cwaction == "apply": form.form_buttons.remove(button) super(CWSearchEntityFormRenderer, self).render_buttons(w, form)
class WebBrowserLogo(HeaderComponent): """ Build the instance logo, usually displayed in the header. """ __regid__ = "logo" __select__ = yes() order = -1 context = _("header-left", ) def render(self, w): w(u"<a href='{0}'><img id='logo' src='{1}' alt='logo'/></a>".format( self._cw.base_url(), self._cw.data_url(os.path.join("icons", "web_browser.ico"))))
def ajaxfunc(implementation=None, selector=yes(), output_type=None, check_pageid=False, regid=None): """promote a standard function to an ``AjaxFunction`` appobject. All parameters are optional: :param selector: a custom selector object if needed, default is ``yes()`` :param output_type: either None, 'json' or 'xhtml' to customize output content-type. Default is None :param check_pageid: whether the function requires a valid `pageid` or not to proceed. Default is False. :param regid: a custom __regid__ for the created ``AjaxFunction`` object. Default is to keep the wrapped function name. ``ajaxfunc`` can be used both as a standalone decorator: .. sourcecode:: python @ajaxfunc def my_function(self): return 42 or as a parametrizable decorator: .. sourcecode:: python @ajaxfunc(output_type='json') def my_function(self): return 42 """ # if used as a parametrized decorator (e.g. @ajaxfunc(output_type='json')) if implementation is None: def _decorator(func): return _ajaxfunc_factory(func, selector=selector, _output_type=output_type, _check_pageid=check_pageid, regid=regid) return _decorator # else, used as a standalone decorator (i.e. @ajaxfunc) return _ajaxfunc_factory(implementation, selector=selector, _output_type=output_type, _check_pageid=check_pageid, regid=regid)
class CreationFormView(EditionFormView): """display primary entity creation form""" __regid__ = 'creation' __select__ = specified_etype_implements('Any') & yes() title = _('creation') def call(self, **kwargs): """creation view for an entity""" # at this point we know etype is a valid entity type, thanks to our # selector etype = kwargs.pop('etype', self._cw.form.get('etype')) entity = self._cw.vreg['etypes'].etype_class(etype)(self._cw) entity.eid = next(self._cw.varmaker) self.render_form(entity) def form_title(self, entity): """the form view title""" if '__linkto' in self._cw.form: if isinstance(self._cw.form['__linkto'], list): # XXX which one should be considered (case: add a ticket to a # version in jpl) rtype, linkto_eid, role = self._cw.form['__linkto'][0].split( ':') else: rtype, linkto_eid, role = self._cw.form['__linkto'].split(':') linkto_rset = self._cw.eid_rset(linkto_eid) linkto_type = linkto_rset.description[0][0] if role == 'subject': title = self._cw.__( 'creating %s (%s %s %s %%(linkto)s)' % (entity.e_schema, entity.e_schema, rtype, linkto_type)) else: title = self._cw.__( 'creating %s (%s %%(linkto)s %s %s)' % (entity.e_schema, linkto_type, rtype, entity.e_schema)) msg = title % {'linkto': self._cw.view('incontext', linkto_rset)} self.w( u'<div class="formTitle notransform"><span>%s</span></div>' % msg) else: super(CreationFormView, self).form_title(entity) def url(self): """return the url associated with this view""" req = self._cw return req.vreg["etypes"].etype_class( req.form['etype']).cw_create_url(req) def submited_message(self): """return the message that will be displayed on successful edition""" return self._cw._('entity created')
class NullView(AnyRsetView): """:__regid__: *null* This view is the default view used when nothing needs to be rendered. It is always applicable and is usually used as fallback view when calling :meth:`_cw.view` to display nothing if the result set is empty. """ __regid__ = 'null' __select__ = yes() def call(self, **kwargs): pass cell_call = call
class Service(AppObject): """Base class for services. A service is a selectable object that performs an action server-side. Use :class:`cubicweb.dbapi.Connection.call_service` to call them from the web-side. When inheriting this class, do not forget to define at least the __regid__ attribute (and probably __select__ too). """ __registry__ = 'services' __select__ = yes() def call(self, **kwargs): raise NotImplementedError
class ApplicationMessage(component.Component): """display messages given using the __message/_cwmsgid parameter into a special div section """ __select__ = yes() __regid__ = 'applmessages' # don't want user to hide this component using a cwproperty cw_property_defs = {} def call(self, msg=None): if msg is None: msg = self._cw.message # XXX don't call self._cw.message twice self.w(u'<div id="appMsg" onclick="%s" class="%s">\n' % (toggle_action('appMsg'), (msg and ' ' or 'hidden'))) self.w(u'<div class="message" id="%s">%s</div>' % (self.domid, msg)) self.w(u'</div>')
class Component(ReloadableMixIn, View): """base class for components""" __registry__ = 'components' __select__ = yes() # XXX huummm, much probably useless (should be...) htmlclass = 'mainRelated' @property def cssclass(self): return '%s %s' % (self.htmlclass, domid(self.__regid__)) # XXX should rely on ReloadableMixIn.domid @property def domid(self): return '%sComponent' % domid(self.__regid__)
def _ajaxfunc_factory(implementation, selector=yes(), _output_type=None, _check_pageid=False, regid=None): """converts a standard python function into an AjaxFunction appobject""" class AnAjaxFunc(AjaxFunction): __regid__ = regid or implementation.__name__ __select__ = selector output_type = _output_type check_pageid = _check_pageid def serialize(self, content): if self.output_type is None: return content elif self.output_type == 'xhtml': self._cw.set_content_type(self._cw.html_content_type()) return ''.join((u'<div>', content.strip(), u'</div>')) elif self.output_type == 'json': self._cw.set_content_type('application/json') return json_dumps(content) raise RemoteCallFailed('no serializer found for output type %s' % self.output_type) def __call__(self, *args, **kwargs): if self.check_pageid: data = self._cw.session.data.get(self._cw.pageid) if data is None: raise RemoteCallFailed(self._cw._('pageid-not-found')) return self.serialize(implementation(self, *args, **kwargs)) AnAjaxFunc.__name__ = implementation.__name__ # make sure __module__ refers to the original module otherwise # vreg.register(obj) will ignore ``obj``. AnAjaxFunc.__module__ = implementation.__module__ # relate the ``implementation`` object to its wrapper appobject # will be used by e.g.: # import base_module # @ajaxfunc # def foo(self): # return 42 # assert foo(object) == 42 # vreg.register_and_replace(foo, base_module.older_foo) implementation.__appobject__ = AnAjaxFunc return implementation
class EntityFormRenderer(BaseFormRenderer): """This is the 'default' renderer for entity's form. You can still use form_renderer_id = 'base' if you want base FormRenderer layout even when selected for an entity. """ __regid__ = 'default' # needs some additional points in some case (XXX explain cases) __select__ = is_instance('Any') & yes() _options = FormRenderer._options + ('main_form_title',) main_form_title = _('main informations') def open_form(self, form, values): attrs_fs_label = '' if self.main_form_title: attrs_fs_label += ('<div class="iformTitle"><span>%s</span></div>' % self._cw._(self.main_form_title)) attrs_fs_label += '<div class="formBody">' return attrs_fs_label + super(EntityFormRenderer, self).open_form(form, values) def close_form(self, form, values): """seems dumb but important for consistency w/ close form, and necessary for form renderers overriding open_form to use something else or more than and <form> """ return super(EntityFormRenderer, self).close_form(form, values) + '</div>' def render_buttons(self, w, form): if len(form.form_buttons) == 3: w("""<table width="100%%"> <tbody> <tr><td align="center"> %s </td><td style="align: right; width: 50%%;"> %s %s </td></tr> </tbody> </table>""" % tuple(button.render(form) for button in form.form_buttons)) else: super(EntityFormRenderer, self).render_buttons(w, form)
class ETypeFacet(facetbase.RelationFacet): __regid__ = 'etype-facet' __select__ = yes() order = 1 rtype = 'is' target_attr = 'name' @property def title(self): return self._cw._('entity type') def vocabulary(self): """return vocabulary for this facet, eg a list of 2-uple (label, value) """ etypes = self.cw_rset.column_types(0) return sorted((self._cw._(etype), etype) for etype in etypes) def add_rql_restrictions(self): """add restriction for this facet into the rql syntax tree""" value = self._cw.form.get(self.__regid__) if not value: return self.select.add_type_restriction(self.filtered_variable, value) def possible_values(self): """return a list of possible values (as string since it's used to compare to a form value in javascript) for this facet """ select = self.select select.save_state() try: facetbase.cleanup_select(select, self.filtered_variable) etype_var = facetbase.prepare_vocabulary_select( select, self.filtered_variable, self.rtype, self.role) attrvar = select.make_variable() select.add_selected(attrvar) select.add_relation(etype_var, 'name', attrvar) return [etype for _, etype in self.rqlexec(select.as_string())] finally: select.recover()
class TableEditFormView(FormViewMixIn, EntityView): __regid__ = 'muledit' __select__ = EntityView.__select__ & yes() title = _('multiple edit') def call(self, **kwargs): """a view to edit multiple entities of the same type the first column should be the eid """ # XXX overriding formvid (eg __form_id) necessary to make work edition: # the edit controller try to select the form with no rset but # entity=entity, and use this form to edit the entity. So we want # edition form there but specifying formvid may have other undesired # side effect. Maybe we should provide another variable optionally # telling which form the edit controller should select (eg difffers # between html generation / post handling form) form = self._cw.vreg['forms'].select(self.__regid__, self._cw, rset=self.cw_rset, copy_nav_params=True, formvid='edition') form.render(w=self.w)
class EditionFormView(FormViewMixIn, EntityView): """display primary entity edition form""" __regid__ = 'edition' # add yes() so it takes precedence over deprecated views in baseforms, # though not baseforms based customized view __select__ = one_line_rset() & non_final_entity() & yes() form_id = 'edition' title = _('modification') def cell_call(self, row, col, **kwargs): entity = self.cw_rset.complete_entity(row, col) self.render_form(entity) def render_form(self, entity): """fetch and render the form""" self.form_title(entity) form = self._cw.vreg['forms'].select(self.form_id, self._cw, entity=entity, submitmsg=self.submited_message()) self.init_form(form, entity) form.render(w=self.w) def init_form(self, form, entity): """customize your form before rendering here""" pass def form_title(self, entity): """the form view title""" ptitle = self._cw._(self.title) self.w(u'<div class="formTitle"><span>%s %s</span></div>' % (entity.dc_type(), ptitle and '(%s)' % ptitle)) def submited_message(self): """return the message that will be displayed on successful edition""" return self._cw._('entity edited')
class RecipientsFinder(Component): """this component is responsible to find recipients of a notification by default user's with their email set are notified if any, else the default email addresses specified in the configuration are used """ __regid__ = 'recipients_finder' __select__ = yes() user_rql = ( 'Any X,E,A WHERE X is CWUser, X in_state S, S name "activated",' 'X primary_email E, E address A') def recipients(self): mode = self._cw.vreg.config['default-recipients-mode'] if mode == 'users': execute = self._cw.execute dests = list(execute(self.user_rql, build_descr=True).entities()) elif mode == 'default-dest-addrs': lang = self._cw.vreg.property_value('ui.language') dests = zip(self._cw.vreg.config['default-dest-addrs'], repeat(lang)) else: # mode == 'none' dests = [] return dests
class MyRegistrableInstance(RegistrableInstance): __regid__ = 'appobject3' __select__ = yes() __registry__ = 'zereg'
class AbstractSessionManager(RegistrableObject): """manage session data associated to a session identifier""" __abstract__ = True __select__ = yes() __registry__ = 'sessions' __regid__ = 'sessionmanager' def __init__(self, repo): vreg = repo.vreg self.session_time = vreg.config['http-session-time'] or None self.authmanager = authentication.RepositoryAuthenticationManager(repo) interval = (self.session_time or 0) / 2. if vreg.config.anonymous_user()[0] is not None: self.cleanup_anon_session_time = vreg.config[ 'cleanup-anonymous-session-time'] or 5 * 60 assert self.cleanup_anon_session_time > 0 if self.session_time is not None: self.cleanup_anon_session_time = min( self.session_time, self.cleanup_anon_session_time) interval = self.cleanup_anon_session_time / 2. # we don't want to check session more than once every 5 minutes self.clean_sessions_interval = max(5 * 60, interval) def clean_sessions(self): """cleanup sessions which has not been unused since a given amount of time. Return the number of sessions which have been closed. """ self.debug('cleaning http sessions') session_time = self.session_time closed, total = 0, 0 for session in self.current_sessions(): total += 1 last_usage_time = session.mtime no_use_time = (time() - last_usage_time) if session.anonymous_session: if no_use_time >= self.cleanup_anon_session_time: self.close_session(session) closed += 1 elif session_time is not None and no_use_time >= session_time: self.close_session(session) closed += 1 return closed, total - closed def current_sessions(self): """return currently open sessions""" raise NotImplementedError() def get_session(self, req, sessionid): """return existing session for the given session identifier""" raise NotImplementedError() def open_session(self, req): """open and return a new session for the given request. raise :exc:`cubicweb.AuthenticationError` if authentication failed (no authentication info found or wrong user/password) """ raise NotImplementedError() def close_session(self, session): """close session on logout or on invalid session detected (expired out, corrupted...) """ raise NotImplementedError()
class ErrorView(AnyRsetView): """default view when no result has been found""" __select__ = yes() __regid__ = 'error' def page_title(self): """returns a title according to the result set - used for the title in the HTML header """ return self._cw._('an error occurred') def _excinfo(self): req = self._cw ex = req.data.get('ex') excinfo = req.data.get('excinfo') if 'errmsg' in req.data: errmsg = req.data['errmsg'] exclass = None else: errmsg = exc_message(ex, req.encoding) exclass = ex.__class__.__name__ return errmsg, exclass, excinfo def call(self): req = self._cw.reset_headers() w = self.w title = self._cw._('an error occurred') w(u'<h2>%s</h2>' % title) ex, exclass, excinfo = self._excinfo() if excinfo is not None and self._cw.vreg.config['print-traceback']: if exclass is None: w(u'<div class="tb">%s</div>' % xml_escape(ex).replace("\n", "<br />")) else: w(u'<div class="tb">%s: %s</div>' % (exclass, xml_escape(ex).replace("\n", "<br />"))) w(u'<hr />') w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, '')) else: w(u'<div class="tb">%s</div>' % (xml_escape(ex).replace("\n", "<br />"))) # if excinfo is not None, it's probably not a bug if excinfo is None: return if self._cw.cnx: vcconf = self._cw.cnx.repo.get_versions() w(u"<div>") eversion = vcconf.get('cubicweb', self._cw._('no version information')) # NOTE: tuple wrapping needed since eversion is itself a tuple w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion, )) cversions = [] for cube in self._cw.vreg.config.cubes(): cubeversion = vcconf.get(cube, self._cw._('no version information')) w(u"<b>Cube %s version:</b> %s<br/>\n" % (cube, cubeversion)) cversions.append((cube, cubeversion)) w(u"</div>") # creates a bug submission link if submit-mail is set if self._cw.vreg.config['submit-mail']: form = self._cw.vreg['forms'].select('base', self._cw, rset=None, mainform=False) binfo = text_error_description(ex, excinfo, req, eversion, cversions) form.add_hidden( 'description', binfo, # we must use a text area to keep line breaks widget=wdgs.TextArea({'class': 'hidden'})) # add a signature so one can't send arbitrary text form.add_hidden('__signature', req.vreg.config.sign_text(binfo)) form.add_hidden('__bugreporting', '1') form.form_buttons = [wdgs.SubmitButton(MAIL_SUBMIT_MSGID)] form.action = req.build_url('reportbug') form.render(w=w)