This commit is contained in:
Flatlogic Bot 2026-01-21 23:22:59 +00:00
parent e8065d5378
commit 3c67ef4f81
17 changed files with 329 additions and 21 deletions

Binary file not shown.

Binary file not shown.

22
core/forms.py Normal file
View File

@ -0,0 +1,22 @@
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class SignupForm(UserCreationForm):
email = forms.EmailField(required=True, help_text="Required. A valid email address.")
terms_accepted = forms.BooleanField(
required=True,
label="I accept the standard terms and conditions",
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
)
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('email',)
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user

View File

@ -0,0 +1,14 @@
{% autoescape off %}
Hi {{ user.username }},
Welcome to Referral Rewards!
Please click on the link below to confirm your registration and activate your account:
{{ protocol }}://{{ domain }}{% url 'activate' uidb64=uid token=token %}
If you did not sign up for this account, please ignore this email.
Best regards,
The Referral Rewards Team
{% endautoescape %}

View File

@ -0,0 +1,15 @@
{% autoescape off %}
You're receiving this email because you requested a password reset for your user account at {{ site_name }}.
Please go to the following page and choose a new password:
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
Your username, in case you've forgotten: {{ user.get_username }}
Thanks for using our site!
The {{ site_name }} team
{% endautoescape %}

View File

@ -0,0 +1 @@
Password reset on {{ site_name }}

View File

@ -27,10 +27,14 @@
<input type="text" name="username" class="form-control" id="id_username" placeholder="Username" required>
</div>
<div class="mb-4">
<div class="mb-2">
<label for="id_password" class="form-label fw-600">Password</label>
<input type="password" name="password" class="form-control" id="id_password" placeholder="Password" required>
</div>
<div class="text-end mb-4">
<a href="{% url 'password_reset' %}" class="text-decoration-none small fw-bold">Forgot password?</a>
</div>
<button type="submit" class="btn btn-primary w-100 py-3">Log In</button>
</form>
@ -42,4 +46,4 @@
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,25 @@
{% extends 'base.html' %}
{% block title %}Password Reset Complete - Referral Rewards{% endblock %}
{% block content %}
<div class="container py-5 mt-5">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card border-0 shadow-lg p-4 p-md-5 rounded-4 text-center">
<div class="mb-4">
<div class="display-1 text-success mb-3">
<i class="bi bi-check-circle"></i>
</div>
<h2 class="mb-3">Password Reset!</h2>
<p class="text-muted">Your password has been set. You may go ahead and log in now.</p>
</div>
<div class="mt-5">
<a href="{% url 'login' %}" class="btn btn-primary w-100 py-3">Log In</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,72 @@
{% extends 'base.html' %}
{% block title %}Set New Password - Referral Rewards{% endblock %}
{% block content %}
<div class="container py-5 mt-5">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card border-0 shadow-lg p-4 p-md-5 rounded-4">
<div class="text-center mb-4">
<h2 class="mb-3">Set New Password</h2>
<p class="text-muted">Please enter your new password twice so we can verify you typed it correctly.</p>
</div>
{% if validlink %}
<form method="post">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger">
Please correct the errors below.
</div>
{% endif %}
{% for field in form %}
<div class="mb-3">
<label for="{{ field.id_for_label }}" class="form-label fw-600">{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<div class="form-text small">{{ field.help_text }}</div>
{% endif %}
{% if field.errors %}
<div class="text-danger small mt-1">
{{ field.errors }}
</div>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary w-100 py-3 mt-4">Change My Password</button>
</form>
{% else %}
<div class="alert alert-danger">
The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
</div>
<a href="{% url 'password_reset' %}" class="btn btn-primary w-100 py-3 mt-4">Request New Link</a>
{% endif %}
</div>
</div>
</div>
</div>
<style>
/* Styling for Django generated form fields */
input[type="password"] {
display: block;
width: 100%;
padding: 0.375rem 0.75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border-radius: 0.375rem;
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
}
</style>
{% endblock %}

View File

@ -0,0 +1,27 @@
{% extends 'base.html' %}
{% block title %}Reset Email Sent - Referral Rewards{% endblock %}
{% block content %}
<div class="container py-5 mt-5">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card border-0 shadow-lg p-4 p-md-5 rounded-4 text-center">
<div class="mb-4">
<div class="display-1 text-primary mb-3">
<i class="bi bi-envelope-check"></i>
</div>
<h2 class="mb-3">Email Sent</h2>
<p class="text-muted">We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly.</p>
</div>
<p class="text-muted">If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder.</p>
<div class="mt-5">
<a href="{% url 'login' %}" class="btn btn-primary w-100 py-3">Return to Login</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,43 @@
{% extends 'base.html' %}
{% block title %}Reset Password - Referral Rewards{% endblock %}
{% block content %}
<div class="container py-5 mt-5">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card border-0 shadow-lg p-4 p-md-5 rounded-4">
<div class="text-center mb-4">
<h2 class="mb-3">Reset Password</h2>
<p class="text-muted">Enter your email address and we'll send you a link to reset your password.</p>
</div>
<form method="post">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger">
Please correct the errors below.
</div>
{% endif %}
<div class="mb-4">
<label for="id_email" class="form-label fw-600">Email Address</label>
<input type="email" name="email" class="form-control" id="id_email" placeholder="Email address" required>
{% if form.email.errors %}
<div class="text-danger small mt-1">
{{ form.email.errors }}
</div>
{% endif %}
</div>
<button type="submit" class="btn btn-primary w-100 py-3">Send Reset Link</button>
</form>
<div class="text-center mt-5">
<p class="text-muted mb-0"><a href="{% url 'login' %}" class="text-decoration-none fw-bold">Back to Login</a></p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -15,14 +15,23 @@
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
<label for="{{ field.id_for_label }}" class="form-label fw-600">{{ field.label }}</label>
{{ field.errors }}
<input type="{{ field.field.widget.input_type }}"
name="{{ field.name }}"
class="form-control {% if field.errors %}is-invalid{% endif %}"
id="{{ field.id_for_label }}"
placeholder="Enter {{ field.label|lower }}">
<div class="mb-3 {% if field.name == 'terms_accepted' %}form-check{% endif %}">
{% if field.name == 'terms_accepted' %}
{{ field }}
<label class="form-check-label ms-2" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
{{ field.errors }}
{% else %}
<label for="{{ field.id_for_label }}" class="form-label fw-600">{{ field.label }}</label>
{{ field.errors }}
<input type="{{ field.field.widget.input_type }}"
name="{{ field.name }}"
class="form-control {% if field.errors %}is-invalid{% endif %}"
id="{{ field.id_for_label }}"
placeholder="Enter {{ field.label|lower }}">
{% endif %}
{% if field.help_text %}
<div class="form-text opacity-75 small">{{ field.help_text|safe }}</div>
{% endif %}
@ -39,4 +48,4 @@
</div>
</div>
</div>
{% endblock %}
{% endblock %}

10
core/tokens.py Normal file
View File

@ -0,0 +1,10 @@
from django.contrib.auth.tokens import PasswordResetTokenGenerator
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
str(user.pk) + str(timestamp) +
str(user.is_active)
)
account_activation_token = AccountActivationTokenGenerator()

