mirror of
https://github.com/Sosokker/ku-polls.git
synced 2025-12-19 05:24:05 +01:00
Format file according to flake8
This commit is contained in:
parent
c81dea9a14
commit
f97a772bf3
12
.flake8
Normal file
12
.flake8
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[flake8]
|
||||||
|
max-line-length = 120
|
||||||
|
exclude=
|
||||||
|
migrations
|
||||||
|
mysite
|
||||||
|
logs
|
||||||
|
.venv
|
||||||
|
apps.py
|
||||||
|
setup.py
|
||||||
|
per-file-ignores =
|
||||||
|
.\polls\tests\test_sentiment_model.py: E501
|
||||||
|
.\polls\models.py: F811
|
||||||
@ -17,12 +17,13 @@ class QuestionAdmin(admin.ModelAdmin):
|
|||||||
("Long Description", {"fields": ["long_description"], "classes": ["collapse"]}),
|
("Long Description", {"fields": ["long_description"], "classes": ["collapse"]}),
|
||||||
("Add Tag", {"fields": ["tags"], "classes": ["collapse"]})
|
("Add Tag", {"fields": ["tags"], "classes": ["collapse"]})
|
||||||
]
|
]
|
||||||
list_display = ["question_text", "pub_date", "end_date", "was_published_recently", "can_vote", "trending_score", "get_tags"]
|
list_display = ["question_text", "pub_date", "end_date", "was_published_recently", "can_vote",
|
||||||
|
"trending_score", "get_tags"]
|
||||||
inlines = [ChoiceInline]
|
inlines = [ChoiceInline]
|
||||||
list_filter = ["pub_date", "end_date"]
|
list_filter = ["pub_date", "end_date"]
|
||||||
search_fields = ["question_text"]
|
search_fields = ["question_text"]
|
||||||
|
|
||||||
|
|
||||||
# https://stackoverflow.com/questions/10904848/adding-inline-many-to-many-objects-in-django-admin
|
# https://stackoverflow.com/questions/10904848/adding-inline-many-to-many-objects-in-django-admin
|
||||||
admin.site.register(Question, QuestionAdmin)
|
admin.site.register(Question, QuestionAdmin)
|
||||||
admin.site.register(Tag) # Add Field to modify tags objects in Question
|
admin.site.register(Tag) # Add Field to modify tags objects in Question
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ from django.apps import AppConfig
|
|||||||
class PollsConfig(AppConfig):
|
class PollsConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
name = 'polls'
|
name = 'polls'
|
||||||
|
|
||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
import polls.signals
|
import polls.signals
|
||||||
|
|
||||||
@ -7,18 +7,19 @@ from django.contrib.auth.models import User
|
|||||||
|
|
||||||
from .models import Question, Tag
|
from .models import Question, Tag
|
||||||
|
|
||||||
|
|
||||||
class SignUpForm(UserCreationForm):
|
class SignUpForm(UserCreationForm):
|
||||||
tailwind_class = "w-full border-2 border-gray-300 bg-gray-100 rounded-lg focus:ring focus:border-blue-300 focus:shadow-none"
|
tailwind_class = """w-full border-2 border-gray-300 bg-gray-100 rounded-lg
|
||||||
|
focus:ring focus:border-blue-300 focus:shadow-none"""
|
||||||
logger = logging.getLogger('signup_form')
|
logger = logging.getLogger('signup_form')
|
||||||
username = forms.CharField(widget=forms.TextInput(attrs={'class': tailwind_class}),
|
username = forms.CharField(widget=forms.TextInput(attrs={'class': tailwind_class}), error_messages={
|
||||||
error_messages={
|
'unique': 'This username is already in use.',
|
||||||
'unique': 'This username is already in use.',
|
'invalid': 'Invalid username format.',
|
||||||
'invalid': 'Invalid username format.',
|
'max_length': 'Username should not exceed 150 characters.',
|
||||||
'max_length': 'Username should not exceed 150 characters.',
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'class': tailwind_class}),
|
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'class': tailwind_class}),
|
||||||
error_messages={'min_length': 'Password must contain at least 8 characters.',}
|
error_messages={'min_length': 'Password must contain at least 8 characters.', }
|
||||||
)
|
)
|
||||||
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class': tailwind_class}),)
|
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class': tailwind_class}),)
|
||||||
|
|
||||||
@ -49,15 +50,24 @@ class PollSearchForm(forms.Form):
|
|||||||
|
|
||||||
|
|
||||||
class PollCreateForm(forms.ModelForm):
|
class PollCreateForm(forms.ModelForm):
|
||||||
box_style = "w-full py-2 px-2 border-2 border-gray-300 bg-gray-100 rounded-lg focus:ring focus:border-blue-300 focus:shadow-none"
|
box_style = """w-full py-2 px-2 border-2 border-gray-300 bg-gray-100 rounded-lg
|
||||||
large_box_style = "w-full border-2 border-gray-300 bg-gray-100 rounded-lg focus:ring focus:border-blue-300 focus:shadow-none"
|
focus:ring focus:border-blue-300 focus:shadow-none"""
|
||||||
|
large_box_style = """w-full border-2 border-gray-300 bg-gray-100 rounded-lg
|
||||||
|
focus:ring focus:border-blue-300 focus:shadow-none"""
|
||||||
|
|
||||||
question_text = forms.CharField(min_length=10, max_length=100, required=True,
|
question_text = forms.CharField(min_length=10, max_length=100, required=True,
|
||||||
widget=forms.TextInput(attrs={'class':box_style, 'placeholder':"What is your question?"}))
|
widget=forms.TextInput(attrs={'class': box_style,
|
||||||
|
'placeholder': "What is your question?"}))
|
||||||
pub_date = forms.DateTimeField(widget=forms.DateInput(attrs={'type': 'date'}))
|
pub_date = forms.DateTimeField(widget=forms.DateInput(attrs={'type': 'date'}))
|
||||||
end_date = forms.DateTimeField(widget=forms.DateInput(attrs={'type': 'date'}))
|
end_date = forms.DateTimeField(widget=forms.DateInput(attrs={'type': 'date'}))
|
||||||
short_description = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'class':box_style, 'placeholder':"Short description (Maximum 200 characters)"}))
|
short_description = forms.CharField(max_length=200,
|
||||||
long_description = forms.CharField(max_length=2000, widget=forms.Textarea(attrs={'class':large_box_style, 'placeholder':"Long description (Maximum 2000 characters)"}))
|
widget=forms.TextInput(
|
||||||
|
attrs={'class': box_style,
|
||||||
|
'placeholder': "Short description (Maximum 200 characters)"}))
|
||||||
|
long_description = forms.CharField(max_length=2000,
|
||||||
|
widget=forms.Textarea(
|
||||||
|
attrs={'class': large_box_style,
|
||||||
|
'placeholder': "Long description (Maximum 2000 characters)"}))
|
||||||
tags = forms.MultipleChoiceField(
|
tags = forms.MultipleChoiceField(
|
||||||
choices=[(tag.id, tag.tag_text) for tag in Tag.objects.all()],
|
choices=[(tag.id, tag.tag_text) for tag in Tag.objects.all()],
|
||||||
widget=forms.CheckboxSelectMultiple,
|
widget=forms.CheckboxSelectMultiple,
|
||||||
@ -69,7 +79,7 @@ class PollCreateForm(forms.ModelForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Question
|
model = Question
|
||||||
fields = ['question_text', 'pub_date', 'end_date', 'short_description', 'long_description', 'tags']
|
fields = ['question_text', 'pub_date', 'end_date', 'short_description', 'long_description', 'tags']
|
||||||
|
|
||||||
@ -12,7 +12,6 @@ Attributes:
|
|||||||
from django.db import models, IntegrityError
|
from django.db import models, IntegrityError
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.db.models import Sum
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
@ -169,7 +168,7 @@ class Question(models.Model):
|
|||||||
self.save()
|
self.save()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
vote = self.sentimentvote_set.filter(user=user)
|
vote = self.sentimentvote_set.filter(user=user)
|
||||||
if vote[0].vote_types == False:
|
if vote[0].vote_types is False:
|
||||||
vote.update(vote_types=True)
|
vote.update(vote_types=True)
|
||||||
self.save()
|
self.save()
|
||||||
else:
|
else:
|
||||||
@ -185,7 +184,7 @@ class Question(models.Model):
|
|||||||
self.save()
|
self.save()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
vote = self.sentimentvote_set.filter(user=user)
|
vote = self.sentimentvote_set.filter(user=user)
|
||||||
if vote[0].vote_types == True:
|
if vote[0].vote_types is True:
|
||||||
vote.update(vote_types=False)
|
vote.update(vote_types=False)
|
||||||
self.save()
|
self.save()
|
||||||
else:
|
else:
|
||||||
@ -207,8 +206,8 @@ class Question(models.Model):
|
|||||||
published_date_duration = timezone.now() - self.pub_date
|
published_date_duration = timezone.now() - self.pub_date
|
||||||
score = 0
|
score = 0
|
||||||
|
|
||||||
if (published_date_duration.seconds < 259200): # Second unit
|
if (published_date_duration.seconds < 259200): # Second unit
|
||||||
score += 100
|
score += 100
|
||||||
elif (published_date_duration.seconds < 604800):
|
elif (published_date_duration.seconds < 604800):
|
||||||
score += 75
|
score += 75
|
||||||
elif (published_date_duration.seconds < 2592000):
|
elif (published_date_duration.seconds < 2592000):
|
||||||
@ -216,7 +215,7 @@ class Question(models.Model):
|
|||||||
else:
|
else:
|
||||||
score += 25
|
score += 25
|
||||||
|
|
||||||
if (up == None) and (down == None):
|
if (up is None) and (down is None):
|
||||||
score += ((self.up_vote_count/5) - (self.down_vote_count/5)) * 100
|
score += ((self.up_vote_count/5) - (self.down_vote_count/5)) * 100
|
||||||
else:
|
else:
|
||||||
score += ((up/5) - (down/5)) * 100
|
score += ((up/5) - (down/5)) * 100
|
||||||
@ -226,10 +225,10 @@ class Question(models.Model):
|
|||||||
def get_tags(self, *args, **kwargs):
|
def get_tags(self, *args, **kwargs):
|
||||||
return "-".join([tag.tag_text for tag in self.tags.all()])
|
return "-".join([tag.tag_text for tag in self.tags.all()])
|
||||||
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""Modify save method of Question object"""
|
"""Modify save method of Question object"""
|
||||||
# to-be-added instance # * https://github.com/django/django/blob/866122690dbe233c054d06f6afbc2f3cc6aea2f2/django/db/models/base.py#L447
|
# to-be-added instance
|
||||||
|
# * https://github.com/django/django/blob/866122690dbe233c054d06f6afbc2f3cc6aea2f2/django/db/models/base.py#L447
|
||||||
if self._state.adding:
|
if self._state.adding:
|
||||||
try:
|
try:
|
||||||
self.trend_score = self.trending_score()
|
self.trend_score = self.trending_score()
|
||||||
@ -271,7 +270,7 @@ class Vote(models.Model):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.user} voted for {self.choice} in {self.question}"
|
return f"{self.user} voted for {self.choice} in {self.question}"
|
||||||
|
|
||||||
|
|
||||||
# ! Most of the code from https://stackoverflow.com/a/70869267
|
# ! Most of the code from https://stackoverflow.com/a/70869267
|
||||||
class SentimentVote(models.Model):
|
class SentimentVote(models.Model):
|
||||||
@ -296,4 +295,4 @@ class SentimentVote(models.Model):
|
|||||||
unique_together (list of str): Ensures that a user can only cast one sentiment vote (upvote or downvote)
|
unique_together (list of str): Ensures that a user can only cast one sentiment vote (upvote or downvote)
|
||||||
for a specific question.
|
for a specific question.
|
||||||
"""
|
"""
|
||||||
unique_together = ['user', 'question']
|
unique_together = ['user', 'question']
|
||||||
|
|||||||
@ -4,6 +4,7 @@ from django.dispatch import receiver
|
|||||||
|
|
||||||
log = logging.getLogger("django")
|
log = logging.getLogger("django")
|
||||||
|
|
||||||
|
|
||||||
def get_client_ip(request):
|
def get_client_ip(request):
|
||||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||||
if x_forwarded_for:
|
if x_forwarded_for:
|
||||||
@ -12,9 +13,10 @@ def get_client_ip(request):
|
|||||||
ip = request.META.get('REMOTE_ADDR')
|
ip = request.META.get('REMOTE_ADDR')
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
#! https://stackoverflow.com/questions/37618473/how-can-i-log-both-successful-and-failed-login-and-logout-attempts-in-django
|
|
||||||
|
# !https://stackoverflow.com/questions/37618473/how-can-i-log-both-successful-and-failed-login-and-logout-attempts-in-django
|
||||||
@receiver(user_logged_in)
|
@receiver(user_logged_in)
|
||||||
def user_logged_in_callback(sender, request, user, **kwargs):
|
def user_logged_in_callback(sender, request, user, **kwargs):
|
||||||
ip = get_client_ip(request)
|
ip = get_client_ip(request)
|
||||||
|
|
||||||
log.info('Login User: {user} via ip: {ip}'.format(
|
log.info('Login User: {user} via ip: {ip}'.format(
|
||||||
@ -22,8 +24,9 @@ def user_logged_in_callback(sender, request, user, **kwargs):
|
|||||||
ip=ip
|
ip=ip
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
@receiver(user_logged_out)
|
@receiver(user_logged_out)
|
||||||
def user_logged_out_callback(sender, request, user, **kwargs):
|
def user_logged_out_callback(sender, request, user, **kwargs):
|
||||||
ip = get_client_ip(request)
|
ip = get_client_ip(request)
|
||||||
|
|
||||||
log.info('Logout User: {user} via ip: {ip}'.format(
|
log.info('Logout User: {user} via ip: {ip}'.format(
|
||||||
@ -31,8 +34,9 @@ def user_logged_out_callback(sender, request, user, **kwargs):
|
|||||||
ip=ip
|
ip=ip
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
@receiver(user_login_failed)
|
@receiver(user_login_failed)
|
||||||
def user_login_failed_callback(sender, credentials, **kwargs):
|
def user_login_failed_callback(sender, credentials, **kwargs):
|
||||||
log.warning('Login Failed for: {credentials}'.format(
|
log.warning('Login Failed for: {credentials}'.format(
|
||||||
credentials=credentials,
|
credentials=credentials,
|
||||||
))
|
))
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.models import User
|
|
||||||
|
|
||||||
from ..models import Question, Vote, Choice
|
from ..models import Question
|
||||||
|
|
||||||
|
|
||||||
def create_question(question_text, day=0):
|
def create_question(question_text, day=0):
|
||||||
@ -11,4 +10,4 @@ def create_question(question_text, day=0):
|
|||||||
in the past, positive for questions that have yet to be published).
|
in the past, positive for questions that have yet to be published).
|
||||||
"""
|
"""
|
||||||
time = timezone.now() + timezone.timedelta(days=day)
|
time = timezone.now() + timezone.timedelta(days=day)
|
||||||
return Question.objects.create(question_text=question_text, pub_date=time)
|
return Question.objects.create(question_text=question_text, pub_date=time)
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
from django.utils import timezone
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|||||||
@ -102,4 +102,4 @@ class QuestionModelTests(TestCase):
|
|||||||
pub_date = timezone.now() - datetime.timedelta(hours=1)
|
pub_date = timezone.now() - datetime.timedelta(hours=1)
|
||||||
end_date = timezone.now() + datetime.timedelta(hours=2)
|
end_date = timezone.now() + datetime.timedelta(hours=2)
|
||||||
question = Question(pub_date=pub_date, end_date=end_date)
|
question = Question(pub_date=pub_date, end_date=end_date)
|
||||||
self.assertIs(question.can_vote(), True)
|
self.assertIs(question.can_vote(), True)
|
||||||
|
|||||||
@ -2,7 +2,6 @@ from django.test import TestCase
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from ..models import Question
|
from ..models import Question
|
||||||
from ..views import search_poll
|
|
||||||
|
|
||||||
|
|
||||||
class SearchPollTest(TestCase):
|
class SearchPollTest(TestCase):
|
||||||
@ -22,4 +21,3 @@ class SearchPollTest(TestCase):
|
|||||||
data = {'q': ''}
|
data = {'q': ''}
|
||||||
response = self.client.get(reverse("polls:search_poll"), data)
|
response = self.client.get(reverse("polls:search_poll"), data)
|
||||||
self.assertQuerysetEqual(response.context['results'], Question.objects.all())
|
self.assertQuerysetEqual(response.context['results'], Question.objects.all())
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ from django.test import TransactionTestCase, Client
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from .base import create_question
|
from .base import create_question
|
||||||
from ..views import up_down_vote
|
|
||||||
|
|
||||||
# ! https://stackoverflow.com/questions/24588520/testing-several-integrityerrors-in-the-same-django-unittest-test-case
|
# ! https://stackoverflow.com/questions/24588520/testing-several-integrityerrors-in-the-same-django-unittest-test-case
|
||||||
# * https://stackoverflow.com/questions/44450533/difference-between-testcase-and-transactiontestcase-classes-in-django-test
|
# * https://stackoverflow.com/questions/44450533/difference-between-testcase-and-transactiontestcase-classes-in-django-test
|
||||||
@ -32,11 +32,11 @@ class UpDownVoteViewTest(TransactionTestCase):
|
|||||||
self.assertEqual(count_up, 0)
|
self.assertEqual(count_up, 0)
|
||||||
self.assertEqual(count_down, 1)
|
self.assertEqual(count_down, 1)
|
||||||
|
|
||||||
def test_can_change_up_to_down(self):
|
def test_can_change_down_to_up(self):
|
||||||
self.client.login(username="test_user", password="12345abc")
|
self.client.login(username="test_user", password="12345abc")
|
||||||
self.q1.downvote(self.user)
|
self.q1.downvote(self.user)
|
||||||
self.q1.upvote(self.user)
|
self.q1.upvote(self.user)
|
||||||
count_up = self.q1.sentimentvote_set.filter(vote_types=True).count()
|
count_up = self.q1.sentimentvote_set.filter(vote_types=True).count()
|
||||||
count_down = self.q1.sentimentvote_set.filter(vote_types=False).count()
|
count_down = self.q1.sentimentvote_set.filter(vote_types=False).count()
|
||||||
self.assertEqual(count_up, 1)
|
self.assertEqual(count_up, 1)
|
||||||
self.assertEqual(count_down, 0)
|
self.assertEqual(count_down, 0)
|
||||||
|
|||||||
@ -42,4 +42,4 @@ class SignUpTestCase(TestCase):
|
|||||||
'password2': 'testpassword123',
|
'password2': 'testpassword123',
|
||||||
}
|
}
|
||||||
response = self.client.post(signup_url, data)
|
response = self.client.post(signup_url, data)
|
||||||
self.assertRedirects(response, reverse("polls:index"))
|
self.assertRedirects(response, reverse("polls:index"))
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from django.contrib.auth.models import User
|
|||||||
from .base import create_question
|
from .base import create_question
|
||||||
from ..models import Vote, Choice
|
from ..models import Vote, Choice
|
||||||
|
|
||||||
|
|
||||||
class VoteViewTest(TestCase):
|
class VoteViewTest(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -20,9 +21,9 @@ class VoteViewTest(TestCase):
|
|||||||
"""
|
"""
|
||||||
self.client.login(username=self.user.username, password="aaa123321aaa")
|
self.client.login(username=self.user.username, password="aaa123321aaa")
|
||||||
|
|
||||||
response = self.client.post(reverse("polls:vote", args=(self.question.id,)),
|
response = self.client.post(reverse("polls:vote", args=(self.question.id,)),
|
||||||
{'choice' : self.choice1.id})
|
{'choice': self.choice1.id})
|
||||||
|
|
||||||
self.assertRedirects(response, reverse("polls:results", args=(self.question.id,)))
|
self.assertRedirects(response, reverse("polls:results", args=(self.question.id,)))
|
||||||
self.assertTrue(Vote.objects.filter(user=self.user, question=self.question).exists())
|
self.assertTrue(Vote.objects.filter(user=self.user, question=self.question).exists())
|
||||||
|
|
||||||
@ -32,18 +33,18 @@ class VoteViewTest(TestCase):
|
|||||||
"""
|
"""
|
||||||
self.client.login(username=self.user.username, password="aaa123321aaa")
|
self.client.login(username=self.user.username, password="aaa123321aaa")
|
||||||
|
|
||||||
response = self.client.post(reverse("polls:vote", args=(self.question.id,)),
|
response = self.client.post(reverse("polls:vote", args=(self.question.id,)),
|
||||||
{'choice' : 1000})
|
{'choice': 1000})
|
||||||
|
|
||||||
self.assertRedirects(response, reverse('polls:detail', args=(self.question.id,)))
|
self.assertRedirects(response, reverse('polls:detail', args=(self.question.id,)))
|
||||||
|
|
||||||
def test_vote_without_login(self):
|
def test_vote_without_login(self):
|
||||||
"""
|
"""
|
||||||
Test the vote view when the user is not logged in.
|
Test the vote view when the user is not logged in.
|
||||||
"""
|
"""
|
||||||
response = self.client.post(reverse("polls:vote", args=(self.question.id,)),
|
response = self.client.post(reverse("polls:vote", args=(self.question.id,)),
|
||||||
{'choice' : self.choice1})
|
{'choice': self.choice1})
|
||||||
|
|
||||||
self.assertRedirects(response, "/accounts/login/?next=/polls/1/vote/")
|
self.assertRedirects(response, "/accounts/login/?next=/polls/1/vote/")
|
||||||
|
|
||||||
def test_vote_voting_not_allowed(self):
|
def test_vote_voting_not_allowed(self):
|
||||||
@ -55,9 +56,8 @@ class VoteViewTest(TestCase):
|
|||||||
self.question_2 = create_question(question_text="Test not allow", day=10)
|
self.question_2 = create_question(question_text="Test not allow", day=10)
|
||||||
self.choice_2 = Choice.objects.create(question=self.question_2, choice_text="Test Choice 2_2")
|
self.choice_2 = Choice.objects.create(question=self.question_2, choice_text="Test Choice 2_2")
|
||||||
|
|
||||||
response = self.client.post(reverse("polls:vote", args=(self.question_2.id,)),
|
response = self.client.post(reverse("polls:vote", args=(self.question_2.id,)), {"choice": self.choice_2.id})
|
||||||
{"choice" : self.choice_2.id})
|
|
||||||
|
|
||||||
self.assertRedirects(response, reverse('polls:index'))
|
self.assertRedirects(response, reverse('polls:index'))
|
||||||
|
|
||||||
def test_vote_with_no_post_data(self):
|
def test_vote_with_no_post_data(self):
|
||||||
@ -81,6 +81,6 @@ class VoteViewTest(TestCase):
|
|||||||
|
|
||||||
response_2 = self.client.post(reverse("polls:vote", args=(self.question.id,)), {"choice": self.choice2.id})
|
response_2 = self.client.post(reverse("polls:vote", args=(self.question.id,)), {"choice": self.choice2.id})
|
||||||
self.assertRedirects(response_2, reverse('polls:results', args=(self.question.id,)))
|
self.assertRedirects(response_2, reverse('polls:results', args=(self.question.id,)))
|
||||||
|
|
||||||
self.assertFalse(Vote.objects.filter(user=self.user, question=self.question, choice=self.choice1).exists())
|
self.assertFalse(Vote.objects.filter(user=self.user, question=self.question, choice=self.choice1).exists())
|
||||||
self.assertTrue(Vote.objects.filter(user=self.user, question=self.question, choice=self.choice2).exists())
|
self.assertTrue(Vote.objects.filter(user=self.user, question=self.question, choice=self.choice2).exists())
|
||||||
|
|||||||
@ -9,8 +9,8 @@ urlpatterns = [
|
|||||||
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
|
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
|
||||||
path("<int:question_id>/vote/", views.vote, name="vote"),
|
path("<int:question_id>/vote/", views.vote, name="vote"),
|
||||||
path("signup/", views.SignUpView.as_view(), name="signup"),
|
path("signup/", views.SignUpView.as_view(), name="signup"),
|
||||||
path("upvote/<int:question_id>", views.up_down_vote, {'vote_type' : 'upvote'}, name="upvote"),
|
path("upvote/<int:question_id>", views.up_down_vote, {'vote_type': 'upvote'}, name="upvote"),
|
||||||
path("downvote/<int:question_id>", views.up_down_vote, {'vote_type' : 'downvote'}, name="downvote"),
|
path("downvote/<int:question_id>", views.up_down_vote, {'vote_type': 'downvote'}, name="downvote"),
|
||||||
path("search", views.search_poll, name="search_poll"),
|
path("search", views.search_poll, name="search_poll"),
|
||||||
path("create", views.create_poll, name="create_poll")
|
path("create", views.create_poll, name="create_poll")
|
||||||
]
|
]
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import logging
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render, redirect
|
from django.shortcuts import get_object_or_404, render, redirect
|
||||||
from django.urls import reverse
|
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.urls import reverse_lazy, reverse
|
from django.urls import reverse_lazy, reverse
|
||||||
@ -26,21 +25,21 @@ class IndexView(generic.ListView):
|
|||||||
context_object_name = "latest_question_list"
|
context_object_name = "latest_question_list"
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
"""
|
"""
|
||||||
Return the last published questions that is published and haven't ended yet.
|
Return the last published questions that is published and haven't ended yet.
|
||||||
"""
|
"""
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
all_poll_queryset = Question.objects.filter(
|
all_poll_queryset = Question.objects.filter(
|
||||||
Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None)))
|
Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None)))
|
||||||
).order_by("-pub_date")
|
).order_by("-pub_date")
|
||||||
|
|
||||||
trend_poll_queryset = Question.objects.filter(
|
trend_poll_queryset = Question.objects.filter(
|
||||||
Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None))) & Q(trend_score__gte=100)
|
Q(pub_date__lte=now) & ((Q(end_date__gte=now) | Q(end_date=None))) & Q(trend_score__gte=100)
|
||||||
).order_by("trend_score", "end_date")[:3]
|
).order_by("trend_score")[:3]
|
||||||
|
|
||||||
queryset = {'all_poll' : all_poll_queryset,
|
queryset = {'all_poll': all_poll_queryset,
|
||||||
'trend_poll' : trend_poll_queryset,}
|
'trend_poll': trend_poll_queryset, }
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class DetailView(LoginRequiredMixin, generic.DetailView):
|
class DetailView(LoginRequiredMixin, generic.DetailView):
|
||||||
@ -102,7 +101,7 @@ class ResultsView(LoginRequiredMixin, generic.DetailView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
user_voted = None
|
user_voted = None
|
||||||
question = self.get_object()
|
question = self.get_object()
|
||||||
if question.sentimentvote_set.filter(user=self.request.user, question=question, vote_types=True).exists():
|
if question.sentimentvote_set.filter(user=self.request.user, question=question, vote_types=True).exists():
|
||||||
@ -113,6 +112,7 @@ class ResultsView(LoginRequiredMixin, generic.DetailView):
|
|||||||
context['user_voted'] = user_voted
|
context['user_voted'] = user_voted
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class SignUpView(generic.CreateView):
|
class SignUpView(generic.CreateView):
|
||||||
"""
|
"""
|
||||||
View that responsible for Sign Up page.
|
View that responsible for Sign Up page.
|
||||||
@ -153,7 +153,7 @@ def vote(request, question_id):
|
|||||||
vote, created = Vote.objects.update_or_create(
|
vote, created = Vote.objects.update_or_create(
|
||||||
user=request.user,
|
user=request.user,
|
||||||
question=question,
|
question=question,
|
||||||
defaults={'choice' : selected_choice}
|
defaults={'choice': selected_choice}
|
||||||
)
|
)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
@ -170,16 +170,15 @@ def vote(request, question_id):
|
|||||||
else:
|
else:
|
||||||
messages.error(request, "Invalid request method.")
|
messages.error(request, "Invalid request method.")
|
||||||
return redirect("polls:index")
|
return redirect("polls:index")
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def up_down_vote(request, question_id, vote_type):
|
def up_down_vote(request, question_id, vote_type):
|
||||||
"""
|
"""
|
||||||
A function that control the upvote and downvote request.
|
A function that control the upvote and downvote request.
|
||||||
"""
|
"""
|
||||||
ip = get_client_ip(request)
|
|
||||||
question = get_object_or_404(Question, pk=question_id)
|
question = get_object_or_404(Question, pk=question_id)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if vote_type == "upvote":
|
if vote_type == "upvote":
|
||||||
if question.upvote(request.user):
|
if question.upvote(request.user):
|
||||||
@ -187,7 +186,7 @@ def up_down_vote(request, question_id, vote_type):
|
|||||||
elif vote_type == "downvote":
|
elif vote_type == "downvote":
|
||||||
if question.downvote(request.user):
|
if question.downvote(request.user):
|
||||||
messages.success(request, "You downvoted this Poll😭")
|
messages.success(request, "You downvoted this Poll😭")
|
||||||
|
|
||||||
return redirect(reverse("polls:results", args=(question_id,)))
|
return redirect(reverse("polls:results", args=(question_id,)))
|
||||||
|
|
||||||
|
|
||||||
@ -207,7 +206,7 @@ def get_client_ip(request):
|
|||||||
def search_poll(request):
|
def search_poll(request):
|
||||||
"""
|
"""
|
||||||
A function that handle the rendering of search result after user search with
|
A function that handle the rendering of search result after user search with
|
||||||
search bar.
|
search bar.
|
||||||
"""
|
"""
|
||||||
form = PollSearchForm
|
form = PollSearchForm
|
||||||
|
|
||||||
@ -222,7 +221,7 @@ def search_poll(request):
|
|||||||
# * If user search with empty string then show every poll.
|
# * If user search with empty string then show every poll.
|
||||||
if q == '':
|
if q == '':
|
||||||
results = Question.objects.all()
|
results = Question.objects.all()
|
||||||
return render(request, 'polls/search.html', {'form':form, 'results':results, 'q':q})
|
return render(request, 'polls/search.html', {'form': form, 'results': results, 'q': q})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
19
setup.py
19
setup.py
@ -17,7 +17,7 @@ def check_python_command():
|
|||||||
return command
|
return command
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def create_virtual_environment(env_name, python_command):
|
def create_virtual_environment(env_name, python_command):
|
||||||
@ -31,7 +31,7 @@ def customize_virtual_environment():
|
|||||||
|
|
||||||
def setup_environment_variables(python_command_in_venv):
|
def setup_environment_variables(python_command_in_venv):
|
||||||
print("Setting up Django environment variables:")
|
print("Setting up Django environment variables:")
|
||||||
|
|
||||||
# SECRET KEY
|
# SECRET KEY
|
||||||
generate_secret_key = input("Generate a Django SECRET_KEY? (yes/no): ").strip().lower()
|
generate_secret_key = input("Generate a Django SECRET_KEY? (yes/no): ").strip().lower()
|
||||||
if generate_secret_key == "yes":
|
if generate_secret_key == "yes":
|
||||||
@ -39,7 +39,7 @@ def setup_environment_variables(python_command_in_venv):
|
|||||||
'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())']).decode().strip()
|
'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())']).decode().strip()
|
||||||
else:
|
else:
|
||||||
secret_key = input("Enter Django SECRET_KEY: ").strip()
|
secret_key = input("Enter Django SECRET_KEY: ").strip()
|
||||||
|
|
||||||
# DEBUG MODE
|
# DEBUG MODE
|
||||||
while True:
|
while True:
|
||||||
debug_mode = input("Enable DEBUG mode? (True/False): ").strip()
|
debug_mode = input("Enable DEBUG mode? (True/False): ").strip()
|
||||||
@ -52,7 +52,7 @@ def setup_environment_variables(python_command_in_venv):
|
|||||||
allowed_hosts = input("Enter ALLOWED_HOSTS (comma-separated, or press Enter for default): ").strip()
|
allowed_hosts = input("Enter ALLOWED_HOSTS (comma-separated, or press Enter for default): ").strip()
|
||||||
if not allowed_hosts:
|
if not allowed_hosts:
|
||||||
allowed_hosts = "*.ku.th,localhost,127.0.0.1,::1"
|
allowed_hosts = "*.ku.th,localhost,127.0.0.1,::1"
|
||||||
|
|
||||||
# TZ
|
# TZ
|
||||||
available_time_zones = ["Asia/Bangkok", "Japan", "UCT", "CST6CDT", "Custom"]
|
available_time_zones = ["Asia/Bangkok", "Japan", "UCT", "CST6CDT", "Custom"]
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ def setup_environment_variables(python_command_in_venv):
|
|||||||
print("Invalid choice. Please enter a valid number.")
|
print("Invalid choice. Please enter a valid number.")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Invalid input. Please enter a valid number.")
|
print("Invalid input. Please enter a valid number.")
|
||||||
|
|
||||||
email_host_password = input("Enter EMAIL_HOST_PASSWORD: ").strip()
|
email_host_password = input("Enter EMAIL_HOST_PASSWORD: ").strip()
|
||||||
|
|
||||||
# SET
|
# SET
|
||||||
@ -116,7 +116,7 @@ def main():
|
|||||||
elif is_windows:
|
elif is_windows:
|
||||||
activate_command = os.path.join(".venv", "Scripts", "activate")
|
activate_command = os.path.join(".venv", "Scripts", "activate")
|
||||||
subprocess.run([activate_command], shell=True)
|
subprocess.run([activate_command], shell=True)
|
||||||
|
|
||||||
python_command = os.path.join(".venv", "bin", "python") if is_posix else os.path.join(".venv", "Scripts", "python")
|
python_command = os.path.join(".venv", "bin", "python") if is_posix else os.path.join(".venv", "Scripts", "python")
|
||||||
else:
|
else:
|
||||||
print("Not setting up a virtual environment. Using the global Python interpreter.")
|
print("Not setting up a virtual environment. Using the global Python interpreter.")
|
||||||
@ -154,19 +154,19 @@ def main():
|
|||||||
print(f"==========================Install Requirement==========================")
|
print(f"==========================Install Requirement==========================")
|
||||||
subprocess.run([python_command_in_venv, "-m", "pip", "install", "-r", "requirements.txt"])
|
subprocess.run([python_command_in_venv, "-m", "pip", "install", "-r", "requirements.txt"])
|
||||||
setup_environment_variables(python_command_in_venv)
|
setup_environment_variables(python_command_in_venv)
|
||||||
|
|
||||||
subprocess.run([python_command_in_venv, "-m", "pip", "install", "-r", "requirements.txt"], check=True)
|
subprocess.run([python_command_in_venv, "-m", "pip", "install", "-r", "requirements.txt"], check=True)
|
||||||
subprocess.run([python_command_in_venv, "manage.py", "migrate"], check=True)
|
subprocess.run([python_command_in_venv, "manage.py", "migrate"], check=True)
|
||||||
subprocess.run([python_command_in_venv, "manage.py", "loaddata", "data/users.json"], check=True)
|
subprocess.run([python_command_in_venv, "manage.py", "loaddata", "data/users.json"], check=True)
|
||||||
subprocess.run([python_command_in_venv, "manage.py", "loaddata", "data/polls.json"], check=True)
|
subprocess.run([python_command_in_venv, "manage.py", "loaddata", "data/polls.json"], check=True)
|
||||||
|
|
||||||
start_server = input("Do you want to start the Django server? (yes/no): ").strip().lower()
|
start_server = input("Do you want to start the Django server? (yes/no): ").strip().lower()
|
||||||
if start_server == "yes":
|
if start_server == "yes":
|
||||||
print("=================================================")
|
print("=================================================")
|
||||||
print("Django run in --insecure mode to load Static File")
|
print("Django run in --insecure mode to load Static File")
|
||||||
print("==================================================")
|
print("==================================================")
|
||||||
subprocess.run([python_command_in_venv, "manage.py", "runserver", "--insecure"], check=True)
|
subprocess.run([python_command_in_venv, "manage.py", "runserver", "--insecure"], check=True)
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"Error: {e}")
|
print(f"Error: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -174,5 +174,6 @@ def main():
|
|||||||
print("\nSetup process aborted.")
|
print("\nSetup process aborted.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user