Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ DATABASE_URL=postgresql+psycopg2://evsy:evsy@db:5432/evsy
FRONTEND_URL=http://localhost:3000

# Frontend
VITE_ENV=demo # dev | prod | demo
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=demo.evsy.dev
VITE_ENV=dev # dev | prod | demo
VITE_API_URL=http://localhost:8000/api/v1
VITE_LOG_LEVEL=error
VITE_LOG_LEVEL=error
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=demo.evsy.dev
File renamed without changes.
11 changes: 11 additions & 0 deletions backend/app/api/v1/routes/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from fastapi import APIRouter

from app.modules.admin.io.router import router as io_router
from app.modules.admin.reset.router import router as reset_router
from app.modules.admin.seed.router import router as seed_router

router = APIRouter(prefix="/admin")

router.include_router(io_router)
router.include_router(seed_router)
router.include_router(reset_router)
48 changes: 25 additions & 23 deletions backend/app/api/v1/routes/events.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from app import crud, schemas
from app.database.database import get_db
from app.core.database import get_db
from app.modules.events import crud as event_crud
from app.modules.events.schemas import EventCreate, EventOut
from app.modules.fields.crud import get_fields_by_ids
from app.modules.tags.crud import get_or_create_tags

router = APIRouter(prefix="/events", tags=["events"])


@router.post(
"/",
response_model=schemas.EventOut,
response_model=EventOut,
status_code=status.HTTP_201_CREATED,
summary="Create a new event",
description=(
Expand All @@ -22,50 +25,49 @@
400: {"description": "One or more fields do not exist"},
},
)
def create_event(event: schemas.EventCreate, db: Session = Depends(get_db)):
db_fields = crud.get_fields_by_ids(db, event.fields)
def create_event_route(event: EventCreate, db: Session = Depends(get_db)):
db_fields = get_fields_by_ids(db, event.fields)

if len(db_fields) != len(event.fields):
raise HTTPException(status_code=400, detail="One or more fields do not exist.")

_ = crud.get_or_create_tags(db, event.tags)
db_event = crud.create_event(db=db, event=event)
get_or_create_tags(db, event.tags)
db_event = event_crud.create_event(db=db, event=event)
return db_event


@router.get(
"/{event_id}",
response_model=schemas.EventOut,
response_model=EventOut,
summary="Get event by ID",
description="Return a single event by its ID. Includes tags and fields.",
responses={
200: {"description": "Event found"},
404: {"description": "Event not found"},
},
)
def get_event(event_id: int, db: Session = Depends(get_db)):
db_event = crud.get_event(db=db, event_id=event_id)
def get_event_route(event_id: int, db: Session = Depends(get_db)):
db_event = event_crud.get_event(db=db, event_id=event_id)
if db_event is None:
raise HTTPException(status_code=404, detail="Event not found")
return db_event


@router.get(
"/",
response_model=list[schemas.EventOut],
response_model=list[EventOut],
response_model_by_alias=False,
summary="List all events",
description="Return a paginated list of all events with their tags and fields.",
responses={200: {"description": "List of events returned"}},
)
def get_events(db: Session = Depends(get_db)):
events = crud.get_events(db=db)
return events
def list_events_route(db: Session = Depends(get_db)):
return event_crud.get_events(db=db)


