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
4 changes: 1 addition & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@
"type": "debugpy",
"request": "launch",
"module": "uvicorn",
// --reload seems to cause issues with browser-use
"args": ["podium.main:app", "--reload"],
// "args": ["podium.main:app"],
"env": {
"ENV_FOR_DYNACONF": "development"
"PYTHON_ENV": "development"
},
"cwd": "${workspaceFolder}/backend",
"justMyCode": true
Expand Down
9 changes: 4 additions & 5 deletions backend/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
version: '3.8'
version: "3.8"

services:
podium:
container_name: podium
build: .
# ports:
# - "8000:8000"
ports:
- "8000:8000"
Comment on lines +7 to +8
Copy link
Collaborator

Choose a reason for hiding this comment

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

This messes with Coolify

Suggested change
ports:
- "8000:8000"
# ports:
# - "8000:8000"

healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
interval: 30s
Expand All @@ -15,5 +15,4 @@ services:
volumes:
- ./settings.toml:/app/settings.toml:ro
- ./.secrets.toml:/app/.secrets.toml:ro

# docker run --rm -it -v "$(pwd)/settings.toml:/app/settings.toml:ro" -v "$(pwd)/.secrets.toml:/app/.secrets.toml:ro" -p 8000:8000 podium
# docker run --rm -it -v "$(pwd)/settings.toml:/app/settings.toml:ro" -v "$(pwd)/.secrets.toml:/app/.secrets.toml:ro" -p 8000:8000 podium
2 changes: 1 addition & 1 deletion backend/podium/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from podium.config import settings as settings
from podium.config import settings as settings, environment as environment
4 changes: 3 additions & 1 deletion backend/podium/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

# type: ignore

print(f"Using environment: {os.getenv('ENV_FOR_DYNACONF', '')}")
environment = os.getenv("PYTHON_ENV", "development")
print(f"Using environment: {environment}")

