add task indicator + some cleaning tasks
authorymh <ymh.work@gmail.com>
Tue, 14 Apr 2015 12:31:07 +0200
changeset 91 59450d864881
parent 90 447bac7821e6
child 92 79c77ca08fd3
add task indicator + some cleaning tasks
src/catedit/__init__.py
src/catedit/config.py.tmpl
src/catedit/settings.py
src/catedit/static/css/style.css
src/catedit/static/js/check_tasks.js
src/catedit/tasks.py
src/catedit/templates/categories/submit.html
src/catedit/templates/categories/workshop.html
src/catedit/templates/layout.html
src/catedit/templates/social/changeset.html
src/catedit/views/__init__.py
src/catedit/views/home.py
src/catedit/views/meta.py
src/catedit/views/utils.py
--- a/src/catedit/__init__.py	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/__init__.py	Tue Apr 14 12:31:07 2015 +0200
@@ -39,7 +39,7 @@
 cache = Cache(app, config=app.config["CACHE_CONFIG"])
 
 # CSRF protection
-CsrfProtect(app)
+csrf = CsrfProtect(app)
 
 # Github
 app.config["GITHUB_CLIENT_ID"] = app.config["PERSISTENCE_CONFIG"].get(
@@ -52,7 +52,8 @@
 )
 github = GitHub(app)
 
-celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
+#celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'], backend=app.config['CE'])
+celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'], backend=app.config['CELERY_RESULT_BACKEND'])
 celery.conf.update(app.config)
 
 @github.access_token_getter
@@ -141,11 +142,12 @@
 app.config["CURRENT_VERSION"] = CURRENT_VERSION
 
 # Views and APIs
-from catedit.views import home, categories, social
+from catedit.views import home, categories, social, meta
 from catedit.resources import CategoryAPI, CategoryChangesAPI
 app.register_blueprint(home.module)
