This is not yet integrated in the sliceview and others, but works in a standalone test view like this
http://localhost:8080/trash/simplevalidatebutton/ple.inria.thierry_parmentelat
—
in a nutshell, we have topmenu display a disabled link ‘validation’ and send a query in background
if anything gets returned by this query - meaning the user is PI at some authority - we then
re-enable the menu button
—
There is one catch at this point, which is that the DOM element attached to the plugin - the menu button - needs to
have the ‘plugin’ class because this is what is used to trigger query events
So in this version we add this plugin class to the topmenu buttons, which is awkward
—
The reason why this plugin is special is, it does not come with its own DOM element but piggybacks on an existing one - which had no reason to have this plugin class attached
The plan to get this right is to have the plugin.js code manage an extra class (for example named pubsub) independantly from the DOM building code and conventions
// reasonably low-noise, shows manifold requests coming in and out
asynchroneous_debug : true,
// print our more details on result publication and related callbacks
- publish_result_debug : false,
+ publish_result_debug : true,
/**
* \brief We use js function closure to be able to pass the query (array)
count += 1;
});
if (manifold.publish_result_debug)
- messages.debug(".. publish_result NEW API (2) count=" + count);
+ messages.debug(".. publish_result (2) has used NEW API on " + count + " records");
manifold.raise_record_event(query.query_uuid, DONE);
+ if (manifold.publish_result_debug)
+ messages.debug(".. publish_result (3) has used NEW API to say DONE");
// OLD PLUGIN API BELOW
/* Publish an update announce */
var channel="/results/" + query.query_uuid + "/changed";
if (manifold.publish_result_debug)
- messages.debug(".. publish_result OLD API (3) " + channel);
+ messages.debug(".. publish_result (4) OLD API on channel" + channel);
$.publish(channel, [result, query]);
if (manifold.publish_result_debug)
- messages.debug(".. publish_result - END (4) q=" + query.__repr());
+ messages.debug(".. publish_result (5) END q=" + query.__repr());
},
/*!
}
if (manifold.asynchroneous_debug)
- messages.debug ("========== asynchroneous_success " + query.object + " -- before process_query_records");
+ messages.debug ("========== asynchroneous_success " + query.object + " -- before process_query_records [" + query.query_uuid +"]");
// once everything is checked we can use the 'value' part of the manifoldresult
var result=data.value;
**************************************************************************/
raise_event_handler: function(type, query_uuid, event_type, value) {
+ if (manifold.publish_result_debug)
+ messages.debug("raise_event_handler, quuid="+query_uuid+" type="+type+" event_type="+event_type);
if ((type != 'query') && (type != 'record'))
throw 'Incorrect type for manifold.raise_event()';
// xxx we observe quite a lot of incoming calls with an undefined query_uuid
- // this should be fixed upstream
+ // this should be fixed upstream in manifold I expect
if (query_uuid === undefined) {
messages.warning("undefined query in raise_event_handler");
return;
$.each(channels, function(i, channel) {
if (value === undefined) {
+ if (manifold.publish_result_debug) messages.debug("triggering [no value] on channel="+channel+" and event_type="+event_type);
$('.plugin').trigger(channel, [event_type]);
} else {
+ if (manifold.publish_result_debug) messages.debug("triggering [value="+value+"] on channel="+channel+" and event_type="+event_type);
$('.plugin').trigger(channel, [event_type, value]);
}
});
# 'django.contrib.admindocs',
'portal',
# temporary - not packaged
- # 'trash',
+ 'trash',
'sample',
'sandbox'
# DEPRECATED # 'django.contrib.formtools',
--- /dev/null
+from unfold.plugin import Plugin
+
+class ValidateButton (Plugin):
+
+ """This plugin is designed to work together with topmenu.
+
+It will check to see if user has PI rights at least on one authority,
+and if so will enable corresponding button in topmenu.
+
+A realistic example would have incoming query as
+
+Query.get('ple:user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
+
+"""
+
+ def __init__ (self, query=None, button_domid=None, **settings):
+ Plugin.__init__ (self, **settings)
+ # set defaults
+ if query is None:
+ query = Query.get('ple:user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
+ if button_domid is None: button_domid="topmenu-validate"
+ self.query=query
+ self.button_domid=button_domid
+
+ # this does not have any materialization
+ def render_content (self, request):
+ return ""
+
+ def requirements (self):
+ return { 'js_files': [ 'js/validatebutton.js', 'js/manifold-query.js', ], }
+
+ def json_settings_list (self):
+ return [ 'query_uuid', 'button_domid', ]
--- /dev/null
+// first application is for the 'validation' button in the topmenu
+// if the subject query is non empty, then we turn on the subject button
+// that is provided through button_domid
+
+(function($){
+
+ var debug=false;
+ debug=true
+
+ var ValidateButton = Plugin.extend({
+
+ init: function(options, element) {
+ this._super(options, element);
+ this.listen_query(options.query_uuid);
+ this.triggered=false;
+ },
+
+ // we have received at least one answer: we'll do something
+ on_new_record: function (record) {
+ // we only need to act on the first record
+ if (this.triggered) return;
+ if (debug) messages.debug("validatebutton.on_query_done - turning on "+this.options.button_domid);
+ $('#'+this.options.button_domid).removeClass('disabled');
+ this.triggered=true;
+ },
+ // for reference only, since there is nothing we need to do at this point
+ on_query_done: function() {
+ },
+ });
+
+ $.plugin('ValidateButton', ValidateButton);
+
+})(jQuery);
--- /dev/null
+# just one instance of validator
+from django.views.generic.base import TemplateView
+from django.template import RequestContext
+from django.shortcuts import render_to_response
+
+from manifold.core.query import Query, AnalyzedQuery
+
+from unfold.page import Page
+
+from ui.topmenu import topmenu_items, the_user
+
+from plugins.validatebutton import ValidateButton
+
+class SimpleValidateButtonView (TemplateView):
+
+ # mention a user name in the URL as .../trash/simplevalidatebutton/ple.inria.thierry_parmentelat
+ def get (self, request, username='ple.inria.thierry_parmentelat'):
+
+ page=Page(request)
+ page.expose_js_metadata()
+ query_pi_auths = Query.get('ple:user').filter_by('user_hrn', '==', username ).select('pi_authorities')
+ page.enqueue_query(query_pi_auths)
+
+ # even though this plugin does not have any html materialization, the corresponding domid
+ # must exist because it is searched at init-time to create the JS plugin
+ # so we simply piggy-back the target button here
+ validatebutton = ValidateButton (page=page,
+ # see above
+ domid='topmenu-validation',
+ query=query_pi_auths,
+ # this one is the target for a $.show() when the query comes back
+ button_domid="topmenu-validation")
+
+ # variables that will get passed to the view-unfold1.html template
+ template_env = {}
+
+ # there is a need to call render() for exposing the query and creating the js plugin
+ # even though this returns an empty string
+ rendered=validatebutton.render(request)
+
+ # write something of our own instead
+ template_env ['unfold_main'] = '<h1>Some title </h1>'
+
+ # more general variables expected in the template
+ template_env [ 'title' ] = 'simple validatebutton %(username)s'%locals()
+ # the menu items on the top
+ template_env [ 'topmenu_items' ] = topmenu_items('Slice', request)
+ # so we can see who is logged
+ template_env [ 'username' ] = the_user (request)
+
+ # don't forget to run the requests
+ page.expose_queries ()
+
+ # the prelude object in page contains a summary of the requirements() for all plugins
+ # define {js,css}_{files,chunks}
+ prelude_env = page.prelude_env()
+
+# print prelude_env.keys()
+# for k in [ 'js_files' ] :
+# print 'prelude_env',prelude_env,k,prelude_env[k]
+
+ template_env.update(prelude_env)
+ result=render_to_response ('view-unfold1.html',template_env,
+ context_instance=RequestContext(request))
+ return result
import trash.simpletableview
import trash.simplegridview
+import trash.simplevalidatebutton
urlpatterns = patterns(
'',
url(r'^dashboard/?$', 'trash.dashboard.dashboard_view'),
url(r'^simpletable/(?P<slicename>[\w\.]+)/?$', trash.simpletableview.SimpleTableView.as_view()),
url(r'^simplegrid/(?P<slicename>[\w\.]+)/?$', trash.simplegridview.SimpleGridView.as_view()),
+ url(r'^simplevalidatebutton/(?P<username>[\w\._]+)/?$', trash.simplevalidatebutton.SimpleValidateButtonView.as_view()),
)
</ul>
</li>
{% else %}
- {% if d.is_active %} <li class='active'> {% else %} <li class='other'> {% endif %}
+ <li class='{% if d.is_active %}active{% else %}other{% endif %} plugin{% if d.disabled %} disabled{%endif%}'
+ {% if d.domid %} id='{{d.domid}}'{% endif %}>
<a href="{{ d.href }}"> {{ d.label }} </a> </li>
{% endif %}
{% endfor %}
# dropdowns are kind of ad hoc for now, and limited to one level
# [
# ### a regular first-level button
-# {'label':...,'href':...},
+# {'label':...,'href':..., ['domid':.., 'disabled':...]},
# ### a dropdown
# { 'label': ..., 'href'=..., 'dropdown':True, 'contents': [ { 'label':.., 'href'} ] }
# , ..]
+# see also templates/widget-topmenu.html for how these items are put together
+# and plugins/validatebutton for how this hident button is turned on when necessary
+
# current: the beginning of the label in the menu that you want to outline
def topmenu_items (current,request=None):
has_user=request.user.is_authenticated()
if has_user:
result.append({'label':'Dashboard', 'href': '/portal/dashboard/'})
result.append({'label':'Request a slice', 'href': '/portal/slice_request/'})
- # ** Where am I a PI **
- # For this we need to ask SFA (of all authorities) = PI function
- user_query = Query().get('local:user').select('config','email')
- user_details = execute_query(request, user_query)
-
- # Required: the user must have an authority in its user.config
- # XXX Temporary solution
- # not always found in user_details...
- config={}
-# Deactivated until fixed
-# if user_details is not None:
-# for user_detail in user_details:
-# #email = user_detail['email']
-# if user_detail['config']:
-# config = json.loads(user_detail['config'])
-# user_detail['authority'] = config.get('authority',"Unknown Authority")
-# print "topmenu: %s", (user_detail['authority'])
-# if user_detail['authority'] is not None:
-# sub_authority = user_detail['authority'].split('.')
-# root_authority = sub_authority[0]
-# pi_authorities_query = Query.get(root_authority+':user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
-# else:
-# pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
-# try:
-# pi_authorities_tmp = execute_query(request, pi_authorities_query)
-# except:
-# pi_authorities_tmp = set()
-# pi_authorities = set()
-# for pa in pi_authorities_tmp:
-# if 'pi_authorities' in pa:
-# pi_authorities |= set(pa['pi_authorities'])
-# print "pi_authorities =", pi_authorities
-# if len(pi_authorities) > 0:
-# result.append({'label':'Validation', 'href': '/portal/validate/'})
- result.append({'label':'Validation', 'href': '/portal/validate/'})
+### # ** Where am I a PI **
+### # For this we need to ask SFA (of all authorities) = PI function
+### user_query = Query().get('local:user').select('config','email')
+### user_details = execute_query(request, user_query)
+###
+### # Required: the user must have an authority in its user.config
+### # XXX Temporary solution
+### # not always found in user_details...
+### config={}
+#### Deactivated until fixed
+#### if user_details is not None:
+#### for user_detail in user_details:
+#### #email = user_detail['email']
+#### if user_detail['config']:
+#### config = json.loads(user_detail['config'])
+#### user_detail['authority'] = config.get('authority',"Unknown Authority")
+#### print "topmenu: %s", (user_detail['authority'])
+#### if user_detail['authority'] is not None:
+#### sub_authority = user_detail['authority'].split('.')
+#### root_authority = sub_authority[0]
+#### pi_authorities_query = Query.get(root_authority+':user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
+#### else:
+#### pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
+#### try:
+#### pi_authorities_tmp = execute_query(request, pi_authorities_query)
+#### except:
+#### pi_authorities_tmp = set()
+#### pi_authorities = set()
+#### for pa in pi_authorities_tmp:
+#### if 'pi_authorities' in pa:
+#### pi_authorities |= set(pa['pi_authorities'])
+#### print "pi_authorities =", pi_authorities
+#### if len(pi_authorities) > 0:
+#### result.append({'label':'Validation', 'href': '/portal/validate/'})
+### result.append({'label':'Validation', 'href': '/portal/validate/'})
+ # always create a disabled button for validation, and let the
+ # validatebutton plugin handle that asynchroneously, based on this domid
+ result.append({'label':'Validation', 'href': '/portal/validate/', 'domid':'topmenu-validation', 'disabled':True})
dropdown = []
dropdown.append({'label':'Platforms', 'href': '/portal/platforms/'})
dropdown.append({'label':'My Account', 'href': '/portal/account/'})
def expose_js_metadata (self):
# expose global MANIFOLD_METADATA as a js variable
# xxx this is fetched synchroneously..
- self.add_js_init_chunks("var MANIFOLD_METADATA =" + self.get_metadata().to_json() + ";")
+ self.add_js_init_chunks("var MANIFOLD_METADATA =" + self.get_metadata().to_json() + ";\n")
def expose_js_manifold_config (self):
config=Config()