Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup/projects and users #20

Merged
merged 72 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
6d79f1d
Fix last name validation on user manager
tomtitherington Jul 17, 2023
614df12
Rename all application references to projects
tomtitherington Jul 17, 2023
fb8d737
Refactor project views to use ModelViewSet and add tests
tomtitherington Jul 17, 2023
9695f7a
Modify projects view to prevent non-admins updating and deleting
tomtitherington Jul 17, 2023
b5c3243
Add new router to allow optional trailing slash
tomtitherington Jul 17, 2023
2338867
Connect login to use api and generate sdk stubs
tomtitherington Sep 3, 2023
b3708ea
Add custom Table component
tomtitherington Sep 8, 2023
2a90ba7
Fix button alignment and sizing
tomtitherington Sep 8, 2023
d174b98
Add 'copy input' component
tomtitherington Sep 8, 2023
b2c42e8
Add api_key field to project model and create UUID base model
tomtitherington Sep 10, 2023
b549c64
Modify serializers for compatibility with OpenAPI generators
tomtitherington Sep 10, 2023
42a5785
Add project key authentication class (untested)
tomtitherington Sep 10, 2023
f0bbd1c
Add migration files
tomtitherington Sep 10, 2023
83bf15a
Add database seed file
tomtitherington Sep 10, 2023
de18c8d
Add db service to docker-compose and adjust env vars
tomtitherington Sep 10, 2023
6a65aec
Remove development mode database check in settings.py
tomtitherington Sep 10, 2023
f95531c
Increase psycopg2 version
tomtitherington Sep 10, 2023
8ed26f7
Add crypto utils for project key encrypt/decrypt (currently unused)
tomtitherington Sep 10, 2023
8ddbbce
Add auth TODO
tomtitherington Sep 11, 2023
99ed944
Add api schema and generated models + functions
tomtitherington Sep 11, 2023
8de04cf
Add ApiState union type to represent state of external call
tomtitherington Sep 11, 2023
590f2d0
Install Zustand library and add projects store
tomtitherington Sep 11, 2023
18d27c0
Add initial projects fetch and render them in sidebar
tomtitherington Sep 11, 2023
8a38084
Create settings page, fetch and render data from api
tomtitherington Sep 11, 2023
eeaa2a1
Add flow page stub
tomtitherington Sep 11, 2023
55a0d52
Add protected route component to use with auth hook
tomtitherington Sep 11, 2023
bc59ee6
Refactor useRouter and add auth token context
tomtitherington Sep 11, 2023
4a91a55
Add custom modal component
tomtitherington Sep 11, 2023
5c9f0e7
Add shadows, gradients, colours and custom font size to config
tomtitherington Oct 20, 2023
539c7be
Create emphasis button component and new buttons directory
tomtitherington Oct 20, 2023
2f9b465
Create text input component and inputs directory
tomtitherington Oct 20, 2023
e308a01
Move projects store and add create project action
tomtitherington Oct 20, 2023
4b710d1
Add 'CreateProjectModal' and corresponding hook/logic
tomtitherington Oct 20, 2023
c6e816c
Fix imports
tomtitherington Oct 20, 2023
0b50f71
Add 'CreateProjectsModal' to sidebar (where it is toggled)
tomtitherington Oct 20, 2023
276b68c
Install react-hot-toast for toasts
tomtitherington Oct 21, 2023
12eb21c
Add simple fade in/out animation
tomtitherington Oct 21, 2023
7e9f938
Create Toast component
tomtitherington Oct 21, 2023
a5ba77d
Add call to toast from create projects modal
tomtitherington Oct 21, 2023
6988333
Refactor sidebar buttons (minor)
tomtitherington Oct 21, 2023
b713f6a
Add projects fetch and set selected project in sidebar on load
tomtitherington Oct 21, 2023
882584d
Add type guards for ApiState
tomtitherington Oct 22, 2023
eb3d962
Add text button (used in menus)
tomtitherington Oct 22, 2023
ec178ee
Refactor and improve projects selection menu in sidebar
tomtitherington Oct 22, 2023
2ccccaf
Add PopperJS and fix alignment of projects selection popover
tomtitherington Oct 22, 2023
fb0a76b
Create 'Copy' input component
tomtitherington Oct 27, 2023
09d0acd
Create 'Members' table component for use in project settings
tomtitherington Oct 27, 2023
d48c1ce
Create 'Outline' button component
tomtitherington Oct 27, 2023
40368ea
Add Ubuntu font
tomtitherington Oct 27, 2023
7c36fc4
Finish project settings page styling and move to /projects folder
tomtitherington Oct 27, 2023
4a7e3fb
Move project settings related files to /projects folder
tomtitherington Oct 27, 2023
6f32e61
Add onClick prop to OutlineButton
tomtitherington Oct 28, 2023
6c8586a
Add ability to delete project from the project settings page
tomtitherington Oct 28, 2023
f1665c4
Create custom container for toasts
tomtitherington Oct 28, 2023
7947fb2
Update Toast component to use custom container and improve styling
tomtitherington Oct 28, 2023
2832488
Display error toast on project deletion failure
tomtitherington Oct 28, 2023
de53d8a
Create main button component
tomtitherington Oct 28, 2023
6c195dd
Update TextButton to support enabled/disabled state
tomtitherington Oct 28, 2023
34ae44b
Update zustand
tomtitherington Oct 28, 2023
a9ffa70
Refactor projects store and use shallow copy
tomtitherington Oct 28, 2023
46b1647
Remove dead code and imports
tomtitherington Oct 29, 2023
1762f6c
Add optional id param to fetchAndSelectProjects (method in the store)
tomtitherington Oct 29, 2023
2c009aa
Wire up save button to call API and update the project
tomtitherington Oct 29, 2023
23165de
Handle potential errors returned from API response (project update)
tomtitherington Oct 29, 2023
fdc4442
Fix members table when rendering a single row
tomtitherington Oct 29, 2023
e61f265
Update 'CopyInput' to use Clipboard API
tomtitherington Oct 29, 2023
30c6384
Remove unused Welcome page and its references
tomtitherington Oct 29, 2023
3d76710
Fix typecheck error by making /projects a module
tomtitherington Oct 29, 2023
cbd7b18
Fix 'yarn typecheck'
tomtitherington Oct 29, 2023
ddbe0dd
Fix 'yarn test'
tomtitherington Oct 29, 2023
662316f
Fix eslint hook dependencies error with useCallback
tomtitherington Oct 29, 2023
3e7a35e
Fix gap between multiple toasts
tomtitherington Oct 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .dictionary/custom.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
viewsets
projs
evenodd
heebo
svgr
Expand Down Expand Up @@ -69,3 +71,18 @@ xlwt
xmlfile
gitcommitmessage
headlessui
isort
pylint
tomli
tomlkit
projectmembership
Qcet
ZIZW
runserver
pgdata
pyca
pycryptodome
zustand
probs
Customise
popperjs
10 changes: 5 additions & 5 deletions backend/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ DEBUG=True
DEVELOPMENT_MODE=True
DJANGO_ALLOWED_HOSTS='localhost,0.0.0.0,127.0.0.1,192.168.1.220'

