diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 0000000000..a2b1864075 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,23 @@ +# Title: Summary, imperative, start upper case, don't end with a period +# No more than 50 chars. #### 50 chars is here: # + +# Remember blank line between title and body. + +# Body: Explain *what* and *why* (not *how*). +# Wrap at 72 chars. ################################## which is here: # + + +# At the end: Include Co-authored-by for all contributors. +# Include at least one empty line before it. Format: +# Co-authored-by: name +# +# How to Write a Git Commit Message: +# https://chris.beams.io/posts/git-commit/ +# +# 1.Separate subject from body with a blank line +# 2. Limit the subject line to 50 characters +# 3. Capitalize the subject line +# 4. Do not end the subject line with a period +# 5. Use the imperative mood in the subject line +# 6. Wrap the body at 72 characters +# 7. Use the body to explain what and why vs. how diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 98679e4dfe..0c889d687d 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -9,6 +9,7 @@ jobs: strategy: matrix: pyversion: ['3.5','3.8'] + services: postgres: image: postgres:10.8 @@ -40,6 +41,8 @@ jobs: run: cd decide;coverage run --branch --source=. ./manage.py test authentication --keepdb; coverage xml; - name: Run tests census run: cd decide;coverage run --branch --source=. ./manage.py test census --keepdb; coverage xml; + - name: Run tests voting + run: cd decide;coverage run --branch --source=. ./manage.py test voting --keepdb; coverage xml; - name: Codacy Coverage Reporter uses: codacy/codacy-coverage-reporter-action@v1.1.0 with: diff --git a/decide/decide/urls.py b/decide/decide/urls.py index 990a90f9b2..79919b7fd6 100644 --- a/decide/decide/urls.py +++ b/decide/decide/urls.py @@ -18,6 +18,7 @@ from django.urls import path, include from django.views.decorators.csrf import csrf_exempt from rest_framework_swagger.views import get_swagger_view +from django.contrib.staticfiles.urls import staticfiles_urlpatterns from visualizer.views import TelegramBot from django.views.generic import TemplateView @@ -36,3 +37,4 @@ urlpatterns += [ path('{}/'.format(module), include('{}.urls'.format(module))) ] + urlpatterns+= staticfiles_urlpatterns() diff --git a/decide/voting/admin.py b/decide/voting/admin.py index 1728eb738d..8138f5401f 100644 --- a/decide/voting/admin.py +++ b/decide/voting/admin.py @@ -2,7 +2,7 @@ from django.utils import timezone -from .models import Detector, Percentage, QuestionOption +from .models import QuestionOption from .models import Question from .models import Voting @@ -37,14 +37,6 @@ class QuestionOptionInline(admin.TabularInline): class QuestionAdmin(admin.ModelAdmin): inlines = [QuestionOptionInline] - -class DetectorAdmin(admin.ModelAdmin): - model = Detector - -class PercentageAdmin(admin.ModelAdmin): - model = Percentage - - class VotingAdmin(admin.ModelAdmin): list_display = ('name', 'start_date', 'end_date') readonly_fields = ('start_date', 'end_date', 'pub_key', @@ -56,7 +48,6 @@ class VotingAdmin(admin.ModelAdmin): actions = [ start, stop, tally ] + admin.site.register(Voting, VotingAdmin) admin.site.register(Question, QuestionAdmin) -admin.site.register(Detector, DetectorAdmin) -admin.site.register(Percentage, PercentageAdmin) diff --git a/decide/voting/migrations/0007_merge_20220103_1820.py b/decide/voting/migrations/0007_merge_20220103_1820.py new file mode 100644 index 0000000000..531055423a --- /dev/null +++ b/decide/voting/migrations/0007_merge_20220103_1820.py @@ -0,0 +1,14 @@ +# Generated by Django 2.0 on 2022-01-03 18:20 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('voting', '0006_auto_20211220_2225'), + ('voting', '0006_alter_voting_postproc_alter_voting_tally'), + ] + + operations = [ + ] diff --git a/decide/voting/migrations/0007_merge_20220104_1653.py b/decide/voting/migrations/0007_merge_20220104_1653.py new file mode 100644 index 0000000000..fe8050f224 --- /dev/null +++ b/decide/voting/migrations/0007_merge_20220104_1653.py @@ -0,0 +1,14 @@ +# Generated by Django 2.0 on 2022-01-04 16:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('voting', '0006_auto_20211220_2225'), + ('voting', '0006_alter_voting_postproc_alter_voting_tally'), + ] + + operations = [ + ] diff --git a/decide/voting/migrations/0008_auto_20220104_1653.py b/decide/voting/migrations/0008_auto_20220104_1653.py new file mode 100644 index 0000000000..e150f2dadd --- /dev/null +++ b/decide/voting/migrations/0008_auto_20220104_1653.py @@ -0,0 +1,19 @@ +# Generated by Django 2.0 on 2022-01-04 16:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('voting', '0007_merge_20220104_1653'), + ] + + operations = [ + migrations.DeleteModel( + name='Detector', + ), + migrations.DeleteModel( + name='Percentage', + ), + ] diff --git a/decide/voting/migrations/0009_question_ynns_question.py b/decide/voting/migrations/0009_question_ynns_question.py new file mode 100644 index 0000000000..e77f536dd2 --- /dev/null +++ b/decide/voting/migrations/0009_question_ynns_question.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0 on 2022-01-05 12:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('voting', '0008_auto_20220104_1653'), + ] + + operations = [ + migrations.AddField( + model_name='question', + name='YNNS_question', + field=models.BooleanField(default=False, help_text='Check the box to create a question of Yes, No or NS/NC', verbose_name='Answers Yes, No, NS/NC'), + ), + ] diff --git a/decide/voting/migrations/0010_merge_20220105_1639.py b/decide/voting/migrations/0010_merge_20220105_1639.py new file mode 100644 index 0000000000..a7b2848b94 --- /dev/null +++ b/decide/voting/migrations/0010_merge_20220105_1639.py @@ -0,0 +1,14 @@ +# Generated by Django 2.0 on 2022-01-05 16:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('voting', '0007_merge_20220103_1820'), + ('voting', '0009_question_ynns_question'), + ] + + operations = [ + ] diff --git a/decide/voting/models.py b/decide/voting/models.py index 64239f5022..4e03a4ec1d 100644 --- a/decide/voting/models.py +++ b/decide/voting/models.py @@ -4,24 +4,9 @@ from django.contrib.postgres.fields import JSONField from django.db.models.signals import post_save from django.dispatch import receiver -from django.core.validators import MinValueValidator, MaxValueValidator from base import mods from base.models import Auth, Key -class Detector(models.Model): - word = models.TextField() - - def __str__(self): - return self.word - -class Percentage(models.Model): - number = models.PositiveIntegerField(validators=[MinValueValidator(0), MaxValueValidator(100)]) - - def __str__(self): - return str(self.number) - - - class Question(models.Model): desc = models.TextField() def clean(self): @@ -32,7 +17,12 @@ def clean(self): def __str__(self): return self.desc + YNNS_question = models.BooleanField(default=False,verbose_name="Answers Yes, No, NS/NC", help_text="Check the box to create a question of Yes, No or NS/NC") + def __str__(self): + return self.desc + +@receiver(post_save, sender=Question) def check_question(sender, instance, **kwargs): if instance.binary_question==True and instance.options.all().count()==0: option1 = QuestionOption(question=instance, number=1, option="Si") @@ -40,6 +30,16 @@ def check_question(sender, instance, **kwargs): option2 = QuestionOption(question=instance, number=2, option="No") option2.save() +@receiver(post_save, sender=Question) +def check_question(sender, instance, **kwargs): + if instance.YNNS_question==True and instance.options.all().count()==0: + option1 = QuestionOption(question=instance, number=1, option="Si") + option1.save() + option2 = QuestionOption(question=instance, number=2, option="No") + option2.save() + option2 = QuestionOption(question=instance, number=3, option="NS/NC") + option2.save() + class QuestionOption(models.Model): question = models.ForeignKey(Question, related_name='options', on_delete=models.CASCADE) diff --git a/decide/voting/serializers.py b/decide/voting/serializers.py index 14480ea283..ac45721ee3 100644 --- a/decide/voting/serializers.py +++ b/decide/voting/serializers.py @@ -1,19 +1,8 @@ from rest_framework import serializers -from . import validators -from .models import Detector, Percentage, Question, QuestionOption, Voting +from .validators import lofensivo +from .models import Question, QuestionOption, Voting from base.serializers import KeySerializer, AuthSerializer - -class DetectorSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = Detector - fields = ('word') - -class PercentageSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = Percentage - fields = ('number') - class QuestionOptionSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = QuestionOption @@ -23,7 +12,7 @@ class Meta: class QuestionSerializer(serializers.HyperlinkedModelSerializer): options = QuestionOptionSerializer(many=True) def validate_desc(self, data): - if(validators.lofensivo(data['desc'])): + if(lofensivo(data['desc'])): raise serializers.ValidationError("Se ha detectado lenguaje ofensivo") return data class Meta: @@ -33,7 +22,7 @@ class Meta: class VotingSerializer(serializers.HyperlinkedModelSerializer): question = QuestionSerializer(many=False) - validators.lofensivo(question.Meta.fields[1]) + lofensivo(question.Meta.fields[1]) pub_key = KeySerializer() auths = AuthSerializer(many=True) diff --git a/decide/voting/tests.py b/decide/voting/tests.py index cfeb6c1228..a04a590036 100644 --- a/decide/voting/tests.py +++ b/decide/voting/tests.py @@ -6,14 +6,14 @@ from django.test import TestCase from rest_framework.test import APIClient from rest_framework.test import APITestCase - +from django.core.exceptions import ValidationError from base import mods from base.tests import BaseTestCase from census.models import Census from mixnet.mixcrypt import ElGamal from mixnet.mixcrypt import MixCrypt from mixnet.models import Auth -from voting.models import Voting, Question, QuestionOption, Detector, Percentage +from voting.models import Voting, Question, QuestionOption class VotingTestCase(BaseTestCase): @@ -106,27 +106,25 @@ def test_complete_voting(self): for q in v.postproc: self.assertEqual(tally.get(q["number"], 0), q["votes"]) - def test_create_detector_word(self): - detector = Detector(word="palabra") - detector.save() - self.assertEqual(detector.word, "palabra") - - def test_create_percentage(self): - percentage = Percentage(number=25) - percentage.save() - self.assertEqual(percentage.number, 25) - - def test_update_detector(self): - detector = Detector(word="palabra") - detector.word = "palabra2" - detector.save() - self.assertEqual(detector.word, "palabra2") - - def test_update_percentage(self): - percentage = Percentage(number=25) - percentage.number = 30 - percentage.save() - self.assertEqual(percentage.number, 30) + def test_lofensivo_dont_pass(self): + self.login() + question = Question(desc='Tonto, esta descripcion contiene alguna palabra ofensiva? Pis, ceporro') + with self.assertRaises(ValidationError): + question.clean() + + def test_lofensivo_pass_by_words(self): + self.login() + question = Question(desc='Esta descripcion no contiene lenguaje ofensivo') + question.clean() + self.assertEqual(question.desc, 'Esta descripcion no contiene lenguaje ofensivo') + + def test_lofensivo_pass_by_percentage(self): + self.login() + question = Question(desc='Esta descripcion contiene solo una palabra ofensiva, tonto, pero se necesita que el 20 por ciento sean palabras ofensivas') + question.clean() + self.assertEqual(question.desc, 'Esta descripcion contiene solo una palabra ofensiva, tonto, pero se necesita que el 20 por ciento sean palabras ofensivas') + + def test_create_voting_from_api(self): data = {'name': 'Example'} diff --git a/decide/voting/validators.py b/decide/voting/validators.py index 4b6c840ea1..aa056a7362 100644 --- a/decide/voting/validators.py +++ b/decide/voting/validators.py @@ -1,15 +1,10 @@ -from django.core.exceptions import ValidationError -#from . import models -"""Comentar y descomentar lsofensiva para hacer las migraciones de las bd, por defecto da - error si se hace con los datos de los modelos""" + +import unicodedata + def lofensivo(value): - lsofensiva=[] - #lsofensiva = models.Detector.objects.all() - lsofensiva2 =[] - - for detector in lsofensiva: - lsofensiva2.append(detector.word) + + lsofensiva = ["caca", "pedo", "pis", "pilila", "ceporro", "tonto", "imbecil", "estupido", "idiota"] if("¿" in value): value=value.replace("¿", "") @@ -24,23 +19,20 @@ def lofensivo(value): if(")" in value): value=value.replace(")", "") - value=value.lower() + value=value.lower() + trans_tab = dict.fromkeys(map(ord, u'\u0301\u0308'), None) + value = unicodedata.normalize('NFKC', unicodedata.normalize('NFKD', value).translate(trans_tab)) palabras = value.split() - - #numero= models.Percentage.objects.last() - #numero= 15 - # if len(models.Percentage.objects.all())==0: - # numero= models.Percentage(number=15) -# numero.save() - #porcentaje= numero.number /100 - porcentaje= 15 /100 + + porcentaje= 20 / 100 + cont = 0 res= False for palabra in palabras: - if(palabra in lsofensiva2): + if(palabra in lsofensiva): cont+=1 if(cont/len(palabras)>porcentaje): diff --git a/docker/Dockerfile b/docker/Dockerfile index 032eed28e2..d88410f73b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -from python:alpine +from python:3.7-alpine RUN apk add --no-cache git postgresql-dev gcc libc-dev RUN apk add --no-cache gcc g++ make libffi-dev python3-dev build-base @@ -10,7 +10,8 @@ RUN pip install ipython WORKDIR /app -RUN git clone https://github.com/wadobo/decide.git . +#RUN git clone https://github.com/wadobo/decide.git . +RUN git clone https://github.com/bencrealc/Decide.git . RUN pip install -r requirements.txt WORKDIR /app/decide diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 095583eb02..4689c5ff98 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -4,11 +4,13 @@ services: db: restart: always container_name: decide_db - image: postgres:alpine + image: postgres:10.15-alpine volumes: - db:/var/lib/postgresql/data networks: - decide + environment: + - POSTGRES_PASSWORD=postgres web: restart: always container_name: decide_web diff --git a/docker/docker-settings.py b/docker/docker-settings.py index 01e643d936..850dc750a4 100644 --- a/docker/docker-settings.py +++ b/docker/docker-settings.py @@ -5,6 +5,7 @@ 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'postgres', 'USER': 'postgres', + 'PASSWORD':'postgres', 'HOST': 'db', 'PORT': 5432, }