views.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. from core.decorators import require_party_login
  2. from core.forms import PoliticianForm, PartyPoliticianForm
  3. from core.models import Politician, Question, State, Answer
  4. from core.models import Statistic, Category, LinkType, Link
  5. from core.tools import set_cookie, get_cookie
  6. from django.contrib.auth.models import User
  7. from django.contrib.auth import authenticate, login, logout
  8. from django.contrib import messages
  9. from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
  10. from django.core.urlresolvers import reverse
  11. from django.db.models import Q, Sum
  12. from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
  13. from django.shortcuts import render, get_object_or_404, redirect
  14. from django.utils.encoding import force_unicode
  15. from django.utils.translation import ugettext_lazy as _
  16. import collections
  17. import csv
  18. ##
  19. # ERROR VIEWS
  20. ##
  21. def handler404(request):
  22. response = render(request, '404.html')
  23. response.status_code = 404
  24. return response
  25. def handler500(request):
  26. response = render(request, '500.html')
  27. response.status_code = 500
  28. return response
  29. ##
  30. # PUBLIC VIEWS
  31. ##
  32. def candidates_view(request):
  33. politician_list = (
  34. Politician.objects.
  35. filter(statistic__id__gt=0).distinct().
  36. order_by('first_name', 'last_name'))
  37. states = State.objects.all().order_by('name')
  38. categories = (
  39. Category.objects.filter(statistic__id__gt=0).
  40. order_by('name').distinct())
  41. category = request.GET.get('category', None)
  42. state = request.GET.get('state', None)
  43. search = request.GET.get('search', None)
  44. per_site = request.GET.get('per_page', 10)
  45. page = request.GET.get('page', 1)
  46. request.GET = request.GET.copy()
  47. stat_cookie = get_cookie(request, 'statistics', {})
  48. if 'evaluate' in request.GET and stat_cookie == {}:
  49. request.GET.pop('evaluate')
  50. if category and category != '0':
  51. if 'evaluate' in request.GET:
  52. stats = get_cookie(request, 'statistics', {})
  53. val = stats.get('category_%s' % category, 0)
  54. else:
  55. val = Question.objects.filter(
  56. category__id=category
  57. ).aggregate(Sum('preferred_answer'))['preferred_answer__sum']
  58. politician_list = (
  59. Politician.get_politicians_by_category(
  60. category, (int(val) * 10)))
  61. if state and state != '0':
  62. politician_list = politician_list.filter(state=state)
  63. if search:
  64. politician_list = politician_list.filter(
  65. Q(last_name__icontains=search) |
  66. Q(first_name__icontains=search) |
  67. Q(state__name__icontains=search) |
  68. Q(party__name__icontains=search) |
  69. Q(party__shortname__icontains=search)
  70. )
  71. paginator = Paginator(politician_list, per_site)
  72. try:
  73. politicians = paginator.page(page)
  74. except PageNotAnInteger:
  75. politicians = paginator.page(1)
  76. except EmptyPage:
  77. politicians = paginator.page(paginator.num_pages)
  78. # remove the page parameter from url
  79. if request.GET.get('page', None):
  80. request.GET.pop('page')
  81. return render(
  82. request,
  83. 'core/candidates/index.html',
  84. {
  85. 'politicians' : politicians,
  86. 'categories' : categories,
  87. 'states' : states,
  88. }
  89. )
  90. def compare_view(request):
  91. questions = Question.objects.all().order_by('question_number')
  92. data = []
  93. session_answers = get_cookie(request, 'answers', {})
  94. session_statistics = get_cookie(request, 'statistics', {})
  95. if request.POST:
  96. for question in questions:
  97. qid = 'question_%d' % question.id
  98. session_answers[qid] = request.POST.get(qid, 0)
  99. categories = Category.objects.all()
  100. for category in categories:
  101. cq = Question.objects.filter(category=category)
  102. values = []
  103. for question in cq:
  104. values.append(
  105. abs(
  106. question.preferred_answer -
  107. int(session_answers.get(
  108. 'question_%d' % question.id, 0))
  109. )
  110. )
  111. session_statistics['category_%d' % category.id] = (
  112. 10 - sum(values) / float(len(cq)))
  113. request.COOKIES['answers'] = session_answers
  114. request.COOKIES['statistics'] = session_statistics
  115. messages.success(request, _('answers_saved_successfully_evaluate'))
  116. for question in questions:
  117. item = {
  118. 'question' : question,
  119. 'value' : session_answers.get('question_%d' % question.id, 0)
  120. }
  121. data.append(item)
  122. response = render(
  123. request,
  124. 'core/compare/index.html',
  125. {
  126. 'data' : data
  127. }
  128. )
  129. set_cookie(response, 'answers', session_answers, 30)
  130. set_cookie(response, 'statistics', session_statistics, 30)
  131. return response
  132. def compare_reset_view(request):
  133. messages.success(request, _('answers_resetted'))
  134. response = HttpResponseRedirect(reverse('compare'))
  135. set_cookie(response, 'answers', {}, 30)
  136. set_cookie(response, 'statistics', {}, 30)
  137. return response
  138. ##
  139. # PUBLIC POLITICIAN VIEWS
  140. ##
  141. def politician_view(request, politician_id):
  142. politician = get_object_or_404(
  143. Politician.objects.filter(statistic__id__gt=0).distinct(),
  144. pk=politician_id)
  145. answers = (
  146. Answer.objects.
  147. filter(politician=politician).
  148. order_by('question__question_number'))
  149. links = (
  150. Link.objects.filter(politician=politician).
  151. order_by('type__name'))
  152. cookie = get_cookie(request, 'answers', {})
  153. answer_obs = []
  154. for a in answers:
  155. answer_obs.append({
  156. 'own_ans': cookie.get('question_%s' % a.question.id, None),
  157. 'politician_ans': a
  158. })
  159. return render(
  160. request,
  161. 'core/profile/index.html',
  162. {
  163. 'politician' : politician,
  164. 'answers' : answer_obs,
  165. 'links' : links
  166. }
  167. )
  168. def politician_statistic_spider_view(request, politician_id):
  169. statistics = Statistic.get_statistics_by_politician(politician_id)
  170. stats = get_cookie(request, 'statistics', {})
  171. values = {
  172. 'politician' : [s.accordance for s in statistics],
  173. 'citizen' : [
  174. stats.get('category_%d' % s.category.id, 0)
  175. for s in statistics]
  176. }
  177. return JsonResponse({
  178. 'categories': [
  179. s.category.name
  180. for s in statistics
  181. ],
  182. 'values': values
  183. })
  184. def politician_statistic_view(request, politician_id):
  185. category_id = int(request.GET.get('category', False))
  186. titles = [force_unicode(_('total'))]
  187. if category_id:
  188. category = get_object_or_404(Category, id=category_id)
  189. titles.append(category.name)
  190. if 'evaluate' in request.GET:
  191. cat_by_id = {
  192. cat.id: cat
  193. for cat
  194. in Category.objects.all()
  195. }
  196. pol_answers = Answer.objects.filter(politician_id=politician_id)
  197. pairs = []
  198. answers = get_cookie(request, 'answers', {})
  199. delta_by_cat = collections.defaultdict(lambda: [])
  200. for ans in pol_answers:
  201. voter_value = int(answers.get('question_%s' % ans.question_id, 0))
  202. delta = abs(ans.agreement_level - voter_value)
  203. delta_by_cat[ans.question.category_id].append(delta)
  204. for cid, cat in cat_by_id.iteritems():
  205. pairs.append({
  206. 'category': cat.name,
  207. 'value': (
  208. 10 - sum(delta_by_cat[cid]) /
  209. float(len(delta_by_cat[cid]))
  210. )
  211. })
  212. sorted_pairs = sorted(pairs, key=lambda k: k['category'])
  213. detail = {
  214. 'categories' : [i['category'] for i in sorted_pairs],
  215. 'values' : [i['value'] for i in sorted_pairs]
  216. }
  217. total = sum(detail['values']) / len(detail['values'])
  218. pos = [total]
  219. neg = [(10 - total)]
  220. if category_id:
  221. val = 10 - (
  222. sum(delta_by_cat[category_id]) /
  223. float(len(delta_by_cat[category_id])))
  224. pos.append(val)
  225. neg.append(10 - val)
  226. summary = {
  227. 'titles' : titles,
  228. 'values' : {
  229. 'positive' : pos,
  230. 'negative' : neg
  231. }
  232. }
  233. else:
  234. statistics = Statistic.get_statistics_by_politician(politician_id)
  235. values = [s.accordance for s in statistics]
  236. total = sum(values) / len(values)
  237. # pos is the green part (agreement level) of the graph,
  238. # neg is the "rest" (red)
  239. pos = [total]
  240. neg = [(10 - total)]
  241. if category_id:
  242. # if category_id is given, the graph should display this
  243. # category in addition to the summary view
  244. statistic = Statistic.objects.get(
  245. politician_id=politician_id, category=category)
  246. pos.append(statistic.value / 10)
  247. neg.append(10 - statistic.value / 10)
  248. summary = {
  249. 'titles' : titles,
  250. 'values' : {
  251. 'positive' : pos,
  252. 'negative' : neg
  253. }
  254. }
  255. detail = {
  256. 'categories' : [s.category.name for s in statistics],
  257. 'values' : values
  258. }
  259. return JsonResponse({'summary': summary, 'detail': detail})
  260. ##
  261. # PRIVATE POLITICIAN VIEWS
  262. ##
  263. def politician_edit_view(request, unique_key):
  264. return redirect(reverse('politician_edit_profile', args=[unique_key]))
  265. def politician_edit_profile_view(request, unique_key):
  266. politician = get_object_or_404(Politician, unique_key=unique_key)
  267. link_types = LinkType.objects.all().order_by('name')
  268. links = (
  269. Link.objects.filter(politician=politician).order_by('type__name'))
  270. if request.POST:
  271. form = PoliticianForm(request.POST, request.FILES, instance=politician)
  272. if form.is_valid():
  273. form.save()
  274. messages.success(request, _('profile_saved_successfully'))
  275. else:
  276. form = PoliticianForm(instance=politician)
  277. return render(
  278. request,
  279. 'core/edit/profile.html',
  280. {
  281. 'politician' : politician,
  282. 'form' : form,
  283. 'link_types' : link_types,
  284. 'links' : links
  285. }
  286. )
  287. def politician_edit_questions_view(request, unique_key):
  288. politician = get_object_or_404(Politician, unique_key=unique_key)
  289. questions = Question.objects.all().order_by('question_number')
  290. answers = Answer.objects.filter(politician=politician)
  291. return render(
  292. request,
  293. 'core/edit/questions.html',
  294. {
  295. 'politician' : politician,
  296. 'questions' : questions,
  297. 'answers' : answers
  298. }
  299. )
  300. def politician_answer_view(request, unique_key):
  301. if request.POST:
  302. question = get_object_or_404(Question, id=request.POST.get('question'))
  303. politician = get_object_or_404(Politician, unique_key=unique_key)
  304. agreement_level = int(request.POST.get('agreement_level', 0))
  305. answer, created = Answer.objects.get_or_create(
  306. question=question,
  307. politician=politician,
  308. defaults={
  309. 'agreement_level' : agreement_level,
  310. }
  311. )
  312. answer.agreement_level = agreement_level
  313. answer.note = request.POST['note']
  314. answer.save()
  315. return HttpResponse('')
  316. def politician_publish_view(request, unique_key):
  317. politician = get_object_or_404(Politician, unique_key=unique_key)
  318. categories = Category.objects.all()
  319. for category in categories:
  320. answers = Answer.objects.filter(
  321. question__category=category, politician=politician)
  322. if answers:
  323. answers_agg = answers.aggregate(Sum('agreement_level'))
  324. value = int(
  325. answers_agg['agreement_level__sum'] /
  326. answers.count() * 10)
  327. stat, created = Statistic.objects.get_or_create(
  328. politician=politician,
  329. category=category,
  330. defaults={'value': value}
  331. )
  332. stat.value = value
  333. stat.save()
  334. return JsonResponse({
  335. 'type': 'success',
  336. 'text': force_unicode(_('answers_published_successfully'))
  337. })
  338. def politician_unpublish_view(request, unique_key):
  339. politician = get_object_or_404(Politician, unique_key=unique_key)
  340. Statistic.objects.filter(politician=politician).delete()
  341. return JsonResponse({
  342. 'type': 'success',
  343. 'text': force_unicode(_('answers_unpublished_successfully'))
  344. })
  345. def politician_link_add_view(request, unique_key):
  346. politician = get_object_or_404(Politician, unique_key=unique_key)
  347. link_type = get_object_or_404(LinkType, id=request.POST.get('link_type'))
  348. url = request.POST.get('url')
  349. error = False
  350. if not url.startswith(('http://', 'https://')):
  351. url = 'http://%s' % url
  352. if '.' not in url:
  353. error = True
  354. if not error:
  355. l = Link(
  356. type=link_type,
  357. politician=politician,
  358. url=url
  359. )
  360. l.save()
  361. url = ''
  362. types = LinkType.objects.all().order_by('name')
  363. links = (
  364. Link.objects.filter(politician=politician).order_by('type__name'))
  365. return render(request, 'core/edit/links.html', {
  366. 'links' : links,
  367. 'link_types' : types,
  368. 'politician' : politician,
  369. 'error' : error,
  370. 'input' : url,
  371. 'link_type' : link_type,
  372. })
  373. def politician_link_delete_view(request, unique_key, link_id):
  374. politician = get_object_or_404(Politician, unique_key=unique_key)
  375. link = get_object_or_404(Link, id=link_id)
  376. link.delete()
  377. types = LinkType.objects.all().order_by('name')
  378. links = (
  379. Link.objects.filter(politician=politician).order_by('type__name'))
  380. return render(request, 'core/edit/links.html', {
  381. 'links' : links,
  382. 'link_types' : types,
  383. 'politician' : politician
  384. })
  385. ##
  386. # PARTY VIEWS
  387. ##
  388. def party_login_view(request, party_name):
  389. user = get_object_or_404(User, username=party_name)
  390. if request.user.is_authenticated() and request.user.username == party_name:
  391. return redirect(reverse('party_dashboard', args=[party_name]))
  392. if request.POST:
  393. user = authenticate(
  394. username=party_name, password=request.POST.get('password'))
  395. if user and user.is_active:
  396. login(request, user)
  397. messages.success(request, _('login_successful'))
  398. return redirect(reverse('party_dashboard', args=[party_name]))
  399. else:
  400. messages.error(request, _('login_error'))
  401. return render(request, 'core/party/login.html')
  402. def party_logout_view(request, party_name):
  403. logout(request)
  404. return redirect(reverse('party_login', args=[party_name]))
  405. @require_party_login
  406. def party_dashboard_view(request, party_name):
  407. return render(
  408. request,
  409. 'core/party/dashboard.html',
  410. {
  411. 'politicians': Politician.objects.filter(user=request.user)
  412. }
  413. )
  414. @require_party_login
  415. def party_politician_add_view(request, party_name):
  416. if request.POST:
  417. form = PartyPoliticianForm(request.POST, request.FILES)
  418. form.data['user'] = request.user.id
  419. if form.is_valid():
  420. form.save()
  421. messages.success(request, _('politician_add_success'))
  422. return redirect(reverse('party_dashboard', args=[party_name]))
  423. else:
  424. messages.error(request, _('politician_add_error'))
  425. else:
  426. form = PartyPoliticianForm()
  427. return render(
  428. request,
  429. 'core/party/politician_edit.html',
  430. {
  431. 'politician' : None,
  432. 'form' : form
  433. }
  434. )
  435. @require_party_login
  436. def party_politician_edit_view(request, party_name, politician_id):
  437. politician = get_object_or_404(Politician, id=politician_id)
  438. if request.POST:
  439. form = PartyPoliticianForm(
  440. request.POST, request.FILES, instance=politician)
  441. form.data['user'] = request.user.id
  442. if form.is_valid():
  443. form.save()
  444. messages.success(request, _('politician_edit_success'))
  445. return redirect(reverse('party_dashboard', args=[party_name]))
  446. else:
  447. messages.error(request, _('politician_edit_error'))
  448. else:
  449. form = PartyPoliticianForm(instance=politician)
  450. return render(
  451. request,
  452. 'core/party/politician_edit.html',
  453. {
  454. 'politician' : None,
  455. 'form' : form
  456. }
  457. )
  458. pass
  459. @require_party_login
  460. def party_export_view(request, party_name):
  461. politicians = Politician.objects.filter(user=request.user)
  462. response = HttpResponse(content_type='text/csv')
  463. response['Content-Disposition'] = (
  464. 'attachment; filename="freedomvote_export_%s.csv"' % party_name
  465. )
  466. writer = csv.writer(response)
  467. writer.writerow([
  468. force_unicode(_('first_name')),
  469. force_unicode(_('last_name')),
  470. force_unicode(_('state')),
  471. force_unicode(_('unique_url'))
  472. ])
  473. for p in politicians:
  474. state = p.state.name if p.state else '-'
  475. cols = [p.first_name, p.last_name, state, p.unique_url]
  476. writer.writerow([c.encode('latin1') for c in cols])
  477. return response
  478. @require_party_login
  479. def party_politician_delete_view(request, party_name, politician_id):
  480. politician = get_object_or_404(Politician, id=politician_id)
  481. politician.delete()
  482. messages.success(
  483. request, _('politician_delete_success') % (
  484. politician.first_name, politician.last_name
  485. ))
  486. return redirect(reverse('party_dashboard', args=[party_name]))