DB_NAME = default_db
DB_USERNAME = default_admin
DB_PASSWORD = default_password
DB_HOST = default_host
DB_PORT = 25060
DB_NAME = crumpet_db
DB_USERNAME = head_baker
DB_PASSWORD = Crumpet2023
DB_HOST = db
DB_PORT = 5432
DB_SSL_MODE = require
2 changes: 1 addition & 1 deletion backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM python:3.11.2
FROM python:3.10-bullseye

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
Expand Down
17 changes: 17 additions & 0 deletions backend/app/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

from .models import Project


class ProjectAPIKeyAuthentication(BaseAuthentication):
def authenticate(self, request):
api_key = request.headers.get("X-API-KEY")
if not api_key:
return None

try:
project = Project.objects.get(api_key=api_key)
return (project, None) # authentication successful
except Project.DoesNotExist:
raise AuthenticationFailed("Invalid API key.")
89 changes: 44 additions & 45 deletions backend/app/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.1.5 on 2023-05-12 12:00
# Generated by Django 4.1.5 on 2023-07-17 09:42

from django.conf import settings
import django.core.validators
Expand Down Expand Up @@ -111,21 +111,6 @@ class Migration(migrations.Migration):
"abstract": False,
},
),
migrations.CreateModel(
name="Application",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name="Element",
fields=[
Expand Down Expand Up @@ -262,6 +247,21 @@ class Migration(migrations.Migration):
),
],
),
migrations.CreateModel(
name="Project",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name="Selector",
fields=[
Expand All @@ -286,30 +286,8 @@ class Migration(migrations.Migration):
),
],
),
migrations.AddField(
model_name="element",
name="event",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="associated_elements",
to="app.event",
),
),
migrations.AddField(
model_name="element",
name="parent",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="children",
to="app.element",
),
),
migrations.CreateModel(
name="ApplicationMembership",
name="ProjectMembership",
fields=[
(
"id",
Expand All @@ -329,10 +307,9 @@ class Migration(migrations.Migration):
),
),
(
"application",
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="app.application",
on_delete=django.db.models.deletion.CASCADE, to="app.project"
),
),
(
Expand All @@ -345,14 +322,36 @@ class Migration(migrations.Migration):
],
),
migrations.AddField(
model_name="application",
model_name="project",
name="members",
field=models.ManyToManyField(
related_name="applications",
through="app.ApplicationMembership",
related_name="projects",
through="app.ProjectMembership",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddField(
model_name="element",
name="event",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="associated_elements",
to="app.event",
),
),
migrations.AddField(
model_name="element",
name="parent",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="children",
to="app.element",
),
),
migrations.CreateModel(
name="ButtonElement",
fields=[],
Expand Down
19 changes: 19 additions & 0 deletions backend/app/migrations/0002_project_api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1.5 on 2023-09-08 17:45

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("app", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="project",
name="api_key",
field=models.CharField(
default="NIzNPqaU5CpCs7ItQ01x8dcvXozQcetR", max_length=256, unique=True
),
),
]
19 changes: 19 additions & 0 deletions backend/app/migrations/0003_alter_project_api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1.5 on 2023-09-08 17:52

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("app", "0002_project_api_key"),
]

