diff --git a/elections/fixtures/mini_2.yaml b/elections/fixtures/mini_2.yaml index ead8005e..77c49ebc 100644 --- a/elections/fixtures/mini_2.yaml +++ b/elections/fixtures/mini_2.yaml @@ -28,22 +28,22 @@ user_permissions: [] - model: popolo.area pk: algarrobo-5602 - fields: {content_type: null, object_id: null, start_date: null, end_date: null, + fields: {slug: algarrobo, content_type: null, object_id: null, start_date: null, end_date: null, name: Algarrobo, identifier: '5602', classification: 'Comuna', parent: null, geom: null, inhabitants: null} - model: popolo.area pk: alhue-13502 - fields: {content_type: null, object_id: null, start_date: null, end_date: null, + fields: {slug: alhue, content_type: null, object_id: null, start_date: null, end_date: null, name: "Alhu\xE9", identifier: '13502', classification: 'Comuna', parent: null, geom: null, inhabitants: null} - model: popolo.area pk: arica-15101 - fields: {content_type: null, object_id: null, start_date: null, end_date: null, + fields: {slug: alhue, content_type: null, object_id: null, start_date: null, end_date: null, name: Arica, identifier: '15101', classification: '', parent: null, geom: null, inhabitants: null} - model: popolo.area pk: fundacion-ciudadano-inteligente - fields: {content_type: null, object_id: null, start_date: null, end_date: null, + fields: {slug: ciudadanoi, content_type: null, object_id: null, start_date: null, end_date: null, name: CiudadanoI, identifier: '15101', classification: '', parent: null, geom: null, inhabitants: null} - model: backend_citizen.profile diff --git a/elections/models.py b/elections/models.py index 56dca975..99b995ac 100644 --- a/elections/models.py +++ b/elections/models.py @@ -39,7 +39,7 @@ class Meta: proxy = True def get_absolute_url(self): - return reverse('area', kwargs={'slug': self.id}) + return reverse('area', kwargs={'slug': self.slug}) def ogp_description(self): return self.name @@ -200,7 +200,7 @@ def ranking_in_election(self): def get_absolute_url(self): if config.CANDIDATE_ABSOLUTE_URL_USING_AREA: return reverse('candidate_detail_view_area', kwargs={ - 'area_slug': self.election.area.id, + 'area_slug': self.election.area.slug, 'slug': self.id }) election_slug = '' diff --git a/elections/tests/candidatorg_views_tests.py b/elections/tests/candidatorg_views_tests.py index e9d52f84..55abb3ae 100644 --- a/elections/tests/candidatorg_views_tests.py +++ b/elections/tests/candidatorg_views_tests.py @@ -54,7 +54,7 @@ def test_candidate_get_absolute_url(self): def test_candidate_get_absolute_url_with_area(self): candidate = self.coquimbo.candidates.get(id=1) url = reverse('candidate_detail_view_area', kwargs={ - 'area_slug': self.tarapaca.area.id, + 'area_slug': self.tarapaca.area.slug, 'slug': candidate.id }) self.assertEquals(candidate.get_absolute_url(), url) diff --git a/elections/tests/template_tags_tests.py b/elections/tests/template_tags_tests.py index ecc4809b..5c332342 100644 --- a/elections/tests/template_tags_tests.py +++ b/elections/tests/template_tags_tests.py @@ -81,9 +81,9 @@ def test_areas_json_template_tag(self): Area.objects.create(name="Mar para Bolivia") Area.objects.create(name="Guatemala") for area in Area.public.all(): - area_dict = {'slug': area.id, + area_dict = {'slug': area.slug, 'name': area.name, - 'detaillink': reverse('area', kwargs={'slug': area.id}) + 'detaillink': area.get_absolute_url() } expected_areas.append(area_dict) diff --git a/elections/tests/version2/elections_per_area_tests.py b/elections/tests/version2/elections_per_area_tests.py index 91a0b630..395aa797 100644 --- a/elections/tests/version2/elections_per_area_tests.py +++ b/elections/tests/version2/elections_per_area_tests.py @@ -24,7 +24,7 @@ def test_an_election_can_have_an_area(self): def test_there_is_a_url_with_the_area(self): argentina = Area.objects.create(name=u'Argentina') - url = reverse('area', kwargs={'slug': argentina.id}) + url = argentina.get_absolute_url() response = self.client.get(url) self.assertEquals(response.status_code, 200) self.assertTemplateUsed(response, 'elections/area.html') @@ -37,7 +37,7 @@ def test_hidden_area(self): @override_config(HIDDEN_AREAS='argentina') def test_hidden_area_is_still_reachable(self): argentina = Area.objects.create(name=u'Argentina') - url = reverse('area', kwargs={'slug': argentina.id}) + url = argentina.get_absolute_url() response = self.client.get(url) self.assertEquals(response.status_code, 200) @@ -177,13 +177,13 @@ def test_areas_redirect_when_necesary(self): mother = Area.objects.create(name="mother") mother.children.add(child) - url = reverse('area', kwargs={'slug': child.id}) + url = child.get_absolute_url() response = self.client.get(url) - url_mother = reverse('area', kwargs={'slug': mother.id}) + url_mother = mother.get_absolute_url() self.assertRedirects(response, url_mother) child2 = Area.objects.create(name="children", classification="Comuna") - url = reverse('area', kwargs={'slug': child2.id}) + url = child2.get_absolute_url() response = self.client.get(url) self.assertEquals(response.status_code, 200) @@ -193,7 +193,7 @@ def setUp(self): self.site = Site.objects.get_current() def test_get_absolute_url(self): - url = reverse('area', kwargs={'slug': self.argentina.id}) + url = reverse('area', kwargs={'slug': self.argentina.slug}) self.assertEquals(url, self.argentina.get_absolute_url()) def test_ogp_things(self): diff --git a/elections/urls.py b/elections/urls.py index 0c8c9446..3cb1bb24 100644 --- a/elections/urls.py +++ b/elections/urls.py @@ -61,7 +61,7 @@ cache_page(60 * settings.CACHE_MINUTES)(CandidateDetailView.as_view(template_name='elections/candidate_detail.html')), name='candidate_detail_view' ), - url(r'^territorio/(?P[-\w]+)/(?P[-\w]+)/?$', + url(r'^candidaturas/(?P[-\w]+)/(?P[-\w]+)/?$', cache_page(60 * settings.CACHE_MINUTES)(CandidateDetailView.as_view(template_name='elections/candidate_detail.html')), name='candidate_detail_view_area' ), @@ -73,10 +73,10 @@ url(r'^eleccion/(?P[-\w]+)/extra_info.html$', ElectionDetailView.as_view(template_name='elections/extra_info.html'), name='election_extra_info'), - url(r'^territorio/(?P[-\w]+)/?$', + url(r'^candidaturas/(?P[-\w]+)/?$', AreaDetailView.as_view(template_name='elections/area.html'), name='area'), - url(r'^territorio/?$', KnowYourCandidatesView.as_view(), name='know_your_candidates'), + url(r'^candidaturas/?$', KnowYourCandidatesView.as_view(), name='know_your_candidates'), ] # urlpatterns += [ diff --git a/elections/views.py b/elections/views.py index 7b91dea9..0d6380b9 100644 --- a/elections/views.py +++ b/elections/views.py @@ -147,7 +147,7 @@ def get_queryset(self): if 'election_slug' in self.kwargs.keys(): queryset_ = queryset.filter(elections__slug=self.kwargs['election_slug']) if 'area_slug' in self.kwargs.keys(): - queryset_ = queryset.filter(elections__area__id=self.kwargs['area_slug']) + queryset_ = queryset.filter(elections__area__slug=self.kwargs['area_slug']) cache.set(candidates_per_election_key, queryset_, 60 * config.INFINITE_CACHE @@ -187,12 +187,12 @@ class AreaDetailView(DetailView, FilterMixin): model = Area context_object_name = 'area' template_name = 'area.html' - slug_field = 'id' + # slug_field = 'id' def dispatch(self, request, *args, **kwargs): area = self.get_object() if area.classification in settings.FILTERABLE_AREAS_TYPE and area.parent: - return HttpResponseRedirect(reverse('area', kwargs={'slug': area.parent.id})) + return HttpResponseRedirect(Area.objects.get(id=area.parent.id).get_absolute_url()) return super(AreaDetailView, self).dispatch(request, *args, **kwargs) diff --git a/popular_proposal/migrations/0021_auto_20170607_2313.py b/popular_proposal/migrations/0021_auto_20170607_2313.py index 48695134..75a6078a 100644 --- a/popular_proposal/migrations/0021_auto_20170607_2313.py +++ b/popular_proposal/migrations/0021_auto_20170607_2313.py @@ -7,15 +7,7 @@ def create_areas(apps, schema_editor): - Area = apps.get_model('elections', 'Area') - try: - Area.objects.get(id=config.HIDDEN_AREAS) - except Area.DoesNotExist as e: - Area.objects.create(id=config.HIDDEN_AREAS, name=config.HIDDEN_AREAS) - try: - Area.objects.get(id=config.DEFAULT_AREA) - except Area.DoesNotExist as e: - Area.objects.create(id=config.DEFAULT_AREA, name=config.DEFAULT_AREA) + pass class Migration(migrations.Migration): diff --git a/popular_proposal/migrations/0027_auto_20170914_1841.py b/popular_proposal/migrations/0027_auto_20170914_1841.py new file mode 100644 index 00000000..9a2d661f --- /dev/null +++ b/popular_proposal/migrations/0027_auto_20170914_1841.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-09-14 18:41 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('popular_proposal', '0026_popularproposal_featured'), + ] + + operations = [ + migrations.AlterModelOptions( + name='popularproposal', + options={'ordering': ['-featured', 'for_all_areas', '-created'], 'verbose_name': 'Propuesta Ciudadana', 'verbose_name_plural': 'Propuestas Ciudadanas'}, + ), + migrations.AlterModelOptions( + name='proposallike', + options={'verbose_name': 'Apoyo', 'verbose_name_plural': 'Apoyos'}, + ), + ] diff --git a/popular_proposal/subscriptions.py b/popular_proposal/subscriptions.py index eaaae465..f5118b55 100644 --- a/popular_proposal/subscriptions.py +++ b/popular_proposal/subscriptions.py @@ -34,30 +34,6 @@ def notify(self): to=[email]) -class NewCommitmentNotification(SubscriptionEventBase): - - def __init__(self, *args, **kwargs): - super(NewCommitmentNotification, self).__init__(*args, **kwargs) - self.commitment = kwargs.pop('commitment') - - def get_who(self): - return self.proposal.likers.exclude(id=self.proposal.proposer.id) - - def get_mail_from(self, person): - return person.email - - def get_template(self): - if self.commitment.commited: - return 'new_commitment' - else: - return 'not_new_commitment' - - def get_context(self, **kwargs): - context = super(NewCommitmentNotification, self).get_context(**kwargs) - context['commitment'] = self.commitment - return context - - class NewCommitmentNotificationToProposer(SubscriptionEventBase): mail_template = 'genia_lograste_compromiso' @@ -146,6 +122,3 @@ def notification_trigger(event, **kwargs): dispatcher = EventDispatcher() proposal = kwargs.pop('proposal') dispatcher.trigger(event, proposal, kwargs) - - - diff --git a/popular_proposal/tests/subscription_tests.py b/popular_proposal/tests/subscription_tests.py index a045636e..6c39405c 100644 --- a/popular_proposal/tests/subscription_tests.py +++ b/popular_proposal/tests/subscription_tests.py @@ -6,7 +6,6 @@ ) from popular_proposal.subscriptions import (SubscriptionEventBase, EventDispatcher, - NewCommitmentNotification, ManyCitizensSupportingNotification, YouAreAHeroNotification, NewCommitmentNotificationToProposer, @@ -59,6 +58,15 @@ class SubscriptionEventsTestCase(SubscriptionTestCaseBase): def setUp(self): super(SubscriptionEventsTestCase, self).setUp() + def test_raises_not_implemented_error(self): + class OnlyForThisTest(SubscriptionEventBase): + pass + bad_dispatcher = OnlyForThisTest(None) + with self.assertRaises(NotImplementedError): + bad_dispatcher.get_who() + with self.assertRaises(NotImplementedError): + bad_dispatcher.get_mail_from(None) + def test_triggering_an_event(self): dispatcher = EventDispatcher() dispatcher.register('test-event', [TestNewCandidateCommitment, ]) @@ -101,42 +109,6 @@ def test_letting_the_proposer_know_of_his_non_commitment(self): self.assertIn(self.proposal.title, the_mail.body) self.assertIn(self.candidate.name, the_mail.body) - def test_letting_know_the_citizens_that_a_candidate_has_commited_to_a_proposal(self): - ProposalLike.objects.create(user=self.feli, - proposal=self.proposal) - commitment = Commitment.objects.create(candidate=self.candidate, - proposal=self.proposal, - commited=True) - previous_amount = len(mail.outbox) - notifier = NewCommitmentNotification(proposal=self.proposal, - commitment=commitment) - notifier.notify() - self.assertEquals(len(mail.outbox), previous_amount + 1) - the_mail = mail.outbox[previous_amount] - self.assertIn(self.feli.email, the_mail.to) - self.assertEquals(len(the_mail.to), 1) - self.assertIn(self.proposal.title, the_mail.body) - self.assertIn(self.candidate.name, the_mail.body) - - def test_letting_the_citizens_know_that_a_candidate_has_said_no(self): - ProposalLike.objects.create(user=self.feli, - proposal=self.proposal) - commitment = Commitment.objects.create(candidate=self.candidate, - proposal=self.proposal, - detail=u'Yo No me comprometo', - commited=False) - previous_amount = len(mail.outbox) - notifier = NewCommitmentNotification(proposal=self.proposal, - commitment=commitment) - notifier.notify() - self.assertEquals(len(mail.outbox), previous_amount + 1) - the_mail = mail.outbox[previous_amount] - self.assertIn(self.feli.email, the_mail.to) - self.assertEquals(len(the_mail.to), 1) - self.assertIn(self.proposal.title, the_mail.body) - self.assertIn(self.candidate.name, the_mail.body) - self.assertIn(commitment.detail, the_mail.body) - def test_notification_trigger_candidate_commit(self): ProposalLike.objects.create(user=self.feli, proposal=self.proposal) @@ -269,6 +241,7 @@ def test_proposal_notification_for_candidates(self): def test_new_proposal_notification_with_login_info(self): self.feli.last_login = None self.feli.save() + CandidacyContact.objects.all().delete() candidacy = Candidacy.objects.create(user=self.feli, candidate=self.candidate ) diff --git a/popular_proposal/tests/views_tests.py b/popular_proposal/tests/views_tests.py index f8efdf4e..75107b8d 100644 --- a/popular_proposal/tests/views_tests.py +++ b/popular_proposal/tests/views_tests.py @@ -174,7 +174,7 @@ def test_filtering_form_by_area(self): self.assertTrue(form.is_valid()) def test_area_detail_view_brings_proposals(self): - url = reverse('area', kwargs={'slug': self.algarrobo.id}) + url = self.algarrobo.get_absolute_url() response = self.client.get(url) self.assertIn(self.popular_proposal1, response.context['popular_proposals']) @@ -182,7 +182,7 @@ def test_area_detail_view_brings_proposals(self): response.context['popular_proposals']) def test_get_area_with_form(self): - url = reverse('area', kwargs={'slug': self.algarrobo.id}) + url = self.algarrobo.get_absolute_url() response = self.client.get(url) self.assertIsInstance(response.context['proposal_filter_form'], Form) diff --git a/popular_proposal/tests/wizard_tests.py b/popular_proposal/tests/wizard_tests.py index 95dbcfe2..16f44a2d 100644 --- a/popular_proposal/tests/wizard_tests.py +++ b/popular_proposal/tests/wizard_tests.py @@ -405,14 +405,3 @@ def test_done_brings_update_proposal_form(self): self.assertIsInstance(form, UpdateProposalForm) self.assertEquals(form.instance, temporary_data.created_proposal) - def test_if_we_say_is_testing_in_wizard_it_creates_a_proposal_in_testing_area(self): - try: - testing_area = Area.objects.get(id=config.HIDDEN_AREAS) - except Area.DoesNotExist: - testing_area = Area.objects.create(id=config.HIDDEN_AREAS, name=config.HIDDEN_AREAS) - response = self.fill_the_whole_wizard(override_example_data={3: {'3-title':'title', - '3-terms_and_conditions': True, - "3-is_testing":True}}) - temporary_data = response.context['popular_proposal'] - - self.assertEquals(temporary_data.created_proposal.area, testing_area) diff --git a/popular_proposal/urls.py b/popular_proposal/urls.py index ac0c5a2a..0c4826ce 100644 --- a/popular_proposal/urls.py +++ b/popular_proposal/urls.py @@ -39,7 +39,7 @@ ProposalWizardFullWithoutArea.as_view(), name='propose_wizard_full_without_area'), url(r'^detail/(?P[-\w]+)/?$', - PopularProposalDetailView.as_view(), + xframe_options_exempt(PopularProposalDetailView.as_view()), name='detail'), url(r'^d/(?P\d+)/?$', PopularProposalDetailRedirectView.as_view(), diff --git a/popular_proposal/views/wizard.py b/popular_proposal/views/wizard.py index 11ae8a31..001c9c53 100644 --- a/popular_proposal/views/wizard.py +++ b/popular_proposal/views/wizard.py @@ -45,8 +45,6 @@ def get_previous_forms(self): def determine_area(self, data): is_testing = data.pop("is_testing", False) - if is_testing: - return Area.objects.get(id=config.HIDDEN_AREAS) if 'area' in data.keys(): return data['area'] elif hasattr(self, 'area'): diff --git a/preguntales/tests/ask_candidates_tests.py b/preguntales/tests/ask_candidates_tests.py index bf330294..545a0031 100644 --- a/preguntales/tests/ask_candidates_tests.py +++ b/preguntales/tests/ask_candidates_tests.py @@ -525,6 +525,9 @@ def setUp(self): self.candidate1 = Candidate.objects.get(id=4) self.candidate2 = Candidate.objects.get(id=5) self.candidate3 = Candidate.objects.get(id=6) + self.election.candidates.add(self.candidate1) + self.election.candidates.add(self.candidate2) + self.election.candidates.add(self.candidate3) def tearDown(self): pass diff --git a/proposal_subscriptions/migrations/0004_commitmentnotification.py b/proposal_subscriptions/migrations/0004_commitmentnotification.py new file mode 100644 index 00000000..5a8b0242 --- /dev/null +++ b/proposal_subscriptions/migrations/0004_commitmentnotification.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-09-14 18:41 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('popular_proposal', '0027_auto_20170914_1841'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('proposal_subscriptions', '0003_auto_20170817_1344'), + ] + + operations = [ + migrations.CreateModel( + name='CommitmentNotification', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('notified', models.BooleanField(default=False)), + ('created', models.DateTimeField(auto_now_add=True, null=True)), + ('commitment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to='popular_proposal.Commitment')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='commitment_notifications', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/proposal_subscriptions/models.py b/proposal_subscriptions/models.py index f28990d5..40d87a04 100644 --- a/proposal_subscriptions/models.py +++ b/proposal_subscriptions/models.py @@ -2,11 +2,15 @@ from django.db import models from django.contrib.auth.models import User +from popular_proposal.models import Commitment from picklefield.fields import PickledObjectField from django.utils import timezone from django.core.urlresolvers import reverse import uuid from django.utils.translation import ugettext_lazy as _ +from django.db.models.signals import post_save +from django.dispatch import receiver +from votainteligente.send_mails import send_mail class SearchSubscription(models.Model): @@ -39,3 +43,51 @@ def queryset(self): qs = self.base_queryset() since_when = timezone.now() - self.oftenity return qs.filter(created__gt=since_when) + + +class CommitmentNotification(models.Model): + user = models.ForeignKey(User, related_name='commitment_notifications') + commitment = models.ForeignKey(Commitment, related_name="notifications") + notified = models.BooleanField(default=False) + created = models.DateTimeField(auto_now_add=True, + blank=True, + null=True) + +class CommitmentNotificationSender(object): + template_prefix = "commitments_summary" + + def __init__(self, user): + self.user = user + + def get_commitments(self): + return Commitment.objects.filter(notifications__user=self.user, notifications__notified=False) + + def get_context(self): + commitments = self.get_commitments() + return { + 'commitments': commitments, + 'user': self.user + } + + def send(self): + context = self.get_context() + if not context['commitments']: + return + for commitment in context['commitments']: + commitment.notifications.filter(user=self.user).update(notified=True) + send_mail(context, self.template_prefix, to=[self.user.email]) + + @classmethod + def send_to_users(cls): + users = User.objects.exclude(commitment_notifications__isnull=True) + for u in users: + instance = cls(user=u) + instance.send() + +@receiver(post_save, sender=Commitment, dispatch_uid="create_notifications") +def create_notifications(sender, instance, created, raw, **kwargs): + commitment = instance + if created: + for user in commitment.proposal.likers.all(): + CommitmentNotification.objects.get_or_create(commitment=commitment, + user=user) diff --git a/proposal_subscriptions/tasks.py b/proposal_subscriptions/tasks.py index 1ca634cb..523fb27c 100644 --- a/proposal_subscriptions/tasks.py +++ b/proposal_subscriptions/tasks.py @@ -1,5 +1,6 @@ from votainteligente.celery import app from proposal_subscriptions.runner import TaskRunner +from proposal_subscriptions.models import CommitmentNotificationSender # import the logging library import logging @@ -11,3 +12,9 @@ def send_new_proposals_to_subscribers(): logger.info('Sending new proposals to subscribers') TaskRunner.send() + + +@app.task +def send_commitment_notifications(): + logger.info('Enviando los compromisos a los usuarios') + CommitmentNotificationSender.send_to_users() diff --git a/proposal_subscriptions/tests/commitment_notifications_tests.py b/proposal_subscriptions/tests/commitment_notifications_tests.py new file mode 100644 index 00000000..46547c46 --- /dev/null +++ b/proposal_subscriptions/tests/commitment_notifications_tests.py @@ -0,0 +1,117 @@ +# coding=utf-8 +from popular_proposal.tests import ProposingCycleTestCaseBase +from proposal_subscriptions.models import (CommitmentNotification, + CommitmentNotificationSender,) +from popular_proposal.models import (PopularProposal, + Commitment, + ProposalLike, + ) +from elections.models import Candidate +from django.contrib.auth.models import User +from django.core import mail + + +class CommitmentNotifications(ProposingCycleTestCaseBase): + def setUp(self): + super(CommitmentNotifications, self).setUp() + self.candidate = Candidate.objects.get(id=1) + self.popular_proposal = PopularProposal.objects.create(proposer=self.fiera, + data=self.data, + title=u'This is a title', + clasification=u'education' + ) + self.popular_proposal2 = PopularProposal.objects.create(proposer=self.fiera, + data=self.data, + title=u'This is a title2', + clasification=u'education' + ) + + def test_instanciate_a_model(self): + u = User.objects.create_user(username="user") + commitment = Commitment.objects.create(candidate=self.candidate, + proposal=self.popular_proposal, + detail=u'Yo me comprometo', + commited=True) + notification = CommitmentNotification.objects.create(user=u, + commitment=commitment) + self.assertTrue(notification.created) + self.assertFalse(notification.notified) + + def test_create_notifications_on_commitments(self): + u = User.objects.create_user(username="user") + ProposalLike.objects.create(user=u, + proposal=self.popular_proposal) + ProposalLike.objects.create(user=u, + proposal=self.popular_proposal2) + u2 = User.objects.create_user(username="user2") + ProposalLike.objects.create(user=u2, + proposal=self.popular_proposal) + + commitment = Commitment.objects.create(candidate=self.candidate, + proposal=self.popular_proposal) + + notifications = CommitmentNotification.objects.all() + self.assertEquals(notifications.filter(commitment=commitment).count(), 2) + commitment2 = Commitment.objects.create(candidate=self.candidate, + proposal=self.popular_proposal2) + notifications = CommitmentNotification.objects.all() + self.assertEquals(notifications.filter(commitment=commitment2).count(), 1) + self.assertTrue(notifications.get(user=u2)) + + def test_notification_sender_to_users(self): + u = User.objects.create_user(username="user", email="bono_u1@themail.com") + ProposalLike.objects.create(user=u, + proposal=self.popular_proposal) + ProposalLike.objects.create(user=u, + proposal=self.popular_proposal2) + u2 = User.objects.create_user(username="user2", email="bono_u2@themail.com") + ProposalLike.objects.create(user=u2, + proposal=self.popular_proposal) + commitment = Commitment.objects.create(candidate=self.candidate, + commited=True, + proposal=self.popular_proposal) + commitment2 = Commitment.objects.create(candidate=self.candidate, + commited=True, + proposal=self.popular_proposal2) + sender = CommitmentNotificationSender(user=u) + context = sender.get_context() + self.assertIn(commitment,context['commitments'].all()) + self.assertIn(commitment2, context['commitments'].all()) + self.assertEquals(context['user'], u) + self.assertEquals(sender.template_prefix, "commitments_summary") + original_amount_of_mails = len(mail.outbox) + sender.send() + self.assertEquals(len(mail.outbox), original_amount_of_mails + 1) + the_mail = mail.outbox[original_amount_of_mails] + self.assertIn(u.email, the_mail.to) + # ahora me quiero asegurar que no se envían de nuevo + sender = CommitmentNotificationSender(user=u) + sender.send() + self.assertFalse(CommitmentNotification.objects.filter(user=u, notified=False)) + self.assertEquals(len(mail.outbox), original_amount_of_mails + 1) + + + def test_email_sender(self): + u = User.objects.create_user(username="user", email="bono_u1@themail.com") + User.objects.create_user(username="user3", email="bono_u3@themail.com") + ProposalLike.objects.create(user=u, + proposal=self.popular_proposal) + ProposalLike.objects.create(user=u, + proposal=self.popular_proposal2) + u2 = User.objects.create_user(username="user2", email="bono_u2@themail.com") + ProposalLike.objects.create(user=u2, + proposal=self.popular_proposal) + Commitment.objects.create(candidate=self.candidate, + commited=True, + proposal=self.popular_proposal) + Commitment.objects.create(candidate=self.candidate, + commited=True, + proposal=self.popular_proposal2) + original_amount_of_mails = len(mail.outbox) + CommitmentNotificationSender.send_to_users() + + self.assertEquals(len(mail.outbox), original_amount_of_mails + 2) + the_mail = mail.outbox[original_amount_of_mails] + self.assertIn(the_mail.to[0], [u.email, u2.email]) + the_mail2 = mail.outbox[original_amount_of_mails + 1] + self.assertIn(the_mail2.to[0], [u.email, u2.email]) diff --git a/requirements.txt b/requirements.txt index 12ad1983..fbb0cbcb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ django-tastypie==0.13.3 linaro-django-pagination==2.0.3 celery==3.1.18 python-memcached==1.58 --e git+https://github.com/openpolis/django-popolo.git#egg=django_popolo-dev +-e git+https://github.com/ciudadanointeligente/django-popolo.git@areas_with_slug#egg=django_popolo-dev django-mathfilters==0.4.0 django-picklefield==0.3.2 -e git+https://github.com/dokterbob/django-newsletter#egg=django_newsletter diff --git a/votai_general_theme/forms.py b/votai_general_theme/forms.py index d9f6ec10..eb40097a 100644 --- a/votai_general_theme/forms.py +++ b/votai_general_theme/forms.py @@ -12,3 +12,7 @@ class PersonalDataForm(forms.Form): required=False, initial='' ) + telefono = forms.CharField(label=u'Teléfono', + required=False, + initial='', + help_text=u"¿Hay algún teléfono donde los ciudadanos interesados en tu campaña se puedan comunicar con tu comando?") diff --git a/votai_general_theme/static/img/lm-footer-fci.svg b/votai_general_theme/static/img/lm-footer-fci.svg index b3bf8770..389973a1 100644 --- a/votai_general_theme/static/img/lm-footer-fci.svg +++ b/votai_general_theme/static/img/lm-footer-fci.svg @@ -1,14 +1,14 @@ - + - Group + Artboard 3 Copy 20 Created with Sketch. - - + + diff --git a/votai_general_theme/static/img/lm-footer-mineduc.svg b/votai_general_theme/static/img/lm-footer-mineduc.svg new file mode 100644 index 00000000..60c3428f --- /dev/null +++ b/votai_general_theme/static/img/lm-footer-mineduc.svg @@ -0,0 +1,75 @@ + + + + Artboard 3 Copy 22 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/votai_general_theme/static/img/lm-footer-unicef.svg b/votai_general_theme/static/img/lm-footer-unicef.svg index 9ce65556..5b0579ff 100644 --- a/votai_general_theme/static/img/lm-footer-unicef.svg +++ b/votai_general_theme/static/img/lm-footer-unicef.svg @@ -1,60 +1,60 @@ - + - Page 1 + Artboard 3 Copy 21 Created with Sketch. - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/votai_general_theme/static/img/lm-footer-vota.svg b/votai_general_theme/static/img/lm-footer-vota.svg index bcdb0d8d..012d8eb8 100644 --- a/votai_general_theme/static/img/lm-footer-vota.svg +++ b/votai_general_theme/static/img/lm-footer-vota.svg @@ -1,12 +1,12 @@ - + - Group 2 + Artboard 3 Created with Sketch. - - + + diff --git a/votai_general_theme/static/img/lm-met.svg b/votai_general_theme/static/img/lm-met.svg index c092703f..5b2d9b78 100644 --- a/votai_general_theme/static/img/lm-met.svg +++ b/votai_general_theme/static/img/lm-met.svg @@ -1,14 +1,14 @@ - Page 1 + Group 4 Created with Sketch. - - + + @@ -16,12 +16,11 @@ - - + - - - + + + diff --git a/votai_general_theme/static/img/lm-redline.svg b/votai_general_theme/static/img/lm-redline.svg new file mode 100644 index 00000000..26767d9e --- /dev/null +++ b/votai_general_theme/static/img/lm-redline.svg @@ -0,0 +1,10 @@ + + + + Fill 1 Copy 2 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/votai_general_theme/static/img/lm-yellowline.svg b/votai_general_theme/static/img/lm-yellowline.svg index 18fc338d..a73ccfd3 100644 --- a/votai_general_theme/static/img/lm-yellowline.svg +++ b/votai_general_theme/static/img/lm-yellowline.svg @@ -1,10 +1,10 @@ - + - Fill 1 Copy 2 + Fill 1 Copy 3 Created with Sketch. - + \ No newline at end of file diff --git a/votai_general_theme/static/lm-favicon.ico b/votai_general_theme/static/lm-favicon.ico new file mode 100644 index 00000000..d6a948fc Binary files /dev/null and b/votai_general_theme/static/lm-favicon.ico differ diff --git a/votai_general_theme/static/sass/_levantalamano.scss b/votai_general_theme/static/sass/_levantalamano.scss index 73e6f0ac..e6fbfd7f 100644 --- a/votai_general_theme/static/sass/_levantalamano.scss +++ b/votai_general_theme/static/sass/_levantalamano.scss @@ -19,6 +19,15 @@ html, body { .img-responsive{ display: inline; } +h1{ + font-family: 'Fredoka One', sans-serif; + letter-spacing: 2px; +} +h2{ + @extend h1; +} + +/*BUTTONS*/ .btn{ border-radius: 20px; border: none; @@ -44,14 +53,42 @@ html, body { box-shadow: none; } } -h1{ - font-family: 'Fredoka One', sans-serif; - letter-spacing: 2px; +.btn-blue{ + border: 3px solid $blue; + background-color: $blue; + color: white; + &:hover{ + background-color: transparent; + color: white; + border: 3px solid white; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } } -h2{ - @extend h1; +h4{ + font-family: 'Nunito', sans-serif; + font-weight: 700; + color: black; + a{ + color: black; + &:hover{ + color: black; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } } - /*MAIN CONTAINERS*/ .color{ color: white; @@ -79,15 +116,21 @@ h2{ background-repeat: no-repeat; min-height: 28px; } -.yellowline{ - background-image: url("../img/lm-yellowline.svg"); +.redline{ + background-image: url("../img/lm-redline.svg"); background-repeat: no-repeat; min-height: 46px; margin-top: -48px; } +.yellowline{ + background-image: url("../img/lm-yellowline.svg"); + background-repeat: no-repeat; + min-height: 28px; + margin-top: -30px; +} .special-position{ position: relative; - top: 100px; + top: 80px; } /*HOME 0*/ @@ -96,21 +139,747 @@ h2{ top: 100px; } #banner{ - min-height: 400px; + min-height: 380px; } #que-es{ - padding: 30px 0 60px; + padding: 30px 0 70px; +} +p.bajada{ + font-size: 18px; + line-height: 22px; +} +p.aviso{ + font-size: 22px; + line-height: 26px; + font-family: 'Nunito', sans-serif; + font-weight: 700; } #contact{ - padding: 30px 0 240px; + padding: 30px 0 80px; +} +#soon{ + padding: 40px 0 210px; + margin-bottom: -170px; +} + +/*PROPOSALS REPOSITORY*/ +#grid{ + position: relative; +} +#grid > #posts .post{ + width: 340px; +} +#posts{ + position: relative; + height: -webkit-fill-available; +} +.post.propuesta{ + position: absolute; + left: 0px; + top: 0px; +} +.post{ + margin: 0 0 50px; +} +.propuesta{ + min-height: 310px; + border-radius: 10px; + padding: 0; + position: relative; + padding: 20px 20px 5px; +} +.propuesta-content{ + height: 110px; +} +.group{ + margin-top: 30px; + margin-bottom: -6px; +} +hr{ + position: relative; + top: 26px; +} +.votita-love-politica{ + border: 3px solid $yellow; + .label-default{ + background: $yellow; + } + .group{ + color: $yellow; + } + hr{ + border: 1px solid $yellow; + } + .btn-apoyo { + color: white; + background-color: $yellow; + border: 3px solid $yellow; + &:hover{ + background-color: transparent; + color: $yellow; + border: 3px solid $yellow; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $yellow; + background-color: transparent; + border: 3px solid $yellow; + &:hover{ + background-color: $yellow; + color: white; + border: 3px solid $yellow; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $yellow; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.votita-love-salud{ + border: 3px solid $blue; + .label-default{ + background: $blue; + } + .group{ + color: $blue; + } + hr{ + border: 1px solid $blue; + } + .btn-apoyo { + color: white; + background-color: $blue; + border: 3px solid $blue; + &:hover{ + background-color: transparent; + color: $blue; + border: 3px solid $blue; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $blue; + background-color: transparent; + border: 3px solid $blue; + &:hover{ + background-color: $blue; + color: white; + border: 3px solid $blue; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $blue; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.votita-love-medio_ambiente{ + border: 3px solid $green; + .label-default{ + background: $green; + } + .group{ + color: $green; + } + hr{ + border: 1px solid $green; + } + .btn-apoyo { + color: white; + background-color: $green; + border: 3px solid $green; + &:hover{ + background-color: transparent; + color: $green; + border: 3px solid $green; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $green; + background-color: transparent; + border: 3px solid $green; + &:hover{ + background-color: $green; + color: white; + border: 3px solid $green; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $green; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.votita-love-cultura{ + border: 3px solid $red; + .label-default{ + background: $red; + } + .group{ + color: $red; + } + hr{ + border: 1px solid $red; + } + .btn-apoyo { + color: white; + background-color: $red; + border: 3px solid $red; + &:hover{ + background-color: transparent; + color: $red; + border: 3px solid $red; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $red; + background-color: transparent; + border: 3px solid $red; + &:hover{ + background-color: $red; + color: white; + border: 3px solid $red; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $red; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.votita-love-diversidad{ + border: 3px solid $purple; + .label-default{ + background: $purple; + } + .group{ + color: $purple; + } + hr{ + border: 1px solid $purple; + } + .btn-apoyo { + color: white; + background-color: $purple; + border: 3px solid $purple; + &:hover{ + background-color: transparent; + color: $purple; + border: 3px solid $purple; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $purple; + background-color: transparent; + border: 3px solid $purple; + &:hover{ + background-color: $purple; + color: white; + border: 3px solid $purple; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $purple; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.votita-love-tecnologia{ + border: 3px solid $blue; + .label-default{ + background: $blue; + } + .group{ + color: $blue; + } + hr{ + border: 1px solid $blue; + } + .btn-apoyo { + color: white; + background-color: $blue; + border: 3px solid $blue; + &:hover{ + background-color: transparent; + color: $blue; + border: 3px solid $blue; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $blue; + background-color: transparent; + border: 3px solid $blue; + &:hover{ + background-color: $blue; + color: white; + border: 3px solid $blue; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $blue; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.votita-love-educacion_y_trabajo{ + border: 3px solid $pink; + .label-default{ + background: $pink; + } + .group{ + color: $pink; + } + hr{ + border: 1px solid $pink; + } + .btn-apoyo { + color: white; + background-color: $pink; + border: 3px solid $pink; + &:hover{ + background-color: transparent; + color: $pink; + border: 3px solid $pink; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $pink; + background-color: transparent; + border: 3px solid $pink; + &:hover{ + background-color: $pink; + color: white; + border: 3px solid $pink; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $pink; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.votita-love-proteccion_y_familia{ + border: 3px solid $yellow; + .label-default{ + background: $yellow; + } + .group{ + color: $yellow; + } + hr{ + border: 1px solid $yellow; + } + .btn-apoyo { + color: white; + background-color: $yellow; + border: 3px solid $yellow; + &:hover{ + background-color: transparent; + color: $yellow; + border: 3px solid $yellow; + } + &:focus{ + @extend .btn-apoyo:hover; + } + &:active:hover{ + @extend .btn-apoyo:hover; + box-shadow: none; + } + } + .btn-blue { + color: $yellow; + background-color: transparent; + border: 3px solid $yellow; + &:hover{ + background-color: $yellow; + color: white; + border: 3px solid $yellow; + } + &:focus{ + @extend .btn-blue:hover; + } + &:active:hover{ + @extend .btn-blue:hover; + box-shadow: none; + } + } + h4{ + a{ + &:hover{ + color: $yellow; + text-decoration: none; + } + &:focus{ + @extend a:hover; + } + &:active:hover{ + @extend a:hover; + box-shadow: none; + } + } + } +} +.label-default{ + @extend .small; +} +.share-card{ + padding: 20px 0 0; + .social-buttons{ + font-size: 10px; + position: relative; + top: 17px; + a{ + color: black; + } + } +} +.apoyo-contador { + text-align: left; +} +.conteo{ + font-family: 'Nunito', sans-serif; + font-weight: 700; + font-size: 30px; + position: relative; + top: 6px; +} + +/*DETAIL*/ +.breadcrumb{ + background-color: transparent; + border-radius: none; + margin: 20px 0; + padding: 0; + color: black; + a{ + color: black; + &:hover{ + color: white; + text-decoration: none; + } + } + .active{ + color: white; + } + li+li:before{ + color: black; + } +} +.votita-love-detail-politica{ + background-color: $yellow; + padding-bottom: 40px; +} +.votita-love-detail-salud{ + background-color: $blue; + padding-bottom: 40px; +} +.votita-love-detail-medio_ambiente{ + background-color: $green; + padding-bottom: 40px; +} +.votita-love-detail-cultura{ + background-color: $red; + padding-bottom: 40px; +} +.votita-love-detail-diversidad{ + background-color: $purple; + padding-bottom: 40px; +} +.votita-love-detail-tecnologia{ + background-color: $blue; + padding-bottom: 40px; +} +.votita-love-detail-educacion_y_trabajo{ + background-color: $pink; + padding-bottom: 40px; +} +.votita-love-detail-proteccion_y_familia{ + background-color: $yellow; + padding-bottom: 40px; +} +.votita-detail{ + .label-default{ + background: white; + color: black; + } + h1{ + font-family: 'Nunito', sans-serif; + font-size: 40px; + color: white; + font-weight: 700; + } + p{ + font-size: 15px; + } + .group{ + font-weight: 600; + letter-spacing: 2px; + } + .invitacion{ + font-size: 20px; + } + .btn-apoyo{ + background-color: white; + color: black; + width: 100%; + &:hover{ + background-color: transparent; + color: white; + } + } + .blue-light-txt{ + font-size: 18px; + position: relative; + top: -4px; + } + hr{ + border: 1px solid white; + margin: 0 0 40px; + } +} +.share-detail{ + padding: 70px 10px 20px; + a{ + color: black; + &:hover{ + color: white; + } + } + .fa-inverse{ + &:hover{ + color: black; + } + } } +/*PLAN*/ +.votita-plan{ + border: 3px solid black; + border-radius: 10px; + padding: 20px 40px 20px; + margin: 20px 0; + h2{ + font-family: 'Nunito', sans-serif; + font-weight: 700; + text-align: center; + } +} +.proposal-plan{ + border: none; + margin: 20px 0 15px; + a{ + color: black; + font-family: 'Nunito', sans-serif; + font-weight: 15px; + font-weight: 700; + &:hover{ + text-decoration: none; + } + } +} + + +/*MODALS*/ +.modal-content{ + box-shadow: none; + border: none; +} +.modal-header{ + border-bottom: none; +} +.modal-footer{ + border-top: none; +} +.btn-info{ + background-color: black; + border: 3px solid black; + &:hover{ + background-color: transparent; + color: black; + border: 3px solid black; + } + &:focus{ + @extend .btn-info:hover; + } + &:active:hover{ + @extend .btn-info:hover; + box-shadow: none; + } +} /*FOOTER*/ .greenline{ background-image: url("../img/lm-footer.svg"); background-repeat: no-repeat; min-height: 144px; - margin-top: -148px; + margin-top: 0px; } footer{ background-color: $green; @@ -132,3 +901,11 @@ footer{ .redes{ margin: 45px 0; } + +/*PRINT*/ +.print_only { + display:none; +} +.print-share-urls{ + display:none; +} diff --git a/votai_general_theme/static/sass/_lm-media-print.scss b/votai_general_theme/static/sass/_lm-media-print.scss new file mode 100644 index 00000000..996a38f4 --- /dev/null +++ b/votai_general_theme/static/sass/_lm-media-print.scss @@ -0,0 +1,64 @@ +@media print { + @page {size: landscape} + html .navbar_visible { + padding-top: 5px; + } + .print_hidden { + display: None; + } + .fondo-blanco { + padding: 0px 15px; + border: 0px; + margin-bottom: 0px; + &.text-width { + max-width: initial; + } + h1 { + font-weight: 500; + font-size: 36px; + letter-spacing: 3px; + } + #proposal-details { + h2 { + margin-top: 20px; + margin-bottom: 10px; + } + } + } + .container { + width: 90%; + } + .print-share-urls { + display: block; + transform: rotate(90deg); + position: absolute; + top: -144px; + border-left: 1px dashed; + padding-left: 10px; + margin-left: 382px; + li { + padding: 2px 0px; + margin: 2px 0px; + border-top: 1px dashed; + } + } + .invitacion { + top: 200px; + position: absolute; + } + .print_only { + display:block; + } + .proposal-banner-org { + display: none; + } + .proposal-tools { + display: none; + } + .apoya-comparte { + display: none; + } + .llamado { + display: none; + } +} diff --git a/votai_general_theme/static/sass/_media-levantalamano.scss b/votai_general_theme/static/sass/_media-levantalamano.scss index 05bff1eb..24cb40c3 100644 --- a/votai_general_theme/static/sass/_media-levantalamano.scss +++ b/votai_general_theme/static/sass/_media-levantalamano.scss @@ -1,12 +1,42 @@ @media screen and (max-width: 991px) { /*HOME 0*/ .logo-title{ - top: 70px; + top: 30px; + } + .special-position{ + top: 30px; } #que-es{ - padding: 100px 0 60px; + padding: 50px 0 60px; } #contact{ - padding: 80px 0 240px; + padding: 20px 0 90px; + } + #soon{ + padding: 40px 0 210px; + } + p.bajada{ + font-size: 16px; + line-height: 20px; + } + p.aviso{ + font-size: 20px; + line-height: 24px; + } + /*DETAIL*/ + .share-detail{ + padding: 50px 10px 0 10px; + } +} +@media screen and (max-width: 991px) { + /*PROPOSALS REPOSITORY*/ + #grid > #posts .post{ + width: 440px; + } +} +@media screen and (max-width: 768px) { + /*PROPOSALS REPOSITORY*/ + #grid > #posts .post{ + width: 100%; } } diff --git a/votai_general_theme/static/sass/main.scss b/votai_general_theme/static/sass/main.scss index 18f3e53f..58546b8b 100644 --- a/votai_general_theme/static/sass/main.scss +++ b/votai_general_theme/static/sass/main.scss @@ -1841,6 +1841,7 @@ input#id_4-title { padding-top: 12px; padding-left: 60px; max-width: 200px; + text-align: center; } .detail-number h3 { diff --git a/votai_general_theme/templates/backend_candidate/complete_profile.html b/votai_general_theme/templates/backend_candidate/complete_profile.html index 62b5acdf..e559a33b 100644 --- a/votai_general_theme/templates/backend_candidate/complete_profile.html +++ b/votai_general_theme/templates/backend_candidate/complete_profile.html @@ -22,7 +22,7 @@

Información para el perfil de {{candidacy.candidate.name}}

{{candidate.name}} {% endthumbnail %} {% else %} - {{candidate.name}} + {{candidate.name}} {% endif %} {% bootstrap_field form.image %} {% for field in form %} diff --git a/votai_general_theme/templates/backend_citizen/_proposals-table.html b/votai_general_theme/templates/backend_citizen/_proposals-table.html index 718d0221..94524352 100644 --- a/votai_general_theme/templates/backend_citizen/_proposals-table.html +++ b/votai_general_theme/templates/backend_citizen/_proposals-table.html @@ -50,7 +50,7 @@ {% trans 'Rechazada' %} {% endif %} - + {% if proposal.status == 'accepted' %} {% if proposal.created_proposal %} diff --git a/votai_general_theme/templates/backend_citizen/my_supports.html b/votai_general_theme/templates/backend_citizen/my_supports.html index cf1b32ca..3b28dc3b 100644 --- a/votai_general_theme/templates/backend_citizen/my_supports.html +++ b/votai_general_theme/templates/backend_citizen/my_supports.html @@ -39,7 +39,7 @@ {% for support in supports %} - + {{support.proposal.title|truncatechars:50}} {{support.proposal.proposer}} diff --git a/votai_general_theme/templates/elections/area.html b/votai_general_theme/templates/elections/area.html index e33e1724..6a954f1f 100644 --- a/votai_general_theme/templates/elections/area.html +++ b/votai_general_theme/templates/elections/area.html @@ -38,7 +38,7 @@ {% block keywords %},{{area.name}}{% endblock keywords %} {% block content %} - diff --git a/votai_general_theme/templates/elections/embedded.html b/votai_general_theme/templates/elections/embedded.html index 801346be..58eaa54e 100644 --- a/votai_general_theme/templates/elections/embedded.html +++ b/votai_general_theme/templates/elections/embedded.html @@ -7,7 +7,7 @@