Skip to content

Commit

Permalink
Merge branch 'master' into refactor/front-end
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelzinhe committed Sep 4, 2018
2 parents d02a66c + 5243a5b commit 10bfba8
Show file tree
Hide file tree
Showing 84 changed files with 22,122 additions and 430 deletions.
9 changes: 6 additions & 3 deletions backend_candidate/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,12 @@ def __init__(self, *args, **kwargs):
def save(self):
image = self.cleaned_data.pop('image', None)
if image:
path = default_storage.save('tmp/' + image.name, ContentFile(image.read()))
tmp_file = os.path.join(settings.MEDIA_ROOT, path)
self.candidate.image = tmp_file
try:
path = default_storage.save('tmp/' + image.name, ContentFile(image.read()))
tmp_file = path
self.candidate.image = tmp_file
except:
pass
self.candidate.save()
for link in self.social_networks:
value = self.cleaned_data.pop(link, None)
Expand Down
5 changes: 2 additions & 3 deletions elections/tests/version2/elections_per_area_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_area_index_view(self):
url = reverse('know_your_candidates')
response = self.client.get(url)
self.assertEquals(response.status_code, 200)
self.assertEquals(response.context['default_election'], election)
self.assertTrue(response.context['default_election'])

def test_area_index_view_if_not_default_area(self):
argentina = Area.objects.create(name=u'Argentina', id='argentina-pais')
Expand All @@ -150,7 +150,7 @@ def test_area_index_view_if_not_default_area(self):
url = reverse('know_your_candidates')
response = self.client.get(url)
self.assertEquals(response.status_code, 200)
self.assertIsNone(response.context['default_election'])
self.assertTrue(response.context['default_election'])

@override_config(SHOW_ALL_CANDIDATES_IN_THIS_ORDER='senador, diputado', DEFAULT_AREA='argentina')
def test_get_all_candidates_if_show_all_candidates_is_true(self):
Expand All @@ -167,7 +167,6 @@ def test_get_all_candidates_if_show_all_candidates_is_true(self):
url = reverse('know_your_candidates')
response = self.client.get(url)
self.assertEquals(response.status_code, 200)
self.assertEquals(response.context['default_election'], election)
self.assertIn('positions', response.context)
self.assertEquals(response.context['positions'][0]['name'], 'senador')
for c in second_e.candidates.all():
Expand Down
Binary file modified locale/pt/LC_MESSAGES/django.mo
Binary file not shown.
8 changes: 6 additions & 2 deletions locale/pt/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-13 22:06+0000\n"
"PO-Revision-Date: 2018-08-13 19:23-0300\n"
"PO-Revision-Date: 2018-08-22 09:30-0300\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: pt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.1\n"
"X-Generator: Poedit 2.1.1\n"

#: agenda/forms.py:24 backend_candidate/forms.py:250
#: votai_general_theme/templates/backend_candidate/add_activity.html:20
Expand Down Expand Up @@ -2544,6 +2544,10 @@ msgid ""
"plan de gobierno.\n"
" "
msgstr ""
"\n"
" Aqui você pode encontrar um total de %(proposals_committed)s propostas "
"que %(candidate_name)s se comprometeu a cumprir dentro do plano do governo.\n"
" "

#: votai_general_theme/templates/elections/candidate_detail.html:153
#, python-format
Expand Down
24 changes: 18 additions & 6 deletions medianaranja2/adapters.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from numpy import matrix, ones
from numpy import matrix, ones, zeros
from constance import config
from django.core.cache import cache
from django.conf import settings
from medianaranja2.candidate_proposals_matrix_generator import CandidateCommitmentsMatrixGenerator


class CandidateGetterFromElectionMixin(object):
@classmethod
def get_candidates_from_election(cls, election):
return election.candidates.order_by('id')
return election.candidates.order_by('id').only('id')

@classmethod
def get_candidates_from_election_as_list(cls, election):
Expand Down Expand Up @@ -90,15 +92,25 @@ def __init__(self, election, proposals):
self.candidates = CommitmentsAdapter.get_candidates_from_election_as_list(election)
self.proposals = proposals
self.ones = ones((len(self.proposals),1))
matrix_generator = CandidateCommitmentsMatrixGenerator()
self.all_candidates_and_proposals = matrix_generator.get_matrix_with_all_proposals()
self.candidate_index_in_matrix = matrix_generator._get_candidate_index_in_matrix()
self.proposal_index_in_matrix = matrix_generator._get_proposal_index_in_matrix()

def get_commitments_matrix(self):
_C = []
for candidate in self.candidates:
vector = []
try:
candidate_index = self.candidate_index_in_matrix[candidate.id]
except KeyError:
_C.append(zeros(len(self.proposals)))
continue
for p in self.proposals:
if candidate.commitments.filter(proposal=p, commited=True).exists():
vector.append(1)
else:
vector.append(0)
proposal_index = self.proposal_index_in_matrix[p.id]
value = self.all_candidates_and_proposals[candidate_index, proposal_index]
vector.append(value)
_C.append(vector)
return matrix(_C)


