# -*- coding: utf-8 -*-
'''
Created on Jul 01, 2014
@author: tc
'''
from datetime import datetime
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.sites.models import get_current_site
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.http import HttpResponse, HttpResponseBadRequest
from django.http import HttpResponseRedirect
from django.http.response import Http404
from django.shortcuts import get_object_or_404, redirect
from django.shortcuts import resolve_url
from django.template.response import TemplateResponse
from django.templatetags.static import static
from django.utils.http import is_safe_url
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic import TemplateView, View
from hdabo.models import Tag, Datasheet, TaggedSheet, Folder
from hdalab.models.dataviz import DbpediaFieldsTranslation
from hdalab.models.renkan import HdalabRenkan
from hdalab.views.ajax import filter_generic
from renkanmanager.models import Renkan
from renkanmanager.utils import LineNodePlacer, renkan_copier, renkan_deleter,\
CircleNodePlacer
from renkanmanager.views import RenkanGetPut
import json
import uuid
import logging
logger = logging.getLogger(__name__)
class BaseRenkanList(TemplateView):
def update_context(self, context, renkan_queryset):
sort_param = self.request.GET.get('sort', "date")
order_param = self.request.GET.get('order', "desc")
sort = {"date":"renkan__modification_date", "title":"renkan__title", "state":"state", "user":"renkan__owner__username"}.get(sort_param)
if order_param=="desc":
order = "-"
opposite = "asc"
else:
order = ""
opposite = "desc"
rl = renkan_queryset.order_by(order + sort)
p = Paginator(rl, settings.RENKANS_PER_PAGE)
page_nb = self.request.GET.get('page')
try:
page = p.page(page_nb)
except PageNotAnInteger:
page = p.page(1)
except EmptyPage:
page = p.page(p.num_pages)
context.update({"page": page, "sort_param":sort_param, "order_param":order_param, "opposite":opposite})
return context
class ProfileHome(BaseRenkanList):
template_name = "profile_home.html"
def get_context_data(self, **kwargs):
return self.update_context( super(ProfileHome, self).get_context_data(**kwargs), HdalabRenkan.objects.select_related("renkan").filter(renkan__owner=self.request.user) )
class RenkanPublicList(BaseRenkanList):
template_name = "renkan_list.html"
def get_context_data(self, **kwargs):
return self.update_context( super(RenkanPublicList, self).get_context_data(**kwargs), HdalabRenkan.objects.select_related("renkan").filter(state=HdalabRenkan.PUBLISHED) )
class RenkanNew(View):
def get(self, request):
rk = Renkan()
rk_id = unicode(uuid.uuid1())
rk.rk_id = rk_id
rk.owner = request.user
rk.content = '{}'
rk.title = "Nouveau Renkan "
rk.save()
hr = HdalabRenkan()
hr.renkan = rk
hr.state = HdalabRenkan.EDITION
hr.save()
return redirect("%s?rk_id=%s" % (reverse('renkan_edit'), rk_id))
class RenkanEdit(TemplateView):
template_name="renkan_edit.html"
def get_context_data(self, **kwargs):
context = super(RenkanEdit, self).get_context_data(**kwargs)
# If a renkan id is set
rk_id = self.request.GET.get("rk_id", "")
if rk_id!="":
hr = get_object_or_404(HdalabRenkan.objects.select_related("renkan", "renkan__owner"), renkan__rk_id=rk_id) #.get(=rk_id)
if hr.renkan.owner!=self.request.user or hr.state!=HdalabRenkan.EDITION:
raise Exception("You are not allowed to edit this renkan")
form = AuthenticationForm(self.request)
context["form"] = form
return context
class HdalabRenkanGetPut(RenkanGetPut):
@csrf_exempt
def dispatch(self, *args, **kwargs):
return super(HdalabRenkanGetPut, self).dispatch(*args, **kwargs)
def get(self, request):
# If a renkan id is set
rk_id = request.GET.get("rk_id", "")
if rk_id!="":
rk = get_object_or_404(Renkan, rk_id=rk_id)
return HttpResponse(rk.content, content_type="application/json")
shape = request.GET.get("shape", "")
no_translate_langs = [ 'fr' ]
lang = request.GET.get('lang',request.LANGUAGE_CODE)
# Start dict for renkan json
now = datetime.now().strftime("%Y-%m-%d %H:%M")
content = {
"id": unicode(uuid.uuid1()),
"title": "",
"description": "(empty description)",
"created": now,
"updated": now,
"nodes": [],
"edges": [],
"views": [],
"users": [],
}
# category image dict
cat_dict = {u"Créateur": static("hdalab/img/category_creator.png"),
u"Datation": static("hdalab/img/category_datation.png"),
u"Discipline artistique": static("hdalab/img/category_discipline.png"),
u"Localisation": static("hdalab/img/category_localisation.png"),
u"Ecole/Mouvement": static("hdalab/img/category_movement.png")}
# category image dict
shapes = { "tag1": "polygon", "notice": "rectangle", "tag2": "star" }
# Renkan Project ID
project_id = unicode(uuid.uuid1())
# If a notice id is set
notice_id = request.GET.get("notice", "")
if notice_id!="":
notice = get_object_or_404(Datasheet, hda_id=notice_id)
# We get the ORDERED tags if we display one sheet
ordered_tags = TaggedSheet.objects.filter(datasheet=notice).select_related("tag", "tag__dbpedia_fields", "tag__category").order_by('order')[:15]
# Prepare Node placer :
np = LineNodePlacer()
if shape=="circle":
np = CircleNodePlacer()
np.init({"datasheet": (1, 1), "tags": (2, len(ordered_tags))})
# Place notice :
content["nodes"].append({
"id": unicode(uuid.uuid1()),
"title": notice.title,
"description": notice.description,
"uri": notice.url,
"position": np.get_place("datasheet"),
"image": "http://www.histoiredesarts.culture.fr/images/pf/" + notice.hda_id + ".jpg",
"size": 0,
"project_id": project_id,
"color": "#FF0033",
#"created_by": "roster_user-84fe909f-ba37-48e6-a25f-9d2f129a95b7",
"shape": shapes["notice"]
})
# Get translated labels
translations = {}
if lang not in no_translate_langs:
transqs = DbpediaFieldsTranslation.objects.filter(master__in = [ot.tag.dbpedia_fields if hasattr(ot.tag, 'dbpedia_fields') and ot.tag.dbpedia_fields else None for ot in ordered_tags], language_code = lang)
translations = dict([(trans.master_id,trans.label) for trans in transqs])
for ot in ordered_tags:
t = ot.tag
img_url = t.dbpedia_fields.thumbnail if hasattr(t, 'dbpedia_fields') and t.dbpedia_fields and t.dbpedia_fields.thumbnail else None
if img_url is None and t.category is not None:
img_url = cat_dict[t.category.label]
content["nodes"].append({
"id": unicode(uuid.uuid1()),
"title": translations.get(t.dbpedia_fields.id, t.label) if hasattr(t, 'dbpedia_fields') and t.dbpedia_fields else t.label,
"description": t.dbpedia_uri,
"uri": "",
"position": np.get_place("tags"),
"image": img_url,
"size": 0,
"project_id": project_id,
"color": "#00FF33",
#"created_by": "roster_user-84fe909f-ba37-48e6-a25f-9d2f129a95b7",
"shape": shapes["tag2"]
})
response = json.dumps(content)
return HttpResponse(response, content_type="application/json")
# If a folder id is set
folder_id = request.GET.get("folder", "")
if folder_id!="":
#TODO : optimize to avoid tag request on each notice
folder = get_object_or_404(Folder.objects.select_related("datasheets", "datasheets__tags"), pk=folder_id)
notices = folder.datasheets.all()
n_tags = []
notice_tag_dict = {}
tag_uuid_dict = {}
for n in notices:
notice_tag_dict[n.pk] = {"uuid":unicode(uuid.uuid1()), "tags":[] }
for t in n.tags.all()[:5]:
if t.pk not in tag_uuid_dict:
tag_uuid_dict[t.pk] = unicode(uuid.uuid1())
notice_tag_dict[n.pk]["tags"].append(tag_uuid_dict[t.pk])
n_tags.append(t)
n_tags = [t.pk for t in n_tags]
all_tags = Tag.objects.filter( pk__in=n_tags ).select_related("dbpedia_fields", "category")
# Get translated labels
translations = {}
if lang not in no_translate_langs:
transqs = DbpediaFieldsTranslation.objects.filter(master__in = [t.dbpedia_fields if hasattr(t, 'dbpedia_fields') and t.dbpedia_fields else None for t in all_tags], language_code = lang)
translations = dict([(trans.master_id,trans.label) for trans in transqs])
# Prepare Node placer :
np = LineNodePlacer()
if shape=="circle":
np = CircleNodePlacer()
np.init({"datasheet": (1, len(notices)), "tags": (2, len(all_tags))})
# Place notices
for n in notices:
content["nodes"].append({
"id": notice_tag_dict[n.pk]["uuid"],
"title": n.title,
"description": n.description,
"uri": n.url,
"position": np.get_place("datasheet"),
"image": "http://www.histoiredesarts.culture.fr/images/pf/" + n.hda_id + ".jpg",
"size": 0,
"project_id": project_id,
"color": "#FF0033",
#"created_by": "roster_user-84fe909f-ba37-48e6-a25f-9d2f129a95b7",
"shape": shapes["notice"]
})
# Place tags
for t in all_tags:
img_url = t.dbpedia_fields.thumbnail if hasattr(t, 'dbpedia_fields') and t.dbpedia_fields and t.dbpedia_fields.thumbnail else None
if img_url is None and t.category is not None:
img_url = cat_dict[t.category.label]
content["nodes"].append({
"id": tag_uuid_dict[t.pk],
"title": translations.get(t.dbpedia_fields.id, t.label) if hasattr(t, 'dbpedia_fields') and t.dbpedia_fields else t.label,
"description": "",
"uri": t.dbpedia_uri,
"position": np.get_place("tags"),
"image": img_url,
"size": 0,
"project_id": project_id,
"color": "#00FF33",
#"created_by": "roster_user-84fe909f-ba37-48e6-a25f-9d2f129a95b7",
"shape": shapes["tag2"]
})
# Place edges
for n_pk in notice_tag_dict:
for tag_id in notice_tag_dict[n_pk]["tags"]:
content["edges"].append({
"id": unicode(uuid.uuid1()),
"title": "",
"description": "",
"uri": "",
"color": None,
"from": notice_tag_dict[n_pk]["uuid"],
"to": tag_id,
"project_id": project_id,
#"created_by": "de68xf75y6hs5rgjhgghxbm217xk"
})
response = json.dumps(content)
return HttpResponse(response, content_type="application/json")
# Otherwise we build the datas
# Get tags and countries
labels = request.GET.get("label", "").split(",")
countries = request.GET.get("country", "").split(",")
# Tags arrive with french label, countries with dbpedia uri
label_list = [t for t in labels if t!=""]
country_list = [c for c in countries if c!=""]
all_tags = Tag.objects.filter( Q(label__in=label_list) | Q(dbpedia_uri__in=country_list) ).select_related("dbpedia_fields", "category")
# Get datasheets from ajax filter search
filter_output = filter_generic(lang, None, ",".join(label_list), ",".join(country_list), content_count=10)
filter_output = json.loads(filter_output)
#logger.debug("COUCOU")
#logger.debug(json.dumps(filter_output, indent=2))
#return HttpResponse(json.dumps(filter_output, indent=2), content_type="application/json")
# Prepare other tags
related_tags = []
all_labels = [t.label for t in all_tags]
title = "Recherche " + ", ".join(all_labels)
content["title"] = title
related_tags_dict = {}
for c in filter_output["contents"]:
c["id"] = unicode(uuid.uuid1())
related_tags_dict[c["id"]] = []
for t in c["tags"]:
if t["label"] not in all_labels and t["order"]<6:
thumbnail_url = ""
for tt in filter_output["tags"]:
if tt["label"]==t["label"]:
thumbnail_url = tt["thumbnail"]
related_tags.append({"label": t["label"], "thumbnail":thumbnail_url, "id":t["id"], "url":t["url"]})
all_labels.append(t["label"])
related_tags_dict[c["id"]].append(t["id"])
# If possible, we search a dbpedia_fields thumbnail or category thumbnail for related tags
r_tags = [t["label"] for t in related_tags if t["thumbnail"] is None or t["thumbnail"]=="" ]
r_tags = Tag.objects.filter( label__in=r_tags ).select_related("dbpedia_fields", "category")
r_tags_dict = {}
for t in r_tags:
img_url = t.dbpedia_fields.thumbnail if hasattr(t, 'dbpedia_fields') and t.dbpedia_fields and t.dbpedia_fields.thumbnail else None
if img_url is None and t.category is not None:
img_url = cat_dict[t.category.label]
if img_url:
r_tags_dict[t.label] = img_url
# Populate related_tags with found image urls
for t in related_tags:
if (t["thumbnail"] is None or t["thumbnail"]=="") and (t["label"] in r_tags_dict):
t["thumbnail"] = r_tags_dict[t["label"]]
# Prepare Node placer :
np = LineNodePlacer()
if shape=="circle":
np = CircleNodePlacer()
np.init({"tags": (1, len(all_tags)), "datasheet": (2, len(filter_output["contents"])), "related": (3, len(related_tags))})
for t in all_tags:
img_url = t.dbpedia_fields.thumbnail if hasattr(t, 'dbpedia_fields') and t.dbpedia_fields and t.dbpedia_fields.thumbnail else None
if img_url is None and t.category is not None:
img_url = cat_dict[t.category.label]
content["nodes"].append({
"id": unicode(uuid.uuid1()),
"title": filter_output["tagtranslations"][t.label] if t.label in filter_output["tagtranslations"] else t.label,
"description": t.dbpedia_uri,
"uri": t.dbpedia_uri,
"position": np.get_place("tags"),
"image": img_url,
"size": 0,
"project_id": project_id,
"color": None,
#"created_by": "roster_user-84fe909f-ba37-48e6-a25f-9d2f129a95b7",
"shape": shapes["tag1"]
})
for c in filter_output["contents"]:
content["nodes"].append({
"id": c["id"],
"title": c["title"],
"description": c["description"],
"uri": c["url"],
"position": np.get_place("datasheet"),
"image": "http://www.histoiredesarts.culture.fr/images/pf/" + c["hda_id"]+ ".jpg",
"size": 0,
"project_id": project_id,
"color": "#FF0033",
#"created_by": "roster_user-84fe909f-ba37-48e6-a25f-9d2f129a95b7",
"shape": shapes["notice"]
})
for t in related_tags:
content["nodes"].append({
"id": t["id"],
"title": filter_output["tagtranslations"][t["label"]],
"description": "",
"uri": t["url"],
"position": np.get_place("related"),
"image": t["thumbnail"],
"size": 0,
"project_id": project_id,
"color": "#00FF33",
#"created_by": "roster_user-84fe909f-ba37-48e6-a25f-9d2f129a95b7",
"shape": shapes["tag2"]
})
for c_id in related_tags_dict:
for tag_id in related_tags_dict[c_id]:
content["edges"].append({
"id": unicode(uuid.uuid1()),
"title": "",
"description": "",
"uri": "",
"color": None,
"from": c_id,
"to": tag_id,
"project_id": project_id,
#"created_by": "de68xf75y6hs5rgjhgghxbm217xk"
})
response = json.dumps(content)
return HttpResponse(response, content_type="application/json")
def post(self, request):
rk_id = request.GET.get("rk_id", "")
#data = json.loads(request.body)
#logger.debug(data["edges"])
#logger.debug(data["nodes"])
#logger.debug(request.user.is_authenticated())
#logger.debug(request.user.is_anonymous())
if rk_id!="":
rk = get_object_or_404(Renkan, rk_id=rk_id)
if rk.owner!=request.user:
return HttpResponseBadRequest("You are not allowed to edit this renkan")
rk.content = request.body
data = json.loads(request.body)
if "title" in data:
rk.title = data["title"]
rk.save()
return HttpResponse("SAVED")
else:
# if rk_id was not a get parameter AND if it is set in json data AND if user is authenticated
# Then we can save the renkan
data = json.loads(request.body)
if "id" in data:
rk_id = data["id"]
if rk_id != "" and Renkan.objects.filter(rk_id=rk_id).count()==0 and request.user.is_authenticated():
rk = Renkan()
rk.rk_id = rk_id
rk.title = data["title"] if "title" in data else ""
rk.content = request.body
rk.owner = request.user
rk.save()
hr = HdalabRenkan()
hr.renkan = rk
hr.state = HdalabRenkan.EDITION
hr.save()
return HttpResponse("rk_id=" + rk_id)
return HttpResponse("NOT SAVED")
class HdalabRenkanCopy(View):
def get(self, request, rk_id):
rk = renkan_copier(request.user, rk_id)
hr = HdalabRenkan()
hr.renkan = rk
hr.state = HdalabRenkan.EDITION
hr.save()
if "next" in request.GET:
return redirect(request.GET["next"])
return redirect(reverse('profile_home'))
class HdalabRenkanDelete(View):
def get(self, request, rk_id):
try:
hr = HdalabRenkan.objects.get(renkan__rk_id=rk_id)
except:
raise Http404('Renkan not found')
renkan_deleter(request.user, rk_id)
hr.delete()
if "next" in request.GET:
return redirect(request.GET["next"])
return redirect(reverse('profile_home'))
class HdalabRenkanModerate(View):
def get(self, request, rk_id, state):
if rk_id!="":
try:
hr = HdalabRenkan.objects.select_related("renkan", "renkan__owner").get(renkan__rk_id=rk_id)
except:
raise Http404('Renkan not found')
if hr.renkan.owner!=request.user and not request.user.is_staff:
return HttpResponseBadRequest("You are not allowed to modify the state this renkan.")
hr.state = state
hr.save()
if "next" in request.GET:
return redirect(request.GET["next"])
return redirect(reverse('profile_home'))
# Function copied from django.contrib.auth.views to simplify ajax login
@sensitive_post_parameters()
@csrf_protect
@never_cache
def ajax_login(request, template_name='ajax_identification/ajax_login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(request, data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)