Skip to content
Open
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
1 change: 1 addition & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ IS_LOCAL=false

# Clerk Authentication
CLERK_SECRET_KEY=sk_test_your_secret_key_here
CLERK_JWKS_URL=https://your-app-domain.clerk.accounts.dev/.well-known/jwks.json
7 changes: 5 additions & 2 deletions backend/app/api/event_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@


@router.get("/", response_model=List[EventFieldResponse])
async def get_event_fields(event_id: str):
"""Get all fields for an event"""
async def get_event_fields(
event_id: str,
auth: AuthenticatedUser = Depends(clerk_auth)
Comment thread
PandaWhoCodes marked this conversation as resolved.
):
"""Get all fields for an event (protected)"""
try:
event = await EventService.get_event(event_id)
if not event:
Expand Down
10 changes: 5 additions & 5 deletions backend/app/api/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async def create_event(
):
"""Create a new event (protected)"""
try:
return await EventService.create_event(event)
return await EventService.create_event(event, auth)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
Expand All @@ -38,7 +38,7 @@ async def get_all_events(

@router.get("/active", response_model=EventResponse)
async def get_active_event():
"""Get currently active event"""
"""Get currently active event. currently one event can be active (protected)"""
try:
event = await EventService.get_active_event()
if not event:
Expand All @@ -61,7 +61,7 @@ async def get_event(
event_id: str,
auth: AuthenticatedUser = Depends(clerk_auth)
):
"""Get event by ID (protected)"""
"""Get event by event ID (protected)"""
try:
event = await EventService.get_event(event_id)
if not event:
Expand All @@ -85,7 +85,7 @@ async def update_event(
event: EventUpdate,
auth: AuthenticatedUser = Depends(clerk_auth)
):
"""Update event (protected)"""
"""Update event details (protected)"""
try:
updated_event = await EventService.update_event(event_id, event)
if not updated_event:
Expand Down Expand Up @@ -134,7 +134,7 @@ async def clone_event(
):
"""Clone an existing event (protected)"""
try:
event = await EventService.clone_event(event_id, new_name)
event = await EventService.clone_event(event_id, new_name, auth)
if not event:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
Expand Down
4 changes: 2 additions & 2 deletions backend/app/api/message_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async def create_template(
):
"""Create a new message template (protected)"""
try:
return await message_template_service.create_template(template_data)
return await message_template_service.create_template(template_data, auth)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

Expand Down Expand Up @@ -62,7 +62,7 @@ async def delete_template(
):
"""Delete a message template (protected)"""
try:
await message_template_service.delete_template(template_id)
await message_template_service.delete_template(template_id )
return {"message": "Template deleted successfully"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
2 changes: 1 addition & 1 deletion backend/app/api/qr_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async def create_qr_code(
):
"""Create a QR code for an event (protected)"""
try:
return await QRService.create_qr_code(qr_data)
return await QRService.create_qr_code(qr_data, auth)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
Expand Down
5 changes: 4 additions & 1 deletion backend/app/core/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
logger.info(f"✅ CLERK_SECRET_KEY loaded: {CLERK_SECRET_KEY[:20]}...")

# JWKS URL for Clerk
JWKS_URL = "https://steady-hawk-55.clerk.accounts.dev/.well-known/jwks.json"
JWKS_URL = os.getenv("CLERK_JWKS_URL")
Comment thread
PandaWhoCodes marked this conversation as resolved.
if not JWKS_URL:
raise ValueError("CLERK_JWKS_URL environment variable is required")

logger.info(f"🔑 Using JWKS URL: {JWKS_URL}")

# Initialize PyJWKClient with SSL verification disabled for localhost
Expand Down
10 changes: 8 additions & 2 deletions backend/app/core/schema_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ def _define_schema(self) -> Dict[str, Table]:
Column('venue_address', 'TEXT', nullable=True),
Column('venue_map_link', 'TEXT', nullable=True),
Column('is_active', 'INTEGER', nullable=True, default='0'),
Column('admin_user_id', 'TEXT', nullable=False),
Column('created_at', 'TEXT', nullable=True, default='CURRENT_TIMESTAMP'),
Column('updated_at', 'TEXT', nullable=True, default='CURRENT_TIMESTAMP'),
],
indexes=[
Index('idx_events_active', 'events', ['is_active'])
Index('idx_events_active', 'events', ['is_active']),
Index('idx_events_admin', 'events', ['admin_user_id'])
]
),

Expand All @@ -79,6 +81,7 @@ def _define_schema(self) -> Dict[str, Table]:
Column('is_required', 'INTEGER', nullable=True, default='0'),
Column('field_options', 'TEXT', nullable=True),
Column('field_order', 'INTEGER', nullable=True, default='0'),
Column('admin_user_id', 'TEXT', nullable=False)
]
),

