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,11 +27,15 @@
<input type="text" name="username" class="form-control" id="id_username" placeholder="Username" required> <input type="text" name="username" class="form-control" id="id_username" placeholder="Username" required>
</div> </div>
<div class="mb-4"> <div class="mb-2">
<label for="id_password" class="form-label fw-600">Password</label> <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> <input type="password" name="password" class="form-control" id="id_password" placeholder="Password" required>
</div> </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> <button type="submit" class="btn btn-primary w-100 py-3">Log In</button>
</form> </form>

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,7 +15,14 @@
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}
<div class="mb-3"> <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> <label for="{{ field.id_for_label }}" class="form-label fw-600">{{ field.label }}</label>
{{ field.errors }} {{ field.errors }}
<input type="{{ field.field.widget.input_type }}" <input type="{{ field.field.widget.input_type }}"
@ -23,6 +30,8 @@
class="form-control {% if field.errors %}is-invalid{% endif %}" class="form-control {% if field.errors %}is-invalid{% endif %}"
id="{{ field.id_for_label }}" id="{{ field.id_for_label }}"
placeholder="Enter {{ field.label|lower }}"> placeholder="Enter {{ field.label|lower }}">
{% endif %}
{% if field.help_text %} {% if field.help_text %}
<div class="form-text opacity-75 small">{{ field.help_text|safe }}</div> <div class="form-text opacity-75 small">{{ field.help_text|safe }}</div>
{% endif %} {% endif %}

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 = [ urlpatterns = [
path("", views.home, name="home"), path("", views.home, name="home"),
path("signup/", views.signup, name="signup"), path("signup/", views.signup, name="signup"),
path("activate/<uidb64>/<token>/", views.activate, name="activate"),
path("dashboard/", views.dashboard, name="dashboard"), path("dashboard/", views.dashboard, name="dashboard"),
path("login/", auth_views.LoginView.as_view(template_name='core/login.html'), name="login"), path("login/", auth_views.LoginView.as_view(template_name='core/login.html'), name="login"),
path("logout/", views.logout_view, name="logout"), 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.shortcuts import render, redirect
from django.contrib.auth import login, logout from django.contrib.auth import login, logout, get_user_model
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib import messages 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 .models import Profile
from .forms import SignupForm
from .tokens import account_activation_token
User = get_user_model()
def home(request): def home(request):
if request.user.is_authenticated: if request.user.is_authenticated:
@ -14,19 +23,57 @@ def signup(request):
if request.user.is_authenticated: if request.user.is_authenticated:
return redirect('dashboard') return redirect('dashboard')
if request.method == 'POST': if request.method == 'POST':
form = UserCreationForm(request.POST) form = SignupForm(request.POST)
if form.is_valid(): if form.is_valid():
user = form.save() 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 = 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) login(request, user)
messages.success(request, "Welcome to Referral Rewards! Your account has been created.") messages.success(request, 'Thank you for your email confirmation. Now you can enjoy our services.')
return redirect('dashboard') return redirect('dashboard')
else: else:
form = UserCreationForm() messages.error(request, 'Activation link is invalid!')
return render(request, 'core/signup.html', {'form': form}) return redirect('home')
@login_required @login_required
def dashboard(request): 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}) return render(request, 'core/dashboard.html', {'profile': profile})
def logout_view(request): def logout_view(request):