Browse Source

Resolves conflicts with last merge

prieto 7 years ago
parent
commit
b79feb2ddf

+ 41
- 2
lodel/leapi/datahandlers/base_classes.py View File

2
 
2
 
3
 ## @package lodel.leapi.datahandlers.base_classes Define all base/abstract class for data handlers
3
 ## @package lodel.leapi.datahandlers.base_classes Define all base/abstract class for data handlers
4
 #
4
 #
5
-# Contains custom exceptions too
5
+# Contains custom exceptions too
6
 
6
 
7
 import copy
7
 import copy
8
 import importlib
8
 import importlib
14
 LodelContext.expose_modules(globals(), {
14
 LodelContext.expose_modules(globals(), {
15
     'lodel.exceptions': ['LodelException', 'LodelExceptions',
15
     'lodel.exceptions': ['LodelException', 'LodelExceptions',
16
         'LodelFatalError', 'DataNoneValid', 'FieldValidationError'],
16
         'LodelFatalError', 'DataNoneValid', 'FieldValidationError'],
17
+    'lodel.leapi.datahandlers.exceptions': ['LodelDataHandlerConsistencyException', 'LodelDataHandlerException'],
17
     'lodel.logger': 'logger'})
18
     'lodel.logger': 'logger'})
18
 
19
 
19
 
20
 
25
     ##@brief Stores the DataHandler childs classes indexed by name
26
     ##@brief Stores the DataHandler childs classes indexed by name
26
     _base_handlers = None
27
     _base_handlers = None
27
     ##@brief Stores custom datahandlers classes indexed by name
28
     ##@brief Stores custom datahandlers classes indexed by name
28
-    # @todo do it ! (like plugins, register handlers... blablabla)
29
+    # @todo do it ! (like plugins, register handlers... blablabla)
29
     __custom_handlers = dict()
30
     __custom_handlers = dict()
30
 
31
 
31
     help_text = 'Generic Field Data Handler'
32
     help_text = 'Generic Field Data Handler'
343
                     logger.warning('Object referenced does not exist')
344
                     logger.warning('Object referenced does not exist')
344
                     return False
345
                     return False
345
         return True
346
         return True
347
+    
348
+    ##@brief Utility method designed to fetch referenced objects
349
+    #@param value mixed : the field value
350
+    #@throw NotImplementedError
351
+    def get_referenced(self, value):
352
+        raise NotImplementedError
346
 
353
 
347
 
354
 
348
 ##@brief This class represent a data_handler for single reference to another object
355
 ##@brief This class represent a data_handler for single reference to another object
365
         #    raise FieldValidationError("List or string expected for a set field")
372
         #    raise FieldValidationError("List or string expected for a set field")
366
         return value
373
         return value
367
 
374
 
