validation_timestamp and create_new_revision are not part of the data. move them to query parameters
--- a/server/python/django2/renkanmanager/api/views.py Tue Jun 21 10:30:08 2016 +0200
+++ b/server/python/django2/renkanmanager/api/views.py Tue Jun 21 17:53:06 2016 +0200
@@ -15,10 +15,14 @@
from django.http import Http404
from django.http.response import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect
+from django.utils import dateparse
from django.views.generic import View
from django.conf import settings
+
from renkanmanager.models import Renkan, Revision, Workspace
from renkanmanager.serializers import RenkanSerializer, RevisionSerializer, WorkspaceSerializer
+from renkanmanager.utils import parse_bool
+
from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
@@ -42,7 +46,6 @@
def post(self, request, workspace_guid='', format=None):
create_data = {key:request.data[key] for key in request.data.keys()}
- logger.debug("HELLO %r", create_data)
source_renkan_guid_str = request.GET.get("source_renkan_id", request.data.get("source_renkan_id", None))
source_revision_guid_str = request.GET.get("source_revision_id", request.data.get("source_revision_id", None))
@@ -69,7 +72,6 @@
create_data["source_revision_id"] = source_revision.revision_guid
create_data["title"] = request.data.get("title", source_revision.title)
create_data["content"] = source_revision.content
- logger.debug("SOURCE_REVISION CONTENT %r", create_data["content"])
try:
workspace_guid_uuid = workspace_guid and uuid.UUID(workspace_guid) or None
@@ -119,7 +121,7 @@
self.check_object_permissions(request, renkan)
serializer = RenkanSerializer(renkan)
- if {'true': True, 'false': False, "0": False, "1": True}.get(request.GET.get("content_only", "false").lower()):
+ if parse_bool(request.GET.get("content_only", "false")):
return Response(json.loads(serializer.data["content"]), status=status.HTTP_200_OK, content_type='application/json')
return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')
@@ -134,20 +136,23 @@
logger.debug("RENKAN PUT: permission? %r", request.user.has_perm("change_renkan", renkan))
self.check_object_permissions(request, renkan)
logger.debug("RENKAN PUT: PERMISSION GRANTED")
- if {'true': True, 'false': False, "0": False, "1": True}.get(request.GET.get("content_only", "false").lower()):
+ if parse_bool(request.GET.get("content_only", "false")):
put_data = {}
put_data["content"] = json.dumps(request.data)
put_data["title"] = request.data.get("title", "")
else:
put_data = request.data
- if put_data.get("validation_timestamp", None) is None and put_data.get("content", None) is not None:
- put_data["validation_timestamp"] = json.loads(put_data["content"]).get("updated", "")
- serializer = RenkanSerializer(renkan, data=put_data)
+ validation_timestamp = request.GET.get("validation_timestamp")
+ if validation_timestamp is None and put_data.get("content") is not None:
+ validation_timestamp = json.loads(put_data["content"]).get("updated", "")
+ if validation_timestamp:
+ validation_timestamp = dateparse.parse_datetime(validation_timestamp)
+ create_new_revision = parse_bool(request.GET.get('create_new_revision', 'false'))
+ serializer = RenkanSerializer(renkan, data=put_data, validation_timestamp=validation_timestamp)
if serializer.is_valid():
- serializer.save(updator=request.user)
- if {'true': True, 'false': False, "0": False, "1": True}.get(request.GET.get("content_only", "false").lower()):
+ serializer.save(updator=request.user, create_new_revision=create_new_revision)
+ if parse_bool(request.GET.get("content_only", "false")):
return Response(json.loads(serializer.data["content"]), status=status.HTTP_200_OK, content_type='application/json')
- logger.debug("RENKAN PUT: SERIALIZER DATA %r", serializer.data)
return Response(serializer.data, status=status.HTTP_200_OK, content_type='application/json')
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
--- a/server/python/django2/renkanmanager/docs/index.md Tue Jun 21 10:30:08 2016 +0200
+++ b/server/python/django2/renkanmanager/docs/index.md Tue Jun 21 17:53:06 2016 +0200
@@ -6,10 +6,10 @@
##### Renkan
-L'objet Renkan est le principal point d'entrée de l'API.
+L'objet Renkan est le principal point d'entrée de l'API.
Chaque Renkan est associé à au plus un workspace et au moins une révision
-* Représentation JSON
+* Représentation JSON
```sh
{
@@ -29,33 +29,33 @@
##### Révisions
-Une révision représente l'état d'un renkan à un instant donné.
-Chaque révision est associé à un unique Renkan. Lorsqu'un renkan est modifié, on peut soit altérer la révision courante, soit créer une nouvelle révision. La dernière révision d'un renkan donné créée est la "révision courante" de ce renkan.
+Une révision représente l'état d'un renkan à un instant donné.
+Chaque révision est associé à un unique Renkan. Lorsqu'un renkan est modifié, on peut soit altérer la révision courante, soit créer une nouvelle révision. La dernière révision d'un renkan donné créée est la "révision courante" de ce renkan.
-C'est au niveau de l'objet Révision que sont stockées les informations de titre et de contenu d'un Renkan.
+C'est au niveau de l'objet Révision que sont stockées les informations de titre et de contenu d'un Renkan.
-* Représentation JSON
+* Représentation JSON
```sh
{
"id" : id de la revision
"title" : titre de la revision
"content" : contenu (JSON) de la revision
- "parent_renkan_id" : id du renkan associé à la révision
- "workspace_id" : si le renkan associé à la révision est assigné à un workspace,
+ "parent_renkan_id" : id du renkan associé à la révision
+ "workspace_id" : si le renkan associé à la révision est assigné à un workspace,
id du workspace du renkan,
"renkan_created_by" : username du créateur du renkan
"renkan_last_updated_by" : username du dernier utilisateur à avoir modifié le renkan
"revision_created_by" : username du créateur de la révision
- "revision_last_updated_by" : username du dernier utilisateur à avoir modifié la révision
+ "revision_last_updated_by" : username du dernier utilisateur à avoir modifié la révision
"revision_modification_date" : date de dernière modification de la révision
}
```
##### Workspaces
-Un workspace (ou espace) renkan est une structure (optionnelle) regroupant un ou plusieurs renkans.
+Un workspace (ou espace) renkan est une structure (optionnelle) regroupant un ou plusieurs renkans.
-* Représentation JSON
+* Représentation JSON
```sh
{
@@ -70,7 +70,8 @@
### Liste exhaustive des endpoints de l'API
#### Endpoints Renkan
-1. **Créer un Renkan**
+
+##### 1. Créer un Renkan
```POST /renkan-api/renkans/```
Données à passer en JSON (facultatif):
@@ -85,22 +86,22 @@
Si succès: Renvoie ```201 CREATED``` et le json associé au renkan créé
-2. **Dupliquer un Renkan**
-```POST /renkan-api/renkans/?source_renkan_id=<:renkan_id>```
+##### 2. Dupliquer un Renkan
+```POST /renkan-api/renkans/?source_renkan_id=<:renkan_id>```
Données à passer en JSON:
```
{
"title": titre de la copie (facultatif)
}
-```
+```
**Note:** Dans l'implémentation actuelle, si la donnée "title" n'est pas fournie, le titre du renkan copié sera identique au titre du renkan source.
-Si succès: renvoie ```201 CREATED``` et le json décrivant le renkan créé.
+Si succès: renvoie ```201 CREATED``` et le json décrivant le renkan créé.
Si échec: renvoie un ```404 NOT FOUND``` si ```<:renkan_id>``` ne correspond à aucun renkan existant
-3. **Modifier un Renkan**
+##### 3. Modifier un Renkan
```PUT /renkan-api/renkans/<:renkan_id>```
Données à passer en JSON:
@@ -110,55 +111,61 @@
}
```
-Si succès: renvoie ```200 OK``` et le json associé au renkan modifié
+###### Paramêtres de requête
+- **```validation_timestamp```** : date (urlencodée) au format ISO8601 correspondant à valeur du champ ```updated``` du contenu du renkan à modifier. Est utilisé pour vérifier que le renkan cible n'ai pas été modifié entre 2 requêtes.
+- **```create_new_revision```** : Force la création d'une nouvelle révision pour le Renkan. Si ```false```, la révision counrant est mise à jour. ```false``` par défaut.
+- **```content_only```** : Retourne seulement le contenu du renkan dans le reeponse, et pas les métadata.
+
+Si succès: renvoie ```200 OK``` et le json associé au renkan modifié
Si échec: renvoie un ```404 NOT FOUND``` si ```<:renkan_id>``` ne correspond à aucun renkan existant.
-4. **Obtenir la liste des Renkan**
+##### 4. Obtenir la liste des Renkan
```GET /renkan-api/renkans/```
Renvoie la liste des renkans auxquels l'utilisateur authentifié a accès en lecture.
Si succès: Renvoie ```200 OK```et une liste où chaque élément correspond à un json de renkan.
-5. **Obtenir les informations sur un Renkan**
-```GET /renkan-api/renkans/<:renkan_id>```
+##### 5. Obtenir les informations sur un Renkan
+```GET /renkan-api/renkans/<:renkan_id>```
-Si succès: renvoie ```200 OK``` et le json associé au renkan requêté
+Si succès: renvoie ```200 OK``` et le json associé au renkan requêté
Si échec: renvoie ```404 NOT FOUND``` si ```<:renkan_id>``` ne correspond à aucun renkan existant.
-6. **Supprimer un renkan**
+##### 6. Supprimer un renkan
```DELETE /renkan-api/renkans/<:renkan_id>```
-Si succès: renvoie ```204 NO CONTENT```
+Si succès: renvoie ```204 NO CONTENT```
Si échec: renvoie un ```404 NOT FOUND``` si ```<:renkan_id>``` ne correspond à aucun renkan existant.
#### Endpoints Révision
-1. **Obtenir la liste des révisions pour un Renkan donné**
+
+##### 1. Obtenir la liste des révisions pour un Renkan donné
```GET /renkan-api/renkans/<:renkan_id>/revisions/```
-Si succès: Renvoie ```200 OK``` et une liste où chaque élément est un json correspondant à une révision.
+Si succès: Renvoie ```200 OK``` et une liste où chaque élément est un json correspondant à une révision.
Si échec: Renvoie un ```404 NOT FOUND``` si le ```<:renkan_id>``` ne correspond à aucun renkan existant
-2. **Obtenir les informations sur une révision**
+##### 2. Obtenir les informations sur une révision
```GET /renkan-api/renkans/<:renkan_id>/revisions/<:revision_id>```
-Si succès: renvoie ```200 OK``` et le json associé à la révision requêtée
+Si succès: renvoie ```200 OK``` et le json associé à la révision requêtée
Si échec: renvoie un ```404 NOT FOUND``` si ```<:renkan_id>``` ne correspond à aucun renkan existant ou que ```<:revision_id>``` ne correspond à aucune révision existante.
-3. **Supprimer une révision**
+##### 3. Supprimer une révision
```DELETE /renkan-api/renkans/<:renkan_id>/revisions/<:revision_id>```
**Note:** il est impossible de supprimer la "révision courante" d'un renkan.
-Si succès: renvoie ```204 NO CONTENT```
+Si succès: renvoie ```204 NO CONTENT```
Si échec: renvoie un ```404 NOT FOUND``` si ```<:renkan_id>``` ne correspond à aucun renkan existant ou si ```<:revision_id>``` ne correspond à aucune révision existante
#### Endpoints Workspace
-1. **Créer un Workspace**
+##### 1. Créer un Workspace
```POST /renkan-api/workspaces/```
Données à fournir en JSON (facultatif):
-```
+```
{
"title": titre du workspace à créer
}
@@ -166,7 +173,7 @@
Si succès: Renvoie ```201 CREATED``` et le json associé au workspace créé
-2. **Créer un Renkan dans un Workspace donné**
+##### 2. Créer un Renkan dans un Workspace donné
```POST /renkan-api/workspaces/<:workspace_id>/renkans/```
Données (facultatif):
@@ -179,34 +186,32 @@
**Note:** Si aucun titre n'est fournie le renkan sera intitulé "Untitled Renkan". Si aucun contenu n'est fourni un JSON minimal sera généré
-Si succès: Renvoie ```201 CREATED``` et le json associé au renkan créé
+Si succès: Renvoie ```201 CREATED``` et le json associé au renkan créé
Si échec: Renvoie un ```404 NOT FOUND``` si le ```<:workspace_id>``` ne correspond à aucun workspace exis-tant
-3. **Obtenir la liste des Workspaces**
+##### 3. Obtenir la liste des Workspaces
```GET /renkan-api/workspaces/ ```
Si succès: renvoie ```200 OK``` et une liste où chaque élément est un json correspondant à un workspace.
-4. **Obtenir la liste des Renkan associé à un Workspace donné**
+##### 4. Obtenir la liste des Renkan associé à un Workspace donné
```GET /renkan-api/workspace/<:workspace_id>/renkans/```
Renvoie la liste des renkans (associés au workspace) auxquels l'utilisateur authentifié a accès en lecture.
-Si succès: Renvoie ```200 OK``` et une liste où chaque élément correspond à un json de renkan.
+Si succès: Renvoie ```200 OK``` et une liste où chaque élément correspond à un json de renkan.
Si échec: Renvoie un ```404 NOT FOUND``` si le ```<:workspace_id>``` ne correspond à aucun workspace exis-tant
-5. **Obtenir les informations sur un Workspace**
+##### 5. Obtenir les informations sur un Workspace
```GET /renkan-api/workspaces/```
-Si succès:renvoie ```200 OK``` et une liste où chaque élément est un json correspondant à un workspace.
+Si succès:renvoie ```200 OK``` et une liste où chaque élément est un json correspondant à un workspace.
Si échec: renvoie un ```404 NOT FOUND``` si le ```<:workspace_id>``` ne correspond à aucun workspace existant
-6. **Supprimer un Workspace**
+##### 6. Supprimer un Workspace
```DELETE /renkan-api/workspaces/<:workspace_id>```
Note: il est impossible de supprimer un workspace s'il reste au moins un renkan assigné à celui-ci.
-Si succès: renvoie ```204 NO CONTENT```
-Si échec: renvoie un ```404 NOT FOUND``` si le ```<:workspace_id>``` ne correspond à aucun workspace existant
-
-
+Si succès: renvoie ```204 NO CONTENT```
+Si échec: renvoie un ```404 NOT FOUND``` si le ```<:workspace_id>``` ne correspond à aucun workspace existant
--- a/server/python/django2/renkanmanager/models.py Tue Jun 21 10:30:08 2016 +0200
+++ b/server/python/django2/renkanmanager/models.py Tue Jun 21 17:53:06 2016 +0200
@@ -133,11 +133,11 @@
Saves over current revision or saves a new revision entirely.
Timestamp must be the current revision modification_date.
"""
- if (not timestamp) or ((self.current_revision is not None) and dateparse.parse_datetime(timestamp) < self.current_revision.modification_date):
+ if (not timestamp) or ((self.current_revision is not None) and timestamp != self.current_revision.modification_date):
logger.error("SAVING RENKAN: provided timestamp is %r, which isn't current revision modification_date %r", timestamp, self.current_revision.modification_date)
raise ValidationError(_("Cannot save, provided timestamp is invalid"))
else:
- dt_timestamp = dateparse.parse_datetime(timestamp)
+ dt_timestamp = timestamp
if create_new_revision:
revision_to_update = Revision(parent_renkan=self)
--- a/server/python/django2/renkanmanager/serializers.py Tue Jun 21 10:30:08 2016 +0200
+++ b/server/python/django2/renkanmanager/serializers.py Tue Jun 21 17:53:06 2016 +0200
@@ -3,8 +3,8 @@
from django.db import transaction
from django.contrib.auth import get_user_model
from django.conf import settings
+from django.utils import six
from django.core.exceptions import ValidationError
-from django.utils import dateparse
from renkanmanager import settings as renkan_settings
from renkanmanager.models import Renkan, Workspace, Revision
from rest_framework import serializers
@@ -23,11 +23,14 @@
title = serializers.CharField(required=False)
content = serializers.JSONField(required=False)
creation_date = serializers.ReadOnlyField()
- modification_date = serializers.SerializerMethodField("get_current_revision_modification_date")
- create_new_revision = serializers.BooleanField(write_only=True, required=False) # only used for updating
- validation_timestamp = serializers.CharField(write_only=True, required=False) # only used for updating is a content json is not provided
+ modification_date = serializers.SerializerMethodField()
+
+ def __init__(self, instance=None, data=serializers.empty, **kwargs):
- # ADD ERROR HANDLING
+ self.validation_timestamp = kwargs.pop('validation_timestamp', None)
+ super(RenkanSerializer, self).__init__(instance, data, **kwargs)
+
+
def get_current_revision_last_updator(self, renkan):
last_updator = renkan.current_revision.last_updated_by
if last_updator:
@@ -36,7 +39,7 @@
return ''
- def get_current_revision_modification_date(self, renkan):
+ def get_modification_date(self, renkan):
return renkan.current_revision.modification_date
@transaction.atomic
@@ -71,19 +74,12 @@
content = validated_data.get('content', '')
if not content:
content = renkan.current_revision.content
- if not 'validation_timestamp' in validated_data:
- raise serializers.ValidationError("No validation timestamp and no content json to extract it from")
- validation_timestamp = validated_data.get('validation_timestamp')
- else:
- validation_timestamp = json.loads(content).get("updated", "")
- if dateparse.parse_datetime(validation_timestamp) < renkan.current_revision.modification_date:
- raise serializers.ValidationError("Provided timestamp is invalid")
if title != json.loads(content).get("title", ""):
content_dict = json.loads(content)
content_dict["title"] = title
content = json.dumps(content_dict)
try:
- renkan.save_renkan(updator=updator, timestamp=validation_timestamp, title=title, content=content, create_new_revision=create_new_revision)
+ renkan.save_renkan(updator=updator, timestamp=self.validation_timestamp, title=title, content=content, create_new_revision=create_new_revision)
except ValidationError as ve:
raise serializers.ValidationError(str(ve.args[0]))
# FORCE Renkan reload.
@@ -113,12 +109,16 @@
raise serializers.ValidationError("Content requires a 'views' entry")
return value
- def validate_validation_timestamp(self, value):
- logger.debug("%r < %r", dateparse.parse_datetime(value).timestamp(), self.get_current_revision_modification_date(self.instance).timestamp())
+ def validate(self, data):
+ if self.instance:
+ validation_timestamp = self.validation_timestamp or data.get('content', {}).get('updated')
+ if not validation_timestamp:
+ raise serializers.ValidationError("No validation timestamp and no content json to extract it from")
+ validation_timestamp = dateparse.parse_datetime(validation_timestamp) if isinstance(validation_timestamp, six.string_types) else validation_timestamp
+ if validation_timestamp != self.instance.current_revision.modification_date:
+ raise serializers.ValidationError("Invalid timestamp was provided")
+ return data
- if self.instance and dateparse.parse_datetime(value) != self.get_current_revision_modification_date(self.instance):
- raise serializers.ValidationError("Invalid timestamp was provided")
- return value
class RevisionSerializer(serializers.Serializer):
id = serializers.ReadOnlyField(source="revision_guid")
--- a/server/python/django2/renkanmanager/tests/v1_0/tests_renkan.py Tue Jun 21 10:30:08 2016 +0200
+++ b/server/python/django2/renkanmanager/tests/v1_0/tests_renkan.py Tue Jun 21 17:53:06 2016 +0200
@@ -1,4 +1,4 @@
-import json
+import json, urllib
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
@@ -311,13 +311,15 @@
# PUTting by updating current revision
###################################################
- put_url = reverse("v1.0:renkan_detail", kwargs={"renkan_guid": renkan_guid})
+ put_url = "%s?%s" % (
+ reverse("v1.0:renkan_detail", kwargs={"renkan_guid": renkan_guid}),
+ urllib.parse.urlencode({'create_new_revision': False})
+ )
put_content_dict = json.loads(self.first_test_content)
put_content_dict["updated"] = post_response_ts
put_data = {
"title" : self.first_test_title,
- "content" : json.dumps(put_content_dict),
- "create_new_revision": False
+ "content" : json.dumps(put_content_dict)
}
put_response = self.client.put(put_url, put_data, format="json")
self.assertEqual(put_response.status_code, status.HTTP_200_OK, "response is %r"%put_response.content)
@@ -351,12 +353,15 @@
# PUTting by creating a new revision
###################################################
+ put_url = "%s?%s" % (
+ reverse("v1.0:renkan_detail", kwargs={"renkan_guid": renkan_guid}),
+ urllib.parse.urlencode({'create_new_revision': True})
+ )
put_content_dict = json.loads(self.second_test_content)
put_content_dict["updated"] = put_response_ts
put_data = {
"title" : self.second_test_title,
- "content" : json.dumps(put_content_dict),
- "create_new_revision": True
+ "content" : json.dumps(put_content_dict)
}
put_response = self.client.put(put_url, put_data, format="json")
self.assertEqual(put_response.status_code, status.HTTP_200_OK, "response is %r"%put_response.content)
@@ -608,8 +613,14 @@
copy_renkan_guid = post_response_dict.get("id", "")
# Adding another revision
- put_data = {"title": self.first_test_title+"_edited!", "validation_timestamp": to_delete_renkan_ts, "create_new_revision": True}
- put_url = reverse("v1.0:renkan_detail", kwargs={"renkan_guid":to_delete_renkan_guid})
+ put_data = {"title": self.first_test_title+"_edited!"}
+ put_url = "%s?%s" % (
+ reverse("v1.0:renkan_detail", kwargs={"renkan_guid":to_delete_renkan_guid}),
+ urllib.parse.urlencode({
+ 'validation_timestamp' : to_delete_renkan_ts,
+ 'create_new_revision' : True
+ })
+ )
put_response = self.client.put(put_url, put_data, format="json")
self.assertEqual(Renkan.objects.count(), 2)
self.assertEqual(Revision.objects.count(), 3)
--- a/server/python/django2/renkanmanager/tests/v1_0/tests_revision.py Tue Jun 21 10:30:08 2016 +0200
+++ b/server/python/django2/renkanmanager/tests/v1_0/tests_revision.py Tue Jun 21 17:53:06 2016 +0200
@@ -1,4 +1,4 @@
-import json
+import json, urllib
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
@@ -101,13 +101,14 @@
# PUTting another revision in test renkan
###################################################
- put_url = reverse("v1.0:renkan_detail", kwargs={"renkan_guid" : self.test_renkan_guid})
put_title = "edited_title"
put_data = {
"title" : put_title,
- "validation_timestamp": self.post_response_content_dict.get("updated", ""),
- "create_new_revision": True
}
+ put_url = "%s?%s" % (
+ reverse("v1.0:renkan_detail", kwargs={"renkan_guid" : self.test_renkan_guid}),
+ urllib.parse.urlencode({'validation_timestamp' : self.post_response_content_dict.get("updated", ""), 'create_new_revision': True})
+ )
put_response = self.client.put(put_url, put_data, format="json")
###################################################
@@ -137,12 +138,16 @@
# PUTting another revision in test renkan
###################################################
- put_url = reverse("v1.0:renkan_detail", kwargs={"renkan_guid" : self.test_renkan_guid})
+ put_url = "%s?%s" % (
+ reverse("v1.0:renkan_detail", kwargs={"renkan_guid" : self.test_renkan_guid}),
+ urllib.parse.urlencode({
+ 'validation_timestamp' : self.post_response_content_dict.get("updated", ""),
+ 'create_new_revision' : True
+ })
+ )
put_title = "edited_title"
put_data = {
"title" : put_title,
- "validation_timestamp": self.post_response_content_dict.get("updated", ""),
- "create_new_revision": True
}
put_response = self.client.put(put_url, put_data, format="json")
put_response_dict = json.loads(put_response.content.decode())
--- a/server/python/django2/renkanmanager/utils.py Tue Jun 21 10:30:08 2016 +0200
+++ b/server/python/django2/renkanmanager/utils.py Tue Jun 21 17:53:06 2016 +0200
@@ -10,6 +10,7 @@
from django.shortcuts import get_object_or_404
from django.utils.encoding import smart_str
from renkanmanager.models import Renkan
+import distutils
import math
import hashlib
import re
@@ -29,12 +30,12 @@
class NodePlacer():
-
+
cat_nb_nodes = {}
-
+
def init(self, cat_nb_nodes_initial):
raise NotImplementedError( "Should have implemented init" )
-
+
def get_place(self, category):
if not category or category not in self.cat_nb_nodes:
raise Http404
@@ -43,9 +44,9 @@
class LineNodePlacer(NodePlacer): #vertical lines
-
+
max_length = 0
-
+
def init(self, cat_nb_nodes_initial):
for c in cat_nb_nodes_initial:
nb = cat_nb_nodes_initial[c]
@@ -67,9 +68,9 @@
class HorLineNodePlacer(NodePlacer): #horizontal lines
-
+
max_length = 0
-
+
def init(self, cat_nb_nodes_initial):
for c in cat_nb_nodes_initial:
nb = cat_nb_nodes_initial[c]
@@ -93,7 +94,7 @@
self.cat_nb_nodes[c].append({ "x": 100*(i+offset), "y": order*450 })
class CircleNodePlacer(NodePlacer):
-
+
def init(self, cat_nb_nodes_initial):
for i_cat,c in enumerate(cat_nb_nodes_initial):
self.cat_nb_nodes[c] = []
@@ -133,4 +134,8 @@
raise ValidationError("You are not allowed to remove this renkan")
-
+def parse_bool(value):
+ try:
+ return bool(value and distutils.util.strtobool(value.lower()))
+ except ValueError:
+ return False