설명 없음

views.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. from django.shortcuts import render
  2. from counter.models import Counter, Reset
  3. from babel.dates import format_timedelta, format_datetime
  4. from datetime import datetime, timedelta
  5. from django import forms
  6. from django.http import HttpResponseRedirect
  7. from django.core import serializers
  8. from django.core.mail import EmailMessage
  9. from graphos.renderers import gchart
  10. from graphos.sources.simple import SimpleDataSource
  11. from graphos.sources.model import ModelDataSource
  12. import random
  13. import math
  14. import copy
  15. from django.utils import timezone
  16. class resetCounterForm(forms.ModelForm):
  17. class Meta:
  18. model = Reset
  19. fields = ['reason', 'counter']
  20. def home(request):
  21. # JSS above this limit will not be displayed on the col graph
  22. JSS_limit = 7
  23. maxJSS = 0
  24. bestSeumeursNumber = 15
  25. # Display counters
  26. lastResets = []
  27. # Calculates infos for each counter
  28. timezero = timedelta(0)
  29. # First we determine if the session
  30. if 'my-counter' in request.session:
  31. chooseCounter = False
  32. try:
  33. myCounter = Counter.objects.get(id=request.session['my-counter'])
  34. lastReset = Reset.objects.filter(
  35. counter=myCounter).order_by('-timestamp')
  36. if (lastReset.count() == 0):
  37. # This person never had the seum
  38. myCounter.lastReset = Reset()
  39. myCounter.lastReset.delta = timezero
  40. myCounter.lastReset.noSeum = True
  41. else:
  42. myCounter.lastReset = lastReset[0]
  43. myCounter.lastReset.noSeum = False
  44. myCounter.lastReset.delta = datetime.now(
  45. ) - myCounter.lastReset.timestamp.replace(tzinfo=None)
  46. myCounter.seumCount = Reset.objects.filter(
  47. counter=myCounter).count()
  48. myCounter.lastReset.formatted_delta = format_timedelta(
  49. myCounter.lastReset.delta, locale='fr', threshold=1)
  50. except ObjectDoesNotExist:
  51. chooseCounter = True
  52. else:
  53. myCounter = None
  54. chooseCounter = True
  55. counters = Counter.objects.all()
  56. for counter in counters:
  57. lastReset = Reset.objects.filter(
  58. counter=counter).order_by('-timestamp')
  59. if (lastReset.count() == 0):
  60. # This person never had the seum
  61. counter.lastReset = Reset()
  62. counter.lastReset.delta = timezero
  63. counter.lastReset.noSeum = True
  64. counter.CSSclass = "warning"
  65. else:
  66. counter.lastReset = lastReset[0]
  67. counter.lastReset.noSeum = False
  68. counter.lastReset.delta = datetime.now(
  69. ) - counter.lastReset.timestamp.replace(tzinfo=None)
  70. if ((counter.lastReset.delta.total_seconds()) / (24 * 3600) <
  71. JSS_limit):
  72. # Less than 7 JSS -> display on graph
  73. lastResets.append(
  74. [counter.trigramme,
  75. {'v': (counter.lastReset.delta.total_seconds()) /
  76. (24 * 3600),
  77. 'f': str(round(
  78. (counter.lastReset.delta.total_seconds()) /
  79. (24 * 3600), 1))}])
  80. # Updating the max JSS displayed on the graph to compute scale
  81. if (counter.lastReset.delta.total_seconds() / (24 * 3600) >
  82. maxJSS):
  83. maxJSS = (counter.lastReset.delta.total_seconds() /
  84. (24 * 3600))
  85. # Defining CSS attributes for the counter
  86. counter.CSSclass = "primary"
  87. counter.opacity = 0.3 + 0.7 * \
  88. math.exp(-(counter.lastReset.delta.total_seconds()) /
  89. (7 * 24 * 3600))
  90. # Computing the total number of resets for this counter
  91. counter.seumCount = Reset.objects.filter(
  92. counter=counter).count()
  93. counter.lastReset.formatted_delta = format_timedelta(
  94. counter.lastReset.delta, locale='fr', threshold=1)
  95. counter.isHidden = "hidden"
  96. counters = sorted(counters, key=lambda t: t.lastReset.delta)
  97. # Column graph
  98. if (len(lastResets) == 0):
  99. noGraph = True
  100. col_chart = None
  101. else:
  102. noGraph = False
  103. lastResets.sort(key=lambda x: x[1]['v'])
  104. lastResets.insert(0, ['Trigramme', 'Jours sans seum'])
  105. col_data = SimpleDataSource(lastResets)
  106. col_chart = gchart.ColumnChart(col_data, options={
  107. 'title': '',
  108. 'legend': 'none',
  109. 'vAxis': {
  110. 'viewWindow': {
  111. 'max': max(maxJSS, 1),
  112. 'min': 0
  113. },
  114. 'ticks': [1, 2, 3, 4, 5, 6, 7],
  115. 'title': 'Jours sans seum'
  116. },
  117. 'hAxis': {'title': 'Trigramme'},
  118. })
  119. # Timeline graph
  120. # Data pre-processing
  121. resets = Reset.objects.filter(
  122. timestamp__gte=timezone.now() - timedelta(days=1))
  123. if (resets.count() == 0):
  124. noTimeline = True
  125. line_chart = None
  126. else:
  127. noTimeline = False
  128. for reset in resets:
  129. reset.timestamp = {
  130. 'v': reset.timestamp.timestamp(),
  131. 'f': "Il y a " + format_timedelta(datetime.now() -
  132. reset.timestamp.replace(
  133. tzinfo=None),
  134. locale='fr', threshold=1)
  135. }
  136. reset.Seum = {
  137. 'v': 0, 'f': reset.counter.trigramme + " : " + reset.reason}
  138. # Drawing the graph
  139. line_data = ModelDataSource(resets, fields=['timestamp', 'Seum'])
  140. line_chart = gchart.LineChart(line_data, options={
  141. 'lineWidth': 0,
  142. 'pointSize': 10,
  143. 'title': '',
  144. 'vAxis': {'ticks': []},
  145. 'hAxis': {
  146. 'ticks': [
  147. {'v': (datetime.now() - timedelta(days=1)
  148. ).timestamp(), 'f': 'Il y a 24 h'},
  149. {'v': datetime.now().timestamp(), 'f': 'Présent'}
  150. ]
  151. },
  152. 'legend': 'none',
  153. 'height': 90
  154. })
  155. # Graph of greatest seumers
  156. seumCounts = []
  157. for counter in counters:
  158. seumCounts.append([counter.trigramme, Reset.objects.filter(
  159. counter=counter).count()])
  160. if (len(seumCounts) == 0):
  161. noBestSeum = True
  162. best_chart = None
  163. else:
  164. seumCounts.sort(key=lambda x: -x[1])
  165. noBestSeum = False
  166. seumCounts.insert(0, ['Trigramme', 'Nombre de seums'])
  167. best_data = SimpleDataSource(seumCounts[:bestSeumeursNumber])
  168. best_chart = gchart.ColumnChart(best_data, options={
  169. 'title': '',
  170. 'legend': 'none',
  171. 'vAxis': {'title': 'Nombre de seums'},
  172. 'hAxis': {'title': 'Trigramme'},
  173. })
  174. # Graph of seum activity
  175. resets = Reset.objects.filter(
  176. timestamp__gte=timezone.now() - timedelta(days=365))
  177. months = {}
  178. for reset in resets:
  179. monthDate = datetime(reset.timestamp.year, reset.timestamp.month, 1)
  180. months[monthDate] = months.get(monthDate, 0) + 1
  181. monthList = sorted(months.items(), key=lambda t: t[0])
  182. seumActivity = []
  183. for month in monthList:
  184. seumActivity.append(
  185. [format_datetime(month[0], locale='fr',
  186. format="MMM Y").capitalize(), month[1]])
  187. if (len(seumActivity) == 0):
  188. noSeumActivity = True
  189. activity_chart = None
  190. else:
  191. noSeumActivity = False
  192. seumActivity.insert(0, ['Mois', 'Nombre de seums'])
  193. activity_data = SimpleDataSource(seumActivity)
  194. activity_chart = gchart.ColumnChart(activity_data, options={
  195. 'title': '',
  196. 'legend': 'none',
  197. 'vAxis': {'title': 'Nombre de seums'},
  198. 'hAxis': {'title': 'Mois'},
  199. })
  200. return render(request, 'homeTemplate.html', {
  201. 'counters': counters,
  202. 'col_chart': col_chart,
  203. 'line_chart': line_chart,
  204. 'best_chart': best_chart,
  205. 'activity_chart': activity_chart,
  206. 'noTimeline': noTimeline,
  207. 'noGraph': noGraph,
  208. 'noBestSeum': noBestSeum,
  209. 'noSeumActivity': noSeumActivity,
  210. 'chooseCounter': chooseCounter,
  211. 'myCounter': myCounter,
  212. })
  213. def resetCounter(request):
  214. # Update Form counter
  215. if (request.method == 'POST'):
  216. # create a form instance and populate it with data from the request:
  217. data = dict(request.POST)
  218. counter = Counter.objects.get(pk=int(data['counter'][0]))
  219. reset = Reset()
  220. reset.counter = counter
  221. reset.reason = data['reason'][0]
  222. reset.timestamp = datetime.now()
  223. reset.save()
  224. # We send the emails only to those who have an email address
  225. emails = [u[0] for u in Counter.objects.all().values_list('email')
  226. if u[0] != 'null@localhost']
  227. # Now send emails to everyone
  228. email_to_send = EmailMessage(counter.name + ' a le seum',
  229. data['reason'][0] + '''
  230. --
  231. SeumBook™ - http://seum.merigoux.ovh
  232. P.S. : Pour ne plus recevoir ces messages, envoie un mail à denis.merigoux@gmail.com''',
  233. 'SeumMan <seum@merigoux.ovh>', emails, [],
  234. reply_to=emails)
  235. email_to_send.send()
  236. return HttpResponseRedirect(data['redirect'][0])
  237. def counter(request, id_counter):
  238. counter = Counter.objects.get(pk=id_counter)
  239. resets = Reset.objects.filter(counter=counter).order_by('-timestamp')
  240. firstReset = copy.copy(resets[len(resets) - 1])
  241. timezero = timedelta(0)
  242. # Display
  243. if (resets.count() == 0):
  244. counter.lastReset = Reset()
  245. counter.lastReset.delta = timezero
  246. counter.lastReset.noSeum = True
  247. seumFrequency = 'inconnu'
  248. else:
  249. counter.lastReset = resets[0]
  250. counter.lastReset.noSeum = False
  251. counter.lastReset.delta = datetime.now(
  252. ) - counter.lastReset.timestamp.replace(tzinfo=None)
  253. counter.lastReset.formatted_delta = format_timedelta(
  254. counter.lastReset.delta, locale='fr', threshold=1)
  255. counter.seumCount = Reset.objects.filter(
  256. counter=counter).count()
  257. seumFrequency = format_timedelta((
  258. datetime.now() - firstReset.timestamp.replace(tzinfo=None)) /
  259. counter.seumCount, locale='fr', threshold=1)
  260. for reset in resets:
  261. reset.date = format_datetime(
  262. reset.timestamp, locale='fr',
  263. format="EEEE dd MMMM Y 'à' HH:mm:ss").capitalize()
  264. # Timeline graph
  265. # Data pre-processing
  266. resets_graph = resets
  267. for reset in resets_graph:
  268. reset.timestamp = {
  269. 'v': reset.timestamp.timestamp(),
  270. 'f': "Il y a " + format_timedelta(
  271. datetime.now() - reset.timestamp.replace(tzinfo=None),
  272. locale='fr', threshold=1)
  273. }
  274. reset.Seum = {'v': 0, 'f': reset.reason}
  275. # Drawing the graph
  276. data = ModelDataSource(resets, fields=['timestamp', 'Seum'])
  277. chart = gchart.LineChart(data, options={
  278. 'lineWidth': 0,
  279. 'pointSize': 10,
  280. 'title': '',
  281. 'vAxis': {'ticks': []},
  282. 'hAxis': {'ticks': [{
  283. 'v': firstReset.timestamp.timestamp(),
  284. 'f': 'Il y a ' + format_timedelta(
  285. datetime.now() - firstReset.timestamp.replace(tzinfo=None),
  286. locale='fr', threshold=1)
  287. }, {
  288. 'v': datetime.now().timestamp(),
  289. 'f': 'Présent'}
  290. ]},
  291. 'legend': 'none',
  292. 'height': 90
  293. })
  294. return render(request, 'counterTemplate.html', {
  295. 'counter': counter,
  296. 'chart': chart,
  297. 'resets': resets,
  298. 'seumFrequency': seumFrequency
  299. })
  300. def setMyCounter(request):
  301. if (request.method == 'POST'):
  302. # create a form instance and populate it with data from the request:
  303. data = dict(request.POST)
  304. # We put the id of the counter in the session
  305. request.session['my-counter'] = data['myCounter'][0]
  306. return HttpResponseRedirect(data['redirect'][0])
  307. def resetMyCounter(request):
  308. if (request.method == 'POST'):
  309. data = dict(request.POST)
  310. del request.session['my-counter']
  311. return HttpResponseRedirect(data['redirect'][0])