@router.put(
"/{event_id}",
response_model=schemas.EventOut,
response_model=EventOut,
summary="Update an existing event",
description=(
"Update an existing analytics event. "
Expand All @@ -78,33 +80,33 @@ def get_events(db: Session = Depends(get_db)):
404: {"description": "Event not found"},
},
)
def update_event(
event_id: int, event: schemas.EventCreate, db: Session = Depends(get_db)
def update_event_route(
event_id: int, event: EventCreate, db: Session = Depends(get_db)
):
db_fields = crud.get_fields_by_ids(db, event.fields)
db_fields = get_fields_by_ids(db, event.fields)

if len(db_fields) != len(event.fields):
raise HTTPException(status_code=400, detail="One or more fields do not exist.")

_ = crud.get_or_create_tags(db, event.tags)
db_event = crud.update_event(db=db, event_id=event_id, event=event)
get_or_create_tags(db, event.tags)
db_event = event_crud.update_event(db=db, event_id=event_id, event=event)
if db_event is None:
raise HTTPException(status_code=404, detail="Event not found")
return db_event


@router.delete(
"/{event_id}",
response_model=schemas.EventOut,
response_model=EventOut,
summary="Delete an event",
description="Delete an analytics event by ID.",
responses={
200: {"description": "Event deleted"},
404: {"description": "Event not found"},
},
)
def delete_event(event_id: int, db: Session = Depends(get_db)):
db_event = crud.delete_event(db=db, event_id=event_id)
def delete_event_route(event_id: int, db: Session = Depends(get_db)):
db_event = event_crud.delete_event(db=db, event_id=event_id)
if db_event is None:
raise HTTPException(status_code=404, detail="Event not found")
return db_event
64 changes: 24 additions & 40 deletions backend/app/api/v1/routes/fields.py
Original file line number Diff line number Diff line change
@@ -1,98 +1,82 @@
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session

from app import crud, schemas
from app.database.database import get_db
from app.core.database import get_db
from app.modules.fields import crud as field_crud
from app.modules.fields.schemas import FieldCreate, FieldOut, FieldOutWithEventCount

router = APIRouter(prefix="/fields", tags=["fields"])


@router.post(
"/",
response_model=schemas.FieldOut,
response_model=FieldOut,
status_code=status.HTTP_201_CREATED,
summary="Create a field",
description="Create a new field that can be associated with events.",
responses={
201: {"description": "Field created successfully"},
},
)
def create_field(field: schemas.FieldCreate, db: Session = Depends(get_db)):
db_field = crud.create_field(db=db, field=field)
return db_field
def create_field_route(field: FieldCreate, db: Session = Depends(get_db)):
return field_crud.create_field(db=db, field=field)


@router.get(
"/",
response_model=list[schemas.FieldOut],
response_model=list[FieldOut],
summary="List all fields",
description="Return a paginated list of all fields that can be assigned to events.",
responses={
200: {"description": "List of fields returned"},
},
)
def get_fields(db: Session = Depends(get_db)):
fields = crud.get_fields(db=db)
return fields
def list_fields_route(db: Session = Depends(get_db)):
return field_crud.get_fields(db=db)


@router.get(
"/{field_id}",
response_model=schemas.FieldOut | schemas.FieldOutWithEventCount,
response_model=FieldOut | FieldOutWithEventCount,
summary="Get field by ID",
description="Return a single field by its ID.",
responses={
200: {"description": "Field found"},
404: {"description": "Field not found"},
},
responses={404: {"description": "Field not found"}},
)
def get_field(
def get_field_route(
field_id: int,
with_event_count: bool = Query(False),
db: Session = Depends(get_db),
):
db_field = crud.get_field(db=db, field_id=field_id)
db_field = field_crud.get_field(db=db, field_id=field_id)
if db_field is None:
raise HTTPException(status_code=404, detail="Field not found")

if with_event_count:
count = crud.get_field_event_count(db=db, field_id=field_id)
return schemas.FieldOutWithEventCount(**db_field.__dict__, event_count=count)
count = field_crud.get_field_event_count(db=db, field_id=field_id)
return FieldOutWithEventCount(**db_field.__dict__, event_count=count)

return db_field


@router.put(
"/{field_id}",
response_model=schemas.FieldOut,
response_model=FieldOut,
summary="Update a field",
description="Update the name, description, or type of a field.",
responses={
200: {"description": "Field updated"},
404: {"description": "Field not found"},
},
responses={404: {"description": "Field not found"}},
)
def update_field(
field_id: int, field: schemas.FieldCreate, db: Session = Depends(get_db)
def update_field_route(
field_id: int, field: FieldCreate, db: Session = Depends(get_db)
):
db_field = crud.update_field(db=db, field_id=field_id, field=field)
db_field = field_crud.update_field(db=db, field_id=field_id, field=field)
if db_field is None:
raise HTTPException(status_code=404, detail="Field not found")
return db_field


@router.delete(
"/{field_id}",
response_model=schemas.FieldOut,
response_model=FieldOut,
summary="Delete a field",
description="Delete a field by its ID. This will remove the field from all related events.",
responses={
200: {"description": "Field deleted"},
404: {"description": "Field not found"},
},
responses={404: {"description": "Field not found"}},
)
def delete_field(field_id: int, db: Session = Depends(get_db)):
db_field = crud.delete_field(db=db, field_id=field_id)
def delete_field_route(field_id: int, db: Session = Depends(get_db)):
db_field = field_crud.delete_field(db=db, field_id=field_id)
if db_field is None:
raise HTTPException(status_code=404, detail="Field not found")
return db_field
3 changes: 2 additions & 1 deletion backend/app/api/v1/routes/generic.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from fastapi import APIRouter, Depends, Response

from app.api.deps import get_settings
from app.schemas import FieldType, LinkType
from app.modules.events.schemas import LinkType
from app.modules.fields.schemas import FieldType
from app.settings import Settings

router = APIRouter()
Expand Down
58 changes: 21 additions & 37 deletions backend/app/api/v1/routes/tags.py
Original file line number Diff line number Diff line change
@@ -1,87 +1,71 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from app import crud, schemas
from app.database.database import get_db
from app.core.database import get_db
from app.modules.tags import crud as tag_crud
from app.modules.tags.schemas import TagCreate, TagOut

router = APIRouter(prefix="/tags", tags=["tags"])


@router.post(
"/",
response_model=schemas.TagOut,
response_model=TagOut,
status_code=status.HTTP_201_CREATED,
summary="Create a tag",
description="Create a tag manually. Typically, tags are created automatically when creating or updating an event.",
responses={
201: {"description": "Tag created successfully"},
},
)
def create_tag(tag: schemas.TagCreate, db: Session = Depends(get_db)):
db_tag = crud.create_tag(db=db, tag=tag)
return db_tag
def create_tag_route(tag: TagCreate, db: Session = Depends(get_db)):
return tag_crud.create_tag(db=db, tag=tag)


@router.get(
"/",
response_model=list[schemas.TagOut],
response_model=list[TagOut],
summary="List all tags",
description="Return a paginated list of all tags available in the system.",
responses={
200: {"description": "List of tags returned"},
},
)
def get_tags(db: Session = Depends(get_db)):
tags = crud.get_tags(db=db)
return tags
def list_tags_route(db: Session = Depends(get_db)):
return tag_crud.get_tags(db=db)


@router.get(
"/{tag_id}",
response_model=schemas.TagOut,
response_model=TagOut,
summary="Get tag by ID",
description="Return a single tag by its unique identifier.",
responses={
200: {"description": "Tag found"},
404: {"description": "Tag not found"},
},
responses={404: {"description": "Tag not found"}},
)
def get_event(tag_id: str, db: Session = Depends(get_db)):
db_tag = crud.get_tag(db=db, tag_id=tag_id)
def get_tag_route(tag_id: str, db: Session = Depends(get_db)):
db_tag = tag_crud.get_tag(db=db, tag_id=tag_id)
if db_tag is None:
raise HTTPException(status_code=404, detail="Tag not found")
return db_tag


@router.put(
"/{tag_id}",
response_model=schemas.TagOut,
response_model=TagOut,
summary="Update a tag",
description="Update the description of an existing tag.",
responses={
200: {"description": "Tag updated"},
404: {"description": "Tag not found"},
},
responses={404: {"description": "Tag not found"}},
)
def update_tag(tag_id: str, tag: schemas.TagCreate, db: Session = Depends(get_db)):
db_tag = crud.update_tag(db=db, tag_id=tag_id, tag=tag)
def update_tag_route(tag_id: str, tag: TagCreate, db: Session = Depends(get_db)):
db_tag = tag_crud.update_tag(db=db, tag_id=tag_id, tag=tag)
if db_tag is None:
raise HTTPException(status_code=404, detail="Tag not found")
return db_tag


@router.delete(
"/{tag_id}",
response_model=schemas.TagOut,
response_model=TagOut,
summary="Delete a tag",
description="Delete a tag by its ID. This will remove the tag from all related events.",
responses={
200: {"description": "Tag deleted"},
404: {"description": "Tag not found"},
},
responses={404: {"description": "Tag not found"}},
)
def delete_tag(tag_id: str, db: Session = Depends(get_db)):
db_tag = crud.delete_tag(db=db, tag_id=tag_id)
def delete_tag_route(tag_id: str, db: Session = Depends(get_db)):
db_tag = tag_crud.delete_tag(db=db, tag_id=tag_id)
if db_tag is None:
raise HTTPException(status_code=404, detail="Tag not found")
return db_tag
File renamed without changes.
Loading