375
+    ##@brief Utility method designed to fetch referenced objects
376
+    #@param value mixed : the field value
377
+    #@return A LeObject child class instance
378
+    #@throw LodelDataHandlerConsistencyException if no referenced object found
379
+    def get_referenced(self, value):
380
+        for leo_cls in self.linked_classes:
381
+            res = leo_cls.get_from_uid(value)
382
+            if res is not None:
383
+                return res
384
+        raise LodelDataHandlerConsistencyException("Unable to find \
385
+referenced object with uid %s" % value)
368
 
386
 
369
 
387
 
370
 ##@brief This class represent a data_handler for multiple references to another object
388
 ##@brief This class represent a data_handler for multiple references to another object
410
             raise FieldValidationError("MultipleRef have for invalid values [%s]  :" % (",".join(error_list)))
428
             raise FieldValidationError("MultipleRef have for invalid values [%s]  :" % (",".join(error_list)))
411
         return new_val
429
         return new_val
412
 
430
 
431
+    ##@brief Utility method designed to fetch referenced objects
432
+    #@param value mixed : the field value
433
+    #@return A list of LeObject child class instance
434
+    #@throw LodelDataHandlerConsistencyException if some referenced objects
435
+    #were not found
436
+    def get_referenced(self, values):
437
+        if values is None or len(values) == 0:
438
+            return list()
439
+        left = set(values)
440
+        values = set(values)
441
+        res = list()
442
+        for leo_cls in self.linked_classes:
443
+            uidname = leo_cls.uid_fieldname()[0] #MULTIPLE UID BROKEN HERE
444
+            tmp_res = leo_cls.get(('%s in (%s)' % (uidname, ','.join(
445
+                [str(l) for l in left]))))
446
+            left ^= set(( leo.uid() for leo in tmp_res))
447
+            res += tmp_res
448
+            if len(left) == 0:
449
+                return res
450
+        raise LodelDataHandlerConsistencyException("Unable to find \
451
+some referenced objects. Followinf uid were not found : %s" % ','.join(left))
413
 
452
 
414
 ## @brief Class designed to handle datas access will fieldtypes are constructing datas
453
 ## @brief Class designed to handle datas access will fieldtypes are constructing datas
415
 #@ingroup lodel2_datahandlers
454
 #@ingroup lodel2_datahandlers

+ 3
- 0
lodel/leapi/datahandlers/exceptions.py View File

1
 def LodelDataHandlerException(Exception):
1
 def LodelDataHandlerException(Exception):
2
     pass
2
     pass
3
+
4
+def LodelDataHandlerConsistencyException(LodelDataHandlerException):
5
+    pass

+ 14
- 0
lodel/leapi/leobject.py View File

633
     #@todo broken multiple UID
633
     #@todo broken multiple UID
634
     @classmethod
634
     @classmethod
635
     def get_from_uid(cls, uid):
635
     def get_from_uid(cls, uid):
636
+        if cls.uid_fieldname() is None:
637
+            raise LodelFatalError(
638
+                "No uid defined for class %s" % cls.__name__)
636
         uidname = cls.uid_fieldname()[0] #Brokes composed UID
639
         uidname = cls.uid_fieldname()[0] #Brokes composed UID
637
         res = cls.get([(uidname,'=', uid)])
640
         res = cls.get([(uidname,'=', uid)])
641
+        
642
+        #dedoublonnage vu que query ou la datasource est bugué
643
+        if len(res) > 1:
644
+            res_cp = res
645
+            res = []
646
+            while len(res_cp) > 0:
647
+                cur_res = res_cp.pop()
648
+                if cur_res.uid() in [ r.uid() for r in res_cp]:
649
+                    logger.error("DOUBLON detected in query results !!!")
650
+                else:
651
+                    res.append(cur_res)
638
         if len(res) > 1:
652
         if len(res) > 1:
639
             raise LodelFatalError("Get from uid returned more than one \
653
             raise LodelFatalError("Get from uid returned more than one \
640
 object ! For class %s with uid value = %s" % (cls, uid))
654
 object ! For class %s with uid value = %s" % (cls, uid))

+ 28
- 0
lodel/maindoc.py View File

1
+#-*- coding: utf-8 -*-
2
+
3
+## @mainpage
4
+#
5
+# @section lodel_general_description General Description
6
+# Lodel is a web publishing system which is configurable to one's specific needs. It is a member of the content management systems' category.
7
+#
8
+# In its 2.0 version, it is composed from a main package, called "lodel" which contains all of its core packages and modules.
9
+#
10
+# @section lodel_core_components Core Components
11
+# The application contains the following packages in its core :
12
+#
13
+# - lodel.auth : the authentication system used to deal with the users' sessions
14
+# - lodel.editorial_model : a package containing all the tools to read/write/update an editorial model
15
+# - lodel.leapi : the main API that will be used to access the documents' data
16
+# - lodel.plugin : a plugin manager (with modules to deal with the hooks, the scripts, the options, etc ... brought in by each plugin)
17
+# - lodel.plugins : this package is used to store all the plugins that are added in Lodel
18
+# - lodel.settings : the settings management tools
19
+# - lodel.utils : several small tools that are useful and common to several core modules
20
+#
21
+# Aside from that, there are core modules :
22
+# - lodel.context : the context manager (used for the multisite functionality)
23
+# - lodel.logger : a global logging tool
24
+#
25
+# @section one_code_and_multiple_websites One code and multiple websites
26
+# Lodel can be used to manage one or many websites using the same core code. Each website will have its own activated plugins,
27
+# editorial model options and settings, all managed by the context manager.
28
+#

+ 3
- 2
lodel/plugins/dummy/main.py View File

2
 
2
 
3
 from lodel.context import LodelContext
3
 from lodel.context import LodelContext
4
 LodelContext.expose_modules(globals(), {
4
 LodelContext.expose_modules(globals(), {
5
-    'lodel.plugin': ['LodelHook', 'CustomMethod']})
5
+    'lodel.plugin': ['LodelHook', 'CustomMethod'],
6
+    'lodel.settings' : 'settings'})
6
 
7
 
7
 @LodelHook('leapi_get_post')
8
 @LodelHook('leapi_get_post')
8
 @LodelHook('leapi_update_pre')
9
 @LodelHook('leapi_update_pre')
12
 @LodelHook('leapi_insert_pre')
13
 @LodelHook('leapi_insert_pre')
13
 @LodelHook('leapi_insert_post')
14
 @LodelHook('leapi_insert_post')
14
 def dummy_callback(hook_name, caller, payload):
15
 def dummy_callback(hook_name, caller, payload):
15
-    if Lodel.settings.Settings.debug:
16
+    if settings.Settings.debug:
16
         print("\tHook %s\tcaller %s with %s" % (hook_name, caller, payload))
17
         print("\tHook %s\tcaller %s with %s" % (hook_name, caller, payload))
17
     return payload
18
     return payload
18
 
19
 

+ 26
- 23
lodel/plugins/mongodb_datasource/datasource.py View File

284
         return list(res.inserted_ids)
284
         return list(res.inserted_ids)
285
     
285
     
286
     ##@brief Update backref giving an action
286
     ##@brief Update backref giving an action
287
-    #@param target leObject child class
288
-    #@param filters
289
-    #@param relational_filters,
290
-    #@param new_datas None | dict : optional new datas if None mean we are deleting
291
-    #@param old_datas_l None | list : if None fetch old datas from db (usefull
287
+    # @param target leObject child class
288
+    # @param filters
289
+    # @param relational_filters
290
+    # @param new_datas None | dict : optional new datas if None mean we are deleting
291
+    # @param old_datas_l None | list : if None fetch old datas from db (usefull
292
     #when modifications are made on instance before updating backrefs)
292
     #when modifications are made on instance before updating backrefs)
293
-    #@return nothing (for the moment
293
+    # @return nothing (for the moment
294
     def __update_backref_filtered(self, target,
294
     def __update_backref_filtered(self, target,
295
             filters, relational_filters, new_datas = None, old_datas_l = None):
295
             filters, relational_filters, new_datas = None, old_datas_l = None):
296
         #Getting all the UID of the object that will be deleted in order
296
         #Getting all the UID of the object that will be deleted in order
309
             self.__update_backref(
309
             self.__update_backref(
310
                 target, old_datas[uidname], old_datas, new_datas)
310
                 target, old_datas[uidname], old_datas, new_datas)
311
 
311
 
312
-    ##@brief Update back references of an object
313
-    #@ingroup plugin_mongodb_bref_op
312
+    ## @brief Update back references of an object
313
+    # @ingroup plugin_mongodb_bref_op
314
     #
314
     #
315
     #old_datas and new_datas arguments are set to None to indicate 
315
     #old_datas and new_datas arguments are set to None to indicate 
316
     #insertion or deletion. Calls examples :
316
     #insertion or deletion. Calls examples :
317
-    #@par LeObject insert __update backref call
318
-    #<pre>
317
+    # @par LeObject insert __update backref call
318
+    # <pre>
319
     #Insert(datas):
319
     #Insert(datas):
320
     #  self.make_insert(datas)
320
     #  self.make_insert(datas)
321
     #  self.__update_backref(self.__class__, None, datas)
321
     #  self.__update_backref(self.__class__, None, datas)
322
-    #</pre>
323
-    #@par LeObject delete __update backref call
322
+    # </pre>
323
+    # @par LeObject delete __update backref call
324
     #Delete()
324
     #Delete()
325
     #  old_datas = self.datas()
325
     #  old_datas = self.datas()
326
     #  self.make_delete()
326
     #  self.make_delete()
327
     #  self.__update_backref(self.__class__, old_datas, None)
327
     #  self.__update_backref(self.__class__, old_datas, None)
328
-    #@par LeObject update __update_backref call
329
-    #<pre>
328
+    # @par LeObject update __update_backref call
329
+    # <pre>
330
     #Update(new_datas):
330
     #Update(new_datas):
331
     #  old_datas = self.datas()
331
     #  old_datas = self.datas()
332
     #  self.make_udpdate(new_datas)
332
     #  self.make_udpdate(new_datas)
333
     #  self.__update_backref(self.__class__, old_datas, new_datas)
333
     #  self.__update_backref(self.__class__, old_datas, new_datas)
334
-    #</pre>
334
+    # </pre>
335
     #
335
     #
336
-    #@param target LeObject child classa
337
-    #@param tuid mixed : The target UID (the value that will be inserted in
336
+    # @param target LeObject child classa
337
+    # @param tuid mixed : The target UID (the value that will be inserted in
338
     #back references)
338
     #back references)
339
-    #@param old_datas dict : datas state before update
340
-    #@param new_datas dict : datas state after the update process
341
-    #retun None
339
+    # @param old_datas dict : datas state before update
340
+    # @param new_datas dict : datas state after the update process
341
+    # retun None
342
     def __update_backref(self, target, tuid, old_datas, new_datas):
342
     def __update_backref(self, target, tuid, old_datas, new_datas):
343
         #upd_dict is the dict that will allow to run updates in an optimized
343
         #upd_dict is the dict that will allow to run updates in an optimized
344
         #way (or try to help doing it)
344
         #way (or try to help doing it)
345
         #
345
         #
346
-        #It's struct looks like :
346
+        #Its structure looks like :
347
         # { LeoCLASS : {
347
         # { LeoCLASS : {
348
         #       UID1: (
348
         #       UID1: (
349
         #           LeoINSTANCE,
349
         #           LeoINSTANCE,
470
     #@param fdh DataHandler : the source Reference DataHandler
470
     #@param fdh DataHandler : the source Reference DataHandler
471
     #@param tuid mixed : the uid of the Leo that make reference to the backref
471
     #@param tuid mixed : the uid of the Leo that make reference to the backref
472
     #@param bref_infos tuple : as returned by __bref_get_check() method
472
     #@param bref_infos tuple : as returned by __bref_get_check() method
473
-    #@param old mixed : (optional **values) the old value
474
-    #@param new mixed : (optional **values) the new value
473
+    #@param values dict : contains the old and new values (optional) with the "old" and "new" keys
475
     #@return the new back reference field value
474
     #@return the new back reference field value
476
     def __back_ref_upd_one_value(self, fname, fdh, tuid, bref_infos, **values):
475
     def __back_ref_upd_one_value(self, fname, fdh, tuid, bref_infos, **values):
477
         bref_cls, bref_leo, bref_dh, bref_val = bref_infos
476
         bref_cls, bref_leo, bref_dh, bref_val = bref_infos
600
     #MongoDbDatasource::_connections static attribute
599
     #MongoDbDatasource::_connections static attribute
601
     #@param username str
600
     #@param username str
602
     #@param password str
601
     #@param password str
602
+    #@param db_name str : database name
603
     #@param ro bool : If True the Datasource is for read only, else the
603
     #@param ro bool : If True the Datasource is for read only, else the
604
     def __connect(self, username, password, db_name, ro):
604
     def __connect(self, username, password, db_name, ro):
605
         conn_string = connection_string(
605
         conn_string = connection_string(
763
     
763
     
764
     ##@brief Convert lodel2 filters to pymongo conditions
764
     ##@brief Convert lodel2 filters to pymongo conditions
765
     #@param filters list : list of lodel filters
765
     #@param filters list : list of lodel filters
766
+    #@param target Datahandler : The datahandler to use to cast the value in the correct type
766
     #@return dict representing pymongo conditions
767
     #@return dict representing pymongo conditions
767
     @classmethod
768
     @classmethod
768
     def __filters2mongo(cls, filters, target):
769
     def __filters2mongo(cls, filters, target):
802
     #Convertion is done using MongoDbDatasource::lodel2mongo_op_map
803
     #Convertion is done using MongoDbDatasource::lodel2mongo_op_map
803
     #@param op str : take value in LeFilteredQuery::_query_operators
804
     #@param op str : take value in LeFilteredQuery::_query_operators
804
     #@param value mixed : the value
805
     #@param value mixed : the value
806
+    #@param dhdl DataHandler: datahandler used to cast the values before sending them to the database
805
     #@return a tuple(mongo_op, mongo_value)
807
     #@return a tuple(mongo_op, mongo_value)
806
     @classmethod
808
     @classmethod
807
     def __op_value_conv(cls, op, value, dhdl):
809
     def __op_value_conv(cls, op, value, dhdl):
863
     ##@brief Correct some datas before giving them to pymongo
865
     ##@brief Correct some datas before giving them to pymongo
864
     #
866
     #
865
     #For example sets has to be casted to lise
867
     #For example sets has to be casted to lise
868
+    #@param cls
866
     #@param datas
869
     #@param datas
867
     #@return datas
870
     #@return datas
868
     @classmethod
871
     @classmethod

+ 6
- 31
lodel/plugins/webui/templates/listing/show_object.html View File

1
 {% extends "base.html" %}
1
 {% extends "base.html" %}
2
+{% import 'macros/show_object.html' as show_object %}
2
 {% import 'components/components.html' as components %}
3
 {% import 'components/components.html' as components %}
3
 {% set my_class = leapi.name2class(classname) %}
4
 {% set my_class = leapi.name2class(classname) %}
4
-{% set uidfield = my_class.uid_fieldname()[0] %}
5
-{% set objects = my_class.get(('%s = %s') % (uidfield, lodel_id)) %}
6
-{% set obj = objects.pop() %}
5
+{% set obj = my_class.get_from_uid(lodel_id) %}
6
+{% if obj is none %}
7
+    ERROR <!-- conception failure, the controller should test this before calling the template -->
8
+{% endif %}
7
 {% if my_class.is_abstract() %}
9
 {% if my_class.is_abstract() %}
8
 {% set classname = obj.data('classname') %}
10
 {% set classname = obj.data('classname') %}
9
 {% set my_class = my_class.name2class(classname) %}
11
 {% set my_class = my_class.name2class(classname) %}
10
 {% endif %}
12
 {% endif %}
11
 {% block title %}Object {{ lodel_id }} {% endblock %}
13
 {% block title %}Object {{ lodel_id }} {% endblock %}
12
-{% import "components/components.html" as components %}
13
 {% block content %}
14
 {% block content %}
14
 <ol class="breadcrumb">
15
 <ol class="breadcrumb">
15
   <li><a href="/{{ root_url }}/">Home</a></li>
16
   <li><a href="/{{ root_url }}/">Home</a></li>
18
   <li class="active">{{ lodel_id }}</li>
19
   <li class="active">{{ lodel_id }}</li>
19
 </ol>
20
 </ol>
20
 <h1 class="h1_lodel">Lodel 2 - {{ classname }} with uid {{ lodel_id }}</h1>
21
 <h1 class="h1_lodel">Lodel 2 - {{ classname }} with uid {{ lodel_id }}</h1>
21
-<ul>
22
-    <!-- To get a component HTML code, it is necessary to call : components.<macro_name>(args) -->
23
-    {% for fieldname, fieldvalue in obj.fields(include_ro = True).items() %}
24
-        {% if fieldvalue is not none %}
25
-           {% if fieldvalue.base_type == 'ref' %}
26
-                {% if obj.data(fieldname) is iterable %}
27
-                    <li>{{ fieldname }}
28
-                    {% set l_classe = fieldvalue.allowed_classes[0] %}
29
-                        <ul>
30
-                    {% for rel in obj.data(fieldname) %}
31
-                            {% set casttype = l_classe.data_handler(l_classe.uid_fieldname()[0]).cast_type %}
32
-                            {% set rel2 = casttype(rel) %}
33
-                            <li><a href="show_object?classname={{ l_classe.__name__ }}&lodel_id={{ rel2 }}" >{{ rel2 }}</a></li>
34
-                    {% endfor %}
35
-                        </ul></li>
36
-                {% elif obj.data(fieldname) is not none %}
37
-                        {% set l_classe = fieldvalue.allowed_classes[0] %}
38
-                         {% set casttype = l_classe.data_handler(l_classe.uid_fieldname()[0]).cast_type %}
39
-                            {% set rel2 = casttype(obj.data(fieldname)) %}
40
-                            <li>{{ fieldname }} : <a href="show_object?classname={{ l_classe.__name__ }}&lodel_id={{ rel2 }}" >{{ obj.data(fieldname) }} </a></li>
41
-                {% endif %}
42
-            {% else %}
43
-                <li> {{ fieldname }} : {{ obj.data(fieldname) }} </li>
44
-            {% endif %}
45
-        {% endif %}
46
-    {% endfor %}
47
-</ul>
22
+    {{ show_object.object_ul(obj) }}
48
 {% endblock %}
23
 {% endblock %}

+ 6
- 31
lodel/plugins/webui/templates/listing/show_object_detailled.html View File

1
 {% extends "base.html" %}
1
 {% extends "base.html" %}
2
+{% import 'macros/show_object.html' as show_object %}
2
 {% import 'components/components.html' as components %}
3
 {% import 'components/components.html' as components %}
3
 {% import "listing/display_obj.html" as edit %}
4
 {% import "listing/display_obj.html" as edit %}
4
 {% set my_class = leapi.name2class(classname) %}
5
 {% set my_class = leapi.name2class(classname) %}
6
+{% set obj = my_class.get_from_uid(lodel_id) %}
7
+{% if obj is none %}
8
+    ERROR <!-- conception failure, the controller should test this before calling the template -->
9
+{% endif %}
5
 {% set uidfield = my_class.uid_fieldname()[0] %}
10
 {% set uidfield = my_class.uid_fieldname()[0] %}
6
 {% set objects = my_class.get(('%s = %s') % (uidfield, lodel_id)) %}
11
 {% set objects = my_class.get(('%s = %s') % (uidfield, lodel_id)) %}
7
 {% set obj = objects.pop() %}
12
 {% set obj = objects.pop() %}
18
   <li class="active">{{ lodel_id }}</li>
23
   <li class="active">{{ lodel_id }}</li>
19
 </ol>
24
 </ol>
20
 <h1 class="h1_lodel">Lodel 2 - {{ classname }} with uid {{ lodel_id }}</h1>
25
 <h1 class="h1_lodel">Lodel 2 - {{ classname }} with uid {{ lodel_id }}</h1>
21
-<ul>
22
-    <!-- To get a component HTML code, it is necessary to call : components.<macro_name>(args) -->
23
-    {% for fieldname, fieldvalue in obj.fields(include_ro = True).items() %}
24
-        {% if fieldvalue is not none %}
25
-           {% if fieldvalue.base_type == 'ref' %}
26
-                {% if obj.data(fieldname) is iterable %}
27
-                    <li>{{ fieldname }}
28
-                    {% set l_classe = fieldvalue.allowed_classes[0] %}
29
-                        <ul>
30
-                    {% set linked_objs=l_classe.get(("%s in (%s)") % (l_classe.uid_fieldname()[0], obj.data(fieldname)|join(','))) %}
31
-                    {% for linked_obj in linked_objs %}
32
-                            {{ edit.display(linked_obj) }}
33
-                            <br/>
34
-                    {% endfor %}
35
-                        </ul></li>
36
-                {% elif obj.data(fieldname) is not none %}
37
-                    <li>{{ fieldname }}
38
-                        <ul>
39
-                        {% set l_classe = fieldvalue.allowed_classes[0] %}
40
-                        {% set linked_objs=l_classe.get(("%s = %s") % (l_classe.uid_fieldname()[0], obj.data(fieldname))) %}
41
-                        {{ edit.display(linked_objs.pop()) }}
42
-                        <br/>
43
-                        </ul>
44
-                    </li>
45
-                {% endif %}
46
-            {% else %}
47
-                <li> {{ fieldname }} : {{ obj.data(fieldname) }} </li>
48
-            {% endif %}
49
-        {% endif %}
50
-    {% endfor %}
51
-</ul>
26
+    {{ show_object.object_ul(obj, 2) }}
52
 {% endblock %}
27
 {% endblock %}

+ 38
- 0
lodel/plugins/webui/templates/macros/show_object.html View File

1
+<!-- Produce a <li></li> with objects informations -->
2
+{% macro object_ul(leo, max_depth = 0, exclude = []) -%}
3
+    <ul>
4
+        {% if max_depth <= 0 %}
5
+            <!-- No need to go deeper -->
6
+            {% for fname, fvalue in leo.datas(True).items() %}
7
+                <li><em>{{ fname }}</em> : {{fvalue}}</li>
8
+            {%endfor%}
9
+        {% else %}
10
+            {% for fname in leo.fieldnames(True) %}
11
+                {% set fvalue = leo.data(fname) %}
12
+                {% set fdh = leo.data_handler(fname) %}
13
+                {% if fvalue is not none and fdh.is_reference() %}
14
+                    {% if fdh.is_singlereference() %}
15
+                        {% set referenced = fdh.get_referenced(fvalue) %}
16
+                        {% if (referenced.__class__.__name__, referenced.uid) in exclude %}
17
+                            <li><em>{{fname}}</em> : {{fvalue}}</li>
18
+                        {% else %}
19
+                            <li><em>{{fname}}</em> : {{object_ul(referenced, max_depth - 1, exclude + [(leo.__class__.__name__, leo.uid())] )}}</li>
20
+                        {% endif %}
21
+                    {% else %}
22
+                        <li><em>{{fname}}</em> : <ul>
23
+                        {% for referenced in fdh.get_referenced(fvalue) %}
24
+                            {% if (referenced.__class__.__name__, referenced.uid) in exclude %}
25
+                                <li><em>{{fname}}</em> : {{fvalue}}</li>
26
+                            {% else %}
27
+                                <li><em>{{fname}}</em> : {{object_ul(referenced, max_depth - 1, exclude + [(leo.__class__.__name__, leo.uid())] )}}</li>
28
+                            {% endif %}
29
+                        {% endfor %}
30
+                        </ul></li>
31
+                    {% endif %}
32
+                {% else %}
33
+                    <li><em>{{fname}}</em> : {{fvalue}}</li>
34
+                {% endif %}
35
+            {% endfor %}
36
+        {% endif %}
37
+    </ul>
38
+{%- endmacro %}

+ 4
- 2
lodel/settings/settings.py View File

54
 # settings.
54
 # settings.
55
 # Here is the conceptual presentation of Settings class initialization stages :
55
 # Here is the conceptual presentation of Settings class initialization stages :
56
 #   -# Preloading (sets values like lodel2 library path or the plugins path)
56
 #   -# Preloading (sets values like lodel2 library path or the plugins path)
57
-#   -# Ask a @ref lodel.settings.setting_loader.SettingsLoader to load all 
57
+#   -# Ask a @ref lodel.settings.settings_loader.SettingsLoader to load all
58
 #configurations files
58
 #configurations files
59
 #   -# Fetch the list of plugins in the loaded settings
59
 #   -# Fetch the list of plugins in the loaded settings
60
 #   -# Merge plugins settings specification with the global lodel settings 
60
 #   -# Merge plugins settings specification with the global lodel settings 
80
     
80
     
81
     ## @brief Instanciate the Settings singleton
81
     ## @brief Instanciate the Settings singleton
82
     # @param conf_dir str : The configuration directory
82
     # @param conf_dir str : The configuration directory
83
-    #@param custom_confspec None | dict : if given overwrite default lodel2
83
+    #@param custom_confspecs None | dict : if given overwrite default lodel2
84
     #confspecs
84
     #confspecs
85
     def __init__(self, conf_dir, custom_confspecs = None):
85
     def __init__(self, conf_dir, custom_confspecs = None):
86
         self.singleton_assert() # check that it is the only instance
86
         self.singleton_assert() # check that it is the only instance
112
 
112
 
113
     ##@brief An utility method that raises if the singleton is not in a good
113
     ##@brief An utility method that raises if the singleton is not in a good
114
     # state
114
     # state
115
+    #@param cls
115
     #@param expect_instanciated bool : if True we expect that the class is
116
     #@param expect_instanciated bool : if True we expect that the class is
116
     # allready instanciated, else not
117
     # allready instanciated, else not
117
     # @throw RuntimeError
118
     # @throw RuntimeError
125
                 raise RuntimeError("The Settings class is already started")
126
                 raise RuntimeError("The Settings class is already started")
126
 
127
 
127
     ##@brief Saves a new configuration for section confname
128
     ##@brief Saves a new configuration for section confname
129
+    #@param cls
128
     #@param confname is the name of the modified section
130
     #@param confname is the name of the modified section
129
     #@param confvalue is a dict with variables to save
131
     #@param confvalue is a dict with variables to save
130
     #@param validator is a dict with adapted validator
132
     #@param validator is a dict with adapted validator

+ 8
- 1
lodel/settings/validator.py View File

58
             raise SettingsValidationError(e)
58
             raise SettingsValidationError(e)
59
     
59
     
60
     ##@brief Register a new validator
60
     ##@brief Register a new validator
61
+    # @param cls SettingValidator
61
     # @param name str : validator name
62
     # @param name str : validator name
62
     # @param callback callable : the function that will validate a value
63
     # @param callback callable : the function that will validate a value
63
     # @param description str
64
     # @param description str
77
         return copy.copy(cls._description)
78
         return copy.copy(cls._description)
78
 
79
 
79
     ##@brief Create and register a list validator
80
     ##@brief Create and register a list validator
81
+    # @param cls SettingValidator
80
     # @param elt_validator callable : The validator that will be used for validate each elt value
82
     # @param elt_validator callable : The validator that will be used for validate each elt value
81
     # @param validator_name str
83
     # @param validator_name str
82
     # @param description None | str
84
     # @param description None | str
100
         return cls(validator_name)
102
         return cls(validator_name)
101
  
103
  
102
     ##@brief Create and register a list validator which reads an array and returns a string
104
     ##@brief Create and register a list validator which reads an array and returns a string
105
+    # @param cls SettingValidator
103
     # @param elt_validator callable : The validator that will be used for validate each elt value
106
     # @param elt_validator callable : The validator that will be used for validate each elt value
104
     # @param validator_name str
107
     # @param validator_name str
105
     # @param description None | str
108
     # @param description None | str
121
         return cls(validator_name)
124
         return cls(validator_name)
122
     
125
     
123
     ##@brief Create and register a regular expression validator
126
     ##@brief Create and register a regular expression validator
127
+    # @param cls SettingValidator
124
     # @param pattern str : regex pattern
128
     # @param pattern str : regex pattern
125
     # @param validator_name str : The validator name
129
     # @param validator_name str : The validator name
126
     # @param description str : Validator description
130
     # @param description str : Validator description
406
 ##@brief Append a piece of confspec
410
 ##@brief Append a piece of confspec
407
 #@note orig is modified during the process
411
 #@note orig is modified during the process
408
 #@param orig dict : the confspec to update
412
 #@param orig dict : the confspec to update
409
-#@param upd dict : the confspec to add
413
+#@param section str : the name of the section to add
414
+#@param key str : the name of the key to add
415
+#@param validator SettingValidator : The validator to use for this configuration key
416
+#@param default : the default value for this configuration key
410
 #@return new confspec
417
 #@return new confspec
411
 def confspec_append(orig, section, key, validator, default):
418
 def confspec_append(orig, section, key, validator, default):
412
     if section not in orig:
419
     if section not in orig:

+ 2
- 0
lodel/utils/mlstring.py View File

58
             self.values[lang] = val
58
             self.values[lang] = val
59
 
59
 
60
     ##@brief Checks that given lang is valid
60
     ##@brief Checks that given lang is valid
61
+    # @param cls MlString
61
     # @param lang str : the lang
62
     # @param lang str : the lang
62
     @classmethod
63
     @classmethod
63
     def lang_is_valid(cls, lang):
64
     def lang_is_valid(cls, lang):
75
         cls.__default_lang = lang
76
         cls.__default_lang = lang
76
     
77
     
77
     ##@brief Return a mlstring loaded from a json string
78
     ##@brief Return a mlstring loaded from a json string
79
+    # @param cls MlString
78
     # @param json_str str : Json string
80
     # @param json_str str : Json string
79
     @classmethod
81
     @classmethod
80
     def from_json(cls, json_str):
82
     def from_json(cls, json_str):

+ 1
- 0
progs/slim/slim.py View File

281
 
281
 
282
 ##@brief Start an instance
282
 ##@brief Start an instance
283
 #@param names list : instance name list
283
 #@param names list : instance name list
284
+#@param foreground bool : defines if the starting instance will be executed as a subprocess in the background (if False) or as the main process (if True)
284
 def start_instances(names, foreground):
285
 def start_instances(names, foreground):
285
     pids = get_pids()
286
     pids = get_pids()
286
     store_datas = get_store_datas()
287
     store_datas = get_store_datas()

+ 34
- 1
scripts/cbl.sh View File

13
 #
13
 #
14
 # Scenario description :
14
 # Scenario description :
15
 #
15
 #
16
-# mass_creation instance_name iteration_count :
16
+# mass_creation instance_name iteration_count :
17
 #	Create iteration_count time a random leobject in given instance_name
17
 #	Create iteration_count time a random leobject in given instance_name
18
 #	note : do note create relation between objects, only populate content
18
 #	note : do note create relation between objects, only populate content
19
 #	
19
 #	
21
 # 	step 2 : loop on creation (using bash function curl_opt_create_CLSNAME)
21
 # 	step 2 : loop on creation (using bash function curl_opt_create_CLSNAME)
22
 #		that return the POST fields (populated with random values)
22
 #		that return the POST fields (populated with random values)
23
 #
23
 #
24
+# mass_get instance_name :
25
+#	Create all possible get for an instance
26
+#	step 1 : fetch all classes
27
+#	step 2 : for each class fetch all id
28
+#	step 3 : for all ids generate the gets
29
+#
24
 # mass_deletion instance_name iteration_count :
30
 # mass_deletion instance_name iteration_count :
25
 #	Foreach non asbtracty class delete iteration_count time an object of
31
 #	Foreach non asbtracty class delete iteration_count time an object of
26
 #	current class in current instance
32
 #	current class in current instance
140
 	rm -v $cls_list_file >&2
146
 	rm -v $cls_list_file >&2
141
 }
147
 }
142
 
148
 
149
+mass_get() {
150
+	#mass get scenario
151
+	#$1 is instance name
152
+	cls_list_file=$(fetch_all_classes $1)
153
+	base_uri=$(_base_uri $1)
154
+
155
+	#Get the site root
156
+	echo "$base_uri/"
157
+	#Get the site class list
158
+	echo "$base_uri/list_classes"
159
+
160
+	for clsname in $(cat $cls_list_file)
161
+	do
162
+		#Get instances list for a class
163
+		echo "$base_uri/show_class?classname=$clsname"
164
+		ids_file=$(fetch_all_ids $1 $clsname)
165
+		for id in $(cat $ids_file)
166
+		do
167
+			#Get details on an instance
168
+			echo "$base_uri/show_object_detailled?classname=${clsname}&lodel_id=$id"
169
+			#Get base informations on an instance
170
+			echo "$base_uri/show_object?classname=${clsname}&lodel_id=$id"
171
+		done
172
+	done
173
+}
174
+
143
 mass_link_edit() {
175
 mass_link_edit() {
144
 	#mass linking & edition scenarion
176
 	#mass linking & edition scenarion
145
 	#$1 is instance name
177
 	#$1 is instance name
376
 	done | shuf
408
 	done | shuf
377
 }
409
 }
378
 
410
 
411
+get_queries_with_params "mass_get" $instance_list
379
 [ "$n_create" -gt 0 ] && get_queries_with_params "mass_creation" $instance_list $n_create
412
 [ "$n_create" -gt 0 ] && get_queries_with_params "mass_creation" $instance_list $n_create
380
 [ "$n_edit" -gt 0 ] && get_queries_with_params "mass_link_edit" $instance_list $n_edit
413
 [ "$n_edit" -gt 0 ] && get_queries_with_params "mass_link_edit" $instance_list $n_edit
381
 [ "$n_delete" -gt 0 ] && get_queries_with_params "mass_deletion" $instance_list $n_delete
414
 [ "$n_delete" -gt 0 ] && get_queries_with_params "mass_deletion" $instance_list $n_delete

+ 15
- 0
tests/datahandlers/test_leobjectsubclassidentifier.py View File

1
+import unittest
2
+from unittest import mock 
3
+from unittest.mock import patch
4
+
5
+import leapi_dyncode as dyncode
6
+
7
+from lodel.leapi.datahandlers.datas import LeobjectSubclassIdentifier
8
+from lodel.plugins.dummy_datasource.datasource import DummyDatasource
9
+
10
+
11
+class LeobjectSubclassIdentifierTestCase(unittest.TestCase):
12
+    
13
+    def test_throws_error_if_not_internal(self):
14
+        self.failUnlessRaises(RuntimeError, LeobjectSubclassIdentifier, internal=False)
15
+        

+ 32
- 0
tests/datahandlers/test_uniqid.py View File

1
+import unittest
2
+from unittest import mock 
3
+from unittest.mock import patch
4
+
5
+import leapi_dyncode as dyncode
6
+
7
+from lodel.leapi.datahandlers.datas import UniqID
8
+from lodel.plugins.dummy_datasource.datasource import DummyDatasource
9
+
10
+
11
+class UniqIDTestCase(unittest.TestCase):
12
+    
13
+    def test_construct_data_sets_new_uid_if_none(self):
14
+        sent_uid = None
15
+        mocked_returned_uid = 987654321
16
+        
17
+        with patch.object(DummyDatasource, 'new_numeric_id', return_value=mocked_returned_uid) as mock_method:
18
+            returned_uid = UniqID.construct_data(UniqID, dyncode.Object, 'lodel_id', '', sent_uid)
19
+            
20
+            mock_method.assert_called_once_with(dyncode.Object)
21
+            self.assertEqual(returned_uid, mocked_returned_uid)
22
+            
23
+    def test_construct_data_returns_already_set_uid(self):
24
+        sent_uid = 123456789
25
+        mocked_returned_uid = 987654321
26
+        
27
+        with patch.object(DummyDatasource, 'new_numeric_id', return_value=mocked_returned_uid) as mock_method:
28
+            returned_uid = UniqID.construct_data(UniqID, dyncode.Object, '', '', sent_uid)
29
+
30
+            self.assertEqual(returned_uid, sent_uid)
31
+            mock_method.assert_not_called()     
32
+        

Loading…
Cancel
Save