Expand Down Expand Up @@ -121,6 +124,7 @@ def _define_schema(self) -> Dict[str, Table]:
Column('event_id', 'TEXT', nullable=False, foreign_key='events(id) ON DELETE CASCADE'),
Column('message', 'TEXT', nullable=False),
Column('qr_type', 'TEXT', nullable=True, default="'message'"),
Column('admin_user_id', 'TEXT', nullable=False),
Column('created_at', 'TEXT', nullable=True, default='CURRENT_TIMESTAMP'),
]
),
Expand All @@ -144,11 +148,13 @@ def _define_schema(self) -> Dict[str, Table]:
Column('id', 'TEXT', nullable=False, primary_key=True),
Column('template_name', 'TEXT', nullable=False),
Column('template_text', 'TEXT', nullable=False),
Column('admin_user_id', 'TEXT', nullable=False),
Column('created_at', 'TEXT', nullable=True, default='CURRENT_TIMESTAMP'),
Column('updated_at', 'TEXT', nullable=True, default='CURRENT_TIMESTAMP'),
],
indexes=[
Index('idx_message_templates_name', 'message_templates', ['template_name'])
Index('idx_message_templates_name', 'message_templates', ['template_name']),
Index('idx_message_templates_admin', 'message_templates', ['admin_user_id'])
]
),

Expand Down
2 changes: 1 addition & 1 deletion backend/app/models/branding.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ class BrandingUpdate(BaseModel):
site_headline: Optional[str] = None
logo_url: Optional[str] = None
text_style: Optional[str] = None
theme: Optional[str] = None
theme: Optional[str] = None
1 change: 1 addition & 0 deletions backend/app/models/message_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class MessageTemplateUpdate(BaseModel):

class MessageTemplate(MessageTemplateBase):
id: str
admin_user_id: str
created_at: str
updated_at: str
variables: List[str] = Field(default_factory=list, description="Extracted variables from template")
Expand Down
2 changes: 2 additions & 0 deletions backend/app/schemas/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class EventFieldResponse(EventFieldCreate):

id: str
event_id: str
admin_user_id:str #this can be useful in the future


class EventCreate(BaseModel):
Expand Down Expand Up @@ -60,6 +61,7 @@ class EventResponse(BaseModel):
venue_address: Optional[str]
venue_map_link: Optional[str]
is_active: bool
admin_user_id:str
created_at: str
updated_at: str
fields: List[EventFieldResponse] = []
1 change: 1 addition & 0 deletions backend/app/schemas/qr_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ class QRCodeResponse(BaseModel):
event_id: str
message: str
qr_type: str
admin_user_id: str
qr_image: str # Base64 encoded image
created_at: str
74 changes: 52 additions & 22 deletions backend/app/services/event_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
from typing import List, Optional
from app.core.database import db
from app.core.auth import AuthenticatedUser
from app.schemas.event import (
EventCreate,
EventUpdate,
Expand All @@ -14,16 +15,16 @@ class EventService:
"""Service for event management"""

@staticmethod
async def create_event(event_data: EventCreate) -> EventResponse:
async def create_event(event_data: EventCreate, auth: AuthenticatedUser) -> EventResponse:
"""Create a new event"""
event_id = str(uuid.uuid4())

# Insert event
await db.execute(
"""
INSERT INTO events (id, name, description, date, time, venue,
venue_address, venue_map_link, is_active)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
venue_address, venue_map_link, is_active, admin_user_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
[
event_id,
Expand All @@ -35,6 +36,7 @@ async def create_event(event_data: EventCreate) -> EventResponse:
event_data.venue_address,
event_data.venue_map_link,
1 if event_data.is_active else 0,
auth.user_id,
],
)

Expand All @@ -44,8 +46,8 @@ async def create_event(event_data: EventCreate) -> EventResponse:
await db.execute(
"""
INSERT INTO event_fields (id, event_id, field_name, field_type,
field_label, is_required, field_options, field_order)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
field_label, is_required, field_options, field_order, admin_user_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
[
field_id,
Expand All @@ -56,6 +58,7 @@ async def create_event(event_data: EventCreate) -> EventResponse:
1 if field.is_required else 0,
field.field_options,
field.field_order,
auth.user_id,
],
)

Expand Down Expand Up @@ -84,6 +87,7 @@ async def get_event(event_id: str) -> Optional[EventResponse]:
is_required=bool(row["is_required"]),
field_options=row["field_options"],
field_order=row["field_order"],
admin_user_id=row["admin_user_id"],
)
for row in fields_rows
]
Expand All @@ -98,31 +102,49 @@ async def get_event(event_id: str) -> Optional[EventResponse]:
venue_address=event["venue_address"],
venue_map_link=event["venue_map_link"],
is_active=bool(event["is_active"]),
admin_user_id=event["admin_user_id"],
created_at=event["created_at"],
updated_at=event["updated_at"],
fields=fields,
)


@staticmethod
async def get_all_events() -> List[EventResponse]:
"""Get all events"""
events = await db.fetch_all("SELECT * FROM events ORDER BY created_at DESC")
events = await db.fetch_all(
"SELECT * FROM events ORDER BY created_at DESC"
)
result = []
for event in events:
event_response = await EventService.get_event(event["id"])
if event_response:
result.append(event_response)
return result



@staticmethod
async def get_active_event() -> List[EventResponse]:
"""Get active event. at this point only 1 event can be active"""
event = await db.fetch_all(
"SELECT * FROM events WHERE is_active = 1 ORDER BY created_at DESC LIMIT 1",
)
if not event:
return None
return await EventService.get_event(event[0]["id"])

# we are not using now but will come handy
@staticmethod
async def get_active_event() -> Optional[EventResponse]:
"""Get currently active event"""
event = await db.fetch_one(
"SELECT * FROM events WHERE is_active = 1 ORDER BY created_at DESC LIMIT 1"
async def get_active_events_by_admin_id(auth: AuthenticatedUser) -> List[EventResponse]:
"""Get all active events for a specific admin"""
event = await db.fetch_all(
"SELECT * FROM events WHERE admin_user_id = ? AND is_active = 1 ORDER BY created_at DESC LIMIT 1",
[auth.user_id]
)
if not event:
return None
return await EventService.get_event(event["id"])
return await EventService.get_event(event[0]["id"])

@staticmethod
async def update_event(event_id: str, event_data: EventUpdate) -> Optional[EventResponse]:
Expand Down Expand Up @@ -188,7 +210,7 @@ async def delete_event(event_id: str) -> bool:
return True

@staticmethod
async def clone_event(event_id: str, new_name: str) -> Optional[EventResponse]:
async def clone_event(event_id: str, new_name: str, auth: AuthenticatedUser) -> Optional[EventResponse]:
"""Clone an existing event"""
source_event = await EventService.get_event(event_id)
if not source_event:
Expand Down Expand Up @@ -217,11 +239,16 @@ async def clone_event(event_id: str, new_name: str) -> Optional[EventResponse]:
],
)

return await EventService.create_event(new_event_data)
return await EventService.create_event(new_event_data, auth)

@staticmethod
async def get_event_registrations(event_id: str) -> List[dict]:
"""Get all registrations for an event"""
# First verify the event exists
event = await db.fetch_one("SELECT id FROM events WHERE id = ?", [event_id])
if not event:
return []

registrations = await db.fetch_all(
"SELECT * FROM registrations WHERE event_id = ? ORDER BY created_at DESC",
[event_id],
Expand All @@ -241,8 +268,8 @@ async def get_event_registrations(event_id: str) -> List[dict]:
]

@staticmethod
async def update_event_fields(event_id: str, fields: List) -> Optional[List[EventFieldResponse]]:
"""Replace all fields for an event"""
async def update_event_fields(event_id: str, fields: List, auth: AuthenticatedUser) -> Optional[List[EventFieldResponse]]:
"""Replace fields for an event"""
event = await db.fetch_one("SELECT id FROM events WHERE id = ?", [event_id])
if not event:
return None
Expand All @@ -256,8 +283,8 @@ async def update_event_fields(event_id: str, fields: List) -> Optional[List[Even
await db.execute(
"""
INSERT INTO event_fields (id, event_id, field_name, field_type,
field_label, is_required, field_options, field_order)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
field_label, is_required, field_options, field_order, admin_user_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
[
field_id,
Expand All @@ -268,6 +295,7 @@ async def update_event_fields(event_id: str, fields: List) -> Optional[List[Even
1 if field.is_required else 0,
field.field_options,
field.field_order,
auth.user_id,
],
)

Expand All @@ -294,8 +322,8 @@ async def add_event_field(event_id: str, field) -> Optional[EventFieldResponse]:
await db.execute(
"""
INSERT INTO event_fields (id, event_id, field_name, field_type,
field_label, is_required, field_options, field_order)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
field_label, is_required, field_options, field_order, admin_user_id)
Comment thread
PandaWhoCodes marked this conversation as resolved.
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
[
field_id,
Expand All @@ -306,6 +334,7 @@ async def add_event_field(event_id: str, field) -> Optional[EventFieldResponse]:
1 if field.is_required else 0,
field.field_options,
next_order,
auth.user_id,
],
)

Expand All @@ -318,13 +347,14 @@ async def add_event_field(event_id: str, field) -> Optional[EventFieldResponse]:
is_required=field.is_required,
field_options=field.field_options,
field_order=next_order,
admin_user_id=auth.user_id,
)

@staticmethod
async def delete_event_field(event_id: str, field_id: str) -> bool:
async def delete_event_field(event_id: str, field_id: str, auth: AuthenticatedUser) -> bool:
"""Delete a field from an event"""
result = await db.execute(
"DELETE FROM event_fields WHERE id = ? AND event_id = ?",
[field_id, event_id]
"DELETE FROM event_fields WHERE id = ? AND event_id = ? AND admin_user_id = ?",
[field_id, event_id, auth.user_id]
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this lockin that only I can delete my content.
Can you run through the changes again and fix this across the board
I do not want to be the only person able to edit delete anything
the dashboard can be used across the board of organizers - no hierarchy there

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PandaWhoCodes so any admin can view,edit or delete anything wrt event? I will make these changes then

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes sir
Any - its the same behaviour we see in luma and google forms. We dont have multiple communities. this is a single community instance.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please resolve these comments

)
return True
Loading