Commit b631fc59 authored by delanoe's avatar delanoe

Merge remote-tracking branch 'origin/c24b-testing' into testing

parents 19154fcf a4d37b16
from rest_framework.status import *
from rest_framework.exceptions import APIException
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
from rest_framework.views import APIView
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from gargantext.models import Node, Ngram, NodeNgram, NodeNodeNgram, NodeNode
from gargantext.constants import RESOURCETYPES, NODETYPES, get_resource
from gargantext.util.db import session, delete, func, bulk_insert
from gargantext.util.db_cache import cache, or_
from gargantext.util.validation import validate
from gargantext.models import Node, Ngram, NodeNgram, NodeNodeNgram, NodeNode
from gargantext.constants import RESOURCETYPES, NODETYPES, get_resource
from gargantext.util.http import ValidationException, APIView, JsonHttpResponse, get_parameters
from gargantext.util.files import upload
from gargantext.util.db import session, delete, func, bulk_insert
from gargantext.util.scheduling import scheduled
#import
#NODES format
_user_default_fields =["is_staff","is_superuser","is_active", "username", "email", "first_name", "last_name", "id"]
_api_default_fields = ['id', 'parent_id', 'name', 'typename', 'date']
_doc_default_fields = ['id', 'parent_id', 'name', 'typename', 'date', "hyperdata"]
#_resource_default_fields = [['id', 'parent_id', 'name', 'typename', "hyperdata.method"]
#_corpus_default_fields = ['id', 'parent_id', 'name', 'typename', 'date', "hyperdata","resource"]
def format_parent(node):
'''format the parent'''
try:
#USER
if node.username != "":
return {field: getattr(node, field) for field in _user_default_fields}
except:
#DOC
if node.typename == "DOCUMENT":
return {field: getattr(node, field) for field in _doc_default_fields}
elif node.typename == "CORPUS":
parent = {field: getattr(node, field) for field in _doc_default_fields}
#documents
#parent["documents"] = {"count":node.children("DOCUMENT").count()}
#resources
#parent["resources"] = {"count":node.children("RESOURCE").count()}
#status
#return {field: getattr(node, field) for field in _doc_default_fields}
parent["status_msg"] = status_message
return parent
#PROJECT, RESOURCES?
else:
return {field: getattr(node, field) for field in _api_default_fields}
def format_records(node_list):
'''format the records list'''
if len(node_list) == 0:
return []
node1 = node_list[0]
#USER
if node1.typename == "USER":
return [{field: getattr(node, field) for field in _user_default_fields} for node in node_list]
#DOCUMENT
elif node1.typename == "DOCUMENT":
return [{field: getattr(node, field) for field in _doc_default_fields} for node in node_list]
#CORPUS, PROJECT, RESOURCES?
elif node1.typename == "CORPUS":
records = []
for node in node_list:
#PROJECTS VIEW SHOULD NE BE SO DETAILED
record = {field: getattr(node, field) for field in _doc_default_fields}
record["resources"] = [n.id for n in node.children("RESOURCE")]
record["documents"] = [n.id for n in node.children("DOCUMENT")]
#record["resources"] = format_records([n for n in node.children("RESOURCE")])
#record["documents"] = format_records([n for n in node.children("DOCUMENT")])
status = node.status()
if status is not None and not status['complete']:
if not status['error']:
status_message = '(in progress: %s, %d complete)' % (
status['action'].replace('_', ' '),
status['progress'],
)
else:
status_message = '(aborted: "%s" after %i docs)' % (
status['error'][-1],
status['progress']
)
else:
status_message = ''
record["status"] = status_message
records.append(record)
return records
else:
return [{field: getattr(node, field) for field in _api_default_fields} for node in node_list]
def check_rights(request, node_id):
'''check that the node belong to USER'''
node = session.query(Node).filter(Node.id == node_id).first()
if node is None:
raise APIException("403 Unauthorized")
# return Response({'detail' : "Node #%s not found" %(node_id) },
# status = status.HTTP_404_NOT_FOUND)
elif node.user_id != request.user.id:
#response_data = {"log": "Unauthorized"}
#return JsonHttpResponse(response_data, status=403)
raise APIException("403 Unauthorized")
else:
return node
def format_response(parent, records):
#print(records)
return { "parent": format_parent(parent),
"records": format_records(records),
"count":len(records)
}
from django.core.exceptions import *
from .api import * #APIView, APIException entre autres
from gargantext.util.db import session
from gargantext.models import Node
from gargantext.util.http import *
class CorpusView(APIView):
'''API endpoint that represent a corpus'''
def get(self, request, project_id, corpus_id, view = "DOCUMENT"):
'''GET corpus detail
default view full documents
'''
params = get_parameters(request)
if "view" in params.keys():
filter_view = params["view"].upper()
if view in ["DOCUMENT", "JOURNAL", "TITLE", "ANALYTICS", "RESSOURCE"]:
view = filter_view
project = session.query(Node).filter(Node.id == project_id, Node.typename == "PROJECT").first()
check_rights(request, project.id)
if project is None:
return Response({'detail' : "PROJECT Node #%s not found" %(project_id) },
status = status.HTTP_404_NOT_FOUND)
corpus = session.query(Node).filter(Node.id == corpus_id, Node.typename == "CORPUS").first()
if corpus is None:
return Response({'detail' : "CORPUS Node #%s not found" %(corpus_id) },
status = status.HTTP_404_NOT_FOUND)
documents = session.query(Node).filter(Node.parent_id == corpus_id, Node.typename == view).all()
context = format_response(corpus, documents)
return Response(context)
def delete(self, request, project_id, corpus_id):
'''DELETE corpus'''
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>delete")
# project = session.query(Node).filter(Node.id == project_id, Node.typename == "PROJECT").first()
# check_rights(request, project.id)
# if project is None:
# return Response({'detail' : "PROJECT Node #%s not found" %(project_id) },
# status = status.HTTP_404_NOT_FOUND)
corpus = session.query(Node).filter(Node.id == corpus_id, Node.typename == "CORPUS").first()
if corpus is None:
return Response({'detail' : "CORPUS Node #%s not found" %(corpus_id) },
status = status.HTTP_404_NOT_FOUND)
documents = session.query(Node).filter(Node.parent_id == corpus_id).all()
session.delete(documents)
session.delete(corpus)
session.commit()
return Response(detail="Deleted corpus #%s" %str(corpus_id), status=HTTP_204_NO_CONTENT)
def put(self, request, project_id, corpus_id, view="DOCUMENT"):
'''UPDATE corpus'''
project = session.query(Node).filter(Node.id == project_id, Node.typename == "PROJECT").first()
project = check_rights(request, project.id)
if project is None:
return Response({'detail' : "PROJECT Node #%s not found" %(project_id) },
status = status.HTTP_404_NOT_FOUND)
corpus = session.query(Node).filter(Node.id == corpus_id, Node.typename == "CORPUS").first()
if corpus is None:
return Response({'detail' : "CORPUS Node #%s not found" %(corpus_id) },
status = status.HTTP_404_NOT_FOUND)
#documents = session.query(Node).filter(Node.parent_id == corpus_id, Node.typename= view).all()
for key, val in request.data.items():
if key in ["name", "date", "username", "hyperdata"]:
if key == "username":
#changement de propriétaire
#user = session.query(Node).filter(Node.typename=="USER", Node.username== username).first()
#print(user)
#set(node, user_id, user.id)
pass
elif key == "hyperdata":
#updating some contextualvalues of the corpus
pass
else:
setattr(node, key, val)
session.add(node)
session.commit()
'''#updating children???
'''
return Response({"detail":"Updated corpus #" %str(corpus.id)}, status=HTTP_202_ACCEPTED)
def post(self, request, project_id, corpus_id):
'''ADD a new RESOURCE to CORPUS'''
project = session.query(Node).filter(Node.id == project_id, Node.typename == "PROJECT").first()
check_rights(request, project.id)
if project is None:
return Response({'detail' : "PROJECT Node #%s not found" %(project_id) },
status = status.HTTP_404_NOT_FOUND)
corpus = session.query(Node).filter(Node.id == corpus_id, Node.typename == "CORPUS").first()
if corpus is None:
return Response({'detail' : "CORPUS Node #%s not found" %(corpus_id) },
status = status.HTTP_404_NOT_FOUND)
from gargantext.models import Node, Ngram, NodeNgram, NodeNodeNgram, NodeNode
from gargantext.constants import NODETYPES, DEFAULT_N_DOCS_HAVING_NGRAM
from gargantext.constants import NODETYPES
from gargantext.util.db import session, delete, func, bulk_insert
from gargantext.util.db_cache import cache, or_
from gargantext.util.validation import validate
......@@ -8,7 +8,7 @@ from gargantext.util.http import ValidationException, APIView \
, get_parameters, JsonHttpResponse, Http404\
, HttpResponse
from .api import *
from collections import defaultdict
import csv
......@@ -67,6 +67,48 @@ def _query_nodes(request, node_id=None):
# return the result!
return parameters, query, count
class Status(APIView):
'''API endpoint that represent the current status of the node'''
renderer_classes = (JSONRenderer, BrowsableAPIRenderer)
def get(self, request, node_id):
user = cache.User[request.user.id]
check_rights(request, node_id)
node = session.query(Node).filter(Node.id == node_id, Node.user_id== user.id).first()
if node is None:
return Response({"detail":"Node not Found for this user"}, status=HTTP_404_NOT_FOUND)
else:
context = format_response(node, [n for n in node.children()])
try:
context["status"] = node.hyperdata["statuses"]
except KeyError:
context["status"] = None
return Response(context)
def post(self, request, data):
'''create a new status for node'''
raise NotImplementedError
def put(self, request, data):
'''update status for node'''
user = cache.User[request.user.id]
check_rights(request, node_id)
node = session.query(Node).filter(Node.id == node_id).first()
raise NotImplementedError
#return Response({"detail":"Udpated status for NODE #%i " %node.id}, status=HTTP_202_ACCEPTED)
def delete(self, request):
'''delete status for node'''
user = cache.User[request.user.id]
check_rights(request, node_id)
node = session.query(Node).filter(Node.id == node_id).first()
if node is None:
return Response({"detail":"Node not Found"}, status=HTTP_404_NOT_FOUND)
node.hyperdata["status"] = []
session.add(node)
session.commit()
return Response({"detail":"Deleted status for NODE #%i " %node.id}, status=HTTP_204_NO_CONTENT)
class NodeListResource(APIView):
......@@ -143,8 +185,6 @@ class NodeListHaving(APIView):
Simple implementation:
Takes IDs of corpus and ngram and returns list of relevent documents in json format
according to TFIDF score (order is decreasing).
2016-09: add total counts to output json
'''
def get(self, request, corpus_id):
parameters = get_parameters(request)
......@@ -155,7 +195,7 @@ class NodeListHaving(APIView):
except :
raise ValidationException('"ngram_ids" needs integers separated by comma.')
limit = DEFAULT_N_DOCS_HAVING_NGRAM
limit=5
nodes_list = []
corpus = session.query(Node).filter(Node.id==corpus_id).first()
......@@ -178,18 +218,26 @@ class NodeListHaving(APIView):
.filter(Node.typename == 'DOCUMENT', Node.parent_id== corpus.id)
.filter(or_(*[NodeNodeNgram.ngram_id==ngram_id for ngram_id in ngram_ids]))
.group_by(Node)
.order_by(func.sum(NodeNodeNgram.score).desc())
.limit(limit)
)
# get the total count before applying limit
nodes_count = nodes_query.count()
# now the query with the limit
nodes_results_query = (nodes_query
.order_by(func.sum(NodeNodeNgram.score).desc())
.limit(limit)
)
for node, score in nodes_results_query:
# print("\n")
# print("in TFIDF:")
# print("\tcorpus_id:",corpus_id)
# convert query result to a list of dicts
# if nodes_query is None:
# print("TFIDF error, juste take sums")
# nodes_query = (session
# .query(Node, func.sum(NodeNgram.weight))
# .join(NodeNgram, NodeNgram.node_id == Node.id)
# .filter(Node.parent_id == corpus_id)
# .filter(Node.typename == 'DOCUMENT')
# .filter(or_(*[NodeNgram.ngram_id==ngram_id for ngram_id in ngram_ids]))
# .group_by(Node)
# .order_by(func.sum(NodeNgram.weight).desc())
# .limit(limit)
# )
for node, score in nodes_query:
print(node,score)
print("\t corpus:",corpus_id,"\t",node.name)
node_dict = {
......@@ -201,10 +249,7 @@ class NodeListHaving(APIView):
node_dict[key] = node.hyperdata[key]
nodes_list.append(node_dict)
return JsonHttpResponse({
'count': nodes_count,
'records': nodes_list
})
return JsonHttpResponse(nodes_list)
......@@ -438,8 +483,7 @@ class CorpusFacet(APIView):
# check that the hyperfield parameter makes sense
_facet_available_subfields = [
'journal', 'publication_year', 'rubrique',
'language_iso2', 'language_iso3', 'language_name',
'authors'
'language_iso2', 'language_iso3', 'language_name'
]
parameters = get_parameters(request)
......
from django.conf.urls import url
from . import nodes
from . import projects
from . import corpora
from . import ngrams
from . import metrics
from . import ngramlists
......@@ -10,7 +12,33 @@ from graph.rest import Graph
urlpatterns = [ url(r'^nodes$' , nodes.NodeListResource.as_view() )
, url(r'^nodes/(\d+)$' , nodes.NodeResource.as_view() )
, url(r'^nodes/(\d+)/having$' , nodes.NodeListHaving.as_view() )
, url(r'^nodes/(\d+)/status$' , nodes.Status.as_view() )
#Projects
, url(r'^projects$' , projects.ProjectList.as_view() )
, url(r'^projects/(\d+)$' , projects.ProjectView.as_view() )
#?view=resource
#?view=docs
#Corpora
, url(r'^projects/(\d+)/corpora/(\d+)$' , corpora.CorpusView.as_view() )
#?view=journal
#?view=title
#?view=analytics
#Sources
#, url(r'^projects/(\d+)/corpora/(\d+)/sources$' , corpora.CorpusSources.as_view() )
#, url(r'^projects/(\d+)/corpora/(\d+)/sources/(\d+)$' , corpora.CorpusSourceView.as_view() )
#Facets
, url(r'^projects/(\d+)/corpora/(\d+)/facets$' , nodes.CorpusFacet.as_view() )
#Favorites
, url(r'^projects/(\d+)/corpora/(\d+)/favorites$', nodes.CorpusFavorites.as_view() )
#Metrics
, url(r'^projects/(\d+)/corpora/(\d+)/metrics$', metrics.CorpusMetrics.as_view() )
#GraphExplorer
, url(r'^projects/(\d+)/corpora/(\d+)/explorer$' , Graph.as_view())
# data for graph explorer (json)
# GET /api/projects/43198/corpora/111107/explorer?
# Corresponding view is : /projects/43198/corpora/111107/explorer?
# Parameters (example):
# explorer?field1=ngrams&field2=ngrams&distance=conditional&bridgeness=5&start=1996-6-1&end=2002-10-5
# Ngrams
, url(r'^ngrams/?$' , ngrams.ApiNgrams.as_view() )
......@@ -63,10 +91,5 @@ urlpatterns = [ url(r'^nodes$' , nodes.NodeListResource.as_view()
, url(r'^ngramlists/maplist$' , ngramlists.MapListGlance.as_view() )
# fast access to maplist, similarly formatted for termtable
, url(r'^projects/(\d+)/corpora/(\d+)/explorer$' , Graph.as_view())
# data for graph explorer (json)
# GET /api/projects/43198/corpora/111107/explorer?
# Corresponding view is : /projects/43198/corpora/111107/explorer?
# Parameters (example):
# explorer?field1=ngrams&field2=ngrams&distance=conditional&bridgeness=5&start=1996-6-1&end=2002-10-5
]
/////////////////////////////////////
//// AJAX CALLS ////
/////////////////////////////////////
// c24b 01/06/2016
// templating +
// Generic AJAX methods (through API) for project and corpus
// - get (listing)
// - create
// - edit
// - delete
// - update
// - recalculate => API metrics
// utils: templateing cookies, error form, selected checkbox
////////////////////////////////////////////////////////////////////////
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
};
function loadTpl(tpl_id, record){
//generic function to load a TPL given its tpl_id (#)
var corpus_tpl = $(tpl_id).html();
corpus_tpl = corpus_tpl.replace(/{count}/g, record.count);
corpus_tpl = corpus_tpl.replace(/{name}/g, record.name);
corpus_tpl = corpus_tpl.replace(/{url}/g, record.url);
corpus_tpl = corpus_tpl.replace(/{status}/g, record.status);
corpus_tpl = corpus_tpl.replace(/{id}/g, record.id);
corpus_tpl = corpus_tpl.replace(/{query}/g, record.query);
corpus_tpl = corpus_tpl.replace(/{source}/g, record.source);
return corpus_tpl
};
// FORM STATUSES
function addFormStatus(status, form, msg){
//inform user from error in back throught API
//alert(form)
dismiss = '<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>'
if(status =="error"){
icon = '<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> '
msg = dismiss+icon+msg
//form
$(form).addClass("alert-danger")
//msg div
msg_div = $(form).children("div#status-form")
console.log(msg_div)
msg_div.html(msg)
msg_div.collapse("show")
}
else{
$(form).collapse("hide")
window.location.reload()
}
}
function resetStatusForm(form){
$(form).removeClass("alert-danger alert-info alert-success");
$("div#status-form").val("");
$("div#status-form").collapse("hide");
//$(form).collapse("hide");
//window.location.reload()
}
//PAGES STATUSES
function addPageStatus(status, msg){
dismiss = '<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>'
if (status == "error"){
icon = '<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> '
msg = dismiss+icon+msg
$('div#status-msg').addClass("alert-danger");
$('div#status-msg').html(msg);
$("div#status").collapse("show");
}
else if (status == "info"){
$('div#status-msg').addClass("alert-info");
icon = '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> '
msg = dismiss+icon+msg
$('div#status-msg').html(msg);
$("div#status").collapse("show");
$('div#editor').addClass("hidden");
}
else{
window.location.reload();
}
}
function selectedUrls(){
var selected = [];
$('input:checked').each(function() {
selected.push($(this).val());
});
return selected
};
function selectedIds(){
//only used for recalc
var selected = [];
$('input:checked').each(function() {
selected.push($(this).data("id"));
});
return selected
};
//// GET FROM API
function getProjects(){
url_ = "/api/projects"
console.log( ">> get_projects() from api/projects VIEW" );
$.ajax({
type: "GET",
url: url_,
dataType: "json",
success : function(data) {
var _content = "";
var _count = data.count;
for(var i in data.records) {
console.log(data.records[i]);
var record = data.records[i];
record.url = "/projects/"+record.id;
_content += loadTpl("#project_item",record)
};
$("#projects").html( _content );
},
error: function(data) {
console.log(data.status, data.responseJSON);
if (data.status == 404){
msg = 'You have no projects for now. Click <strong>Add project</strong> to create a new one'
addPageStatus("info", msg);
return;
}
else{
msg = data.status+':'+data.responseJSON["detail"]
addPageStatus("error", msg);
return;
}
},
});
};
function getCorpora(){
console.log( ">> get_CORPORA() from api/projects/<pid> VIEW" );
var pathname = window.location.pathname; // Returns path only
//alert(pathname)
url_ = "/api"+pathname
$.ajax({
type: "GET",
url: url_,
success : function(data) {
project = data.parent;
corpus_nb = data.count
corpora = data.records
//manque another request to serve resources
resources = getRessources(pathname);
var _content = "";
corpora.forEach(function(corpus) {
//getCorpus() info
corpus.url = pathname+"/corpora/"+corpus.id
corpus.count = corpus.documents.length
//corpus.resources = getCorpusResource(pathname+"/corpora/"+corpus.id)
_content += loadTpl("#corpus_item", corpus);
//corpus.status = setInterval( getCorpusStatus(pathname+"/corpora/"+corpus.id), 5000 );
//corpus.status = getCorpusStatus()
});
$("div#corpora").html( _content);
},
error: function(data) {
console.log(data.status, data.responseJSON);
if (data.status == 404){
msg = 'You have no corpora for now. Click <strong>Add corpus</strong> to create a new one'
addPageStatus("info", msg);
return;
}
else{
msg = data.status+':'+data.responseJSON["detail"]
addPageStatus("error", msg);
return;
}
},
});
};
function getRessources(){
var pathname = window.location.pathname;
url_ = "/api"+pathname+"/resources"
alert(url_)
}
//// POST TO API
//// PUT AND PATCH TO API
function deleteOne(url){
$.ajax({
url: '/api'+url,
type: 'delete',
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function(xhr) {
console.log("SUCCESS!");
//msg = "Sucessfully deleted"
//addPageStatus("success", "#editForm", msg);
window.location.reload()
},
error: function(xhr) {
console.log("FAIL!");
window.location.reload()
//console.log(xhr.status);
//var status = xhr.status;
//var info = xhr["detail"];
//var msg = "ERROR deleting project"+ url
//console.log(msg)
//addPageStatus("info", msg);
//window.location.reload();
},
});
};
function editOne(url, id, data){
$.ajax({
url: '/api'+url+"?"+jQuery.param(data),
type: 'PUT',
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function(response) {
console.log(response);
console.log("EDIT SUCCESS!");
addFormStatus("success", "div#editForm-"+id, response["detail"]);
window.location.reload()
},
error: function(xhr) {
console.log("EDIT FAIL!")
var status = xhr.status;
var info = xhr.responseJSON["detail"];
var msg = "<strong>ERROR ["+status+"]:</strong>"+ "<p>"+info+"</p>"
addFormStatus("error", "div#editForm-"+id, msg);
},
});
};
function recalculateOne(id){
$.ajax({
url: '/api/metrics/'+id,
type: 'PATCH',
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function(response) {
console.log("RECALC SUCCESS!");
window.location.reload();
},
error: function(xhr) {
console.log("RECALC FAIL!")
console.log(result)
var status = xhr.status;
var info = xhr["detail"];
var msg = "<strong>ERROR ["+status+"]:</strong>"+ "<p>"+info+"</p>"
//no form error is sent to page status alert
addPageStatus("error", msg);
},
});
};
/////////////////////////////////////////////////
/// PAGE INTERACTION
////////////////////////////////////////////////
//CONTEXTUAL HELP
$(document).on("hover", "button", function(){
//make tooltip on buttons using title attr
$(this).tooltip();
});
//MULTIPLE SELECTION ACTION
// checkbox with BUTTON #delete, #edit #refresh
//DELETE MULTI
$(document).on("click","#delete", function(){
var selected = selectedUrls();
selected.forEach(function(url) {
deleteOne(url);
});
//window.location.reload();
});
//EDIT MULTI
$(document).on("click","#edit", function(){
var selected = selectedUrls();
var statuses = [];
// selected.forEach(function(url) {
// editOne(url, data);
// });
//alert("Not Implemented Yet")
});
//RECALC MULTI
$(document).on("click","#recalculate", function(){
//alert("Recalculate");
var selected = selectedIds();
selected.forEach(function(id) {
recalculateOne(id);
});
window.location.reload();
});
//UNIQUE action
// button with .delete, .edit, .refresh
// UNIQUE DELETION
$(document).on("click", ".delete", function() {
var url = $( this ).data("url");
deleteOne(url);
//window.location.reload();
});
//UNIQUE EDITION
$(document).on("click",".edit", function(){
var id = $(this).data("id")
var url = $( this ).data("url")
console.log(id)
//newform.collapse("show");
$('#editForm-'+id).collapse('toggle')
$(document).bind('keypress', function(e) {
if(e.keyCode==13){
$('#edit-submit-'+id).trigger('click');
}
});
$("#edit-submit-"+id).on('click', function(){
//alert(url)
name = $("input#name-"+id).val()
data = {"name": name}
editOne(url, id, data);
//window.location.reload();
});
$("#edit-cancel-"+id).on('click', function(){
//alert("cancel")
$('input#name-'+id).val("");
resetStatusForm("#editForm-"+id);
});
$("button").on("click", ".edit", function(){
$('input#name-'+id).val("");
resetStatusForm("#editForm-"+id);
})
})
//UNIQUE RECALC
$(document).on("click",".refresh", function(){
alert(refresh)
//console.log( $(this))
var id = $(this).data("id")
//var url = $( this ).data("url")
recalculateOne(id)
window.location.reload();
});
function createProject() {
//alert("Creating a new project");
//simple post: with the name
//onclick inside element because probleme of scope with modal
//we recover the element by hand for the moment
var project_name = $(".popover #inputName").val();
//alert(project_name);
console.log("Create project #"+project_name);
console.log("POST /api/projects");
$.ajax({
url: '/api/projects',
type: 'post',
data: {"name":project_name},
dataType: 'json',
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function(xhr, response) {
console.log(xhr.status);
console.log(response["detail"]);
location.reload();
},
error: function(data) {
console.log(data)
status = data.status;
info = data.responseJSON["detail"];
msg = "<strong>ERROR ["+status+"]:</strong>"+ "<p>"+info+"</p>"
addFormStatus("error","div#createForm", msg)
},
})
};
function createCorpus(url, method, form){
alert(method)
alert(url)
console.log(form)
console.log("POST corpus")
$.ajax({
url: '/api/'+url+'?method='+method,
type: 'post',
async: true,
contentType: false, // obligatoire pour de l'upload
processData: false, // obligatoire pour de l'upload
dataType: 'json', // selon le retour attendu
data: form,
cache: false,
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function(data) {
console.log(data)
status = data.status;
info = data["detail"];
msg = "<strong>OK ["+status+"]:</strong>"+ "<p>"+info+"</p>"
addFormStatus("success", "form#formCorpus", msg)
setTimeout(function(){
$('div#info').slideUp('slow').fadeOut(function() {
window.location.reload(true);
});
}, 6000);
},
error: function(data) {
console.log(data);
console.log(data)
status = data.status;
info = data.responseJSON["detail"];
msg = "<strong>ERROR ["+status+"]:</strong>"+ "<p>"+info+"</p>"
alert(msg)
addFormStatus("error","form#formCorpus", msg);
//$(".collapse").collapse("hide");
//_content = '<h2><span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span>Error while creating the corpus.</h2>'
//$("div#info").append(_content);
//$("div#info").addClass("alert-danger");
//$("div#info").collapse("show");
},
})
};
......@@ -7,7 +7,6 @@
<script type="text/javascript" src="{% static "lib/jquery/1.11.1/jquery.min.js" %}"></script>
<script type="text/javascript" src="{% static "lib/gargantext/garganrest.js" %}"></script>
<link rel="stylesheet" href="{% static "lib/jquery/1.11.2/jquery-ui.css" %}">
<script type="text/javascript" src="{% static "lib/morris/morris.min.js" %}"></script>
<link rel="stylesheet" href="{% static "lib/morris/morris.css" %}">
......@@ -36,138 +35,124 @@
Projects
</h1>
</div>
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="col-md-3"></div>
<div class="col-md-5">
<p>
<br>
<button
type="button"
class="btn btn-primary btn-lg"
data-container="body"
data-toggle="popover"
data-placement="bottom"
>
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
<button id="add" type="button" class="btn btn-primary btn-lg" data-container="body" data-toggle="popover" data-placement="bottom">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
Add a new project
</button>
<div id="popover-content" class="hide">
<form enctype='multipart/form-data' action='/projects/' method='post'>
{% csrf_token %}
<p>
<label for="id_name">Name:</label>
<input id="id_name" maxlength="255" name="name" type="text" />
</p>
<input type='submit' class="btn" value='Add this project !'/>
</form>
</div>
</p>
</div>
</button>
<div id="popover-content" class="hide">
<div id="createForm" class="form-group">
{% csrf_token %}
<div id="status-form" class="collapse">
</div>
<div class="row inline">
<label class="col-lg-3" for="inputName" ><span class="pull-right">Name:</span></label>
<input class="col-lg-8" type="text" id="inputName" class="form-control">
</div>
<div class="row inline">
<div class="col-lg-3"></div>
<button id="createProject" class="btn btn-primary btn-sm col-lg-8 push-left">Add Project</button>
<div class="col-lg-2"></div>
</div>
</div>
</div>
</p>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="container">
<div class="container">
<div class="container">
{% if projects %}
{% for project in projects %}
<!--<div class="col-md-offset-7 col-md-4 content" style="background-color:grey">!-->
<div id="project_{{project.id}}" class="row">
<h3>
<div class="col-md-5 content">
<a
href="/projects/{{ project.id }}">
<span class="glyphicon glyphicon-book" aria-hidden="true"></span>
{{ project.name }}
</a>
</div>
<div class="col-md-3 content">
<a href="/projects/{{project.id}}" >
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
</button>
</a>
<button type="button" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="bottom"
data-content=" <ul>
<!--
<li>Rename</li>
--!>
<li onclick=&quot;
garganrest.nodes.delete({{project.id}}, function(){$('#project_'+{{project.id}}).remove()});
$(this).parent().parent().remove();
&quot;><a href=&quot;#&quot;>Delete</a>
</li>
</ul>
">
<span class="glyphicon glyphicon-trash pull-right" aria-hidden="true"></span>
</button>
</div>
{% if common_users %}
<!-- <a style="cursor:pointer;"><img class="share_button" data-id="{{ project.id }}" title="Share it!" width="20px" src="{% static "img/share.png" %}"></img></a> --!>
{% endif %}
</h3>
<h4>{{ project.subtitle }}<h4>
</div>
{% endfor %}
{% endif %}
{% if common_projects %}
<br><br><br><br><br><br>
<h3><i> - - Shared projects - -</i></h3>
{% for project in common_projects %}
<!--<div class="col-md-offset-7 col-md-4 content" style="background-color:grey">!-->
<div class="col-md-3 content">
<h3><a href="/projects/{{ project.id }}">{{ project.name }}</a>
<button type="button" class="btn btn-xs btn-default" data-container="body" data-toggle="popover" data-placement="bottom"
data-content='
<ul>
<li> Rename </li>
<li><a href="/projects/{{ project.id }}">Add new corpus</a></li>
<li><a href="/delete/{{ project.id }}">Delete</a></li>
</ul>
'>Manage</button>
</h3>
<h4>{{ project.subtitle }}<h4>
</div>
{% endfor %}
{% endif %}
<!-- GENERIC STATUS INFO -->
<div id="status" class="row col-lg-12 collapse">
<div id="status-msg" class="alert">
</div>
</div>
</div>
</div>
</div>
<!-- CHECKBOX EDITION -->
<div class="row" id="editor">
<button title="delete selected project" type="button" class="btn btn-danger" id="delete">
<span class="glyphicon glyphicon-trash " aria-hidden="true" ></span>
</button>
<!--
<button title="edit selected project" type="button" class="btn btn-warning" id="edit">
<span class="glyphicon glyphicon-pencil " aria-hidden="true" onclick="editProjects()"></span>
</button> -->
<!-- <button type="button" class="btn btn-info" id="recalculate">
<span class="glyphicon glyphicon-refresh " aria-hidden="true" onclick="recalculateProjects()"></span>
</button>
-->
</div>
<div id="sharemodal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<br />
<div class="row container" id="projects">
<!--here loading projectlist from GET /projects-->
</div>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Share this Corpus with your Groups</h3>
</div>
<div class="modal-body form-horizontal">
<h4>List of available groups:</h4>
<div id="groups_list">here show the groups</div>
<div class="modal-footer">
<button id="closesharemodal" type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button id="send_share" type="button" class="btn btn-primary" >Share<span id="simpleloader"></span></button>
</div>
</div>
<script type="html/tpl" id="project_item">
<div id="{url}" class="item row">
<h3>
<div class="col-md-6 content">
<input id="checkbox" type="checkbox" value="{url}" data-id="{id}">
<a href="{url}">
<span class="glyphicon glyphicon-book" aria-hidden="true"></span>
<span class="item_name">{name}</span>
</a>
</div>
</h3>
<div id="project_detail" class="col-md-4 content">
<div id="item-editor">
<!-- GET Project -->
<a href="{url}">
<button type="button" title="see project" class="btn btn-default show pull-right" aria-label="Left Align">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
</button>
</a>
<!-- EDIT PROJECT-->
<button class="btn btn-default edit pull-right" data-id="{id}" data-url="{url}" data-toggle="collapse">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
</button>
<!-- DELETE PROJECT -->
<button type="button" class="btn btn-default delete pull-right" data-url="{url}" >
<span class="glyphicon glyphicon-trash pull-right" aria-hidden="true"></span>
</button>
<!-- REFRESH PROJECT -->
<!--
<button type="button" class="btn btn-default refresh pull-right" data-id="{id}">
<span class="glyphicon glyphicon-refresh pull-right" aria-hidden="true"></span>
</button>
-->
</div>
<div id="project_status">
<!-- Here add nb of the corpus? -->
</div>
</div>
</div>
</div>
<div id="editForm-{id}" class="collapse ">
<!-- status of the form -->
<div id="status-form" class="collapse"></div>
<b>Name:</b><input type="text" id="name-{id}" />
<button id="edit-submit-{id}" class="btn btn-success btn-sm"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button>
<button id="edit-cancel-{id}" class="btn btn-danger btn-sm" ><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button>
</div>
</script>
<style type="text/css">
label {
......@@ -181,80 +166,28 @@
}
</style>
<script type="text/javascript" src="{% static "lib/gargantext/garganrest_projects.js" %}"></script>
<script type="text/javascript">
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var last_project = -1
function get_groups() {
console.log( "IN get_groups()!" )
var url_ = "/get_groups"
$.ajax({
type: "GET",
url: url_,
dataType: "json",
success : function(data, textStatus, jqXHR) {
var _content = ""
for(var i in data) {
var g_id = data[i][0] , g_name=data[i][1]
_content += '<label><input name="groups" data-id="'+g_id+'" type="checkbox" />&nbsp;'+g_name+'</label>'
}
$("#groups_list").html( _content )
},
error: function(exception) {
console.log("exception!:"+exception.status)
}
getProjects();
$(document).bind('keypress', function(e) {
if(e.keyCode==13){
$('#createProject').trigger('click');
}
});
}
if( $(".share_button").length>0 ) {
$(document).on("click","#createProject", function(e){
//alert("clicked");
//
//resetStatusForm("#createForm");
//$('input#inputName').val("");
createProject();
$('#add').on('hidden.bs.popover', function () {
// do something…
resetStatusForm("#createForm");
})
$(".share_button").click(function(){
last_project = $(this).data("id")
get_groups()
$("#sharemodal").modal("show");
});
$("#send_share").click(function() {
$('input[name=groups]:checked').each(function () {
$("#send_share").attr("disabled","disabled")
console.log( $(this).data("id") );
$("#simpleloader").html('<img width="30px" src="{% static "img/loading-bar.gif" %}"></img>')
$.ajax({
url: "/api/share/"+last_project+"/"+$(this).data("id"),
type: 'POST',
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function(data) {
console.log("SUCCESS!")
window.location.reload();
},
error: function(result) {
console.log("FAIL!")
console.log(result)
}
});
});
});
})
}
</script>
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment