Django Library PyGal
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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
  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. return w.render(context)
  142. else:
  143. return pygal_access_denied(request, context)
  144. def pygal_item(request, responsetype, rel_path):
  145. full_path = pygal.get_full_path(rel_path)
  146. i = get_item_by_rel_path(rel_path)
  147. if not i.may_read(request.user):
  148. im = other(full_path, request) # This will return a mime icon instead of the image itself
  149. else:
  150. im = get_image_instance(full_path, request)
  151. #
  152. if responsetype == pygal.RESP_TYPE_THUMBNAIL:
  153. return HttpResponse(im.thumbnail_picture(), content_type=im.mime_type_xnails)
  154. elif responsetype == pygal.RESP_TYPE_WEBNAIL:
  155. return HttpResponse(im.webnail_picture(), content_type=im.mime_type_xnails)
  156. else:
  157. if i.may_read(request.user):
  158. mimetypes.init()
  159. mime_type = mimetypes.types_map.get(os.path.splitext(full_path)[1])
  160. data = open(full_path, 'rb').read()
  161. return HttpResponse(data, content_type=mime_type)
  162. else:
  163. im = media.image(os.path.join(os.path.dirname(__file__), 'forbidden.png'))
  164. if responsetype == pygal.RESP_TYPE_THUMBNAIL:
  165. im.resize(int(pygal.get_thumbnail_size(request) * .75))
  166. return HttpResponse(im.image_data(), content_type='image/png')
  167. @login_required
  168. def pygal_profile(request):
  169. context = Context(request) # needs to be executed first because of time mesurement
  170. current_thumbnail_size = pygal.get_thumbnail_size(request)
  171. current_webnail_size = pygal.get_webnail_size(request)
  172. profile_pre_actions(request, context, UserProfileFormLanguageOnly)
  173. context_adaption(context, request, '', title=_('Profile for %(username)s') % {'username': request.user.username})
  174. context['THUMBNAIL_SIZES'] = settings.THUMBNAIL_SIZES
  175. context['thumbnail_size'] = current_thumbnail_size
  176. context['WEBNAIL_SIZES'] = settings.WEBNAIL_SIZES
  177. context['webnail_size'] = current_webnail_size
  178. if request.POST:
  179. # store thumbnail size, if changed
  180. thumbnail_size = int(request.POST.get('thumbnail_size'))
  181. if current_thumbnail_size != thumbnail_size:
  182. pygal.set_thumbnail_size(request, thumbnail_size)
  183. current_thumbnail_size = thumbnail_size
  184. messages.info(request, _('The Thumbnail Size was set to "%d"') % (thumbnail_size))
  185. # store webnail size, if changed
  186. webnail_size = int(request.POST.get('webnail_size'))
  187. if current_webnail_size != webnail_size:
  188. pygal.set_webnail_size(request, webnail_size)
  189. current_webnail_size = webnail_size
  190. messages.info(request, _('The Webnail Size was set to "%d"') % (webnail_size))
  191. return profile_post_actions(request, context)
  192. else:
  193. return render(request, 'pygal/profile.html', context=context)
  194. def tag_context_adaption(context, w, request, enable_tag_area_selection):
  195. context['item'] = w
  196. context['next'] = get_next(request)
  197. context['enable_tag_area_selection'] = enable_tag_area_selection
  198. if enable_tag_area_selection:
  199. i_w, i_h = w.width, w.height
  200. max_size = int(pygal.get_webnail_size(request) / 2)
  201. factor_to_original = max(i_w, i_h) / max_size
  202. context['factor_to_original'] = factor_to_original
  203. context['tag_img_width'] = int(i_w / factor_to_original)
  204. context['tag_img_height'] = int(i_h / factor_to_original)
  205. def pygal_addtag(request, rel_path):
  206. context = Context(request) # needs to be executed first because of time mesurement
  207. full_path = pygal.get_full_path(rel_path)
  208. w = get_userview_wrapper_instance(full_path, request)
  209. if not w.may_modify():
  210. messages.error(request, _('You don\'t have the rights to add a Tag to this Item.'))
  211. return redirect(get_next(request))
  212. else:
  213. context_adaption(
  214. context,
  215. request,
  216. rel_path,
  217. title=_('Add Tag for %s') % w.name
  218. )
  219. tag_context_adaption(context, w, request, get_item_type(full_path) in [TYPE_IMAGE])
  220. if request.POST:
  221. tag = Tag(item=w.item)
  222. form = TagForm(request.POST, instance=tag, factor_to_original=context['factor_to_original'])
  223. if form.is_valid():
  224. form.save()
  225. messages.info(request, _('Thanks for adding a Tag to %s') % w.name)
  226. return redirect(get_next(request))
  227. else:
  228. form = TagForm(factor_to_original=context['factor_to_original'])
  229. context['form'] = form
  230. return render(request, 'pygal/tagedit.html', context=context)
  231. def pygal_tagedit(request, tag_id):
  232. context = Context(request) # needs to be executed first because of time mesurement
  233. try:
  234. t = Tag.objects.get(pk=tag_id)
  235. except Tag.DoesNotExist:
  236. messages.error(request, _('Tag %d does not exist!') % tag_id)
  237. return redirect(get_next(request))
  238. if not t.item.may_modify(request.user):
  239. messages.error(request, _('You don\'t have the rights to change Tag %(tag_id)d.') % {'tag_id': tag_id})
  240. return redirect(get_next(request))
  241. else:
  242. w = get_userview_wrapper_instance(pygal.get_full_path(t.item.rel_path), request)
  243. context_adaption(
  244. context,
  245. request,
  246. t.item.rel_path,
  247. title=_('Edit Tag %(tag_id)d for %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name}
  248. )
  249. tag_context_adaption(context, w, request, t.item.type in [TYPE_IMAGE])
  250. context['enable_delete_button'] = True
  251. if request.POST:
  252. if request.POST.get('save'):
  253. form = TagForm(request.POST, instance=t, factor_to_original=context['factor_to_original'])
  254. if form.is_valid():
  255. form.save()
  256. messages.info(request, _('Thanks for editing Tag %(tag_id)d to %(item_name)s') % {'tag_id': tag_id, 'item_name': w.name})
  257. return redirect(get_next(request))
  258. else:
  259. t.delete()
  260. messages.info(request, _('Tag %(tag_id)d of %(item_name)s has been deleted.') % {'tag_id': tag_id, 'item_name': w.name})
  261. return redirect(get_next(request))
  262. else:
  263. form = TagForm(instance=t, factor_to_original=context['factor_to_original'])
  264. context['form'] = form
  265. return render(request, 'pygal/tagedit.html', context=context)
  266. def pygal_favourite(request, set_favourite, rel_path):
  267. nxt = request.GET.get('next', '/')
  268. item = get_item_by_rel_path(rel_path)
  269. if not set_favourite and request.user in item.favourite_of.all():
  270. item.favourite_of.remove(request.user)
  271. item.save()
  272. if nxt.startswith(pygal.url_favouriteview(request)):
  273. nxt = pygal.url_favouriteview(request)
  274. elif set_favourite and request.user not in item.favourite_of.all():
  275. item.favourite_of.add(request.user)
  276. item.save()
  277. else:
  278. messages.error(request, 'Favourite setting is already in targetstate!')
  279. return redirect(nxt + '#%s' % item.name)