-app.register_blueprint(categories.module)
-app.register_blueprint(social.module)
+app.register_blueprint(categories.module, url_prefix='/cat')
+app.register_blueprint(social.module, url_prefix='/social')
+app.register_blueprint(meta.meta, url_prefix='/meta')
 
 
 api.add_resource(CategoryAPI,
--- a/src/catedit/config.py.tmpl	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/config.py.tmpl	Tue Apr 14 12:31:07 2015 +0200
@@ -6,6 +6,7 @@
 from rdflib import RDF, RDFS, Literal
 from rdflib.namespace import SKOS
 from kombu import Queue
+import os
 
 class AppConfig(object):
 
@@ -13,7 +14,8 @@
 
     HOST = "0.0.0.0"
     DEBUG = True
-	
+
+
     # WTForms settings
 
     SECRET_KEY = 'totally-secret-key'
@@ -27,7 +29,7 @@
     LOGGING_CONFIG = {
         "IS_LOGGING": False,
         "LOGGING_LEVEL": "DEBUG",
-        "LOG_FILE_PATH": "../../run/log/log.txt",
+        "LOG_FILE_PATH": os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),'../../run/log/log.txt')),
     }
 
     """
@@ -73,34 +75,35 @@
         "GITHUB_CLIENT_ID" : "github-client-placeholder",
         "GITHUB_CLIENT_SECRET" : "github-secret-placeholder",
     }
-	
+
     PROPERTY_LIST = {
         "http://www.w3.org/2000/01/rdf-schema#comment": {
-			"descriptive_label_fr": "Commentaire",
-			"descriptive_label_en": "Comment",
-			"object_type": "literal",
-			"usable_in_editor": false,
-			"rdflib_class": "http://www.w3.org/2000/01/rdf-schema#comment"
-		},
-		"http://www.w3.org/2000/01/rdf-schema#Resource": {
-			"descriptive_label_fr": "Ressource",
-			"descriptive_label_en": "Resource",
-			"object_type": "uriref-link",
-			"usable_in_editor": false,
-			"rdflib_class": "http://www.w3.org/2000/01/rdf-schema#Resource"
-		},
-		"http://www.w3.org/2004/02/skos/core#related": {
-			"descriptive_label_fr": "En relation avec",
-			"descriptive_label_en": "Related to",
-			"object_type": "uriref-category",
-			"usable_in_editor": false,
-			"rdflib_class": "http://www.w3.org/2004/02/skos/core#related"
-		}
+            "descriptive_label_fr": "Commentaire",
+            "descriptive_label_en": "Comment",
+            "object_type": "literal",
+            "usable_in_editor": false,
+            "rdflib_class": "http://www.w3.org/2000/01/rdf-schema#comment"
+        },
+        "http://www.w3.org/2000/01/rdf-schema#Resource": {
+            "descriptive_label_fr": "Ressource",
+            "descriptive_label_en": "Resource",
+            "object_type": "uriref-link",
+            "usable_in_editor": false,
+            "rdflib_class": "http://www.w3.org/2000/01/rdf-schema#Resource"
+        },
+        "http://www.w3.org/2004/02/skos/core#related": {
+            "descriptive_label_fr": "En relation avec",
+            "descriptive_label_en": "Related to",
+            "object_type": "uriref-category",
+            "usable_in_editor": false,
+            "rdflib_class": "http://www.w3.org/2004/02/skos/core#related"
+        }
     }
-    
+
     # Celery settings
-    
-    CELERY_BROKER_URL = 'sqla+sqlite:////Users/durandn/IRIProjects/catedit/src/catedit/celerydb.sqlite'
+
+    CELERY_BROKER_URL = 'sqla+sqlite:///' + os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),'../../run/files/celerydb.sqlite'))
+    CELERY_RESULT_BACKEND = 'db+sqlite:///' + os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)),'../../run/files/celeryresults.sqlite'))
     if PERSISTENCE_CONFIG["METHOD"] == "PersistenceToGithub":
         CELERY_QUEUES = tuple(
             Queue("repo_"+repository, routing_key="task_for_"+repository) for repository in PERSISTENCE_CONFIG["REPOSITORY_LIST"]
--- a/src/catedit/settings.py	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/settings.py	Tue Apr 14 12:31:07 2015 +0200
@@ -15,5 +15,7 @@
 
     BASE_NAMESPACE = "http://ld.iri-research.org/ontology/categorisation"
     CATEGORY_NAMESPACE = Namespace("http://ld.iri-research.org/ontology/categorisation/category#")
+    CELERY_IGNORE_RESULT = False
     CELERY_TASK_SERIALIZER = 'json'
     CELERY_ACCEPT_CONTENT = ['json', 'msgpack', 'yaml']
+    CELERY_DISABLE_RATE_LIMITS = True
--- a/src/catedit/static/css/style.css	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/static/css/style.css	Tue Apr 14 12:31:07 2015 +0200
@@ -81,3 +81,15 @@
   width: 100%;
   height: 60px;
 }
+
+
+#task_message {
+  position: absolute;
+  top: 70px;
+  right: 10px;
+  white-space: nowrap;
+}
+
+#task_message span {
+  margin-right: 15px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/catedit/static/js/check_tasks.js	Tue Apr 14 12:31:07 2015 +0200
@@ -0,0 +1,56 @@
+// -*- coding: utf-8 -*-
+/*!
+ *
+ */
+"use strict";
+
+function setTasksMessage(running_tasks_nb) {
+  var message;
+  var klass;
+
+  console.log('running_tasks_nb : ', running_tasks_nb);
+
+  if(running_tasks_nb === 0) {
+    message = 'Soumission terminée. <button type="button" onclick="document.location.reload(true);" class="btn btn-default">Recharger</button>';
+    klass = 'alert-success';
+  }
+  else if(running_tasks_nb === 1) {
+    message = '1 soummission en cour.';
+    klass = 'alert-info';
+  }
+  else {
+    message =  running_tasks_nb.toString() + ' soumissions en cour.'
+    klass = 'alert-info';
+  }
+
+  $('#task_indicator').html(message);
+  //TODO: check something mor efficient
+  $('#task_message').removeClass('alert-info alert-success').addClass(klass);
+  if(!$('#task_message').data('closed')) {
+    $('#task_message').removeClass('hide');
+  }
+
+}
+
+
+function checkTasks(endpoint_url) {
+  $.get(endpoint_url).done(function(data) {
+
+    console.log("check tasks", data);
+    setTasksMessage(parseInt(data.running_tasks_nb));
+
+  });
+}
+
+
+$(function() {
+
+  setTasksMessage(running_tasks_nb);
+  setInterval(function() {
+    checkTasks(check_tasks_url);
+  }, 5000);
+
+  $('#task_message a.close').click(function(e) {
+    $(e.target).data('closed', 'true');
+  });
+});
--- a/src/catedit/tasks.py	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/tasks.py	Tue Apr 14 12:31:07 2015 +0200
@@ -33,9 +33,9 @@
                 modified_cat_dict=modified_categories,
                 message=message
             )
-            requests.get(app.config['BASE_URL']+"/cache-clear-after-task")
-
-@app.route('/cache-clear-after-task', methods=["GET"])
-def cache_clear_endpoint():
-    cache.clear()
-    return ('', 204)
+            r = requests.post(app.config['BASE_URL']+"/meta/cache-clear")
+            try:
+                r.raise_for_status()
+            except:
+                logger.exception("Error when clearing cache.")
+                pass
--- a/src/catedit/templates/categories/submit.html	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/templates/categories/submit.html	Tue Apr 14 12:31:07 2015 +0200
@@ -7,7 +7,6 @@
 {% block title %}{{current_repository}}: Soumission{% endblock title %}
 {% block head %}
   {{ super() }}
-  <script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}" language="Javascript" type="text/javascript"></script>
   <script>
     $(document).ready(function(){
       $(".cat-delete-div").hide();
--- a/src/catedit/templates/categories/workshop.html	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/templates/categories/workshop.html	Tue Apr 14 12:31:07 2015 +0200
@@ -7,7 +7,6 @@
 {% block title %}{{current_repository}}: Atelier{% endblock title %}
 {% block head %}
   {{ super() }}
-  <script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}" language="Javascript" type="text/javascript"></script>
   <script>
     $(document).ready(function(){
       $(".cat-delete-div").hide();
@@ -25,7 +24,7 @@
    		$("#properties_"+evt.target.id.split('_').slice(2,5).join('_')).slideToggle(function(){
        		 $("#info_button_"+evt.target.id.split('_').slice(2,5).join('_')).children().toggleClass("glyphicon-plus-sign");
              $("#info_button_"+evt.target.id.split('_').slice(2,5).join('_')).children().toggleClass("glyphicon-minus-sign");
-   	    });	
+   	    });
       });
     });
   </script>
@@ -50,7 +49,7 @@
   </div>
   {% endif %}
   <p>
-  <h3>Etat de l'ensemble de catégories 
+  <h3>Etat de l'ensemble de catégories
     <a title="Afficher/Cacher tableau" class="btn btn-default cat-table-toggle">
       <span class="glyphicon glyphicon-chevron-up"/>
     </a>
@@ -66,7 +65,7 @@
         <li>
           <b> Soumettre tous mes changements: </b><a href="{{ url_for('categories.submit', repository=current_repository)}}" title="Soumettre changements" class="btn btn-default" {% if readonly %}disabled{% endif %}><span class="glyphicon glyphicon-share"/></a>
         </li>
-        {% endif %} 
+        {% endif %}
         {% if session["modified_categories"][current_repository] or session["deleted_categories"][current_repository] %}
         <li>
           <b> Supprimer tous mes changements: </b>
--- a/src/catedit/templates/layout.html	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/templates/layout.html	Tue Apr 14 12:31:07 2015 +0200
@@ -8,6 +8,15 @@
     <title>{% block title %}{% endblock title %}</title>
     <link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
     <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet">
+    <script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}"></script>
+    {% if current_repository  and session.get('tasks',{}).get(current_repository,[]) and running_tasks_nb %}
+    <script>
+        var check_tasks_url = "{{url_for('meta.query_tasks_status', repository=current_repository)}}";
+        var running_tasks_nb = {{running_tasks_nb}};
+    </script>
+    <script src="{{ url_for('static', filename='js/check_tasks.js') }}"></script>
+    <script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
+    {% endif %}
   {% endblock head %}
 </head>
 <body>
@@ -30,10 +39,10 @@
             <li><a href="{{ url_for('home.index') }}">Accueil</a></li>
           {% endblock navbar_items %}
         </ul>
-        <div class="navbar-text navbar-right">
+        <p class="navbar-text navbar-right">
           {% if not session.get("user_logged", None)%} Non authentifié - <a href="{{ url_for('home.login') }}" class="navbar-link">S'authentifier</a>
           {% else %} Authentifié: {{ session["user_login"] }} - <a href="{{ url_for('home.logout') }}" class="navbar-link">Quitter</a>{% endif %}
-        </div>
+        </p>
         {% if session["user_logged"] %}
           <form class="navbar-form navbar-right">
             <select class="form-control select-repo" name="navrepo" onchange="window.location.href=this.form.navrepo.options[this.form.navrepo.selectedIndex].value">
@@ -49,6 +58,12 @@
     </div>
   </div>
   <div class="container">
+    {% if current_repository  and session.get('tasks',{}).get(current_repository,[]) and running_tasks_nb %}
+    <div class="alert alert-info hide" id="task_message" data-closed='false'>
+        <a class="close" data-dismiss="alert">&times;</a>
+        <span id="task_indicator"></span>
+    </div>
+    {% endif %}
     {% block page_content %}
     {% endblock page_content %}
   </div>
--- a/src/catedit/templates/social/changeset.html	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/templates/social/changeset.html	Tue Apr 14 12:31:07 2015 +0200
@@ -7,7 +7,6 @@
 {% block title %}{{super()}}{% endblock title %}
 {% block head %}
   {{super()}}
-  <script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}" language="Javascript" type="text/javascript"></script>
   <script>
     $(document).ready(function(){
       $(".cat-info-div").hide();
--- a/src/catedit/views/__init__.py	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/views/__init__.py	Tue Apr 14 12:31:07 2015 +0200
@@ -1,1 +1,1 @@
-__all__ = ["home", "categories", "social"]
+__all__ = ["home", "categories", "social", "meta"]
--- a/src/catedit/views/home.py	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/views/home.py	Tue Apr 14 12:31:07 2015 +0200
@@ -50,7 +50,7 @@
     logger.debug(session["user_code"])
     session["user_logged"] = True
     session["user_login"] = "auth-error"
-    
+
     session["properties"] = {
         repo: {} for repo
         in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]
@@ -67,7 +67,7 @@
         repo: [] for repo
         in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]
     }
-    
+
     try:
         session["user_login"] = github.get(
             "user",
@@ -125,20 +125,5 @@
         Github, else when logging back in, github will send the app the
         same oauth code
     """
