From f44c5a4320e96117a4f463114e8adb10372cfb9e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jordan=20Aug=C3=A9?= Date: Tue, 11 Jun 2013 15:52:45 +0200 Subject: [PATCH] updated portal --- manifold/core/query.py | 55 +++++++++++++++---- manifold/js/manifold.js | 32 +++++++---- manifold/manifoldproxy.py | 9 ++- plugins/form/__init__.py | 43 ++++----------- plugins/form/form.html | 10 ++-- plugins/form/form.js | 32 ++++++----- plugins/wizard/wizard.js | 2 +- .../user-registration-step2.html | 0 portal/views.py | 5 +- 9 files changed, 111 insertions(+), 77 deletions(-) rename portal/{ => templates}/user-registration-step2.html (100%) diff --git a/manifold/core/query.py b/manifold/core/query.py index e3118e0c..bedf04b6 100644 --- a/manifold/core/query.py +++ b/manifold/core/query.py @@ -148,21 +148,26 @@ class Query(object): self.filters = Filter([]) self.params = {} self.fields = set([]) - self.timestamp = "now" + self.timestamp = "now" self.timestamp = 'now' # ignored for now @returns(StringTypes) def __str__(self): + return "SELECT %(select)s%(from)s%(where)s%(at)s" % { + "select": ", ".join(self.get_select()) if self.get_select() else "*", + "from" : "\n FROM %s" % self.get_from(), + "where" : "\n WHERE %s" % self.get_where() if self.get_where() else "", + "at" : "\n AT %s" % self.get_timestamp() if self.get_timestamp() else "" + } + + @returns(StringTypes) + def __repr__(self): return "SELECT %s FROM %s WHERE %s" % ( ", ".join(self.get_select()) if self.get_select() else '*', self.get_from(), self.get_where() ) - @returns(StringTypes) - def __repr__(self): - return self.__str__() - def __key(self): return (self.action, self.object, self.filters, frozendict(self.params), frozenset(self.fields)) @@ -284,6 +289,10 @@ class Query(object): @classmethod def execute(self, object): return self.action('execute', object) + def at(self, timestamp): + self.timestamp = timestamp + return self + def filter_by(self, *args): if len(args) == 1: filters = args[0] @@ -298,7 +307,11 @@ class Query(object): raise Exception, 'Invalid expression for filter' return self - def select(self, fields): + def select(self, fields=None): + if not fields: + # Delete all fields + self.fields = set() + return self if not isinstance(fields, (set, list, tuple)): fields = [fields] for field in fields: @@ -313,8 +326,9 @@ class AnalyzedQuery(Query): # XXX we might need to propagate special parameters sur as DEBUG, etc. - def __init__(self, query=None): + def __init__(self, query=None, metadata=None): self.clear() + self.metadata = metadata if query: self.query_uuid = query.query_uuid self.analyze(query) @@ -324,8 +338,10 @@ class AnalyzedQuery(Query): @returns(StringTypes) def __str__(self): out = [] + fields = self.get_select() + fields = ", ".join(fields) if fields else '*' out.append("SELECT %s FROM %s WHERE %s" % ( - ", ".join(self.get_select()), + fields, self.get_from(), self.get_where() )) @@ -343,12 +359,25 @@ class AnalyzedQuery(Query): def subquery(self, method): # Allows for the construction of a subquery if not method in self._subqueries: - analyzed_query = AnalyzedQuery() + analyzed_query = AnalyzedQuery(metadata=self.metadata) analyzed_query.action = self.action - analyzed_query.object = method + try: + type = self.metadata.get_field_type(self.object, method) + except ValueError ,e: # backwards 1..N + type = method + analyzed_query.object = type self._subqueries[method] = analyzed_query return self._subqueries[method] + def get_subquery(self, method): + return self._subqueries.get(method, None) + + def remove_subquery(self, method): + del self._subqueries[method] + + def get_subquery_names(self): + return set(self._subqueries.keys()) + def subqueries(self): for method, subquery in self._subqueries.iteritems(): yield (method, subquery) @@ -360,6 +389,8 @@ class AnalyzedQuery(Query): for predicate in filters: if '.' in predicate.key: method, subkey = pred.key.split('.', 1) + # Method contains the name of the subquery, we need the type + # XXX type = self.metadata.get_field_type(self.object, method) sub_pred = Predicate(subkey, pred.op, pred.value) self.subquery(method).filter_by(sub_pred) else: @@ -372,6 +403,8 @@ class AnalyzedQuery(Query): for field in fields: if '.' in field: method, subfield = field.split('.', 1) + # Method contains the name of the subquery, we need the type + # XXX type = self.metadata.get_field_type(self.object, method) self.subquery(method).select(subfield) else: super(AnalyzedQuery, self).select(field) @@ -381,6 +414,8 @@ class AnalyzedQuery(Query): for param, value in self.params.items(): if '.' in param: method, subparam = param.split('.', 1) + # Method contains the name of the subquery, we need the type + # XXX type = self.metadata.get_field_type(self.object, method) self.subquery(method).set({subparam: value}) else: super(AnalyzedQuery, self).set({param: value}) diff --git a/manifold/js/manifold.js b/manifold/js/manifold.js index d24211ca..927924f3 100644 --- a/manifold/js/manifold.js +++ b/manifold/js/manifold.js @@ -77,10 +77,10 @@ var manifold = { * \brief We use js function closure to be able to pass the query (array) * to the callback function used when data is received */ - success_closure: function(query, publish_uuid, domid) + success_closure: function(query, publish_uuid, callback /*domid*/) { return function(data, textStatus) { - manifold.asynchroneous_success(data, query, publish_uuid, domid); + manifold.asynchroneous_success(data, query, publish_uuid, callback /*domid*/); } }, @@ -109,18 +109,20 @@ var manifold = { } // not quite sure what happens if we send a string directly, as POST data is named.. // this gets reconstructed on the proxy side with ManifoldQuery.fill_from_POST - jQuery.post(manifold.proxy_url, {'json':query_json} , manifold.success_closure(query, publish_uuid, tuple.domid)); + jQuery.post(manifold.proxy_url, {'json':query_json} , manifold.success_closure(query, publish_uuid, tuple.callback /*domid*/)); }) }, /** * \brief Forward a query to the manifold backend * \param query (dict) the query to be executed asynchronously + * \param callback (function) the function to be called when the query terminates + * Deprecated: * \param domid (string) the domid to be notified about the results (null for using the pub/sub system */ - forward: function(query, domid) { + forward: function(query, callback /*domid*/) { var query_json = JSON.stringify(query); - $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, query.query_uuid, domid)); + $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, query.query_uuid, callback/*domid*/)); }, /*! @@ -177,8 +179,12 @@ var manifold = { // most of the time publish_uuid will be query.query_uuid // however in some cases we wish to publish the result under a different uuid // e.g. an updater wants to publish its result as if from the original (get) query - asynchroneous_success : function (data, query, publish_uuid, domid) { + asynchroneous_success : function (data, query, publish_uuid, callback /*domid*/) { // xxx should have a nicer declaration of that enum in sync with the python code somehow + + /* If a callback has been specified, we redirect results to it */ + if (!!callback) { callback(data); return; } + if (data.code == 2) { // ERROR alert("Your session has expired, please log in again"); window.location="/logout/"; @@ -192,18 +198,20 @@ var manifold = { // once everything is checked we can use the 'value' part of the manifoldresult var result=data.value; if (result) { - if (!!domid) { - /* Directly inform the requestor */ - if (manifold.asynchroneous_debug) messages.debug("directing result to " + domid); - jQuery('#' + domid).trigger('results', [result]); - } else { + //if (!!callback /* domid */) { + // /* Directly inform the requestor */ + // if (manifold.asynchroneous_debug) messages.debug("directing result to callback"); + // callback(result); + // //if (manifold.asynchroneous_debug) messages.debug("directing result to " + domid); + // //jQuery('#' + domid).trigger('results', [result]); + //} else { /* XXX Jordan XXX I don't need publish_uuid here... What is it used for ? */ /* query is the query we sent to the backend; we need to find the * corresponding analyezd_query in manifold.all_queries */ tmp_query = manifold.find_query(query.query_uuid); manifold.publish_result_rec(tmp_query.analyzed_query, result); - } + //} } }, diff --git a/manifold/manifoldproxy.py b/manifold/manifoldproxy.py index 99de7849..fd4c5ad9 100644 --- a/manifold/manifoldproxy.py +++ b/manifold/manifoldproxy.py @@ -53,7 +53,14 @@ with the query passed using POST""" manifold_query.fill_from_POST(request.POST) offline_filename="offline-%s-%s.json"%(manifold_query.action,manifold_query.object) # retrieve session for request - manifold_api_session_auth = request.session['manifold']['auth'] + + # We allow some requests to use the ADMIN user account + if manifold_query.get_from() == 'local:user' and manifold_query.get_action() == 'create': + print "W: Used hardcoded demo account for admin queries" + manifold_api_session_auth = {'AuthMethod': 'password', 'Username': 'demo', 'AuthString': 'demo'} + else: + manifold_api_session_auth = request.session['manifold']['auth'] + if debug_empty and manifold_query.action.lower()=='get': json_answer=json.dumps({'code':0,'value':[]}) print "By-passing : debug_empty & 'get' request : returning a fake empty list" diff --git a/plugins/form/__init__.py b/plugins/form/__init__.py index cbbac201..ff569d5f 100644 --- a/plugins/form/__init__.py +++ b/plugins/form/__init__.py @@ -7,16 +7,13 @@ class CreateForm (Plugin): Plugin.__init__(self, **settings) print "SETTINGS", settings assert 'page' in settings, "You should specify page" - assert 'object' in settings or 'fields' in settings, "You should specify object or field list" + assert 'object' in settings, "You should specify object" if 'object' in settings: - # Retrieve object fields from metadata - metadata = settings['page'].get_metadata() - md_o = metadata.details_by_object(settings['object']) - self.columns = md_o['column'] + self.object = settings['object'] - elif 'fields' in settings: - self.columns = [] + if 'fields' in settings: + self.fields = [] for field in settings['fields']: c = { 'name' : field.get('name', ''), @@ -27,7 +24,12 @@ class CreateForm (Plugin): 'validate_err' : field.get('validate_err', ''), 'old_value' : 'POST', } - self.columns.append(c) + self.fields.append(c) + else: + # Attempt to retrieve object fields from metadata + metadata = settings['page'].get_metadata() + md_o = metadata.details_by_object(settings['object']) + self.fields = md_o['column'] def requirements (self): # Some should be included by default by manifold @@ -42,32 +44,9 @@ class CreateForm (Plugin): def template_env (self, request): env={} env.update(self.__dict__) - #env['columns']=self.columns return env def template_file (self): return "form.html" - def json_settings_list (self): return ['plugin_uuid', 'columns'] - - def get_validation_js(self): - # XXX We need to avoid sending the same query twice !" - # somehow store something into the dom, to perform an update afterwards - # XXX This should be moved to a template - # XXX We also need some storage into the wizard to be displayed later - return """ - // Useless since this is now a parameter - //frm = document.forms['form_%(domid)s']; - - // Loop on the fields and test regexp if present - err = false; - $.each(options.columns, function(column) { - if (!frm.elements[column['field']].match(column['validate_rx'])) { - $('err_%(domid)s_' + column['field']).html(column['validation_err']); - err = true; - } - }); - if (!err) { - // Issue json query - } - """ % self.__dict__ + def json_settings_list (self): return ['plugin_uuid', 'object', 'fields'] diff --git a/plugins/form/form.html b/plugins/form/form.html index cc2226f1..9fd413ce 100644 --- a/plugins/form/form.html +++ b/plugins/form/form.html @@ -2,12 +2,12 @@
- {% for c in columns %} + {% for f in fields %}
- - -

