mirror of
https://github.com/Sosokker/ku-polls.git
synced 2025-12-20 14:04:05 +01:00
Merge pull request #22 from Sosokker/iteration2
Add new Feature according to Iteration 2 Plan / Externalize Secret Variable
This commit is contained in:
commit
356449c396
@ -28,6 +28,8 @@ or
|
|||||||
|
|
||||||
**Don't forget to change `your_secret_key` to your secret key (without quote)**
|
**Don't forget to change `your_secret_key` to your secret key (without quote)**
|
||||||
|
|
||||||
|
**You can look at `sample.env` for more information and others environment variables to set.**
|
||||||
|
|
||||||
4. Run these commands
|
4. Run these commands
|
||||||
```bash
|
```bash
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
|
|||||||
@ -11,7 +11,7 @@ https://docs.djangoproject.com/en/4.2/ref/settings/
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from decouple import config
|
from decouple import config, Csv
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
@ -20,14 +20,15 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
#! SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = config('SECRET_KEY', default='fake-secret-key')
|
SECRET_KEY = config('SECRET_KEY', default='k2pd1p)zwe0qy0k25=sli+7+n^vd-0h*&6vga6oldq=781+7qw')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
#! SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = config('DEBUG', default=False, cast=bool)
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='*', cast=Csv())
|
||||||
|
|
||||||
|
TIME_ZONE = config('TIME_ZONE', default='Asia/Bangkok', cast=str)
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 4.2.4 on 2023-09-05 13:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('polls', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='question',
|
||||||
|
name='end_date',
|
||||||
|
field=models.DateTimeField(null=True, verbose_name='date ended'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='question',
|
||||||
|
name='pub_date',
|
||||||
|
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='date published'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -26,7 +26,8 @@ class Question(models.Model):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
question_text = models.CharField(max_length=200)
|
question_text = models.CharField(max_length=200)
|
||||||
pub_date = models.DateTimeField("date published")
|
pub_date = models.DateTimeField("date published", default=timezone.now)
|
||||||
|
end_date = models.DateTimeField("date ended", null=True)
|
||||||
|
|
||||||
def was_published_recently(self):
|
def was_published_recently(self):
|
||||||
"""
|
"""
|
||||||
@ -53,6 +54,29 @@ class Question(models.Model):
|
|||||||
"""
|
"""
|
||||||
return self.question_text
|
return self.question_text
|
||||||
|
|
||||||
|
def is_published(self):
|
||||||
|
"""
|
||||||
|
Checks if the question is published or not.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the question is published, else False.
|
||||||
|
"""
|
||||||
|
now = timezone.now()
|
||||||
|
return now >= self.pub_date
|
||||||
|
|
||||||
|
def can_vote(self):
|
||||||
|
"""
|
||||||
|
Checks if the question can be voted on or not.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the question is published and not ended, else False.
|
||||||
|
"""
|
||||||
|
now = timezone.now()
|
||||||
|
if self.end_date is None:
|
||||||
|
return self.pub_date <= now
|
||||||
|
else:
|
||||||
|
return self.pub_date <= now <= self.end_date
|
||||||
|
|
||||||
|
|
||||||
class Choice(models.Model):
|
class Choice(models.Model):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
</section>
|
</section>
|
||||||
<section class="polls-section">
|
<section class="polls-section">
|
||||||
<h2>Recent Polls</h2>
|
<h2>Recent Polls</h2>
|
||||||
<p class="total-polls">Total number of polls: {{ total_polls }}</p>
|
<p class="total-polls">Total number of polls: {{ total_open_polls }}</p>
|
||||||
<div class="poll-cards">
|
<div class="poll-cards">
|
||||||
{% if latest_question_list %}
|
{% if latest_question_list %}
|
||||||
{% for question in latest_question_list %}
|
{% for question in latest_question_list %}
|
||||||
|
|||||||
@ -37,6 +37,64 @@ class QuestionModelTests(TestCase):
|
|||||||
self.assertIs(recent_question.was_published_recently(), True)
|
self.assertIs(recent_question.was_published_recently(), True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_published_with_future_question(self):
|
||||||
|
"""
|
||||||
|
is_published() should return False for questions whos pub_date is in the
|
||||||
|
future.
|
||||||
|
"""
|
||||||
|
future_date = timezone.now() + datetime.timedelta(days=30)
|
||||||
|
future_question = Question(pub_date=future_date)
|
||||||
|
self.assertIs(future_question.is_published(), False)
|
||||||
|
|
||||||
|
def test_is_published_with_past_question(self):
|
||||||
|
"""
|
||||||
|
is_published() should return True for questions whose pub_date is in the
|
||||||
|
past.
|
||||||
|
"""
|
||||||
|
past_date = timezone.now() - datetime.timedelta(days=1)
|
||||||
|
past_question = Question(pub_date=past_date)
|
||||||
|
self.assertIs(past_question.is_published(), True)
|
||||||
|
|
||||||
|
def test_can_vote_with_question_not_ended(self):
|
||||||
|
"""
|
||||||
|
can_vote() should return True for questions that are published and have not
|
||||||
|
ended.
|
||||||
|
"""
|
||||||
|
pub_date = timezone.now() - datetime.timedelta(hours=1)
|
||||||
|
end_date = timezone.now() + datetime.timedelta(hours=1)
|
||||||
|
question = Question(pub_date=pub_date, end_date=end_date)
|
||||||
|
self.assertIs(question.can_vote(), True)
|
||||||
|
|
||||||
|
def test_can_vote_with_question_ended(self):
|
||||||
|
"""
|
||||||
|
can_vote() should return False for questions that are published but have
|
||||||
|
ended.
|
||||||
|
"""
|
||||||
|
pub_date = timezone.now() - datetime.timedelta(hours=2)
|
||||||
|
end_date = timezone.now() - datetime.timedelta(hours=1)
|
||||||
|
question = Question(pub_date=pub_date, end_date=end_date)
|
||||||
|
self.assertIs(question.can_vote(), False)
|
||||||
|
|
||||||
|
def test_can_vote_with_question_no_end_date(self):
|
||||||
|
"""
|
||||||
|
can_vote() should return True for questions that are published and have no
|
||||||
|
specified end date.
|
||||||
|
"""
|
||||||
|
pub_date = timezone.now() - datetime.timedelta(hours=1)
|
||||||
|
question = Question(pub_date=pub_date, end_date=None)
|
||||||
|
self.assertIs(question.can_vote(), True)
|
||||||
|
|
||||||
|
def test_can_vote_with_question_ending_in_future(self):
|
||||||
|
"""
|
||||||
|
can_vote() should return True for questions that are published and
|
||||||
|
the current time is within the allowed voting period.
|
||||||
|
"""
|
||||||
|
pub_date = timezone.now() - datetime.timedelta(hours=1)
|
||||||
|
end_date = timezone.now() + datetime.timedelta(hours=2)
|
||||||
|
question = Question(pub_date=pub_date, end_date=end_date)
|
||||||
|
self.assertIs(question.can_vote(), True)
|
||||||
|
|
||||||
|
|
||||||
def create_question(question_text, days):
|
def create_question(question_text, days):
|
||||||
"""
|
"""
|
||||||
Create a question with the given `question_text` and published the
|
Create a question with the given `question_text` and published the
|
||||||
|
|||||||
@ -17,8 +17,14 @@ class HomeView(TemplateView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['latest_question_list'] = Question.objects.filter(pub_date__lte=timezone.now()).order_by("-pub_date")[:5]
|
all_questions = Question.objects.all()
|
||||||
context['total_polls'] = Question.objects.count()
|
#* Check if the question is published and can be voted. Then, sort by pub_date
|
||||||
|
published_questions = [q for q in all_questions if q.is_published() and q.can_vote()]
|
||||||
|
latest_published_questions = sorted(published_questions, key=lambda q: q.pub_date, reverse=True)[:5]
|
||||||
|
|
||||||
|
context['latest_question_list'] = latest_published_questions
|
||||||
|
context['total_open_polls'] = sum(1 for q in published_questions if q.end_date is None)
|
||||||
|
context['total_polls'] = all_questions.count()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
10
sample.env
Normal file
10
sample.env
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Copy this file to .env and edit the values
|
||||||
|
# Create a secret key using (todo: how to create a secret key?)
|
||||||
|
SECRET_KEY = secret-key-value-without-quotes
|
||||||
|
# Set DEBUG to True for development, False for actual use
|
||||||
|
DEBUG = False
|
||||||
|
# ALLOWED_HOSTS is a comma-separated list of hosts that can access the app.
|
||||||
|
# You can use wildcard chars (*) and IP addresses. Use * for any host.
|
||||||
|
ALLOWED_HOSTS = *.ku.th, localhost, 127.0.0.1, ::1
|
||||||
|
# Your timezone
|
||||||
|
TIME_ZONE = Asia/Bangkok
|
||||||
Loading…
Reference in New Issue
Block a user