settings = Dynaconf(
envvar_prefix="PODIUM",
load_dotenv=True,
Expand Down
2 changes: 1 addition & 1 deletion backend/podium/db/migration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# python -m podium.db.migration | Tee-Object -FilePath migration.txt
# $env:ENV_FOR_DYNACONF="production"
# $env:PYTHON_ENV="production"
# $env:PYTHONIOENCODING="utf-8"
from podium.db import users
from podium.db.user import UserPrivate, UserSignupPayload
Expand Down
5 changes: 2 additions & 3 deletions backend/podium/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import importlib
import os
from pathlib import Path
import uvicorn
from fastapi import FastAPI
Expand All @@ -9,11 +8,11 @@
from contextlib import asynccontextmanager
from typing import AsyncIterator
import sentry_sdk

from podium.config import environment

sentry_sdk.init(
dsn=""
if os.getenv("ENV_FOR_DYNACONF") == "development"
if environment == "development"
else "https://489f4a109d07aeadfd13387bcd3197ab@o4508979744210944.ingest.de.sentry.io/4508979747553360",
# Add data like request headers and IP for users,
# see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
Expand Down
20 changes: 15 additions & 5 deletions backend/podium/routers/auth.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from datetime import datetime, timedelta, timezone

# import smtplib
# from email.mime.text import MIMEText
from typing import Annotated

from podium import db, settings
from podium import db, settings, environment

from fastapi import APIRouter, HTTPException, Query, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
Expand All @@ -23,7 +22,7 @@
ALGORITHM = str(settings.jwt_algorithm)
ACCESS_TOKEN_EXPIRE_MINUTES: int = settings.jwt_expire_minutes # type: ignore
MAGIC_LINK_EXPIRE_MINUTES = 15

magic_urls = []

DEBUG_EMAIL = "[email protected]"

Expand All @@ -48,6 +47,9 @@ def create_access_token(
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt

def get_mail():
""" kinda like /letter_box but in python or smt."""
return magic_urls

Comment on lines 49 to 53
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
def get_mail():
""" kinda like /letter_box but in python or smt."""
return magic_urls

async def send_magic_link(email: str, redirect: str = ""):
token_data = {"sub": email}
Expand All @@ -58,7 +60,8 @@ async def send_magic_link(email: str, redirect: str = ""):
magic_link = f"{settings.production_url}/login?token={token}"
if redirect:
magic_link += f"&redirect={redirect}"

if environment == "development":
magic_urls.append(MagicLink(email=email, magic_link=magic_link))
Copy link
Collaborator

Choose a reason for hiding this comment

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

MagicLink isn't defined

if settings.sendgrid_api_key:
message = Mail(
from_email=settings.sendgrid_from_email,
Expand All @@ -81,6 +84,13 @@ async def send_magic_link(email: str, redirect: str = ""):
)


@router.get("/letter_box")
async def letter_box():
"""
This is a temporary endpoint to get the magic links that have been sent.
"""
return get_mail()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure if it's possible, but an even better approach would be to wrap the entire function in a conditional so it's not even defined in prod

Suggested change
return get_mail()
return magic_urls


@router.post("/request-login")
# https://fastapi.tiangolo.com/tutorial/query-param-models/
async def request_login(user: UserLoginPayload, redirect: Annotated[str, Query()]):
Expand Down Expand Up @@ -297,4 +307,4 @@ def magic_link_email_content(magic_link: str) -> dict:
- Hack Club`
"""

return {"html": html, "text": text}
return {"html": html, "text": text}
1 change: 1 addition & 0 deletions frontend/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PUBLIC_API_URL=http://localhost:8000
8 changes: 8 additions & 0 deletions frontend/src/lib/components/Admin/Button.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
// get text from props
export let text = "Click me";
</script>

<button class="btn border-2 border-dashed border-orange-500 bg-orange-500/10">
{text}
</button>
1 change: 1 addition & 0 deletions frontend/src/lib/components/CreateEvent.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
// Clear the form
eventName = "";
eventDescription = "";
await goto('/events');
}
</script>

Expand Down
61 changes: 60 additions & 1 deletion frontend/src/lib/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function handleError(
error: HTTPValidationError | ErrorWithDetail | Error | unknown,
) {
// If it's a FastAPI HTTPException, it will have a detail field. Same with validation errors.
console.error("Error", error)
console.error("Error", error);
if (error && typeof error === "object" && "detail" in error) {
if (Array.isArray(error?.detail)) {
// const invalidFields = error.detail.map((e) => e.msg);
Expand Down Expand Up @@ -72,3 +72,62 @@ export async function customInvalidateAll() {
await invalidateAll();
await invalidateUser();
}

function randomFromArray<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)];
}

function randomInt(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

function randomId(length = 12) {
return [...Array(length)].map(() => Math.random().toString(36)[2]).join("");
}

export function generateUser() {
const firstNames = ["Alice", "Bob", "Charlie", "Dana", "Elliot", "Fiona"];
const lastNames = ["Smith", "Johnson", "Lee", "Garcia", "Brown", "Taylor"];
const streets = ["Main St", "Oak Ave", "Pine Rd", "Maple Blvd"];
const cities = ["New York", "Los Angeles", "Chicago", "Seattle"];
const states = ["NY", "CA", "IL", "WA"];
const countries = ["USA", "Canada"];

const first_name = randomFromArray(firstNames);
const last_name = randomFromArray(lastNames);
const email = `${first_name.toLowerCase()}.${last_name.toLowerCase()}@example.com`;
const phone = `+1${randomInt(2000000000, 9999999999)}`;

const street_1 = `${randomInt(100, 9999)} ${randomFromArray(streets)}`;
const street_2 = Math.random() < 0.5 ? `Apt ${randomInt(1, 999)}` : null;
const city = randomFromArray(cities);
const state = randomFromArray(states);
const zip_code = `${randomInt(10000, 99999)}`;
const country = randomFromArray(countries);

const year = randomInt(2008, 2020);
const month = String(randomInt(1, 12)).padStart(2, "0");
const day = String(randomInt(1, 28)).padStart(2, "0");
const dob = `${year}-${month}-${day}`;

return {
first_name,
last_name,
email,
phone,
street_1,
street_2,
city,
state,
zip_code,
country,
dob,
id: randomId(),
votes: [],
projects: [],
collaborations: [],
owned_events: [],
attending_events: [],
referral: [],
};
}
48 changes: 48 additions & 0 deletions frontend/src/routes/letter_box/+page.svelte
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be using the generated SDK, not fetch.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts">
import { PUBLIC_API_URL } from "$env/static/public";
let data = $state([]);
const reload = async () => {
const res = await fetch(`${PUBLIC_API_URL}letter_box`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
if (res.ok) {
const json = await res.json();
data = json;
console.log(data);
} else {
handleError(res);
}
};

const handleError = (res: Response) => {
console.error(`Error: ${res.status} - ${res.statusText}`);
alert("Failed to load data. Please try again later.");
};
reload();
</script>

<div class="hero">
<div class=" hero-content text-left">
<div class="max-w-md">
<h1 class="text-4xl font-bold">Letter box</h1>
<button class="btn btn-primary" onclick={() => reload()}>Reload</button>
<br />
{#if data && data.length === 0}
<p class="text-base-content/70">No letters found.</p>
{:else}
<ul class="list-disc pl-5">
{#each data as letter}
<li class="mb-2">
<strong>{letter[0]}:</strong>
{#let url = new URL(letter[1])}
<a href={url.pathname + url.search}>{letter[1]}</a>
</li>
{/each}
</ul>
{/if}
</div>
</div>
</div>
Loading