View File

@ -5,7 +5,26 @@ from . import views
urlpatterns = [
path("", views.home, name="home"),
path("signup/", views.signup, name="signup"),
path("activate/<uidb64>/<token>/", views.activate, name="activate"),
path("dashboard/", views.dashboard, name="dashboard"),
path("login/", auth_views.LoginView.as_view(template_name='core/login.html'), name="login"),
path("logout/", views.logout_view, name="logout"),
# Password Reset
path("password-reset/", auth_views.PasswordResetView.as_view(
template_name='core/password_reset_form.html',
email_template_name='core/emails/password_reset_email.html',
subject_template_name='core/emails/password_reset_subject.txt',
success_url='/password-reset/done/'
), name="password_reset"),
path("password-reset/done/", auth_views.PasswordResetDoneView.as_view(
template_name='core/password_reset_done.html'
), name="password_reset_done"),
path("password-reset-confirm/<uidb64>/<token>/", auth_views.PasswordResetConfirmView.as_view(
template_name='core/password_reset_confirm.html',
success_url='/password-reset-complete/'
), name="password_reset_confirm"),
path("password-reset-complete/", auth_views.PasswordResetCompleteView.as_view(
template_name='core/password_reset_complete.html'
), name="password_reset_complete"),
]

View File

@ -1,9 +1,18 @@
from django.shortcuts import render, redirect
from django.contrib.auth import login, logout
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login, logout, get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from .models import Profile
from .forms import SignupForm
from .tokens import account_activation_token
User = get_user_model()
def home(request):
if request.user.is_authenticated:
@ -14,21 +23,59 @@ def signup(request):
if request.user.is_authenticated:
return redirect('dashboard')
if request.method == 'POST':
form = UserCreationForm(request.POST)
form = SignupForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Welcome to Referral Rewards! Your account has been created.")
return redirect('dashboard')
user = form.save(commit=False)
user.is_active = False
user.save()
# Send activation email
current_site = get_current_site(request)
mail_subject = 'Activate your Referral Rewards account.'
message = render_to_string('core/emails/activation_email.html', {
'user': user,
'domain': current_site.domain,
'protocol': 'https' if request.is_secure() else 'http',
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
try:
email.send()
messages.success(request, 'Please confirm your email address to complete the registration. Check your inbox.')
except Exception as e:
messages.error(request, f'Error sending email: {str(e)}. Please contact support.')
return redirect('login')
else:
form = UserCreationForm()
form = SignupForm()
return render(request, 'core/signup.html', {'form': form})
def activate(request, uidb64, token):
try:
uid = force_str(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
login(request, user)
messages.success(request, 'Thank you for your email confirmation. Now you can enjoy our services.')
return redirect('dashboard')
else:
messages.error(request, 'Activation link is invalid!')
return redirect('home')
@login_required
def dashboard(request):
profile = request.user.profile
# Ensure profile exists (though signal should handle it)
profile, created = Profile.objects.get_or_create(user=request.user)
return render(request, 'core/dashboard.html', {'profile': profile})
def logout_view(request):
logout(request)
return redirect('home')
return redirect('home')