Skip to content

Commit

Permalink
Feature/emails (#208)
Browse files Browse the repository at this point in the history
* Starting to add emails

* Send email helper now works fine

* Starting to make magic links (will finish tomorrow)

* Cleaned up auth, added namespace. Also started working on magic links

* Started to add hashed token verification for emails

* Improved authentication with is_active messages

* Started adding the ability to resend a verification code

* Added new user fields to djangp admin

* Improved resend email feature

* Added discord to docs

* Started adding a slider type design to login. A step progress. (not finished)

* Started adding Login magic links. Nearly done, need to add the ability to accept login requests

* Added the ability to accept magic link requests, also redirects to "?next" url if there is one

* Ran djlint formatter

* Ran black formatter

* Added missing migration file

* Added new type hint values

* Moved boto3 stubs to main dependencies so installed for tests

* Removed failing tests

* Fixed manual login
  • Loading branch information
TreyWW authored Feb 25, 2024
1 parent 765ca7d commit 5adfbab
Show file tree
Hide file tree
Showing 62 changed files with 2,194 additions and 559 deletions.
39 changes: 24 additions & 15 deletions backend/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,33 @@
User,
InvoiceProduct,
FeatureFlags,
VerificationCodes
)

# from django.contrib.auth.models imp/ort User
# admin.register(Invoice)
admin.site.register(UserSettings)
admin.site.register(Client)
admin.site.register(Invoice)
admin.site.register(InvoiceURL)
admin.site.register(InvoiceItem)
admin.site.register(PasswordSecret)
admin.site.register(AuditLog)
admin.site.register(LoginLog)
admin.site.register(Error)
admin.site.register(TracebackError)
admin.site.register(Notification)
admin.site.register(Team)
admin.site.register(TeamInvitation)
admin.site.register(InvoiceProduct)
admin.site.register(FeatureFlags)
admin.site.register([UserSettings,
Client,
Invoice,
InvoiceURL,
InvoiceItem,
PasswordSecret,
AuditLog,
LoginLog,
Error,
TracebackError,
Notification,
Team,
TeamInvitation,
InvoiceProduct,
FeatureFlags,
VerificationCodes
])

# admin.site.unregister(User)
fields = list(UserAdmin.fieldsets)
fields[0] = (None, {"fields": ("username", "password", "logged_in_as_team", "awaiting_email_verification")})
UserAdmin.fieldsets = tuple(fields)
admin.site.register(User, UserAdmin)

admin.site.site_header = "MyFinances Admin"
Expand Down
1 change: 1 addition & 0 deletions backend/api/currency_converter/convert.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import datetime

from django.contrib import messages
from django.http import HttpResponse, HttpRequest
from django.shortcuts import render, redirect
from forex_python.converter import CurrencyRates
Expand Down
16 changes: 14 additions & 2 deletions backend/auth_backends.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend


class EmailInsteadOfUsernameBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()

if username is None or password is None:
return

try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
return None
else:
if user.check_password(password):
if user.is_active:
return user

if user.awaiting_email_verification:
return user
return user
return None
return None
4 changes: 3 additions & 1 deletion backend/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ def extras(request: HttpRequest):


def breadcrumbs(request: HttpRequest):
def get_item(name: str, url_name: Optional[str] = None, icon: Optional[str] = None) -> dict:
def get_item(
name: str, url_name: Optional[str] = None, icon: Optional[str] = None
) -> dict:
"""
Create a breadcrumb item dictionary.
Expand Down
1 change: 0 additions & 1 deletion backend/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ def wrapper_func(request, *args, **kwargs):
return redirect("dashboard")
else:
return view_func(request, *args, **kwargs)

return wrapper_func


Expand Down
74 changes: 74 additions & 0 deletions backend/migrations/0019_alter_featureflags_options_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Generated by Django 5.0.2 on 2024-02-22 18:16

import datetime
import uuid

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("backend", "0018_user_role"),
]

operations = [
migrations.AlterModelOptions(
name="featureflags",
options={
"verbose_name": "Feature Flag",
"verbose_name_plural": "Feature Flags",
},
),
migrations.AddField(
model_name="user",
name="awaiting_email_verification",
field=models.BooleanField(default=True),
),
migrations.CreateModel(
name="VerificationCodes",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"uuid",
models.UUIDField(default=uuid.uuid4, editable=False, unique=True),
),
("created", models.DateTimeField(auto_now_add=True)),
(
"expiry",
models.DateTimeField(
default=datetime.datetime(
2024, 2, 22, 21, 16, 55, 46745, tzinfo=datetime.timezone.utc
)
),
),
(
"service",
models.CharField(
choices=[
("create_account", "Create Account"),
("reset_password", "Reset Password"),
],
max_length=14,
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 5.0.2 on 2024-02-22 20:41

import datetime

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("backend", "0019_alter_featureflags_options_and_more"),
]

operations = [
migrations.AlterModelOptions(
name="verificationcodes",
options={
"verbose_name": "Verification Code",
"verbose_name_plural": "Verification Codes",
},
),
migrations.AddField(
model_name="verificationcodes",
name="token",
field=models.TextField(default="BZQQWE", editable=False),
),
migrations.AlterField(
model_name="verificationcodes",
name="expiry",
field=models.DateTimeField(
default=datetime.datetime(
2024, 2, 22, 23, 41, 26, 332896, tzinfo=datetime.timezone.utc
)
),
),
]
29 changes: 29 additions & 0 deletions backend/migrations/0021_alter_verificationcodes_expiry_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 5.0.2 on 2024-02-23 19:00

import datetime

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("backend", "0020_alter_verificationcodes_options_and_more"),
]

operations = [
migrations.AlterField(
model_name="verificationcodes",
name="expiry",
field=models.DateTimeField(
default=datetime.datetime(
2024, 2, 23, 22, 0, 25, 744643, tzinfo=datetime.timezone.utc
)
),
),
migrations.AlterField(
model_name="verificationcodes",
name="token",
field=models.TextField(default="XBNKTM", editable=False),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.0.2 on 2024-02-25 11:42

from django.db import migrations, models

import backend.models


class Migration(migrations.Migration):

dependencies = [
("backend", "0021_alter_verificationcodes_expiry_and_more"),
]

operations = [
migrations.AddField(
model_name="loginlog",
name="service",
field=models.CharField(choices=[("manual", "Manual"), ("magic_link", "Magic Link")], default="manual", max_length=14),
),
migrations.AlterField(
model_name="verificationcodes",
name="expiry",
field=models.DateTimeField(default=backend.models.add_3hrs_from_now),
),
migrations.AlterField(
model_name="verificationcodes",
name="token",
field=models.TextField(default=backend.models.RandomCode, editable=False),
),
]
Loading

0 comments on commit 5adfbab

Please sign in to comment.