Django Library PyGal
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.

__init__.py 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. from ..context import context_adaption
  2. from django.conf import settings
  3. from django.contrib import messages
  4. from django.contrib.auth.decorators import login_required
  5. from django.http import FileResponse, HttpResponseNotAllowed
  6. from django.shortcuts import render, HttpResponse, redirect
  7. from django.urls.base import reverse
  8. from django.utils.translation import gettext as _
  9. from ..forms import TagForm
  10. import fstools
  11. from ..help import help_pages
  12. from .xnail import get_image_instance, other
  13. from .infoviews import get_wrapper_instance as get_infoview_wrapper_instance
  14. import media
  15. import mimetypes
  16. from ..models import get_item_by_rel_path, get_item_type, TYPE_IMAGE, Tag, Item
  17. import os
  18. import pygal
  19. from ..queries import search_result_query
  20. import tempfile
  21. from themes import Context
  22. from users.views import profile_pre_actions, profile_post_actions
  23. from users.forms import UserProfileFormLanguageOnly
  24. from .userviews import get_wrapper_instance as get_userview_wrapper_instance
  25. import zipfile
  26. from pygal.views.userviews import query_view, ItemDoesNotEsistWithinParent
  27. def pygal_item_does_not_exist(request, context):
  28. context.set_additional_title(_('Page does not exist!'))
  29. messages.error(request, _('The Item for the given URL does not exist.'))
  30. return render(request, 'pygal/empty.html', context=context)
  31. def pygal_access_denied(request, context):
  32. context.set_additional_title(_('Access denied!'))
  33. messages.error(request, _('Access Denied: You don\'t have access rights.'))
  34. return render(request, 'pygal/empty.html', context=context)
  35. def get_next(request):
  36. if not request.POST:
  37. return request.GET.get('next', '/')
  38. else:
  39. return request.POST.get('next', '/')
  40. def pygal_responses(request, responsetype=pygal.RESP_TYPE_USERVIEW, datatype=pygal.DATA_TYPE_SEARCH, rel_path=''):
  41. # raw and scaled items
  42. if responsetype in [pygal.RESP_TYPE_RAWITEM, pygal.RESP_TYPE_WEBNAIL, pygal.RESP_TYPE_THUMBNAIL]:
  43. return pygal_item(request, responsetype, rel_path)
  44. # userview and infoview for items
  45. elif responsetype in [pygal.RESP_TYPE_USERVIEW, pygal.RESP_TYPE_INFOVIEW] and datatype == pygal.DATA_TYPE_ITEM:
  46. return pygal_userview_infoview(request, responsetype, rel_path)
  47. # download
  48. elif responsetype == pygal.RESP_TYPE_DOWNLOAD:
  49. return pygal_download(request, datatype, rel_path)
  50. # search
  51. elif responsetype in [pygal.RESP_TYPE_USERVIEW, pygal.RESP_TYPE_INFOVIEW] and datatype == pygal.DATA_TYPE_SEARCH:
  52. if not rel_path:
  53. return pygal_search(request, rel_path)
  54. else:
  55. return pygal_userview_infoview(request, responsetype, rel_path)
  56. else:
  57. d = {
  58. 'responsetype': responsetype,
  59. 'datatype': datatype,
  60. }
  61. messages.error(request, _('No response implemented in pygal.views.pygal_responses for responsetype="%(responsetype)s" and datatype="%(datatype)s".') % d)
  62. return redirect('/')
  63. def pygal_search(request, rel_path):
  64. context = Context(request) # needs to be executed first because of time mesurement
  65. w = query_view(request, search_result_query(request))
  66. context_adaption(context, request, '', wrapper_instance=w)
  67. context.set_additional_title(w.name)
  68. return w.render(context)
  69. def pygal_download(request, datatype, rel_path):
  70. full_path = pygal.get_full_path(rel_path)
  71. if os.path.isfile(full_path):
  72. # Download a file
  73. temp = open(full_path, 'rb')
  74. fn = os.path.basename(full_path)
  75. else:
  76. if pygal.is_favouriteview(request) or pygal.is_searchview(request) and rel_path == '':
  77. if pygal.is_favouriteview(request):
  78. fn = 'favourites.zip'
  79. else:
  80. fn = 'search.zip'
  81. # Download the favourites or search results
  82. fp_list = []
  83. for i in search_result_query(request):
  84. if i.may_read(request.user):
  85. fp_list.append(pygal.get_full_path(i.rel_path))
  86. else:
  87. # Download the folder full_path
  88. fn = (os.path.basename(full_path) or 'root') + '.zip'
  89. fp_list = []
  90. for i in get_item_by_rel_path(rel_path).all_itemslist():
  91. if i.may_read(request.user):
  92. fp_list.append(pygal.get_full_path(i.rel_path))
  93. #
  94. # Create the Archive from fp_list
  95. #
  96. flat = pygal.is_flat(request)
  97. if not os.path.exists(settings.TEMP_ROOT):
  98. fstools.mkdir(settings.TEMP_ROOT)
  99. temp = tempfile.TemporaryFile(dir=settings.TEMP_ROOT)
  100. archive = zipfile.ZipFile(temp, 'w', zipfile.ZIP_STORED)
  101. for fp in fp_list:
  102. archive.write(fp, os.path.basename(pygal.get_rel_path(fp)) if flat else pygal.get_rel_path(fp))
  103. archive.close()
  104. temp.seek(0)
  105. #
  106. # return file response
  107. #
  108. response = FileResponse(temp, content_type=mimetypes.types_map.get(os.path.splitext(fn)[1]))
  109. response['Content-Disposition'] = 'attachment; filename="%s"' % fn
  110. return response
  111. def pygal_helpview(request, page='main'):
  112. context = Context(request) # needs to be executed first because of time mesurement
  113. help_content = help_pages[page]
  114. context_adaption(
  115. context, # the base context
  116. request, # the request object to be used in context_adaption
  117. rel_path='', # the current help_page to identify which taskbar entry has to be highlighted
  118. title=_('Help'), # the title for the page (template)
  119. current_help_page=page,
  120. )
  121. context['help_content'] = help_content # the help content itself (template)
  122. return render(request, 'pygal/help.html', context=context)
  123. context = Context(request) # needs to be executed first because of time mesurement
  124. context_adaption(context, request, '', title=_('Help'))
  125. return help_data(request, context)
  126. def pygal_userview_infoview(request, responsetype, rel_path):
  127. context = Context(request) # needs to be executed first because of time mesurement
  128. full_path = pygal.get_full_path(rel_path)
  129. try:
  130. if responsetype == pygal.RESP_TYPE_INFOVIEW:
  131. w = get_infoview_wrapper_instance(full_path, request)
  132. else:
  133. w = get_userview_wrapper_instance(full_path, request)
  134. except LookupError:
  135. context_adaption(context, request, '')
  136. return pygal_item_does_not_exist(request, context)
  137. context_adaption(context, request, rel_path, wrapper_instance=w)
  138. #
  139. if w.may_read():
  140. context.set_additional_title(w.name)
  141. try:
  142. return w.render(context)
  143. except ItemDoesNotEsistWithinParent:
  144. return redirect('?'.join([request.META['PATH_INFO'].replace(rel_path, ''), request.META['QUERY_STRING']]))
  145. else:
  146. return pygal_access_denied(request, context)
  147. def pygal_item(request, responsetype, rel_path):
  148. full_path = pygal.get_full_path(rel_path)
  149. i = get_item_by_rel_path(rel_path)
  150. if not i.may_read(request.user):
  151. im = other(full_path, request) # This will return a mime icon instead of the image itself
  152. else:
  153. im = get_image_instance(full_path, request)
  154. #
  155. if responsetype == pygal.RESP_TYPE_THUMBNAIL:
  156. return HttpResponse(im.thumbnail_picture(), content_type=im.mime_type_xnails)
  157. elif responsetype == pygal.RESP_TYPE_WEBNAIL:
  158. return HttpResponse(im.webnail_picture(), content_type=im.mime_type_xnails)
  159. else:
  160. if i.may_read(request.user):
  161. mimetypes.init()
  162. mime_type = mimetypes.types_map.get(os.path.splitext(full_path)[1])
  163. data = open(full_path, 'rb').read()
  164. return HttpResponse(data, content_type=mime_type)
  165. else:
  166. im = media.image(os.path.join(os.path.dirname(__file__), 'forbidden.png'))
  167. if responsetype == pygal.RESP_TYPE_THUMBNAIL:
  168. im.resize(int(pygal.get_thumbnail_size(request) * .75))
  169. return HttpResponse(im.image_data(), content_type='image/png')
  170. @login_required
  171. def pygal_profile(request):
  172. context = Context(request) # needs to be executed first because of time mesurement
  173. current_thumbnail_size = pygal.get_thumbnail_size(request)
  174. current_webnail_size = pygal.get_webnail_size(request)
  175. profile_pre_actions(request, context, UserProfileFormLanguageOnly)
  176. context_adaption(context, request, '', title=_('Profile for %(username)s') % {'username': request.user.username})
  177. context['THUMBNAIL_SIZES'] = settings.THUMBNAIL_SIZES
  178. context['thumbnail_size'] = current_thumbnail_size
  179. context['WEBNAIL_SIZES'] = settings.WEBNAIL_SIZES
  180. context['webnail_size'] = current_webnail_size
  181. if request.POST:
  182. # store thumbnail size, if changed
  183. thumbnail_size = int(request.POST.get('thumbnail_size'))
  184. if current_thumbnail_size != thumbnail_size:
  185. pygal.set_thumbnail_size(request, thumbnail_size)
  186. current_thumbnail_size = thumbnail_size
  187. messages.info(request, _('The Thumbnail Size was set to "%d"') % (thumbnail_size))
  188. # store webnail size, if changed
  189. webnail_size = int(request.POST.get('webnail_size'))
  190. if current_webnail_size != webnail_size:
  191. pygal.set_webnail_size(request, webnail_size)
  192. current_webnail_size = webnail_size
  193. messages.info(request, _('The Webnail Size was set to "%d"') % (webnail_size))
  194. return profile_post_actions(request, context)
  195. else:
  196. return render(request, 'pygal/profile.html', context=context)
  197. def tag_context_adaption(context, w, request, enable_tag_area_selection):
  198. context['item'] = w
  199. context['next'] = get_next(request)
  200. context['enable_tag_area_selection'] = enable_tag_area_selection
  201. if enable_tag_area_selection:
  202. i_w, i_h = w.width, w.height
  203. max_size = int(pygal.get_webnail_size(request) / 2)
  204. factor_to_original = max(i_w, i_h) / max_size
  205. context['factor_to_original'] = factor_to_original
  206. context['tag_img_width'] = int(i_w / factor_to_original)
  207. context['tag_img_height'] = int(i_h / factor_to_original)
  208. def pygal_addtag(request, rel_path):
  209. context = Context(request) # needs to be executed first because of time mesurement
  210. full_path = pygal.get_full_path(rel_path)
  211. w = get_userview_wrapper_instance(full_path, request)
  212. if not w.may_modify():
  213. messages.error(request, _('You don\'t have the rights to add a Tag to this Item.'))
  214. return redirect(get_next(request))
  215. else:
  216. context_adaption(
  217. context,
  218. request,
  219. rel_path,
  220. title=_('Add Tag for %s') % w.name
  221. )
  222. tag_context_adaption(context, w, request, get_item_type(full_path) in [TYPE_IMAGE])
  223. if request.POST:
  224. tag = Tag(item=w.item)
  225. form = TagForm(request.POST, instance=tag, factor_to_original=context.get('factor_to_original'))
  226. if form.is_valid():
  227. form.save()
  228. messages.info(request, _('Thanks for adding a Tag to %s') % w.name)
  229. return redirect(get_next(request))
  230. else:
  231. form = TagForm(factor_to_original=context.get('factor_to_original'))
  232. context['form'] = form
  233. return render(request, 'pygal/tagedit.html', context=context)
  234. def pygal_tagedit(request, tag_id):
  235. context = Context(request) # needs to be executed first because of time mesurement
  236. try:
  237. t = Tag.objects.get(pk=tag_id)
  238. except Tag.DoesNotExist:
  239. messages.error(request, _('Tag %d does not exist!') % tag_id)
  240. return redirect(get_next(request))
  241. if not t.item.may_modify(request.user):
  242. messages.error(request, _('You don\'t have the rights to change Tag %(tag_id)d.') % {'tag_id': tag_id})
  243. return redirect(get_next(request))
  244. else:
  245. w = get_userview_wrapper_instance(pygal.get_full_path(t.item.rel_path), request)
  246. context_adaption(
  247. context,
  248. request,
  249. t.item.rel_path,
  250. title=_('Edit Tag %(tag_id)d for %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name}
  251. )
  252. tag_context_adaption(context, w, request, t.item.type in [TYPE_IMAGE])
  253. context['enable_delete_button'] = True
  254. if request.POST:
  255. if request.POST.get('save'):
  256. form = TagForm(request.POST, instance=t, factor_to_original=context.get('factor_to_original'))
  257. if form.is_valid():
  258. form.save()
  259. messages.info(request, _('Thanks for editing Tag %(tag_id)d to %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name})
  260. return redirect(get_next(request))
  261. else:
  262. t.delete()
  263. messages.info(request, _('Tag %(tag_id)d of %(item_name)s has been deleted.') % {'tag_id': tag_id, 'item_name': w.name})
  264. return redirect(get_next(request))
  265. else:
  266. form = TagForm(instance=t, factor_to_original=context.get('factor_to_original'))
  267. context['form'] = form
  268. return render(request, 'pygal/tagedit.html', context=context)
  269. def pygal_favourite(request, set_favourite, rel_path):
  270. nxt = request.GET.get('next', '/')
  271. item = get_item_by_rel_path(rel_path)
  272. if not set_favourite and request.user in item.favourite_of.all():
  273. item.favourite_of.remove(request.user)
  274. item.save()
  275. if nxt.startswith(pygal.url_favouriteview(request)):
  276. nxt = pygal.url_favouriteview(request)
  277. elif set_favourite and request.user not in item.favourite_of.all():
  278. item.favourite_of.add(request.user)
  279. item.save()
  280. else:
  281. messages.error(request, 'Favourite setting is already in targetstate!')
  282. return redirect(nxt + '#%s' % item.name)