-    session["user_logged"] = None
-    session["user_code"] = None
-    session["user_login"] = None
-    session["user_can_edit"] = None
-    session["modified_categories"] = {
-        repo: {} for
-        repo in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]
-    }
-    session["deleted_categories"] = {
-        repo: {} for repo
-        in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]
-    }
-    session["properties"] = {
-        repo: {} for repo
-        in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]
-    }
+    session.clear()
     return redirect(url_for('home.index'))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/catedit/views/meta.py	Tue Apr 14 12:31:07 2015 +0200
@@ -0,0 +1,67 @@
+"""
+meta.py:
+the views that provide meta actions on the system
+"""
+
+from celery.result import AsyncResult
+from celery.states import SUCCESS, FAILURE, REVOKED
+from flask import Blueprint, session, jsonify, request
+
+from catedit import app, cache, celery, csrf
+from catedit.views import utils
+
+meta = Blueprint('meta', __name__)
+logger = app.logger
+
+
+@csrf.exempt
+@meta.route('/cache-clear', defaults={'cache_keys': None}, methods=["POST"])
+@meta.route('/cache-clear/<cache_keys>', methods=["POST"])
+def cache_clear_endpoint(cache_keys):
+    if not cache_keys:
+        cache.clear()
+    else:
+        cache_keys_list = cache_keys.split(",")
+        cache.delete_many(*cache_keys_list)
+    return ('', 204)
+
+
+@meta.route('/query-tasks-status/<string:repository>', defaults={'task_ids': None}, methods=["GET"])
+@meta.route('/query-tasks-status/<string:repository>/<string:task_ids>', methods=["GET"])
+def query_tasks_status(repository, task_ids=None):
+
+    logger.debug('task_ids %r' % task_ids)
+    if not task_ids:
+        task_ids_list = session.get('tasks', {}).get(repository, [])
+    else:
+        task_ids_list = task_ids.split(',')
+
+
+    logger.debug('tasks_ids_list %r' % task_ids_list)
+
+    res = utils.get_tasks_status(task_ids_list, not task_ids, repository)
+
+    return jsonify(**res)
+
+@meta.route('/help', methods = ['GET'])
+def help():
+    """Print available functions."""
+    func_list = {}
+    for rule in app.url_map.iter_rules():
+        if rule.endpoint != 'static':
+            func_list[rule.rule] = app.view_functions[rule.endpoint].__doc__
+    return jsonify(func_list)
+
+@app.context_processor
+def inject_running_tasks():
+    logger.debug("inject_running_tasks : %r" % request.view_args)
+    if 'repository' in request.view_args:
+        repository = request.view_args['repository']
+        task_ids_list = session.get('tasks', {}).get(repository, [])
+        if task_ids_list:
+            tasks_status = utils.get_tasks_status(task_ids_list, True, repository)
+            return {'running_tasks_nb': tasks_status.get('running_tasks_nb',0)}
+        else:
+            return {'running_tasks_nb': 0}
+    else:
+        return {}
--- a/src/catedit/views/utils.py	Fri Apr 10 17:30:19 2015 +0200
+++ b/src/catedit/views/utils.py	Tue Apr 14 12:31:07 2015 +0200
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*- 
+# -*- coding: utf-8 -*-
 """
 utils.py:
 Module that groups utility functions and classes that are used by views,
@@ -7,7 +7,7 @@
 be cached
 """
 
-from catedit import app, github, cache, log_api_rate, save_links
+from catedit import app, github, cache, log_api_rate, save_links, celery
 from catedit.models import Category
 from catedit.resources import CategoryAPI, CategoryChangesAPI
 from flask import redirect, url_for, session
@@ -572,3 +572,21 @@
                 }
             )
     return cat_list
+
+
+def get_tasks_status(task_ids_list, delete_task_from_session, repository) :
+    logger.debug("get_tasks_status : %r " % task_ids_list)
+    res = { 'states' : {} }
+    running_tasks_nb = 0
+    for task_id in task_ids_list:
+        a_res = celery.AsyncResult(task_id)
+        res['states'][task_id] = a_res.state
+        if a_res.ready():
+            a_res.forget()
+            if delete_task_from_session:
+                session.get('tasks',{}).get(repository, []).remove(task_id)
+        else:
+            running_tasks_nb += 1
+    res['running_tasks_nb'] = running_tasks_nb
+
+    return res