Skip to content

Commit

Permalink
Merge branch 'main' into feat/docker-compose
Browse files Browse the repository at this point in the history
  • Loading branch information
kritzl committed Jul 11, 2024
2 parents 60f7346 + bc4fb9e commit a8ce41a
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 31 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ To start it:
pipenv shell
./src/manage.py check --deploy
./src/manage.py migrate
./src/manage.py
./src/manage.py runserver
```

## Configuration
Expand Down
1 change: 1 addition & 0 deletions src/manage.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""

import os
import sys

Expand Down
1 change: 1 addition & 0 deletions src/vinywaji/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from . import models

admin.site.register(models.Transaction)
admin.site.register(models.WebhookConfig)
12 changes: 9 additions & 3 deletions src/vinywaji/core/management/commands/load_old_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ def handle(self, *args, **options):

# re-add users
for user_data in (
i for i in fixture_json if i["model"] == "django_auth_mafiasi.mafiasiauthmodeluser"
i
for i in fixture_json
if i["model"] == "django_auth_mafiasi.mafiasiauthmodeluser"
):
logger.info(
"adding user %s with openid sub %s",
Expand All @@ -41,8 +43,12 @@ def handle(self, *args, **options):
)

# re-add transactions
for transact_data in (i for i in fixture_json if i["model"] == "vinywaji_core.transaction"):
user = openid_models.OpenidUser.objects.get(sub=transact_data["fields"]["user"]).user
for transact_data in (
i for i in fixture_json if i["model"] == "vinywaji_core.transaction"
):
user = openid_models.OpenidUser.objects.get(
sub=transact_data["fields"]["user"]
).user
parsed_datetime = timezone.datetime.strptime(
transact_data["fields"]["time"], "%Y-%m-%dT%H:%M:%S.%fZ"
)
Expand Down
53 changes: 43 additions & 10 deletions src/vinywaji/core/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@


class Migration(migrations.Migration):

initial = True

dependencies = [
Expand All @@ -25,11 +24,19 @@ class Migration(migrations.Migration):
(
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("password", models.CharField(max_length=128, verbose_name="password")),
("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")),
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
(
"is_superuser",
models.BooleanField(
Expand All @@ -41,17 +48,36 @@ class Migration(migrations.Migration):
(
"username",
models.CharField(
error_messages={"unique": "A user with that username already exists."},
error_messages={
"unique": "A user with that username already exists."
},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[django.contrib.auth.validators.UnicodeUsernameValidator()],
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
verbose_name="username",
),
),
("first_name", models.CharField(blank=True, max_length=150, verbose_name="first name")),
("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")),
("email", models.EmailField(blank=True, max_length=254, verbose_name="email address")),
(
"first_name",
models.CharField(
blank=True, max_length=150, verbose_name="first name"
),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
),
(
"email",
models.EmailField(
blank=True, max_length=254, verbose_name="email address"
),
),
(
"is_staff",
models.BooleanField(
Expand All @@ -70,7 +96,9 @@ class Migration(migrations.Migration):
),
(
"date_joined",
models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined"),
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
(
"groups",
Expand Down Expand Up @@ -130,7 +158,12 @@ class Migration(migrations.Migration):
help_text="How much money was involved in this transaction in euro-cent. Negative amounts represent purchases while positive amounts represent deposits."
),
),
("time", models.DateTimeField(auto_now_add=True, help_text="When this transaction occurred")),
(
"time",
models.DateTimeField(
auto_now_add=True, help_text="When this transaction occurred"
),
),
(
"user",
models.ForeignKey(
Expand Down
18 changes: 15 additions & 3 deletions src/vinywaji/core/models.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import uuid
import secrets

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.urls import reverse


def uuid_default() -> "uuid.UUID":
return uuid.uuid4()


def webhook_trigger_default() -> str:
return secrets.token_urlsafe(64)


class User(AbstractUser):
@property
def current_balance(self) -> int:
"""How much money the user currently has in their account"""
aggregate = self.transactions.aggregate(transaction_sum=models.Sum("amount", default=0))
aggregate = self.transactions.aggregate(
transaction_sum=models.Sum("amount", default=0)
)
return aggregate["transaction_sum"]


class Transaction(models.Model):
id = models.UUIDField(primary_key=True, default=uuid_default, help_text="The ID of this transaction")
id = models.UUIDField(
primary_key=True, default=uuid_default, help_text="The ID of this transaction"
)
user = models.ForeignKey(
to="User",
on_delete=models.CASCADE,
Expand All @@ -34,7 +44,9 @@ class Transaction(models.Model):
help_text="How much money was involved in this transaction in euro-cent. "
"Negative amounts represent purchases while positive amounts represent deposits."
)
time = models.DateTimeField(auto_now_add=True, help_text="When this transaction occurred")
time = models.DateTimeField(
auto_now_add=True, help_text="When this transaction occurred"
)

def __str__(self):
if self.description != "":
Expand Down
4 changes: 3 additions & 1 deletion src/vinywaji/metrics/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def init_instrumentation(self):
}
)
metric_reader = PrometheusMetricReader()
meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
meter_provider = MeterProvider(
resource=resource, metric_readers=[metric_reader]
)
metrics.set_meter_provider(meter_provider)
async_instruments.create_async_instruments()
25 changes: 19 additions & 6 deletions src/vinywaji/metrics/async_instruments.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,17 @@ def count_transactions(_options: CallbackOptions) -> Iterable[Observation]:
n_positive = models.Transaction.objects.filter(amount__gt=0).count()
yield Observation(value=n_negative, attributes={"transaction_type": "withdrawal"})
yield Observation(value=n_positive, attributes={"transaction_type": "deposit"})
yield Observation(value=n_positive + n_negative, attributes={"transaction_type": "any"})
yield Observation(
value=n_positive + n_negative, attributes={"transaction_type": "any"}
)


def count_users(_options: CallbackOptions) -> Iterable[Observation]:
n = models.User.objects.all().count()
n_balance = (
models.User.objects.annotate(current_balance=Sum("transactions__amount", default=0))
models.User.objects.annotate(
current_balance=Sum("transactions__amount", default=0)
)
.exclude(current_balance=0)
.count()
)
Expand All @@ -59,18 +63,27 @@ def count_users(_options: CallbackOptions) -> Iterable[Observation]:

def calc_transaction_aggregates(_options: CallbackOptions) -> Iterable[Observation]:
negative_sum = (
models.Transaction.objects.all().filter(amount__gt=0).aggregate(sum=Sum("amount", default=0))
models.Transaction.objects.all()
.filter(amount__gt=0)
.aggregate(sum=Sum("amount", default=0))
)
positive_sum = (
models.Transaction.objects.all().filter(amount__lt=0).aggregate(sum=Sum("amount", default=0))
models.Transaction.objects.all()
.filter(amount__lt=0)
.aggregate(sum=Sum("amount", default=0))
)

yield Observation(
attributes={"transaction_type": "withdrawal"},
value=negative_sum["sum"],
)
yield Observation(attributes={"transaction_type": "deposit"}, value=positive_sum["sum"])
yield Observation(attributes={"transaction_type": "all"}, value=positive_sum["sum"] + negative_sum["sum"])
yield Observation(
attributes={"transaction_type": "deposit"}, value=positive_sum["sum"]
)
yield Observation(
attributes={"transaction_type": "all"},
value=positive_sum["sum"] + negative_sum["sum"],
)


def calc_balances(_options: CallbackOptions) -> Iterable[Observation]:
Expand Down
13 changes: 10 additions & 3 deletions src/vinywaji/metrics/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
class PrometheusMetricsView(View):
def is_allowed(self, request: HttpRequest) -> bool:
"""Whether the requestor is allowed to access this view"""
if settings.TRUST_REVERSE_PROXY and "HTTP_X_FORWARDED_FOR" in request.META.keys():
if (
settings.TRUST_REVERSE_PROXY
and "HTTP_X_FORWARDED_FOR" in request.META.keys()
):
x_forwarded_for = request.META["HTTP_X_FORWARDED_FOR"]
remote_ip = ip_address(x_forwarded_for.split(",")[0])
else:
Expand All @@ -27,6 +30,10 @@ def get(self, request: HttpRequest) -> HttpResponse:
if not self.is_allowed(request):
return HttpResponse(status=HTTPStatus.FORBIDDEN)

encode, content_type = prometheus_client.exposition.choose_encoder(request.META["HTTP_ACCEPT"])
encode, content_type = prometheus_client.exposition.choose_encoder(
request.META["HTTP_ACCEPT"]
)
content = encode(REGISTRY)
return HttpResponse(status=HTTPStatus.OK, content=content, content_type=content_type)
return HttpResponse(
status=HTTPStatus.OK, content=content, content_type=content_type
)
17 changes: 13 additions & 4 deletions src/vinywaji/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@
SECRET_KEY = env.str("VW_SECRET_KEY")
ALLOWED_HOSTS = env.list("VW_ALLOWED_HOSTS")
ALLOWED_METRICS_NETS = [
ip_network(i) for i in env.list("VW_ALLOWED_METRICS_NETS", default=["127.0.0.0/8", "::/64"])
ip_network(i)
for i in env.list("VW_ALLOWED_METRICS_NETS", default=["127.0.0.0/8", "::/64"])
]

DATABASES = {"default": env.dj_db_url("VW_DB")}
CACHES = {"default": env.dj_cache_url("VW_CACHE", default="dummy://" if DEBUG else "locmem://")}
CACHES = {
"default": env.dj_cache_url(
"VW_CACHE", default="dummy://" if DEBUG else "locmem://"
)
}

INSTALLED_APPS = [
"django.contrib.auth",
Expand Down Expand Up @@ -95,7 +100,9 @@
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
Expand Down Expand Up @@ -141,7 +148,9 @@
LOGOUT_REDIRECT_URL = "/"

OPENID_PROVIDER_NAME = env.str("VW_OPENID_PROVIDER_NAME", default="mafiasi")
OPENID_ISSUER = env.str("VW_OPENID_ISSUER", default="https://identity.mafiasi.de/realms/mafiasi")
OPENID_ISSUER = env.str(
"VW_OPENID_ISSUER", default="https://identity.mafiasi.de/realms/mafiasi"
)
OPENID_CLIENT_ID = env.str("VW_OPENID_CLIENT_ID")
OPENID_CLIENT_SECRET = env.str("VW_OPENID_CLIENT_SECRET")
OPENID_SCOPE = env.str("VW_OPENID_SCOPE")
Expand Down

0 comments on commit a8ce41a

Please sign in to comment.