add sign up process for backlogger
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.contrib.auth.admin import UserAdmin
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from .models import Item
|
from .models import Item
|
||||||
|
|
||||||
|
|
||||||
@@ -7,3 +9,14 @@ class ItemAdmin(admin.ModelAdmin):
|
|||||||
list_display = ['name', 'category', 'progress_percent', 'favorite', 'created_at']
|
list_display = ['name', 'category', 'progress_percent', 'favorite', 'created_at']
|
||||||
list_filter = ['category', 'favorite']
|
list_filter = ['category', 'favorite']
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.unregister(User)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(User)
|
||||||
|
class CustomUserAdmin(UserAdmin):
|
||||||
|
list_display = ['username', 'email', 'is_active', 'date_joined']
|
||||||
|
list_editable = ['is_active']
|
||||||
|
list_filter = ['is_active']
|
||||||
|
ordering = ['date_joined']
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from .models import Item
|
from .models import Item
|
||||||
|
|
||||||
|
|
||||||
|
class SignupForm(UserCreationForm):
|
||||||
|
email = forms.EmailField(required=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ['username', 'email', 'password1', 'password2']
|
||||||
|
|
||||||
|
|
||||||
class ItemForm(forms.ModelForm):
|
class ItemForm(forms.ModelForm):
|
||||||
progress_percent = forms.FloatField(
|
progress_percent = forms.FloatField(
|
||||||
min_value=0,
|
min_value=0,
|
||||||
|
|||||||
@@ -89,7 +89,13 @@
|
|||||||
<p class="subtitle">Backlogger</p>
|
<p class="subtitle">Backlogger</p>
|
||||||
|
|
||||||
{% if form.non_field_errors %}
|
{% if form.non_field_errors %}
|
||||||
<div class="error-banner">Invalid username or password.</div>
|
{% for error in form.non_field_errors %}
|
||||||
|
{% if 'inactive' in error|lower or 'active' in error|lower %}
|
||||||
|
<div class="error-banner">Your account is pending approval. You'll be able to log in once it's activated.</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="error-banner">Invalid username or password.</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
@@ -109,6 +115,9 @@
|
|||||||
|
|
||||||
<button type="submit" class="btn">Log in</button>
|
<button type="submit" class="btn">Log in</button>
|
||||||
</form>
|
</form>
|
||||||
|
<p style="text-align:center; margin-top:1.25rem; font-size:0.83rem; color:#64748b;">
|
||||||
|
No account? <a href="/accounts/signup/" style="color:#38bdf8; text-decoration:none;">Sign up</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
117
backlogger/templates/backlogger/signup.html
Normal file
117
backlogger/templates/backlogger/signup.html
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Sign up — Backlogger</title>
|
||||||
|
<style>
|
||||||
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
background: #0f172a;
|
||||||
|
color: #e2e8f0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: #0a0f1e;
|
||||||
|
border: 1px solid #1e293b;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2.5rem 2rem;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 360px;
|
||||||
|
}
|
||||||
|
.brand {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
color: #38bdf8;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
text-align: center;
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
.field { margin-bottom: 1.1rem; }
|
||||||
|
.field label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
color: #94a3b8;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.07em;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
.field input {
|
||||||
|
width: 100%;
|
||||||
|
background: #1e293b;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #e2e8f0;
|
||||||
|
padding: 0.6rem 0.75rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.field input:focus { outline: none; border-color: #38bdf8; }
|
||||||
|
.btn {
|
||||||
|
width: 100%;
|
||||||
|
background: #38bdf8;
|
||||||
|
color: #0f172a;
|
||||||
|
font-weight: 600;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0.6rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
.btn:hover { opacity: 0.88; }
|
||||||
|
.errorlist { list-style: none; color: #f87171; font-size: 0.8rem; margin-top: 0.3rem; }
|
||||||
|
.help { font-size: 0.75rem; color: #475569; margin-top: 0.3rem; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="card">
|
||||||
|
<a class="brand" href="/">killmybacklog.com</a>
|
||||||
|
<p class="subtitle">Create an account</p>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.username.id_for_label }}">Username</label>
|
||||||
|
{{ form.username }}
|
||||||
|
{{ form.username.errors }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.email.id_for_label }}">Email</label>
|
||||||
|
{{ form.email }}
|
||||||
|
{{ form.email.errors }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.password1.id_for_label }}">Password</label>
|
||||||
|
{{ form.password1 }}
|
||||||
|
{{ form.password1.errors }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.password2.id_for_label }}">Confirm password</label>
|
||||||
|
{{ form.password2 }}
|
||||||
|
{{ form.password2.errors }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn">Request account</button>
|
||||||
|
</form>
|
||||||
|
<p style="text-align:center; margin-top:1.25rem; font-size:0.83rem; color:#64748b;">
|
||||||
|
Already have an account? <a href="/accounts/login/" style="color:#38bdf8; text-decoration:none;">Log in</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
51
backlogger/templates/backlogger/signup_pending.html
Normal file
51
backlogger/templates/backlogger/signup_pending.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Account requested — Backlogger</title>
|
||||||
|
<style>
|
||||||
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
background: #0f172a;
|
||||||
|
color: #e2e8f0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: #0a0f1e;
|
||||||
|
border: 1px solid #1e293b;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2.5rem 2rem;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 360px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.brand {
|
||||||
|
display: block;
|
||||||
|
color: #38bdf8;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.icon { font-size: 2rem; margin: 1.25rem 0 0.75rem; }
|
||||||
|
h2 { font-size: 1rem; font-weight: 600; margin-bottom: 0.6rem; }
|
||||||
|
p { font-size: 0.85rem; color: #64748b; line-height: 1.5; }
|
||||||
|
a { color: #38bdf8; text-decoration: none; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="card">
|
||||||
|
<a class="brand" href="/">killmybacklog.com</a>
|
||||||
|
<div class="icon">✓</div>
|
||||||
|
<h2>Account requested</h2>
|
||||||
|
<p>Your account is pending approval.<br>You'll receive access once it's activated.</p>
|
||||||
|
<p style="margin-top:1.5rem;"><a href="/accounts/login/">Back to log in</a></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,7 +1,20 @@
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import render, get_object_or_404, redirect
|
from django.shortcuts import render, get_object_or_404, redirect
|
||||||
from .models import Item
|
from .models import Item
|
||||||
from .forms import ItemForm
|
from .forms import ItemForm, SignupForm
|
||||||
|
|
||||||
|
|
||||||
|
def signup(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = SignupForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
user = form.save(commit=False)
|
||||||
|
user.is_active = False
|
||||||
|
user.save()
|
||||||
|
return render(request, 'backlogger/signup_pending.html')
|
||||||
|
else:
|
||||||
|
form = SignupForm()
|
||||||
|
return render(request, 'backlogger/signup.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
SORT_MAP = {
|
SORT_MAP = {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
from backlogger.views import signup
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('accounts/login/', auth_views.LoginView.as_view(template_name='backlogger/login.html'), name='login'),
|
path('accounts/login/', auth_views.LoginView.as_view(template_name='backlogger/login.html'), name='login'),
|
||||||
path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'),
|
path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'),
|
||||||
|
path('accounts/signup/', signup, name='signup'),
|
||||||
path('backlogger/', include('backlogger.urls')),
|
path('backlogger/', include('backlogger.urls')),
|
||||||
path('daily-stone/', include('dailystone.urls')),
|
path('daily-stone/', include('dailystone.urls')),
|
||||||
path('', include('core.urls')),
|
path('', include('core.urls')),
|
||||||
|
|||||||
Reference in New Issue
Block a user