65 changes: 65 additions & 0 deletions medianaranja2/candidate_proposals_matrix_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# coding=utf-8
from numpy import matrix
from django.core.cache import cache
from elections.models import Candidate
from popular_proposal.models import PopularProposal


class CandidateCommitmentsMatrixGenerator(object):
def __init__(self):
self.cache_key = 'matrix_proposals_candidates'
self.candidate_index_in_matrix = {}
self.proposal_index_in_matrix = {}

def _set_candidate_index_in_matrix(self, candidate, index):
self.candidate_index_in_matrix[candidate.id] = index

def _get_candidate_index_in_matrix(self):
cache_key = 'candidate_index_in_matrix'
if cache.get(cache_key) is not None:
return cache.get(cache_key)
else:
cache.set('candidate_index_in_matrix', self.candidate_index_in_matrix)
return self.candidate_index_in_matrix

def _get_proposal_index_in_matrix(self):
cache_key = 'proposal_index_in_matrix'
if cache.get(cache_key) is not None:
return cache.get(cache_key)
else:
cache.set('proposal_index_in_matrix', self.proposal_index_in_matrix)
return self.proposal_index_in_matrix

def _set_proposal_index_in_matrix(self, proposal, index):
self.proposal_index_in_matrix[proposal.id] = index

def set_cache(self, time=7200):
m = self._get_matrix_with_all_proposals()
cache.set(self.cache_key, m, time)
cache.set('candidate_index_in_matrix', self.candidate_index_in_matrix)
cache.set('proposal_index_in_matrix', self.proposal_index_in_matrix)
return m

def get_matrix_with_all_proposals(self):
if cache.get(self.cache_key) is not None:
return cache.get(self.cache_key)
return self.set_cache()

def _get_matrix_with_all_proposals(self):
_C = []
candidate_index = 0
all_proposals = PopularProposal.objects.all()
for candidate in Candidate.objects.filter(commitments__isnull=False):
vector = []
self._set_candidate_index_in_matrix(candidate, candidate_index)
candidate_index += 1
proposal_index = 0
for p in all_proposals:
self._set_proposal_index_in_matrix(p, proposal_index)
proposal_index += 1
if candidate.commitments.filter(proposal=p, commited=True).exists():
vector.append(1)
else:
vector.append(0)
_C.append(vector)
return matrix(_C)
5 changes: 4 additions & 1 deletion medianaranja2/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,11 @@ def done(self, form_list, **kwargs):
for election in elections:
calculator = self.calculator_class(election, positions, proposals, **self.calculator_extra_kwargs)
results.append(calculator.get_result())
if settings.ORGANIZATIONS_IN_12_RESULT:
organization_templates = self.get_organization_templates(proposals)
else:
organization_templates = []