{{c.description}}

- {{c.validation_err}} + + +

{{f.description}}

+ {{f.validation_err}}
{% endfor %} diff --git a/plugins/form/form.js b/plugins/form/form.js index 8cec1746..b9d30d39 100644 --- a/plugins/form/form.js +++ b/plugins/form/form.js @@ -66,10 +66,6 @@ /* methods */ - this.on_result = function(data) { - - } - /** * \brief Validate the form * \param validate_callback (function) a callback to be triggered when validation is done @@ -83,32 +79,40 @@ // Loop on the fields and test regexp if present var err = false; var params = {} - $.each(options.columns, function(i, column) { - var value = frm.elements[column['field']].value; - var rx = column['validate_rx']; + $.each(options.fields, function(i, field) { + var value = frm.elements[field['field']].value; + var rx = field['validate_rx']; var str = ''; if (rx && !value.match(rx)) { - str = column['validate_err']; + str = field['validate_err']; err = true; } - params[column['field']] = value; - $('#err-' + options.plugin_uuid + '-' + column['field']).html(str); + params[field['field']] = value; + $('#err-' + options.plugin_uuid + '-' + field['field']).html(str); }); /* If the form correctly validates, we issue a create query */ if (!err) { var query = { 'action': 'create', - 'object': 'local:user', + 'object': options.object, 'params': params, }; /* Inform user about ongoing query: spinner */ - this.disable(); + this.enable(false); manifold.spin($obj); /* Issue json query and wait for callback */ - manifold.forward(query, this.onresult); + manifold.forward(query, function(data) { + manifold.spin($obj, false); + if (data.code != 0) { // ERROR OR WARNING, which we don't expect + alert("ERROR IN CALLING THE API"); + validate_callback(false); + return; + } + validate_callback(true); + }); } /* Note, if the create has already been done (or fails, or ... ?) @@ -122,7 +126,7 @@ /** * \brief Disable the form entirely, during a create query for example */ - this.disable = function() { + this.enable = function(is_enabled) { } diff --git a/plugins/wizard/wizard.js b/plugins/wizard/wizard.js index f974259e..c95826f2 100644 --- a/plugins/wizard/wizard.js +++ b/plugins/wizard/wizard.js @@ -358,7 +358,7 @@ } /* Otherwise, proceed to next step */ - this.GoToNextStep(); + $this.GoToNextStep(); } this.doForwardProgress = function() diff --git a/portal/user-registration-step2.html b/portal/templates/user-registration-step2.html similarity index 100% rename from portal/user-registration-step2.html rename to portal/templates/user-registration-step2.html diff --git a/portal/views.py b/portal/views.py index ba7f30f1..869bd2dc 100644 --- a/portal/views.py +++ b/portal/views.py @@ -44,9 +44,10 @@ def index(request): sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0)) start_step += 1 else: - # XXX This should become local:user # We could pass a list of fields also, instead of retrieving them from metadata # Otherwise we need some heuristics to display nice forms + # XXX Could we log the user in after the form is validated ? + # XXX Explain the password is for XXX field_list = [{ 'name' : 'First name', 'field' : 'firstname', @@ -77,7 +78,7 @@ def index(request): 'type' : 'password', 'description' : 'Enter your password again', }] - sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, fields = field_list)) + sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list)) # STEP 2 # If the user already exists (is logged), let's display a summary of its institution -- 2.43.0