mirror of
https://github.com/Sosokker/ku-polls.git
synced 2025-12-18 13:04:05 +01:00
commit
5eef14cdf3
@ -6,8 +6,8 @@ on the [Django Tutorial project](https://docs.djangoproject.com/en/4.2/intro/tut
|
||||
|
||||
## Install and Run
|
||||
### Run Setup.py Method
|
||||
|
||||
Clone this repository and Run `setup.py` to install and run the project
|
||||
1. Install [Python 3.11 or later](https://www.python.org/downloads/)
|
||||
2. Clone this repository and Run `setup.py` to install and run the project
|
||||
|
||||
**Don't forget to answer the question from `setup.py` to setup the project**
|
||||
```bash
|
||||
|
||||
@ -10,6 +10,8 @@ For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.2/ref/settings/
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from decouple import config, Csv
|
||||
|
||||
@ -70,6 +72,95 @@ TEMPLATES = [
|
||||
|
||||
WSGI_APPLICATION = 'mysite.wsgi.application'
|
||||
|
||||
# * Loggin template from https://www.youtube.com/watch?v=m_EkU56KdJg, Modify a bit.
|
||||
|
||||
LOGS_DIR = os.path.join(BASE_DIR, 'logs')
|
||||
|
||||
if not os.path.exists(LOGS_DIR):
|
||||
os.makedirs(LOGS_DIR)
|
||||
|
||||
# ! LOGGERS -> entry point into the logging system.
|
||||
|
||||
LOGGERS = (
|
||||
{
|
||||
"django": {
|
||||
"handlers": ["console_handler", "info_handler"],
|
||||
"level": "INFO",
|
||||
},
|
||||
"django.request": {
|
||||
"handlers": ["error_handler"],
|
||||
"level": "INFO",
|
||||
"propagate": True,
|
||||
},
|
||||
"django.template": {
|
||||
"handlers": ["error_handler"],
|
||||
"level": "DEBUG",
|
||||
"propagate": True,
|
||||
},
|
||||
"django.server": {
|
||||
"handlers": ["error_handler"],
|
||||
"level": "INFO",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
# ! FORMATTER -> a log record needs to be rendered as text. Formatters describe the exact format of that text.
|
||||
|
||||
FORMATTERS = (
|
||||
{
|
||||
"verbose": {
|
||||
"format": "{levelname} {asctime:s} {name} {threadName} {thread:d} {module} {filename} {lineno:d} {name} {funcName} {process:d} {message}",
|
||||
"style": "{",
|
||||
},
|
||||
"simple": {
|
||||
"format": "{levelname} {asctime:s} {name} {module} {filename} {lineno:d} {funcName} {message}",
|
||||
"style": "{",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
# ! HANDLERS -> The handler is the engine that determines what happens to each message in a logger
|
||||
|
||||
HANDLERS = {
|
||||
# StreamHandler -> sends log messages to the console
|
||||
"console_handler": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "simple",
|
||||
"level": "DEBUG"
|
||||
}, # RotatingFileHandlers -> write log messages to files
|
||||
"info_handler": {
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": f"{BASE_DIR}/logs/blogthedata_info.log",
|
||||
"mode": "a",
|
||||
"encoding": "utf-8",
|
||||
"formatter": "verbose",
|
||||
"level": "INFO",
|
||||
"backupCount": 5,
|
||||
"maxBytes": 1024 * 1024 * 5, # 5 MB
|
||||
},
|
||||
"error_handler": {
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": f"{BASE_DIR}/logs/blogthedata_error.log",
|
||||
"mode": "a",
|
||||
"formatter": "verbose",
|
||||
"level": "WARNING",
|
||||
"backupCount": 5,
|
||||
"maxBytes": 1024 * 1024 * 5, # 5 MB
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# ! LOGGING
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False, # If set to True, it disables all loggers from previous configurations
|
||||
"formatters": FORMATTERS[0],
|
||||
"handlers": HANDLERS,
|
||||
"loggers": LOGGERS[0],
|
||||
}
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||
|
||||
@ -4,4 +4,6 @@ from django.apps import AppConfig
|
||||
class PollsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'polls'
|
||||
|
||||
|
||||
def ready(self) -> None:
|
||||
import polls.signals
|
||||
@ -1,3 +1,6 @@
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from django.contrib.auth.models import User
|
||||
@ -5,7 +8,7 @@ from django.contrib.auth.models import User
|
||||
|
||||
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"
|
||||
|
||||
logger = logging.getLogger('signup_form')
|
||||
username = forms.CharField(widget=forms.TextInput(attrs={'class': tailwind_class}),
|
||||
error_messages={
|
||||
'unique': 'This username is already in use.',
|
||||
@ -18,6 +21,16 @@ class SignUpForm(UserCreationForm):
|
||||
)
|
||||
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class': tailwind_class}),)
|
||||
|
||||
# commit -> default =True -> If commit is True -> want to save the user object to the database.
|
||||
def save(self, commit: bool = True) -> Any:
|
||||
user = super().save(commit=False)
|
||||
|
||||
if commit:
|
||||
user.save()
|
||||
self.logger.info(f"User registered with username: {user.username}")
|
||||
|
||||
return user
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('username', 'password1', 'password2')
|
||||
|
||||
38
polls/signals.py
Normal file
38
polls/signals.py
Normal file
@ -0,0 +1,38 @@
|
||||
import logging
|
||||
from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
|
||||
from django.dispatch import receiver
|
||||
|
||||
log = logging.getLogger("django")
|
||||
|
||||
def get_client_ip(request):
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0]
|
||||
else:
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
return ip
|
||||
|
||||
#! https://stackoverflow.com/questions/37618473/how-can-i-log-both-successful-and-failed-login-and-logout-attempts-in-django
|
||||
@receiver(user_logged_in)
|
||||
def user_logged_in_callback(sender, request, user, **kwargs):
|
||||
ip = get_client_ip(request)
|
||||
|
||||
log.info('Login User: {user} via ip: {ip}'.format(
|
||||
user=user,
|
||||
ip=ip
|
||||
))
|
||||
|
||||
@receiver(user_logged_out)
|
||||
def user_logged_out_callback(sender, request, user, **kwargs):
|
||||
ip = get_client_ip(request)
|
||||
|
||||
log.info('Logout User: {user} via ip: {ip}'.format(
|
||||
user=user,
|
||||
ip=ip
|
||||
))
|
||||
|
||||
@receiver(user_login_failed)
|
||||
def user_login_failed_callback(sender, credentials, **kwargs):
|
||||
log.warning('Login Failed for: {credentials}'.format(
|
||||
credentials=credentials,
|
||||
))
|
||||
@ -1,4 +1,5 @@
|
||||
from django.http import HttpResponseRedirect
|
||||
import logging
|
||||
|
||||
from django.shortcuts import get_object_or_404, render, redirect
|
||||
from django.urls import reverse
|
||||
from django.views import generic
|
||||
@ -13,6 +14,9 @@ from .forms import SignUpForm
|
||||
from .models import Choice, Question, Vote
|
||||
|
||||
|
||||
logger = logging.getLogger("django")
|
||||
|
||||
|
||||
class IndexView(generic.ListView):
|
||||
"""View for index.html."""
|
||||
|
||||
@ -98,15 +102,19 @@ def vote(request, question_id):
|
||||
A function that updates the database. Adds a vote count to the choice that the user votes for
|
||||
in a specific question_id.
|
||||
"""
|
||||
ip = get_client_ip(request)
|
||||
question = get_object_or_404(Question, pk=question_id)
|
||||
|
||||
if request.method == "POST":
|
||||
try:
|
||||
selected_choice = question.choice_set.get(pk=request.POST["choice"])
|
||||
except (KeyError, Choice.DoesNotExist):
|
||||
logger.error(f"User {request.user.username} ({ip}) didn't select choice.")
|
||||
messages.error(request, "You didn't select a choice.")
|
||||
return redirect("polls:detail", question_id)
|
||||
|
||||
logger.info(f"User {request.user.username} ({ip}) select choice {selected_choice}")
|
||||
|
||||
if question.can_vote():
|
||||
# ! Return 1. object element 2. boolean status of creation
|
||||
vote, created = Vote.objects.update_or_create(
|
||||
@ -116,8 +124,10 @@ def vote(request, question_id):
|
||||
)
|
||||
|
||||
if created:
|
||||
logger.info(f"User {request.user.username} ({ip}) vote on choice {selected_choice}")
|
||||
messages.success(request, "You voted successfully🥳")
|
||||
else:
|
||||
logger.info(f"User {request.user.username} ({ip}) update his answer to {selected_choice}")
|
||||
messages.success(request, "You updated your vote🥳")
|
||||
|
||||
return redirect("polls:results", question_id)
|
||||
@ -126,4 +136,14 @@ def vote(request, question_id):
|
||||
return redirect("polls:index")
|
||||
else:
|
||||
messages.error(request, "Invalid request method.")
|
||||
return redirect("polls:index")
|
||||
return redirect("polls:index")
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/4581789/how-do-i-get-user-ip-address-in-django
|
||||
def get_client_ip(request):
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0]
|
||||
else:
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
return ip
|
||||
|
||||
Loading…
Reference in New Issue
Block a user