Skip to content

Commit

Permalink
Enhance/production settings (#203)
Browse files Browse the repository at this point in the history
* Attempting to add mysql + postgres to Dockerfile for production and still work with testing

* Attempting to add mysql + postgres to Dockerfile for production and still work with testing

* v0.2.1

* Run postgres no matter what unless you specify not to

* Run postgres no matter what unless you specify not to

* Updated poetry lock

* Updated sqlmode for prod too

* Ran black formatter

* Added support for AWS S3

* Ran black formatter

* Added feature flags via AWS AppConfig

* Cleaned up feature flags

* Ready for 0.2.1-alpha.6

* Revert "Ready for 0.2.1-alpha.6"

This reverts commit 4fa6f45.

* Ready for 0.2.1-alpha.6

* Ran black formatter

* Ready for FeatureFlags + More testing

* Ran formatter

* Adding debug statements

* Adding feature flags (AWS AppConfig / Cache)

* Changed the buttons to be "Dashboard" if logged in, rather than "login" and "register"

* Added user roles (USER/DEV/TESTER/STAFF)

* Ran formatters

* v0.2.1

* Minor cleanup
  • Loading branch information
TreyWW authored Feb 20, 2024
1 parent a183ccf commit 87c64e3
Show file tree
Hide file tree
Showing 23 changed files with 30,930 additions and 343 deletions.
4 changes: 3 additions & 1 deletion backend/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from backend.models import (
Expand All @@ -16,8 +17,8 @@
TeamInvitation,
User,
InvoiceProduct,
FeatureFlags,
)
from django.contrib import admin

# admin.register(Invoice)
admin.site.register(UserSettings)
Expand All @@ -34,6 +35,7 @@
admin.site.register(Team)
admin.site.register(TeamInvitation)
admin.site.register(InvoiceProduct)
admin.site.register(FeatureFlags)
admin.site.register(User, UserAdmin)

admin.site.site_header = "MyFinances Admin"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 5.0.2 on 2024-02-14 19:26

from django.db import migrations, models

import settings.settings


class Migration(migrations.Migration):

dependencies = [
("backend", "0015_alter_notification_user_alter_team_name"),
]

operations = [
migrations.AlterField(
model_name="invoice",
name="logo",
field=models.ImageField(
blank=True,
null=True,
storage=settings.settings.CustomPrivateMediaStorage(),
upload_to="invoice_logos",
),
),
migrations.AlterField(
model_name="receipt",
name="image",
field=models.ImageField(
storage=settings.settings.CustomPrivateMediaStorage(),
upload_to="receipts",
),
),
migrations.AlterField(
model_name="usersettings",
name="profile_picture",
field=models.ImageField(
blank=True,
null=True,
storage=settings.settings.CustomPublicMediaStorage(),
upload_to="profile_pictures/",
),
),
]
30 changes: 30 additions & 0 deletions backend/migrations/0017_featureflags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.0.2 on 2024-02-18 20:17

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("backend", "0016_alter_invoice_logo_alter_receipt_image_and_more"),
]

operations = [
migrations.CreateModel(
name="FeatureFlags",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
("value", models.BooleanField(default=False)),
("updated_at", models.DateTimeField(auto_now=True)),
],
),
]
27 changes: 27 additions & 0 deletions backend/migrations/0018_user_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 5.0.1 on 2024-02-20 10:18

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("backend", "0017_featureflags"),
]

operations = [
migrations.AddField(
model_name="user",
name="role",
field=models.CharField(
choices=[
("DEV", "Developer"),
("STAFF", "Staff"),
("USER", "User"),
("TESTER", "Tester"),
],
default="USER",
max_length=10,
),
),
]
31 changes: 28 additions & 3 deletions backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ class User(AbstractUser):

logged_in_as_team = models.ForeignKey("Team", on_delete=models.SET_NULL, null=True)

class Role(models.TextChoices):
# NAME DJANGO ADMIN NAME
DEV = "DEV", "Developer"
STAFF = "STAFF", "Staff"
USER = "USER", "User"
TESTER = "TESTER", "Tester"

role = models.CharField(max_length=10, choices=Role.choices, default=Role.USER)


class CustomUserMiddleware:
def __init__(self, get_response):
Expand Down Expand Up @@ -79,7 +88,10 @@ class UserSettings(models.Model):
choices=[(code, info["name"]) for code, info in CURRENCIES.items()],
)
profile_picture = models.ImageField(
upload_to="profile_pictures/", blank=True, null=True
upload_to="profile_pictures/",
storage=settings.CustomPublicMediaStorage(),
blank=True,
null=True,
)

