No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

admin.py 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. # -*- coding: utf-8 -*-
  2. from ...exceptions import *
  3. from .base import get_response
  4. from lodel.context import LodelContext
  5. LodelContext.expose_modules(globals(), {
  6. 'lodel.leapi.exceptions': [],
  7. 'lodel.logger': 'logger',
  8. 'lodel.leapi.datahandlers.base_classes': ['MultipleRef'],
  9. 'lodel.leapi.exceptions': ['LeApiDataCheckErrors'],
  10. 'lodel.exceptions': ['LodelExceptions']})
  11. LodelContext.expose_dyncode(globals(), 'dyncode')
  12. from ...client import WebUiClient
  13. import warnings
  14. LIST_SEPARATOR = ','
  15. ##@brief These functions are called by the rules defined in ../urls.py
  16. ## To administrate the instance of the editorial model
  17. ##@brief Controller's function to redirect on the home page of the admin
  18. # @param request : the request (get or post)
  19. # @note the response is given in a html page called in get_response_function
  20. def index_admin(request):
  21. # We have to be identified to admin the instance
  22. # temporary, the acl will be more restrictive
  23. #if WebUiClient.is_anonymous():
  24. # return get_response('users/signin.html')
  25. return get_response('admin/admin.html')
  26. ##@brief Controller's function to update an object of the editorial model
  27. # @param request : the request (get or post)
  28. # @note the response is given in a html page (in templates/admin) called in get_response_function
  29. def admin_update(request):
  30. # We have to be identified to admin the instance
  31. # temporary, the acl will be more restrictive
  32. #if WebUiClient.is_anonymous():
  33. # return get_response('users/signin.html')
  34. msg=''
  35. datas = process_form(request)
  36. if not(datas is False):
  37. if 'lodel_id' not in datas:
  38. raise HttpException(400)
  39. target_leo = dyncode.Object.name2class(datas['classname'])
  40. leo = target_leo.get_from_uid(datas['lodel_id'])
  41. #for in_value in datas:
  42. # if datas[in_value] == '':
  43. # datas[in_value] = None
  44. if leo is None:
  45. raise HttpException(404,
  46. custom = 'No %s with id %s' % (
  47. target_leo.__name__, datas['lodel_id']))
  48. try:
  49. leo.update(
  50. { f:datas[f] for f in datas if f not in ('classname', 'lodel_id')})
  51. except LeApiDataCheckErrors as e:
  52. raise HttpErrors(
  53. title='Form validation errors', errors = e._exceptions)
  54. # Display of the form with the object's values to be updated
  55. if 'classname' in request.GET:
  56. # We need the class of the object to update
  57. classname = request.GET['classname']
  58. if len(classname) > 1:
  59. raise HttpException(400)
  60. classname = classname[0]
  61. try:
  62. target_leo = dyncode.Object.name2class(classname)
  63. except LeApiError:
  64. # classname = None
  65. raise HttpException(400)
  66. logger.warning('Composed uids broken here')
  67. uid_field = target_leo.uid_fieldname()[0]
  68. # We need the uid of the object
  69. test_valid = 'lodel_id' in request.GET \
  70. and len(request.GET['lodel_id']) == 1
  71. if test_valid:
  72. try:
  73. dh = target_leo.field(uid_field)
  74. # we cast the uid extrated form the request to the adequate type
  75. # given by the datahandler of the uidfield's datahandler
  76. lodel_id = dh.cast_type(request.GET['lodel_id'][0])
  77. except (ValueError, TypeError):
  78. test_valid = False
  79. if not test_valid:
  80. raise HttpException(400)
  81. else:
  82. # Check if the object actually exists
  83. # We get it from the database
  84. query_filters = list()
  85. query_filters.append((uid_field,'=',lodel_id))
  86. obj = target_leo.get(query_filters)
  87. if len(obj) == 0:
  88. raise HttpException(404)
  89. return get_response('admin/admin_edit.html', target=target_leo, lodel_id =lodel_id)
  90. ##@brief Controller's function to create an object of the editorial model
  91. # @param request : the request (get or post)
  92. # @note the response is given in a html page (in templates/admin) called in get_response_function
  93. def admin_create(request):
  94. # We have to be identified to admin the instance
  95. # temporary, the acl will be more restrictive
  96. #if WebUiClient.is_anonymous():
  97. # return get_response('users/signin.html')
  98. datas = process_form(request)
  99. if not(datas is False):
  100. target_leo = dyncode.Object.name2class(datas['classname'])
  101. if 'lodel_id' in datas:
  102. raise HttpException(400)
  103. try:
  104. for in_value in datas:
  105. if datas[in_value] == '':
  106. datas[in_value] = None
  107. new_uid = target_leo.insert(
  108. { f:datas[f] for f in datas if f != 'classname'})
  109. except LeApiDataCheckErrors as e:
  110. raise HttpErrors(
  111. title='Form validation errors', errors = e._exceptions)
  112. if new_uid is None:
  113. raise HttpException(400, "Creation fails")
  114. else:
  115. return get_response(
  116. 'admin/admin_create.html', target=target_leo,
  117. msg = "Created with uid %s" % new_uid)
  118. # Display of an empty form
  119. if 'classname' in request.GET:
  120. # We need the class to create an object in
  121. classname = request.GET['classname']
  122. if len(classname) > 1:
  123. raise HttpException(400)
  124. classname = classname[0]
  125. try:
  126. target_leo = dyncode.Object.name2class(classname)
  127. except LeApiError:
  128. classname = None
  129. if classname is None or target_leo.is_abstract():
  130. raise HttpException(400)
  131. return get_response('admin/admin_create.html', target=target_leo)
  132. ##@brief Controller's function to delete an object of the editorial model
  133. # @param request : the request (get)
  134. # @note the response is given in a html page (in templates/admin) called in get_response_function
  135. def admin_delete(request):
  136. # We have to be identified to admin the instance
  137. # temporary, the acl will be more restrictive
  138. #if WebUiClient.is_anonymous():
  139. # return get_response('users/signin.html')
  140. classname = None
  141. if 'classname' in request.GET:
  142. # We need the class to delete an object in
  143. classname = request.GET['classname']
  144. if len(classname) > 1:
  145. raise HttpException(400)
  146. classname = classname[0]
  147. try:
  148. target_leo = dyncode.Object.name2class(classname)
  149. except LeApiError:
  150. # classname = None
  151. raise HttpException(400)
  152. logger.warning('Composed uids broken here')
  153. uid_field = target_leo.uid_fieldname()[0]
  154. # We also need the uid of the object to delete
  155. test_valid = 'lodel_id' in request.GET \
  156. and len(request.GET['lodel_id']) == 1
  157. if test_valid:
  158. try:
  159. dh = target_leo.field(uid_field)
  160. # we cast the uid extrated form the request to the adequate type
  161. # given by the datahandler of the uidfield's datahandler
  162. lodel_id = dh.cast_type(request.GET['lodel_id'][0])
  163. except (ValueError, TypeError):
  164. test_valid = False
  165. if not test_valid:
  166. raise HttpException(400)
  167. else:
  168. query_filters = list()
  169. query_filters.append((uid_field,'=',lodel_id))
  170. nb_deleted = target_leo.delete_bundle(query_filters)
  171. if nb_deleted == 1:
  172. msg = 'Object successfully deleted';
  173. else:
  174. msg = 'Oops something wrong happened...object still here'
  175. return get_response('admin/admin_delete.html', target=target_leo, lodel_id =lodel_id, msg = msg)
  176. def admin_classes(request):
  177. # We have to be identified to admin the instance
  178. # temporary, the acl will be more restrictive
  179. #if WebUiClient.is_anonymous():
  180. # return get_response('users/signin.html')
  181. return get_response('admin/list_classes_admin.html', my_classes = dyncode.dynclasses)
  182. def create_object(request):
  183. # We have to be identified to admin the instance
  184. # temporary, the acl will be more restrictive
  185. #if WebUiClient.is_anonymous():
  186. # return get_response('users/signin.html')
  187. return get_response('admin/list_classes_create.html', my_classes = dyncode.dynclasses)
  188. def delete_object(request):
  189. # We have to be identified to admin the instance
  190. # temporary, the acl will be more restrictive
  191. #if WebUiClient.is_anonymous():
  192. # return get_response('users/signin.html')
  193. return get_response('admin/list_classes_delete.html', my_classes = dyncode.dynclasses)
  194. def admin_class(request):
  195. # We have to be identified to admin the instance
  196. # temporary, the acl will be more restrictive
  197. #if WebUiClient.is_anonymous():
  198. # return get_response('users/signin.html')
  199. # We need the class we'll list to select the object to edit
  200. if 'classname' in request.GET:
  201. classname = request.GET['classname']
  202. if len(classname) > 1:
  203. raise HttpException(400)
  204. classname = classname[0]
  205. try:
  206. target_leo = dyncode.Object.name2class(classname)
  207. except LeApiError:
  208. classname = None
  209. if classname is None or target_leo.is_abstract():
  210. raise HttpException(400)
  211. return get_response('admin/show_class_admin.html', target=target_leo)
  212. def delete_in_class(request):
  213. # We have to be identified to admin the instance
  214. # temporary, the acl will be more restrictive
  215. #if WebUiClient.is_anonymous():
  216. # return get_response('users/signin.html')
  217. # We need the class we'll list to select the object to delete
  218. if 'classname' in request.GET:
  219. classname = request.GET['classname']
  220. if len(classname) > 1:
  221. raise HttpException(400)
  222. classname = classname[0]
  223. try:
  224. target_leo = dyncode.Object.name2class(classname)
  225. except LeApiError:
  226. classname = None
  227. if classname is None or target_leo.is_abstract():
  228. raise HttpException(400)
  229. return get_response('admin/show_class_delete.html', target=target_leo)
  230. def admin(request):
  231. # We have to be identified to admin the instance
  232. # temporary, the acl will be more restrictive
  233. #if WebUiClient.is_anonymous():
  234. # return get_response('users/signin.html')
  235. return get_response('admin/admin.html')
  236. def search_object(request):
  237. if request.method == 'POST':
  238. classname = request.POST['classname']
  239. searchstring = request.POST['searchstring']
  240. try:
  241. target_leo = dyncode.Object.name2class(classname)
  242. except LeApiError:
  243. raise HttpException(400)
  244. # TODO The get method must be implemented here
  245. return get_response('admin/admin_search.html', my_classes = dyncode.dynclasses)
  246. ##@brief Process a form POST and return the posted datas
  247. #@param request : the request object
  248. #@return a dict with datas as value and fieldname as key
  249. def process_form(request):
  250. if request.method != 'POST':
  251. return False
  252. res = dict()
  253. errors = dict()
  254. #Fetch concerned LeObject
  255. if 'classname' not in request.form:
  256. logger.error("Received a form without classname !")
  257. raise HttpException(400)
  258. res['classname'] = classname = request.form['classname']
  259. try:
  260. target_leo = dyncode.Object.name2class(classname)
  261. except LeApiError:
  262. logger.error(
  263. "Received a form with an invalid leo name : '%s'" % classname)
  264. raise HttpException(400, "No leobject named '%s'" % classname)
  265. if target_leo.is_abstract():
  266. logger.error(
  267. "Received a form with an abstract leo : '%s'" % classname)
  268. raise HttpException(400, '%s is abstract' % classname)
  269. #Process input fields
  270. for fieldname, value in request.form.items():
  271. if fieldname == 'classname':
  272. continue
  273. elif fieldname == 'uid':
  274. fieldname = 'lodel_id' #wow
  275. elif fieldname.startswith('field_input_'):
  276. fieldname = fieldname[12:]
  277. try:
  278. dh = target_leo.data_handler(fieldname)
  279. except NameError as e:
  280. errors[fieldname] = e
  281. continue
  282. if dh.is_reference() and not dh.is_singlereference():
  283. #Converting multiple references fields
  284. value = value.strip()
  285. if len(value) == 0:
  286. #handling default value for empty string
  287. if hasattr(dh, 'default'):
  288. value = dh.default
  289. else:
  290. #if not explicit default value, enforcing default as
  291. #an empty list
  292. value = []
  293. else:
  294. value = [ v.strip() for v in value.split(LIST_SEPARATOR) ]
  295. value = [ v for v in value if len(v) > 0]
  296. else:
  297. #Handling default value for empty string
  298. if len(value.strip()) == 0 and hasattr(dh, 'default'):
  299. value = dh.default
  300. res[fieldname] = value
  301. if len(errors) > 0:
  302. del(res)
  303. raise HttpErrors(errors, title="Form validation error")
  304. return res