operations = [
migrations.AlterField(
model_name="project",
name="api_key",
field=models.CharField(
default="PhZIZWGhUv2snEoQ5S4G3O1FQ608FUx8", max_length=256, unique=True
),
),
]
19 changes: 19 additions & 0 deletions backend/app/migrations/0004_alter_project_api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1.5 on 2023-09-08 20:36

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("app", "0003_alter_project_api_key"),
]

operations = [
migrations.AlterField(
model_name="project",
name="api_key",
field=models.CharField(
default="<function uuid4 at 0x105dc6200>", max_length=256, unique=True
),
),
]
19 changes: 19 additions & 0 deletions backend/app/migrations/0005_alter_project_api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1.5 on 2023-09-08 20:44

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("app", "0004_alter_project_api_key"),
]

operations = [
migrations.AlterField(
model_name="project",
name="api_key",
field=models.CharField(
default="<function uuid4 at 0x101eda200>", max_length=256, unique=True
),
),
]
18 changes: 18 additions & 0 deletions backend/app/migrations/0006_alter_project_api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.1.5 on 2023-09-08 20:46

from django.db import migrations, models
import uuid


class Migration(migrations.Migration):
dependencies = [
("app", "0005_alter_project_api_key"),
]

operations = [
migrations.AlterField(
model_name="project",
name="api_key",
field=models.CharField(default=uuid.uuid4, max_length=256, unique=True),
),
]
2 changes: 1 addition & 1 deletion backend/app/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
ButtonElement,
)
from .user import User
from .application import Application, ApplicationMembership
from .project import Project, ProjectMembership
from .selector import Selector
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
from django.db import models
# from django.utils.crypto import get_random_string
import uuid

from app.models import User
from django.db import models


class Application(models.Model):
class Project(models.Model):
name = models.CharField(max_length=100)
members = models.ManyToManyField(
User,
through="ApplicationMembership",
related_name="applications",
through="ProjectMembership",
related_name="projects",
)
# TODO: Replace this with proper key generation
api_key = models.CharField(
max_length=256,
unique=True,
default=uuid.uuid4,
null=False,
blank=False,
)

def __str__(self):
return self.name


class ApplicationMembership(models.Model):
class ProjectMembership(models.Model):
class MembershipType(models.TextChoices):
ADMIN = "ADM", "Admin"
MEMBER = "MEM", "Member"

user = models.ForeignKey(User, on_delete=models.CASCADE)
application = models.ForeignKey(Application, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)

type = models.CharField(
max_length=3,
Expand Down
4 changes: 2 additions & 2 deletions backend/app/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class UserManager(BaseUserManager):
"""
Custom user model manager with email is the identifier.
Custom user model manager with email as the identifier.
"""

model: Type["User"]
Expand All @@ -19,7 +19,7 @@ def create_user(self, email, password, first_name, last_name, **extra_fields):
if not first_name:
raise ValueError("Users must have a first name")
if not last_name:
raise ValueError("Users must have a password")
raise ValueError("Users must have a last name")
email = self.normalize_email(email)
user = self.model(
email=email, first_name=first_name, last_name=last_name, **extra_fields
Expand Down
10 changes: 10 additions & 0 deletions backend/app/models/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import uuid

from django.db import models


class UUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

class Meta:
abstract = True
1 change: 1 addition & 0 deletions backend/app/permissions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .projects import ProjectAdminPermission, ProjectMemberPermission
7 changes: 7 additions & 0 deletions backend/app/permissions/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from rest_framework import permissions


class CrumpetBasePermission(permissions.BasePermission):
"""
A base class for custom permissions.
"""
Loading
Loading