@property
Expand Down Expand Up @@ -148,7 +160,9 @@ class Receipt(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
organization = models.ForeignKey(Team, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=100)
image = models.ImageField(upload_to="receipts")
image = models.ImageField(
upload_to="receipts", storage=settings.CustomPrivateMediaStorage()
)
total_price = models.FloatField(null=True, blank=True)
date = models.DateField(null=True, blank=True)
date_uploaded = models.DateTimeField(auto_now_add=True)
Expand Down Expand Up @@ -254,7 +268,12 @@ class Invoice(models.Model):
reference = models.CharField(max_length=100, blank=True, null=True)
invoice_number = models.CharField(max_length=100, blank=True, null=True)
vat_number = models.CharField(max_length=100, blank=True, null=True)
logo = models.ImageField(upload_to="invoice_logos", blank=True, null=True)
logo = models.ImageField(
upload_to="invoice_logos",
storage=settings.CustomPrivateMediaStorage(),
blank=True,
null=True,
)
notes = models.TextField(blank=True, null=True)

payment_status = models.CharField(
Expand Down Expand Up @@ -414,6 +433,12 @@ def __str__(self):
return str(self.error)


class FeatureFlags(models.Model):
name = models.CharField(max_length=100)
value = models.BooleanField(default=False)
updated_at = models.DateTimeField(auto_now=True)


def SEND_SENDGRID_EMAIL(
to_email,
subject,
Expand Down
24 changes: 22 additions & 2 deletions backend/signals.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from django.core.files.storage import default_storage
from django.db.models.signals import pre_save, post_delete, post_save
from django.db.models.signals import pre_save, post_delete, post_save, post_migrate
from django.dispatch import receiver

from backend.models import UserSettings, Receipt, User
from backend.models import UserSettings, Receipt, User, FeatureFlags


@receiver(pre_save, sender=UserSettings)
Expand Down Expand Up @@ -51,3 +51,23 @@ def user_account_create_make_usersettings(sender, instance, created, **kwargs):

if not users_settings:
UserSettings.objects.create(user=instance)


@receiver(post_delete, sender=Receipt)
def delete_receipt_image_on_delete(sender, instance: Receipt, **kwargs):
instance.image.delete(False)


feature_flags = [{"name": "areSignupsEnabled", "default": True, "pk": 1}]


def insert_initial_data(**kwargs):
for feature in feature_flags:
FeatureFlags.objects.get_or_create(
id=feature.get("pk"),
name=feature.get("name"),
value=feature.get("default"),
)


post_migrate.connect(insert_initial_data)
19 changes: 19 additions & 0 deletions backend/utils.py
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
from django.core.cache import cache
from django.core.cache.backends.redis import RedisCacheClient

cache: RedisCacheClient = cache

from backend.models import FeatureFlags


def get_feature_status(feature):
key = f"myfinances:feature_flag:{feature}"
cached_value = cache.get(key)
if cached_value:
return cached_value

value = FeatureFlags.objects.filter(name=feature).first()
if value:
cache.set(key, value.value, timeout=300)
return value.value
else:
return False
1 change: 1 addition & 0 deletions backend/views/core/other/index.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.core.cache import cache
from django.http import HttpRequest
from django.shortcuts import render

Expand Down
15 changes: 15 additions & 0 deletions backend/views/core/other/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

from backend.decorators import *
from backend.models import LoginLog, AuditLog, User
from backend.utils import get_feature_status

# from backend.utils import appconfig
from settings.settings import (
SOCIAL_AUTH_GITHUB_ENABLED,
SOCIAL_AUTH_GOOGLE_OAUTH2_ENABLED,
Expand Down Expand Up @@ -66,6 +69,10 @@ class CreateAccountChooseView(View):
def get(self, request):
if request.user.is_authenticated:
return redirect("dashboard")
SIGNUPS_ENABLED = get_feature_status("areSignupsEnabled")
if not SIGNUPS_ENABLED:
messages.error(request, "New account signups are currently disabled")
return redirect("login")
return render(
request,
"pages/login/create_account_choose.html",
Expand All @@ -80,11 +87,19 @@ class CreateAccountManualView(View):
def get(self, request):
if request.user.is_authenticated:
return redirect("dashboard")
SIGNUPS_ENABLED = get_feature_status("areSignupsEnabled")
if not SIGNUPS_ENABLED:
messages.error(request, "New account signups are currently disabled")
return redirect("login")
return render(request, "pages/login/create_account_manual.html")

def post(self, request):
if request.user.is_authenticated:
return redirect("dashboard")
SIGNUPS_ENABLED = get_feature_status("areSignupsEnabled")
if not SIGNUPS_ENABLED:
messages.error(request, "New account signups are currently disabled")
return redirect("login")

email = request.POST.get("email")
password = request.POST.get("password")
Expand Down
33 changes: 30 additions & 3 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
# Changelog

## [v0.1.1](https://github.com/TreyWW/MyFinances/releases/tag/v0.1.1) <small>([view diff](https://github.com/TreyWW/MyFinances/compare/v0.1.0...v0.1.1))</small>
## [v0.2.1](https://github.com/TreyWW/MyFinances/releases/tag/v0.2.1) <small>([view diff](https://github.com/TreyWW/MyFinances/compare/v0.2.0...v0.2.1))</small>
### Overview
* 🚩 Added **feature flags**
* 🐘 Added more **postgres** support
* 🚅 Added **cache** settings
* 🎉 **Deployment** has been **successful** and will now undergo more testing!
* 👋 Possible clients already interested and ready for official launches!


## [v0.2.0](https://github.com/TreyWW/MyFinances/releases/tag/v0.2.0) <small>([view diff](https://github.com/TreyWW/MyFinances/compare/v0.1.2...v0.2.0))</small>
### Overview
* 👥 Added **Teams** functionality
* 🐘 Added **PostgreSQL** database support
* 🐧 Added **matrix** support so we can now run tests with multiple django versions and multiple ubuntu versions
* 🧾 Added PDF Upload option for receipts
* 🧹 Added djLint for HTML file linting
* 📦 Ready to start getting the product ready for pre-production and more testing


### Features
## [v0.1.2](https://github.com/TreyWW/MyFinances/releases/tag/v0.1.2) <small>([view diff](https://github.com/TreyWW/MyFinances/compare/v0.1.1...v0.1.2))</small>
### Overview
* 📦 Added [python poetry](https://python-poetry.org/)
* ✏️ Added the ability to edit invoices
* 📜 Added [hyperscript](https://hyperscript.org/)
* 🧾 Added more info for receipts & the ability to SAFELY download them
* 🐬 Fixed docker builds, now uses poetry, and runs much faster


## [v0.1.1](https://github.com/TreyWW/MyFinances/releases/tag/v0.1.1) <small>([view diff](https://github.com/TreyWW/MyFinances/compare/v0.1.0...v0.1.1))</small>
### Overview
* Added documentation
* Added social logins (github + google)
* Added custom colours for tailwind theme
* Added signal for UserSettings addition on user creation

## [v0.1.0](https://github.com/TreyWW/MyFinances/releases/tag/v0.1.0)

### Overview
First release of the project. Some core features that we made a start to:
- 🧾 Receipts
- 📜 Invoices
Expand Down
12 changes: 11 additions & 1 deletion docs/getting-setup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,14 @@ Welcome to MyFinances, this guide will help you get setup and running the app fo
- [Setup with PyCharm PRO](getting-setup/pycharm/fork)
- [Setup with anything else](getting-setup/other-environments/)

Then you can setup a local database. [View our guide](getting-setup/databases/)
### Setting up a database

Then you can setup a local database. [View our guide](getting-setup/databases/)

### Setting up AWS

We support many AWS Services, primarily S3 and Cloudfront

#### S3 for media

These are files that users upload. [View our Guide]()
5 changes: 5 additions & 0 deletions docs/getting-setup/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@
- [Social Login Setup](getting-setup/social-logins?id=social-login)
* [Github](getting-setup/social-logins?id=set-up-social-login-with-github)
* [Google](getting-setup/social-logins?id=set-up-social-login-with-google)
- [Using AWS](getting-setup/aws)
* [Setting up a CDN for Static Files](getting-setup/aws)
* [Setting up Media public storage](getting-setup/aws)
* [Setting up Media private storage](getting-setup/aws)
* [Setting up Feature Flags](getting-setup/aws/feature-flags)
Loading

0 comments on commit 87c64e3

Please sign in to comment.