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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 .image import get_image_instance, other
  13. from .infoviews import get_wrapper_instance as get_infoview_wrapper_instance
  14. import mimetypes
  15. from ..models import get_item_by_rel_path, get_item_type, TYPE_IMAGE, Tag, Item
  16. import os
  17. import pygal
  18. from ..queries import search_result_query
  19. import tempfile
  20. from themes import Context
  21. from users.views import profile_pre_actions, profile_post_actions
  22. from users.forms import UserProfileFormLanguageOnly
  23. from .userviews import get_wrapper_instance as get_userview_wrapper_instance
  24. import zipfile
  25. from pygal.views.userviews import query_view
  26. from pygal.views.image import mm_image
  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. temp = tempfile.TemporaryFile(dir=settings.TEMP_ROOT)
  98. archive = zipfile.ZipFile(temp, 'w', zipfile.ZIP_STORED)
  99. for fp in fp_list:
  100. archive.write(fp, os.path.basename(pygal.get_rel_path(fp)) if flat else pygal.get_rel_path(fp))
  101. archive.close()
  102. temp.seek(0)
  103. #
  104. # return file response
  105. #
  106. response = FileResponse(temp, content_type=mimetypes.types_map.get(os.path.splitext(fn)[1]))
  107. response['Content-Disposition'] = 'attachment; filename="%s"' % fn
  108. return response
  109. def pygal_helpview(request, page='main'):
  110. context = Context(request) # needs to be executed first because of time mesurement
  111. help_content = help_pages[page]
  112. context_adaption(
  113. context, # the base context
  114. request, # the request object to be used in context_adaption
  115. rel_path='', # the current help_page to identify which taskbar entry has to be highlighted
  116. title=_('Help'), # the title for the page (template)
  117. current_help_page=page,
  118. )
  119. context['help_content'] = help_content # the help content itself (template)
  120. return render(request, 'pygal/help.html', context=context)
  121. context = Context(request) # needs to be executed first because of time mesurement
  122. context_adaption(context, request, '', title=_('Help'))
  123. return help_data(request, context)
  124. def pygal_userview_infoview(request, responsetype, rel_path):
  125. context = Context(request) # needs to be executed first because of time mesurement
  126. full_path = pygal.get_full_path(rel_path)
  127. try:
  128. if responsetype == pygal.RESP_TYPE_INFOVIEW:
  129. w = get_infoview_wrapper_instance(full_path, request)
  130. else:
  131. w = get_userview_wrapper_instance(full_path, request)
  132. except LookupError:
  133. context_adaption(context, request, '')
  134. return pygal_item_does_not_exist(request, context)
  135. context_adaption(context, request, rel_path, wrapper_instance=w)
  136. #
  137. if w.may_read():
  138. context.set_additional_title(w.name)
  139. return w.render(context)
  140. else:
  141. return pygal_access_denied(request, context)
  142. def pygal_item(request, responsetype, rel_path):
  143. full_path = pygal.get_full_path(rel_path)
  144. i = get_item_by_rel_path(rel_path)
  145. if not i.may_read(request.user):
  146. im = other(full_path, request) # This will return a mime icon instead of the image itself
  147. else:
  148. im = get_image_instance(full_path, request)
  149. #
  150. if responsetype == pygal.RESP_TYPE_THUMBNAIL:
  151. return HttpResponse(im.thumbnail_picture(), content_type=im.mime_type_xnails)
  152. elif responsetype == pygal.RESP_TYPE_WEBNAIL:
  153. return HttpResponse(im.webnail_picture(), content_type=im.mime_type_xnails)
  154. else:
  155. if i.may_read(request.user):
  156. mimetypes.init()
  157. mime_type = mimetypes.types_map.get(os.path.splitext(full_path)[1])
  158. data = open(full_path, 'rb').read()
  159. return HttpResponse(data, content_type=mime_type)
  160. else:
  161. im = mm_image(os.path.join(os.path.dirname(__file__), 'forbidden.png'))
  162. if responsetype == pygal.RESP_TYPE_THUMBNAIL:
  163. im.resize(int(pygal.get_thumbnail_size(request) * .75))
  164. return HttpResponse(im.image_data(), content_type='image/png')
  165. @login_required
  166. def pygal_profile(request):
  167. context = Context(request) # needs to be executed first because of time mesurement
  168. current_thumbnail_size = pygal.get_thumbnail_size(request)
  169. current_webnail_size = pygal.get_webnail_size(request)
  170. profile_pre_actions(request, context, UserProfileFormLanguageOnly)
  171. context_adaption(context, request, '', title=_('Profile for %(username)s') % {'username': request.user.username})
  172. context['THUMBNAIL_SIZES'] = settings.THUMBNAIL_SIZES
  173. context['thumbnail_size'] = current_thumbnail_size
  174. context['WEBNAIL_SIZES'] = settings.WEBNAIL_SIZES
  175. context['webnail_size'] = current_webnail_size
  176. if request.POST:
  177. # store thumbnail size, if changed
  178. thumbnail_size = int(request.POST.get('thumbnail_size'))
  179. if current_thumbnail_size != thumbnail_size:
  180. pygal.set_thumbnail_size(request, thumbnail_size)
  181. current_thumbnail_size = thumbnail_size
  182. messages.info(request, _('The Thumbnail Size was set to "%d"') % (thumbnail_size))
  183. # store webnail size, if changed
  184. webnail_size = int(request.POST.get('webnail_size'))
  185. if current_webnail_size != webnail_size:
  186. pygal.set_webnail_size(request, webnail_size)
  187. current_webnail_size = webnail_size
  188. messages.info(request, _('The Webnail Size was set to "%d"') % (webnail_size))
  189. return profile_post_actions(request, context)
  190. else:
  191. return render(request, 'pygal/profile.html', context=context)
  192. def tag_context_adaption(context, w, request, enable_tag_area_selection):
  193. context['item'] = w
  194. context['next'] = get_next(request)
  195. context['enable_tag_area_selection'] = enable_tag_area_selection
  196. if enable_tag_area_selection:
  197. i_w, i_h = w.width, w.height
  198. max_size = int(pygal.get_webnail_size(request) / 2)
  199. factor_to_original = max(i_w, i_h) / max_size
  200. context['factor_to_original'] = factor_to_original
  201. context['tag_img_width'] = int(i_w / factor_to_original)
  202. context['tag_img_height'] = int(i_h / factor_to_original)
  203. def pygal_addtag(request, rel_path):
  204. context = Context(request) # needs to be executed first because of time mesurement
  205. full_path = pygal.get_full_path(rel_path)
  206. w = get_userview_wrapper_instance(full_path, request)
  207. if not w.may_modify():
  208. messages.error(request, _('You don\'t have the rights to add a Tag to this Item.'))
  209. return redirect(get_next(request))
  210. else:
  211. context_adaption(
  212. context,
  213. request,
  214. rel_path,
  215. title=_('Add Tag for %s') % w.name
  216. )
  217. tag_context_adaption(context, w, request, get_item_type(full_path) in [TYPE_IMAGE])
  218. if request.POST:
  219. tag = Tag(item=w.item)
  220. form = TagForm(request.POST, instance=tag, factor_to_original=context['factor_to_original'])
  221. if form.is_valid():
  222. form.save()
  223. messages.info(request, _('Thanks for adding a Tag to %s') % w.name)
  224. return redirect(get_next(request))
  225. else:
  226. form = TagForm(factor_to_original=context['factor_to_original'])
  227. context['form'] = form
  228. return render(request, 'pygal/tagedit.html', context=context)
  229. def pygal_tagedit(request, tag_id):
  230. context = Context(request) # needs to be executed first because of time mesurement
  231. try:
  232. t = Tag.objects.get(pk=tag_id)
  233. except Tag.DoesNotExist:
  234. messages.error(request, _('Tag %d does not exist!') % tag_id)
  235. return redirect(get_next(request))
  236. if not t.item.may_modify(request.user):
  237. messages.error(request, _('You don\'t have the rights to change Tag %(tag_id)d.') % {'tag_id': tag_id})
  238. return redirect(get_next(request))
  239. else:
  240. w = get_userview_wrapper_instance(pygal.get_full_path(t.item.rel_path), request)
  241. context_adaption(
  242. context,
  243. request,
  244. t.item.rel_path,
  245. title=_('Edit Tag %(tag_id)d for %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name}
  246. )
  247. tag_context_adaption(context, w, request, t.item.type in [TYPE_IMAGE])
  248. context['enable_delete_button'] = True
  249. if request.POST:
  250. if request.POST.get('save'):
  251. form = TagForm(request.POST, instance=t, factor_to_original=context['factor_to_original'])
  252. if form.is_valid():
  253. form.save()
  254. messages.info(request, _('Thanks for editing Tag %(tag_id)d to %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name})
  255. return redirect(get_next(request))
  256. else:
  257. t.delete()
  258. messages.info(request, _('Tag %(tag_id)d of %(item_name)s has been deleted.') % {'tag_id': tag_id, 'item_name': w.name})
  259. return redirect(get_next(request))
  260. else:
  261. form = TagForm(instance=t, factor_to_original=context['factor_to_original'])
  262. context['form'] = form
  263. return render(request, 'pygal/tagedit.html', context=context)
  264. def pygal_favourite(request, set_favourite, rel_path):
  265. nxt = request.GET.get('next', '/')
  266. item = get_item_by_rel_path(rel_path)
  267. if not set_favourite and request.user in item.favourite_of.all():
  268. item.favourite_of.remove(request.user)
  269. item.save()
  270. if nxt.startswith(pygal.url_favouriteview(request)):
  271. nxt = pygal.url_favouriteview(request)
  272. elif set_favourite and request.user not in item.favourite_of.all():
  273. item.favourite_of.add(request.user)
  274. item.save()
  275. else:
  276. messages.error(request, 'Favourite setting is already in targetstate!')
  277. return redirect(nxt + '#%s' % item.name)