--- 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">×</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