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))
@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]
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:
# 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)
@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()
))
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)
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:
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)
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})
* \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*/);
}
},
}
// 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*/));
},
/*!
// 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/";
// 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);
- }
+ //}
}
},
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"
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', ''),
'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
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']
<form class="cmxform" id="form_{{domid}}" method="post" action="#" enctype="multipart/form-data" onsubmit="return validate_form_{{domid}}(this)">
<fieldset>
- {% for c in columns %}
+ {% for f in fields %}
<div class="field">
- <label for="lname">{{c.name}}</label>
- <input type="{{c.type}}" id="{{domid}}-{{c.field}}" name="{{c.field}}" size="25" class="required" minlength="2" value="{{c.old_value}}"/>
- <p class="hint">{{c.description}}</p>
- <span id='err-{{domid}}-{{c.field}}'><font color='red'>{{c.validation_err}}</font></span>
+ <label for="lname">{{f.name}}</label>
+ <input type="{{f.type}}" id="{{domid}}-{{f.field}}" name="{{f.field}}" size="25" class="required" minlength="2" value="{{f.old_value}}"/>
+ <p class="hint">{{f.description}}</p>
+ <span id='err-{{domid}}-{{f.field}}'><font color='red'>{{f.validation_err}}</font></span>
</div>
{% endfor %}
/* methods */
- this.on_result = function(data) {
-
- }
-
/**
* \brief Validate the form
* \param validate_callback (function) a callback to be triggered when validation is done
// 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 ... ?)
/**
* \brief Disable the form entirely, during a create query for example
*/
- this.disable = function() {
+ this.enable = function(is_enabled) {
}
}
/* Otherwise, proceed to next step */
- this.GoToNextStep();
+ $this.GoToNextStep();
}
this.doForwardProgress = function()
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',
'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