@ -1,8 +1,37 @@ |
|||||||
from django.contrib import admin |
from django.contrib import admin |
||||||
|
from django.contrib.auth.admin import UserAdmin |
||||||
|
from .models import User # Import your custom User model |
||||||
|
|
||||||
from .models import BaseUser |
class CustomUserAdmin(UserAdmin): |
||||||
|
model = User |
||||||
|
|
||||||
# Register your models here. |
# Fields to display in the list view of the admin |
||||||
|
list_display = ['email', 'first_name', 'last_name', 'is_staff', 'is_superuser', 'is_active'] |
||||||
|
|
||||||
admin.site.register(BaseUser) |
# Fields to search in the admin |
||||||
|
search_fields = ['email', 'first_name', 'last_name'] |
||||||
|
|
||||||
|
# Default ordering of records in the admin |
||||||
|
ordering = ['email'] |
||||||
|
|
||||||
|
# Fieldsets for the add and change forms in the admin |
||||||
|
fieldsets = ( |
||||||
|
(None, {'fields': ('email', 'password')}), |
||||||
|
('Personal Info', {'fields': ('first_name', 'last_name')}), |
||||||
|
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser')}), |
||||||
|
('Important Dates', {'fields': ('last_login',)}), # Remove 'date_joined' if it doesn't exist |
||||||
|
) |
||||||
|
|
||||||
|
# Fieldsets for the add form in the admin |
||||||
|
add_fieldsets = ( |
||||||
|
(None, { |
||||||
|
'classes': ('wide',), |
||||||
|
'fields': ('email', 'first_name', 'last_name', 'password1', 'password2', 'is_staff', 'is_superuser', 'is_active'), |
||||||
|
}), |
||||||
|
) |
||||||
|
|
||||||
|
# Filters for the list view in the admin |
||||||
|
list_filter = ('is_staff', 'is_superuser', 'is_active') |
||||||
|
|
||||||
|
# Register your custom User model with the custom UserAdmin class |
||||||
|
admin.site.register(User, CustomUserAdmin) |
@ -1,45 +1,52 @@ |
|||||||
from django import forms |
from django import forms |
||||||
from django.contrib.auth.forms import UserCreationForm |
from django.contrib.auth.forms import AuthenticationForm |
||||||
from .models import BaseUser |
from .models import User |
||||||
|
|
||||||
class BaseUserForm(UserCreationForm): |
class UserRegistrationForm(forms.ModelForm): |
||||||
class Meta: |
password = forms.CharField( |
||||||
model = BaseUser |
widget=forms.PasswordInput(attrs={ |
||||||
fields = [ |
'class': 'form-control', |
||||||
'first_name', |
'placeholder': 'Enter your password', |
||||||
'last_name', |
}) |
||||||
'bio', |
|
||||||
'address', |
|
||||||
'contact_number', |
|
||||||
'image', |
|
||||||
'citizenship', |
|
||||||
'certificate', |
|
||||||
'price', |
|
||||||
'role', |
|
||||||
'email', |
|
||||||
] |
|
||||||
password1 = forms.CharField( |
|
||||||
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Password'}), |
|
||||||
label='Password', |
|
||||||
min_length=8, |
|
||||||
) |
) |
||||||
password2 = forms.CharField( |
confirm_password = forms.CharField( |
||||||
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Confirm Password'}), |
widget=forms.PasswordInput(attrs={ |
||||||
label='Confirm Password', |
'class': 'form-control', |
||||||
min_length=8, |
'placeholder': 'Confirm your password', |
||||||
|
}) |
||||||
) |
) |
||||||
|
|
||||||
def clean_password2(self): |
class Meta: |
||||||
password1 = self.cleaned_data.get('password1') |
model = User |
||||||
password2 = self.cleaned_data.get('password2') |
fields = ['first_name', 'last_name', 'email', 'password'] |
||||||
|
widgets = { |
||||||
|
'first_name': forms.TextInput(attrs={ |
||||||
|
'class': 'form-control', |
||||||
|
'placeholder': 'Enter your first name', |
||||||
|
}), |
||||||
|
'last_name': forms.TextInput(attrs={ |
||||||
|
'class': 'form-control', |
||||||
|
'placeholder': 'Enter your last name', |
||||||
|
}), |
||||||
|
'email': forms.EmailInput(attrs={ |
||||||
|
'class': 'form-control', |
||||||
|
'placeholder': 'Enter your email address', |
||||||
|
}), |
||||||
|
} |
||||||
|
|
||||||
|
def clean(self): |
||||||
|
cleaned_data = super().clean() |
||||||
|
password = cleaned_data.get('password') |
||||||
|
confirm_password = cleaned_data.get('confirm_password') |
||||||
|
|
||||||
if password1 and password2 and password1 != password2: |
if password and confirm_password and password != confirm_password: |
||||||
raise forms.ValidationError("Passwords don't match.") |
raise forms.ValidationError("Passwords do not match.") |
||||||
return password2 |
|
||||||
|
|
||||||
def save(self, commit=True): |
class UserLoginForm(AuthenticationForm): |
||||||
user = super().save(commit=False) |
def __init__(self, *args, **kwargs): |
||||||
user.set_password(self.cleaned_data['password1']) |
self.request = kwargs.pop('request', None) |
||||||
if commit: |
super(UserLoginForm, self).__init__(*args, **kwargs) |
||||||
user.save() |
# Change the username field label and placeholder to 'Email' |
||||||
return user |
self.fields['username'].label = 'Email' |
||||||
|
self.fields['username'].widget.attrs.update({'placeholder': 'Enter your email'}) |
||||||
|
self.fields['password'].widget.attrs.update({'placeholder': 'Enter your password'}) |
||||||
|
@ -0,0 +1,43 @@ |
|||||||
|
# Generated by Django 5.1.4 on 2025-01-11 19:36 |
||||||
|
|
||||||
|
import datetime |
||||||
|
import django.utils.timezone |
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('main', '0001_initial'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AddField( |
||||||
|
model_name='user', |
||||||
|
name='bio', |
||||||
|
field=models.CharField(default=datetime.datetime(2025, 1, 11, 19, 36, 0, 579795, tzinfo=datetime.timezone.utc), max_length=200), |
||||||
|
preserve_default=False, |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='user', |
||||||
|
name='member_since', |
||||||
|
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), |
||||||
|
preserve_default=False, |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='user', |
||||||
|
name='price', |
||||||
|
field=models.PositiveBigIntegerField(default=10), |
||||||
|
preserve_default=False, |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='user', |
||||||
|
name='profile', |
||||||
|
field=models.ImageField(blank=True, null=True, upload_to=''), |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='user', |
||||||
|
name='updated_on', |
||||||
|
field=models.DateField(auto_now=True), |
||||||
|
), |
||||||
|
] |
@ -1,41 +1,110 @@ |
|||||||
from django.contrib.auth.models import AbstractUser |
|
||||||
from django.db import models |
from django.db import models |
||||||
|
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin |
||||||
|
from django.core.mail import send_mail |
||||||
|
from django.utils.encoding import force_bytes |
||||||
|
from django.template.loader import render_to_string |
||||||
|
from django.contrib.auth.tokens import default_token_generator |
||||||
|
from django.conf import settings |
||||||
|
from django.utils.http import urlsafe_base64_encode |
||||||
|
|
||||||
class BaseUser(AbstractUser): |
|
||||||
# Additional fields to extend the default user model |
|
||||||
|
|
||||||
# Profile-related fields |
class Service(models.Model): |
||||||
image = models.ImageField(upload_to='user_profiles/', blank=True, null=True) |
name = models.CharField(max_length=20) |
||||||
bio = models.TextField(blank=True, null=True) |
description = models.CharField(max_length=100, blank=True, null=True) |
||||||
address = models.TextField(blank=True, null=True) |
def __str__(self): |
||||||
contact_number = models.CharField(max_length=15, blank=True, null=True) |
return self.name |
||||||
citizenship = models.CharField(max_length=100, blank=True, null=True) |
|
||||||
certificate = models.FileField(upload_to='certificates/', blank=True, null=True) |
class UserManager(BaseUserManager): |
||||||
|
def create_user(self, first_name, last_name, email, password=None, **extra_fields): |
||||||
|
""" |
||||||
|
Creates and saves a User with the given first name, last name, email, and password. |
||||||
|
""" |
||||||
|
if not email: |
||||||
|
raise ValueError('Users must have an email address') |
||||||
|
|
||||||
|
email = self.normalize_email(email) |
||||||
|
user = self.model( |
||||||
|
first_name=first_name, |
||||||
|
last_name=last_name, |
||||||
|
email=email, |
||||||
|
**extra_fields |
||||||
|
) |
||||||
|
user.set_password(password) |
||||||
|
user.save(using=self._db) |
||||||
|
|
||||||
|
# Send verification email |
||||||
|
try: |
||||||
|
self.send_verification_email(user) |
||||||
|
except: |
||||||
|
print("Couldnot send verification email.") |
||||||
|
|
||||||
|
return user |
||||||
|
|
||||||
|
def create_superuser(self, first_name, last_name, email, password=None, **extra_fields): |
||||||
|
""" |
||||||
|
Creates and saves a superuser with the given first name, last name, email, and password. |
||||||
|
""" |
||||||
|
extra_fields.setdefault('is_staff', True) |
||||||
|
extra_fields.setdefault('is_superuser', True) |
||||||
|
extra_fields.setdefault('is_active', True) |
||||||
|
|
||||||
# Verification and status |
if extra_fields.get('is_staff') is not True: |
||||||
is_verified = models.BooleanField(default=False) |
raise ValueError('Superuser must have is_staff=True.') |
||||||
|
if extra_fields.get('is_superuser') is not True: |
||||||
|
raise ValueError('Superuser must have is_superuser=True.') |
||||||
|
|
||||||
# Financial or business-related fields |
return self.create_user(first_name, last_name, email, password, **extra_fields) |
||||||
price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True) |
|
||||||
ratings = models.DecimalField(max_digits=3, decimal_places=2, default=0.00) |
|
||||||
|
|
||||||
# Role and other identifiers |
def send_verification_email(self, user): |
||||||
role = models.CharField( |
# Generate the token and the uid for the verification URL |
||||||
max_length=50, |
token = default_token_generator.make_token(user) |
||||||
choices=[('CLIENT', 'CLIENT'), ('ADMIN', 'ADMIN'), ('SERVICE_PROVIDER', 'SERVICE_PROVIDER')], |
uid = urlsafe_base64_encode(force_bytes(user.pk)) |
||||||
default='CLIENT' |
verification_url = f"{settings.FRONTEND_URL}/verify-email/{uid}/{token}/" |
||||||
) |
|
||||||
|
|
||||||
# Time-related fields |
subject = "Verify Your Email Address" |
||||||
|
message = render_to_string('emails/verification_email.html', { |
||||||
|
'user': user, |
||||||
|
'verification_url': verification_url, |
||||||
|
}) |
||||||
|
|
||||||
|
send_mail( |
||||||
|
subject, |
||||||
|
message, |
||||||
|
settings.DEFAULT_FROM_EMAIL, |
||||||
|
[user.email], |
||||||
|
fail_silently=False, |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
class User(AbstractBaseUser, PermissionsMixin): |
||||||
|
email = models.EmailField(unique=True) |
||||||
|
first_name = models.CharField(max_length=30) |
||||||
|
last_name = models.CharField(max_length=30) |
||||||
|
is_active = models.BooleanField(default=True) |
||||||
|
is_staff = models.BooleanField(default=False) |
||||||
|
is_superuser = models.BooleanField(default=False) |
||||||
|
profile = models.ImageField(blank=True,null=True) |
||||||
|
price = models.PositiveBigIntegerField(blank=True, null=True) |
||||||
|
bio = models.CharField(max_length=200, blank=True, null=True) |
||||||
member_since = models.DateTimeField(auto_now_add=True) |
member_since = models.DateTimeField(auto_now_add=True) |
||||||
profile_updated = models.DateTimeField(auto_now=True) |
updated_on = models.DateField(auto_now=True) |
||||||
|
USERNAME_FIELD = 'email' |
||||||
|
REQUIRED_FIELDS = ['first_name', 'last_name'] |
||||||
|
|
||||||
# Token field for verification or authentication purposes |
objects = UserManager() |
||||||
token = models.CharField(max_length=256, blank=True, null=True) |
|
||||||
|
|
||||||
def __str__(self): |
def __str__(self): |
||||||
return self.username |
return self.email |
||||||
|
|
||||||
|
def get_full_name(self): |
||||||
|
return f"{self.first_name} {self.last_name}" |
||||||
|
|
||||||
|
def get_short_name(self): |
||||||
|
return self.first_name |
||||||
|
|
||||||
class Meta: |
class ServiceRequest(models.Model): |
||||||
verbose_name = 'Base User' |
client = models.ForeignKey(User,on_delete=models.CASCADE,related_name="client") |
||||||
verbose_name_plural = 'Base Users' |
service_provider = models.ForeignKey(User,on_delete=models.CASCADE,related_name="client") |
||||||
|
agreed_price = models.DecimalField(max_digits=999,decimal_places=2 , default=0) |
||||||
|
agreed_on = models.DateField(auto_now_add=True) |
||||||
|
is_completed = models.BooleanField(default=False) |
||||||
|
@ -0,0 +1,12 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Verify Your Email Address</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<p>Hello {{ user.get_full_name }},</p> |
||||||
|
<p>Please click the link below to verify your email address:</p> |
||||||
|
<p><a href="{{ verification_url }}">{{ verification_url }}</a></p> |
||||||
|
<p>If you did not create an account, please ignore this email.</p> |
||||||
|
</body> |
||||||
|
</html> |
@ -1,17 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html lang="en"> |
|
||||||
<head> |
|
||||||
<meta charset="UTF-8"> |
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"> |
|
||||||
<title>Document</title> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
|
|
||||||
<form method="post"> |
|
||||||
{% csrf_token %} |
|
||||||
{{ form.as_p }} |
|
||||||
<button type="submit">Create</button> |
|
||||||
</form> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -1,5 +0,0 @@ |
|||||||
<form method="post"> |
|
||||||
{% csrf_token %} |
|
||||||
<p>Are you sure you want to delete {{ object }}?</p> |
|
||||||
<button type="submit">Delete</button> |
|
||||||
</form> |
|
@ -0,0 +1,63 @@ |
|||||||
|
{% extends 'base.html' %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||||
|
<title>Login Form</title> |
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"> |
||||||
|
<style> |
||||||
|
.login-container { |
||||||
|
height: 100vh; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
background: #f4f7fc; |
||||||
|
} |
||||||
|
.login-card { |
||||||
|
padding: 2rem; |
||||||
|
border-radius: 8px; |
||||||
|
background: white; |
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
||||||
|
width: 100%; |
||||||
|
max-width: 400px; |
||||||
|
} |
||||||
|
.login-card h2 { |
||||||
|
text-align: center; |
||||||
|
margin-bottom: 1rem; |
||||||
|
} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div class="login-container"> |
||||||
|
<div class="login-card"> |
||||||
|
<h2>Login</h2> |
||||||
|
<form action="#" method="post"> |
||||||
|
{% csrf_token %} |
||||||
|
<div class="mb-3"> |
||||||
|
<label for="email" class="form-label">Email</label> |
||||||
|
<input type="text" class="form-control" id="email" name="email" placeholder="Enter your email" required> |
||||||
|
</div> |
||||||
|
<div class="mb-3"> |
||||||
|
<label for="password" class="form-label">Password</label> |
||||||
|
<input type="password" class="form-control" id="password" name="password" placeholder="Enter your password" required> |
||||||
|
</div> |
||||||
|
<div class="d-flex justify-content-between align-items-center"> |
||||||
|
<div class="form-check"> |
||||||
|
<input type="checkbox" class="form-check-input" id="rememberMe"> |
||||||
|
<label class="form-check-label" for="rememberMe">Remember Me</label> |
||||||
|
</div> |
||||||
|
<a href="#" class="small">Forgot password?</a> |
||||||
|
</div> |
||||||
|
<button type="submit" class="btn btn-primary w-100 mt-3">Login</button> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
|
||||||
|
{% endblock %} |
@ -0,0 +1,63 @@ |
|||||||
|
{% extends 'base.html' %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||||
|
<title>Login Form</title> |
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"> |
||||||
|
<style> |
||||||
|
.login-container { |
||||||
|
height: 100vh; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
background: #f4f7fc; |
||||||
|
} |
||||||
|
.login-card { |
||||||
|
padding: 2rem; |
||||||
|
border-radius: 8px; |
||||||
|
background: white; |
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
||||||
|
width: 100%; |
||||||
|
max-width: 400px; |
||||||
|
} |
||||||
|
.login-card h2 { |
||||||
|
text-align: center; |
||||||
|
margin-bottom: 1rem; |
||||||
|
} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div class="login-container"> |
||||||
|
<div class="login-card"> |
||||||
|
<h2>Login</h2> |
||||||
|
<form action="#" method="post"> |
||||||
|
{% csrf_token %} |
||||||
|
<div class="mb-3"> |
||||||
|
<label for="email" class="form-label">Email</label> |
||||||
|
<input type="text" class="form-control" id="email" name="email" placeholder="Enter your email" required> |
||||||
|
</div> |
||||||
|
<div class="mb-3"> |
||||||
|
<label for="password" class="form-label">Password</label> |
||||||
|
<input type="password" class="form-control" id="password" name="password" placeholder="Enter your password" required> |
||||||
|
</div> |
||||||
|
<div class="d-flex justify-content-between align-items-center"> |
||||||
|
<div class="form-check"> |
||||||
|
<input type="checkbox" class="form-check-input" id="rememberMe"> |
||||||
|
<label class="form-check-label" for="rememberMe">Remember Me</label> |
||||||
|
</div> |
||||||
|
<a href="#" class="small">Forgot password?</a> |
||||||
|
</div> |
||||||
|
<button type="submit" class="btn btn-primary w-100 mt-3">Login</button> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
|
||||||
|
{% endblock %} |
@ -1,65 +0,0 @@ |
|||||||
{% load static %} |
|
||||||
|
|
||||||
<!DOCTYPE html> |
|
||||||
<html lang="en"> |
|
||||||
<head> |
|
||||||
<meta charset="UTF-8"> |
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
||||||
<title>Welcome to Sahara</title> |
|
||||||
<style> |
|
||||||
body { |
|
||||||
font-family: Arial, sans-serif; |
|
||||||
color: #333; |
|
||||||
background-color: #f7f7f7; |
|
||||||
padding: 30px; |
|
||||||
} |
|
||||||
|
|
||||||
.email-container { |
|
||||||
background-color: #ffffff; |
|
||||||
padding: 20px; |
|
||||||
border-radius: 8px; |
|
||||||
max-width: 600px; |
|
||||||
margin: 0 auto; |
|
||||||
} |
|
||||||
|
|
||||||
h1 { |
|
||||||
color: #2c3e50; |
|
||||||
} |
|
||||||
|
|
||||||
.company-logo { |
|
||||||
max-width: 150px; |
|
||||||
margin-bottom: 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.cta-button { |
|
||||||
background-color: #3498db; |
|
||||||
color: #ffffff; |
|
||||||
padding: 10px 20px; |
|
||||||
border-radius: 5px; |
|
||||||
text-decoration: none; |
|
||||||
display: inline-block; |
|
||||||
font-size: 16px; |
|
||||||
} |
|
||||||
|
|
||||||
.cta-button:hover { |
|
||||||
background-color: #2980b9; |
|
||||||
} |
|
||||||
|
|
||||||
p { |
|
||||||
font-size: 16px; |
|
||||||
} |
|
||||||
</style> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<div class="email-container"> |
|
||||||
<h1>Welcome to Sahara!</h1> |
|
||||||
<img src="{% static 'images/sahara_logo.png' %}" alt="Sahara" class="company-logo"> |
|
||||||
<p>Hello {{ user.first_name }},</p> |
|
||||||
<p>Thank you for signing up with Sahara! We're excited to have you on board.</p> |
|
||||||
<p>Please click the button below to activate your account:</p> |
|
||||||
<a href="{{ activation_link }}" class="cta-button">Activate Your Account</a> |
|
||||||
<p>If you did not sign up for this account, please ignore this email.</p> |
|
||||||
<p>Best regards,<br>Sahara Team</p> |
|
||||||
</div> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -1,14 +0,0 @@ |
|||||||
Welcome to Sahara! |
|
||||||
|
|
||||||
Hello {{ user.first_name }}, |
|
||||||
|
|
||||||
Thank you for signing up with Sahara! We're excited to have you on board. |
|
||||||
|
|
||||||
Please click the link below to activate your account: |
|
||||||
|
|
||||||
{{ activation_link }} |
|
||||||
|
|
||||||
If you did not sign up for this account, please ignore this email. |
|
||||||
|
|
||||||
Best regards, |
|
||||||
Sahara Team |
|
@ -0,0 +1,36 @@ |
|||||||
|
{% extends 'base.html' %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<div class="container"> |
||||||
|
<h2>Register</h2> |
||||||
|
<form method="post"> |
||||||
|
{% csrf_token %} |
||||||
|
<div class="form-group"> |
||||||
|
<label for="{{ form.first_name.id_for_label }}">First Name</label> |
||||||
|
{{ form.first_name }} |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label for="{{ form.last_name.id_for_label }}">Last Name</label> |
||||||
|
{{ form.last_name }} |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label for="{{ form.username.id_for_label }}">Username</label> |
||||||
|
{{ form.username }} |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label for="{{ form.email.id_for_label }}">Email</label> |
||||||
|
{{ form.email }} |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label for="{{ form.password.id_for_label }}">Password</label> |
||||||
|
{{ form.password }} |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label for="{{ form.confirm_password.id_for_label }}">Confirm Password</label> |
||||||
|
{{ form.confirm_password }} |
||||||
|
</div> |
||||||
|
<button type="submit" class="btn btn-primary">Register</button> |
||||||
|
</form> |
||||||
|
<p>Already have an account? <a href="{% url 'login' %}">Login here</a>.</p> |
||||||
|
</div> |
||||||
|
{% endblock %} |
@ -1,5 +0,0 @@ |
|||||||
<form method="post"> |
|
||||||
{% csrf_token %} |
|
||||||
{{ form.as_p }} |
|
||||||
<button type="submit">Update</button> |
|
||||||
</form> |
|
@ -1,5 +0,0 @@ |
|||||||
|
|
||||||
{% for user in users %} |
|
||||||
<p><a href="{% url 'update_user' pk=user.pk %}">{{ user }}</a> |
|
||||||
<a href="{% url 'delete_user' pk=user.pk %}">(delete)</a></p> |
|
||||||
{% endfor %} |
|
@ -0,0 +1,10 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Email Verification Failed</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h1>Email Verification Failed</h1> |
||||||
|
<p>The verification link is invalid or has expired.</p> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,10 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Email Verified</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h1>Email Verified Successfully</h1> |
||||||
|
<p>Your email has been verified. You can now log in.</p> |
||||||
|
</body> |
||||||
|
</html> |
@ -1,9 +1,11 @@ |
|||||||
from django.urls import path |
from django.urls import path |
||||||
from .views import homeView,send_mail_page,createUserView,activate_account |
from . import views |
||||||
|
|
||||||
urlpatterns = [ |
urlpatterns = [ |
||||||
path('',homeView, name="home"), |
path('', views.home, name="home"), |
||||||
path('send-email/',send_mail_page,name="sendmail"), |
path('register/', views.register, name='register'), |
||||||
path('user/register/',createUserView,name="register"), |
path('activate/<str:uidb64>/<str:token>/', views.activate_account, name='activate_account'), |
||||||
path('activate/<str:token>/', activate_account, name='activate'), |
# path('verify-email/<str:uidb64>/<str:token>/', views.verify_email, name='verify_email'), |
||||||
|
path('login/', views.user_login, name='login'), |
||||||
|
path('logout/', views.user_logout, name='logout'), |
||||||
] |
] |
@ -1,26 +0,0 @@ |
|||||||
from django.core.mail import send_mail |
|
||||||
from django.template.loader import render_to_string |
|
||||||
from django.utils.html import strip_tags |
|
||||||
from django.conf import settings |
|
||||||
from django.urls import reverse |
|
||||||
from django.contrib.sites.shortcuts import get_current_site |
|
||||||
|
|
||||||
|
|
||||||
def send_welcome_email(user, request): |
|
||||||
token = 'generated_token_here' |
|
||||||
activation_link = f"{get_current_site(request).domain}{reverse('account:activate', args=[token])}" |
|
||||||
subject = "Welcome to Sahara - Please Activate Your Account" |
|
||||||
|
|
||||||
html_message = render_to_string('welcome_email.html', { |
|
||||||
'user': user, |
|
||||||
'activation_link': activation_link, |
|
||||||
}) |
|
||||||
plain_message = strip_tags(html_message) |
|
||||||
|
|
||||||
send_mail( |
|
||||||
subject, |
|
||||||
plain_message, |
|
||||||
settings.DEFAULT_FROM_EMAIL, |
|
||||||
[user.email], |
|
||||||
html_message=html_message, |
|
||||||
) |
|
@ -1,63 +1,82 @@ |
|||||||
from django.shortcuts import render,redirect,HttpResponse |
from django.shortcuts import render, redirect,HttpResponse |
||||||
from django.core.mail import send_mail |
from django.contrib.auth import login, logout, authenticate |
||||||
from django.conf import settings |
|
||||||
from django.template.loader import render_to_string |
|
||||||
from django.utils.html import strip_tags |
|
||||||
from django.conf import settings |
|
||||||
from django.urls import reverse |
|
||||||
from django.contrib.sites.shortcuts import get_current_site |
|
||||||
from . forms import BaseUserForm |
|
||||||
from django.contrib import messages |
|
||||||
from django.contrib.auth.tokens import default_token_generator |
from django.contrib.auth.tokens import default_token_generator |
||||||
# Create your views here. |
from django.utils.http import urlsafe_base64_decode |
||||||
|
from django.contrib.auth.decorators import login_required |
||||||
|
from django.contrib import messages |
||||||
|
from .models import User |
||||||
|
from .forms import UserRegistrationForm, UserLoginForm |
||||||
|
import logging |
||||||
|
|
||||||
from .models import BaseUser |
|
||||||
|
|
||||||
def homeView(request): |
logger = logging.getLogger('main') |
||||||
return HttpResponse("home") |
def home(request): |
||||||
|
return render(request,"main/home.html") |
||||||
|
|
||||||
def createUserView(request): |
|
||||||
|
def register(request): |
||||||
if request.method == 'POST': |
if request.method == 'POST': |
||||||
form = BaseUserForm(request.POST, request.FILES) |
form = UserRegistrationForm(request.POST) |
||||||
print(form) |
|
||||||
if form.is_valid(): |
if form.is_valid(): |
||||||
form.save() |
user = form.save(commit=False) |
||||||
form.is_a |
user.set_password(form.cleaned_data['password']) |
||||||
#return redirect('home') |
user.save() |
||||||
return HttpResponse("<h1>User Created</h1>") |
|
||||||
else: |
|
||||||
form = BaseUserForm() |
|
||||||
return render(request, 'main/create_user.html', { |
|
||||||
'form': form |
|
||||||
}) |
|
||||||
|
|
||||||
|
try: |
||||||
|
user.send_verification_email() |
||||||
|
messages.success(request, 'Registration successful! Please check your email to activate your account.') |
||||||
|
except Exception as e: |
||||||
|
logger.error(f"Error sending verification email: {e}") |
||||||
|
messages.error(request, 'Error sending verification email. Please try again later.') |
||||||
|
|
||||||
def send_mail_page(): |
return redirect('login') |
||||||
address = "sajeshmaan@gmail.com" |
else: |
||||||
subject = "Congrts Team Flash" |
form = UserRegistrationForm() |
||||||
message = "Congrts Team Flash hackx committe has announced your team as a winner" |
return render(request, 'main/register.html', {'form': form}) |
||||||
try: |
|
||||||
send_mail(subject, message, settings.EMAIL_HOST_USER, [address,'rajakiaryal0@gmail.com']) |
|
||||||
result= 'Email sent successfully' |
|
||||||
except Exception as e: |
|
||||||
result = f'Error sending email: {e}' |
|
||||||
|
|
||||||
|
def activate_account(request, uidb64, token): |
||||||
|
try: |
||||||
|
uid = urlsafe_base64_decode(uidb64).decode() |
||||||
|
user = User.objects.get(pk=uid) |
||||||
|
except (TypeError, ValueError, OverflowError, User.DoesNotExist): |
||||||
|
user = None |
||||||
|
|
||||||
|
if user is not None and default_token_generator.check_token(user, token): |
||||||
|
user.is_active = True |
||||||
|
user.save() |
||||||
|
messages.success(request, 'Your account has been activated. You can now log in.') |
||||||
|
return redirect('login') |
||||||
|
else: |
||||||
|
messages.error(request, 'Invalid activation link.') |
||||||
|
return redirect('register') |
||||||
|
|
||||||
|
def user_login(request): |
||||||
|
print(request.user.is_authenticated) |
||||||
|
if request.user.is_authenticated: |
||||||
|
return redirect('home') |
||||||
|
|
||||||
def activate_account(request,token): |
if request.method == 'POST': |
||||||
return |
email = request.POST['email'] |
||||||
try: |
password = request.POST['password'] |
||||||
# Decode token and retrieve user |
user = authenticate(request, email = email, password = password) |
||||||
user = BaseUser.objects.get(email__iexact="") |
if user is not None: |
||||||
if user: |
form = login(request, user) |
||||||
# Activate user account |
messages.success(request, f' welcome {user} !!') |
||||||
user.is_active = True |
return redirect('home') |
||||||
user.save() |
|
||||||
messages.success(request, "Account activated successfully!") |
|
||||||
return redirect('login') # Redirect to the login page |
|
||||||
else: |
else: |
||||||
messages.error(request, "Invalid activation link.") |
messages.info(request, f'account done not exit plz sign in') |
||||||
except Exception as e: |
|
||||||
messages.error(request, str(e)) |
messages.info(request, f'You are Already Logged in as {request.user}') |
||||||
return redirect('home') # Redirect to homepage in case of error |
return render(request, 'main/login.html', {'title':'log in'}) |
||||||
|
|
||||||
|
|
||||||
|
@login_required |
||||||
|
def user_logout(request): |
||||||
|
logout(request) |
||||||
|
messages.success(request, 'You have been logged out.') |
||||||
|
return redirect('login') |
||||||
|
|
||||||
|
# def verify_email(request, uidb64, token): |
||||||
|
# # This view is redundant if it does the same as activate_account |
||||||
|
# # Consider removing or assigning a different purpose |
||||||
|
# pass |
Before Width: | Height: | Size: 273 KiB |
Before Width: | Height: | Size: 273 KiB |
Before Width: | Height: | Size: 273 KiB |
Before Width: | Height: | Size: 273 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 273 KiB |
@ -1,12 +1,7 @@ |
|||||||
from django.contrib import admin |
from django.contrib import admin |
||||||
from django.urls import path,include |
from django.urls import path, include |
||||||
from django.conf import settings |
|
||||||
from django.conf.urls.static import static |
|
||||||
|
|
||||||
urlpatterns = [ |
urlpatterns = [ |
||||||
path('admin/', admin.site.urls), |
path('admin/', admin.site.urls), |
||||||
path('',include("main.urls")) |
path('', include('main.urls')), |
||||||
] |
] |
||||||
|
|
||||||
if settings.DEBUG: |
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) |
|
@ -0,0 +1,38 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||||
|
<title>Sahara</title> |
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> |
||||||
|
<link rel="stylesheet" href="styles.css"> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<nav class="navbar navbar-expand-lg bg-body-tertiary"> |
||||||
|
<div class="container-fluid"> |
||||||
|
<a class="navbar-brand" href="#"><img src="img/logofinal.png" height="50px" width="75px" alt="Logo"></a> |
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> |
||||||
|
<span class="navbar-toggler-icon"></span> |
||||||
|
</button> |
||||||
|
<ul class="nav justify-content-center"> |
||||||
|
<li class="nav-item"> |
||||||
|
<a class="nav-link active" aria-current="page" href="#">Home</a> |
||||||
|
</li> |
||||||
|
<li class="nav-item"> |
||||||
|
<a class="nav-link" href="#">About us</a> |
||||||
|
</li> |
||||||
|
<li class="nav-item"> |
||||||
|
<a class="nav-link" href="#">Services</a> |
||||||
|
</li> |
||||||
|
|
||||||
|
</ul> |
||||||
|
<div class="login"> |
||||||
|
<a href="#" class="btn btn-outline-primary">Login</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</nav> |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
|
||||||
|
{% endblock %} |