organization_templates = self.get_organization_templates(proposals)
return render(self.request, self.done_template_name, {
'results': results,
'organizations': organization_templates
Expand Down
Empty file.
Empty file.
16 changes: 16 additions & 0 deletions medianaranja2/management/commands/set_cache_for_medianaranja.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.core.management.base import BaseCommand
from medianaranja2.candidate_proposals_matrix_generator import CandidateCommitmentsMatrixGenerator


class Command(BaseCommand):
help = "Updates the cache for medianaranja"

def add_arguments(self, parser):
parser.add_argument('time', type=int, default=7200, nargs="*")

def handle(self, *args, **options):
matrix_generator = CandidateCommitmentsMatrixGenerator()
time = options['time'][0]
m = matrix_generator.set_cache(time)
shape = m.shape
self.stdout.write("Saved matrix of dimensions (%d, %d) for %d miliseconds" % (shape[0], shape[1], time))
4 changes: 2 additions & 2 deletions medianaranja2/proposals_getter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def get_elections(self, proposals_container_element):
has_parent = True
elections = []
while has_parent:
if proposals_container_element.elections.all():
elections += list(proposals_container_element.elections.all())
if proposals_container_element.elections.filter(candidates__commitments__isnull=False).distinct():
elections += list(proposals_container_element.elections.filter(candidates__commitments__isnull=False).distinct())
if not proposals_container_element.parent:
has_parent = False
else:
Expand Down
34 changes: 34 additions & 0 deletions merepresenta/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,39 @@
from __future__ import unicode_literals

from django.contrib import admin
from django.conf import settings
from merepresenta.models import Candidate
from django.contrib.auth.models import User

# Register your models here.


class MeRepresentaCandidateAdmin(admin.ModelAdmin):
list_display = ('name', 'username_do_facebook', 'esta_logado')

actions = ['apagar_datos']
search_fields = ['name',]

def esta_logado(self, candidate):
return candidate.candidacy_set.exists()

def username_do_facebook(self, candidate):
if candidate.candidacy_set.exists():
return candidate.candidacy_set.first().user.username
return ""
# return candidate.candidacy_set.first().user.username

def apagar_datos(self, request, queryset):
for candidate in queryset.all():
User.objects.filter(candidacies__candidate=candidate)
candidate.candidacy_set.all().delete()
candidate.lgbt_desc.clear()
candidate.taken_positions.all().delete()
candidate.candidatequestioncategory_set.all().delete()

apagar_datos.short_description = u"Apagar dados de candidatas seleccionadas"

esta_logado.boolean = True
esta_logado.admin_order_field = 'candidacy__user__last_login'

admin.site.register(Candidate, MeRepresentaCandidateAdmin)
3 changes: 3 additions & 0 deletions merepresenta/candidatos/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class MeRepresentaCandidateAnsweringForm(MediaNaranjaSingleCandidateMixin, forms
def __init__(self, *args, **kwargs):
super(MeRepresentaCandidateAnsweringForm, self).__init__(*args, **kwargs)
self.set_fields_for(self.category)
for field in self.fields:
if isinstance(self.fields[field], forms.fields.ChoiceField):
self.fields[field].required = True

def save(self):
self.save_answer_for(self.category)
Expand Down
30 changes: 30 additions & 0 deletions merepresenta/migrations/0018_auto_20180830_1923.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.9 on 2018-08-30 19:23
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('merepresenta', '0017_auto_20180815_1604'),
]

operations = [
migrations.AlterField(
model_name='candidate',
name='bio',
field=models.TextField(blank=True, default=''),
),
migrations.AlterField(
model_name='candidate',
name='lgbt_desc',
field=models.ManyToManyField(blank=True, to='merepresenta.LGBTQDescription'),
),
migrations.AlterField(
model_name='candidate',
name='renovacao_politica',
field=models.CharField(blank=True, default='', max_length=512),
),
]
36 changes: 29 additions & 7 deletions merepresenta/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
from elections.models import Candidate as OriginalCandidate
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from backend_candidate.models import CandidacyContact
from backend_candidate.models import CandidacyContact, Candidacy
from votai_utils.send_mails import send_mail
from django.utils import timezone
import datetime
from elections.models import QuestionCategory as OriginalQuestionCategory
from django.utils.encoding import python_2_unicode_compatible

from django.dispatch import receiver
from django.db.models.signals import post_save


class MeRepresentaPopularProposal(PopularProposal):
Expand Down Expand Up @@ -46,7 +47,15 @@ def get_queryset(self):
output_field=PositiveSmallIntegerField())

)
qs = qs.annotate(desprivilegio=F('is_women') + F('is_non_white'))
qs = qs.annotate(bad_email=Case(
When(email_repeated=True, then=Value(1)),
When(original_email__isnull=True, then=Value(1)),
When(original_email="", then=Value(1)),
default=Value(0),
output_field=PositiveSmallIntegerField())

)
qs = qs.annotate(desprivilegio=F('is_women') + F('is_non_white') + F('bad_email'))
return qs

class LimitCandidatesForVolunteers(ForVolunteersManager):
Expand All @@ -55,6 +64,7 @@ def get_queryset(self):
qs = qs.exclude(contacts__isnull=False)
qs = qs.exclude(is_ghost=True)
qs = qs.exclude(facebook_contacted=True)
qs = qs.exclude(candidacy__isnull=False)
minutes = 30
from_time = timezone.now() - datetime.timedelta(minutes=minutes)
qs = qs.exclude(volunteerincandidate__created__gte=from_time)
Expand Down Expand Up @@ -113,10 +123,10 @@ class Candidate(OriginalCandidate, RaceMixin):
facebook_contacted = models.BooleanField(default=False)
data_de_nascimento = models.DateField(null=True)
partido = models.ForeignKey("Partido", null=True)
bio = models.TextField(default='')
lgbt = models.BooleanField(default=False)
lgbt_desc = models.ManyToManyField(LGBTQDescription)
renovacao_politica = models.CharField(max_length=512, default='')
bio = models.TextField(default='', blank=True)
lgbt = models.BooleanField(default=False, blank=True)
lgbt_desc = models.ManyToManyField(LGBTQDescription, blank=True)
renovacao_politica = models.CharField(max_length=512, default='', blank=True)
candidatura_coletiva = models.BooleanField(default=False)
objects = ForVolunteersManager()

Expand Down Expand Up @@ -202,6 +212,18 @@ class CandidateQuestionCategory(models.Model):
updated = models.DateTimeField(auto_now_add=True)


@receiver(post_save, sender=Candidacy, dispatch_uid="say_thanks_to_the_volunteer")
def say_thanks_to_the_volunteer(sender, instance, created, raw, **kwargs):
if raw:
return
if created:
try:
log = VolunteerGetsCandidateEmailLog.objects.get(candidate=instance.candidate)
context = {'candidate': log.candidate}
send_mail(context, 'candidato_com_a_gente_por_sua_acao', to=[log.volunteer.email],)
except VolunteerGetsCandidateEmailLog.DoesNotExist:
pass

##### VOLUNTEERS PART!!!
## I wrote this as part of #MeRepresenta, this means that we haven't needed volunteers doing research on candidates before
## This is why I kept it here until now
Expand Down
Loading

0 comments on commit 10bfba8

Please sign in to comment.