-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from QuizCast/dev
deploying to Azure
- Loading branch information
Showing
19 changed files
with
441 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.venv | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
name: Build and Deploy to Azure | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
workflow_dispatch: | ||
|
||
env: | ||
IMAGE_NAME: supabse-app | ||
ACR_NAME: pawan | ||
CONTAINER_APP_NAME: supabase-fastapi | ||
RESOURCE_GROUP: github | ||
|
||
jobs: | ||
build-and-deploy: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout Code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Log in to Azure | ||
uses: azure/login@v2 | ||
with: | ||
creds: ${{ secrets.AZURE_CREDENTIALS }} | ||
|
||
- name: Log in to Azure Container Registry | ||
run: | | ||
az acr login --name ${{ env.ACR_NAME }} | ||
- name: Create .env File with Secrets | ||
run: | | ||
echo "SUPABASE_URL=${{ secrets.SUPABASE_URL }}" >> .env | ||
echo "SUPABASE_KEY=${{ secrets.SUPABASE_KEY }}" >> .env | ||
echo "SUPABASE_BUCKET=${{ secrets.SUPABASE_BUCKET }}" >> .env | ||
echo ".env file created successfully." | ||
- name: Build and Push Docker Image | ||
run: | | ||
IMAGE_TAG=${{ env.ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }} | ||
docker build -t $IMAGE_TAG . | ||
docker push $IMAGE_TAG | ||
- name: Deploy New Image to Azure Container App | ||
run: | | ||
IMAGE_TAG=${{ env.ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }} | ||
az containerapp update \ | ||
--name ${{ env.CONTAINER_APP_NAME }} \ | ||
--resource-group ${{ env.RESOURCE_GROUP }} \ | ||
--image $IMAGE_TAG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
.venv | ||
.env | ||
test_supabase.py | ||
test_supabase.py | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Use the official Python image | ||
FROM python:3.10-slim | ||
|
||
# Set environment variables to prevent Python from writing .pyc files and to buffer stdout and stderr | ||
ENV PYTHONDONTWRITEBYTECODE=1 | ||
ENV PYTHONUNBUFFERED=1 | ||
|
||
# Create and set the working directory | ||
WORKDIR /app | ||
|
||
# Install system dependencies | ||
RUN apt-get update && apt-get install -y \ | ||
gcc \ | ||
libpq-dev \ | ||
--no-install-recommends && \ | ||
apt-get clean && \ | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
# Copy the requirements file and install dependencies | ||
COPY requirements.txt . | ||
RUN pip install --no-cache-dir --upgrade pip && \ | ||
pip install --no-cache-dir -r requirements.txt | ||
|
||
# Copy the application files to the working directory | ||
COPY . . | ||
|
||
# Expose the port | ||
EXPOSE 8000 | ||
|
||
# Run the application | ||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from typing import List, Union | ||
from fastapi import APIRouter, Request, HTTPException, Depends, WebSocket, WebSocketDisconnect | ||
from app.schemas import quizEntry_schema | ||
from app.core.config import SUPABASE_URL, SUPABASE_KEY | ||
from app.db.db import supabase | ||
from app.crud import quiz_crud | ||
import json | ||
|
||
|
||
router = APIRouter( | ||
prefix="/quiz", | ||
tags=["Quiz"], | ||
) | ||
|
||
@router.post("/join", response_model=List[quizEntry_schema.Question]) | ||
async def add_participant(participant:quizEntry_schema.Participant ): | ||
return quiz_crud.join_quiz(participant) | ||
|
||
|
||
@router.put("/updateScore", response_model=List[quizEntry_schema.LeaderBoard]) | ||
async def submit_answer(answer: quizEntry_schema.UpdateScore): | ||
return quiz_crud.update_score(answer) | ||
|
||
|
||
@router.post("/addQuestions", response_model=quizEntry_schema.RoomKey) | ||
async def add_question(request: quizEntry_schema.AddQuestionsRequest): | ||
return quiz_crud.add_questions(request.questions, request.user_id) | ||
|
||
# @router.websocket("/ws/{room_key}") | ||
# async def websocket_endpoint(websocket: WebSocket, room_key: int): | ||
# await manager.connect(websocket, room_key) | ||
# try: | ||
# while True: | ||
# await websocket.receive_text() # Keep connection alive | ||
# except WebSocketDisconnect: | ||
# manager.disconnect(websocket, room_key) | ||
|
||
|
||
# @router.post("/broadcast-message/") | ||
# async def broadcast_message(room_key: int, message: str): | ||
# await manager.broadcast(f"{room_key}", json.dumps({"type": "announcement", "message": message})) | ||
# return {"message": "Broadcast sent"} | ||
|
||
# @router.post("/startQuiz") | ||
# async def create_quiz(room_key: int, host_id: int): | ||
# response = supabase.table("leaderboard").insert({ | ||
# "room_key": room_key, | ||
# "id": host_id | ||
# }).execute() | ||
|
||
# if response.error: | ||
# raise HTTPException(status_code=400, detail=response.error.message) | ||
|
||
# return {"message": "Quiz created successfully", "room_key": room_key} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from typing import List | ||
from fastapi import APIRouter, Request, HTTPException, Depends | ||
from app.schemas import user_schema | ||
from app.core.config import SUPABASE_URL, SUPABASE_KEY | ||
from app.db.db import supabase | ||
from app.crud import user_crud | ||
|
||
router = APIRouter( | ||
prefix="/user", | ||
tags=["users"], | ||
) | ||
|
||
|
||
@router.post("/users", response_model=List[user_schema.UserResponse]) | ||
async def get_users(): | ||
return user_crud.get_users() | ||
|
||
@router.post("/create_user", response_model=user_schema.UserResponse) | ||
async def create_user(user: user_schema.UserCreate): | ||
return user_crud.create_user(user) | ||
|
||
@router.put("/update_user", response_model=user_schema.UserResponse) | ||
async def update_user(user: user_schema.UserUpdate): | ||
return user_crud.update_user(user) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import os | ||
import dotenv | ||
from supabase import create_client, Client, AClient, acreate_client | ||
|
||
dotenv.load_dotenv() | ||
SUPABASE_URL = os.getenv("SUPABASE_URL") | ||
SUPABASE_KEY = os.getenv("SUPABASE_KEY") | ||
|
||
# supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) | ||
|
||
def handle_record_updated(payload): | ||
print("Record Updated") | ||
print(payload) | ||
|
||
async def main(): | ||
supabase: AClient = await acreate_client(SUPABASE_URL, SUPABASE_KEY) | ||
|
||
await supabase.realtime.connect() | ||
|
||
await (supabase.realtime | ||
.channel("my_channel") | ||
.on_postgres_changes("*", schema="public", table="demo-table", callback=handle_record_updated) | ||
.subscribe()) | ||
|
||
await supabase.realtime.listen() | ||
|
||
import asyncio | ||
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import os | ||
import dotenv | ||
|
||
dotenv.load_dotenv() | ||
|
||
SUPABASE_URL = os.getenv("SUPABASE_URL") | ||
SUPABASE_KEY = os.getenv("SUPABASE_KEY") | ||
SUPABASE_BUCKET = os.getenv("SUPABASE_BUCKET") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
from app.schemas import quizEntry_schema | ||
from fastapi import HTTPException, status | ||
from app.db.db import supabase | ||
from typing import List | ||
|
||
|
||
def join_quiz(participant: quizEntry_schema.Participant): | ||
try: | ||
# Check if the quiz exists | ||
user_id = supabase.table("leaderboard").select("id").eq("room_key", participant.room_key).execute() | ||
if not user_id.data: | ||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Quiz not found") | ||
|
||
# Register participant | ||
try: | ||
result = supabase.table("participants").insert({ | ||
"room_key": participant.room_key, | ||
"user_id": user_id.data[0]["id"], | ||
"name": participant.name, | ||
"score": 0 | ||
}).execute() | ||
except Exception as e: | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to register participant: {e}") | ||
|
||
# Fetch quiz questions | ||
questions = supabase.table("questions").select("question", "answers", "correct_answer").eq("room_key", participant.room_key).execute() | ||
if not questions.data: | ||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No questions found for the quiz") | ||
|
||
# Return list of questions | ||
return [quizEntry_schema.Question( | ||
id=result.data[0]["id"], | ||
room_key=participant.room_key, | ||
question=question["question"], | ||
answers=question["answers"]["answers"], | ||
correct_answer=question["correct_answer"] | ||
) for question in questions.data] | ||
|
||
except Exception as e: | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to join quiz: {e}") | ||
|
||
def update_score(answer: quizEntry_schema.UpdateScore): | ||
try: | ||
try: | ||
# Update the participant's score | ||
response = supabase.table("participants").update({ | ||
"score": answer.score | ||
}).eq("id", answer.id).execute() | ||
|
||
except Exception as e: | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to update score: {e}") | ||
|
||
|
||
# Fetch the updated leaderboard | ||
leaderboard = supabase.table("participants").select("*").eq("room_key", answer.room_key).order("score", desc=True).execute() | ||
|
||
return [quizEntry_schema.LeaderBoard( | ||
id=participant["id"], | ||
room_key=participant["room_key"], | ||
name=participant["name"], | ||
score=participant["score"] | ||
) for participant in leaderboard.data] | ||
|
||
except Exception as e: | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to update score: {e}") | ||
|
||
def create_room(host_id: int): | ||
try: | ||
# create a new room | ||
response = supabase.table("leaderboard").insert({ | ||
"id": host_id | ||
}).execute() | ||
|
||
return {"message": "Room created successfully", "room_key": response.data[0]["room_key"]} | ||
|
||
except Exception as e: | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to create room: {e}") | ||
|
||
def add_questions(questions: List[quizEntry_schema.AddQuestion], user_id: int): | ||
try: | ||
# create a new room | ||
room_key = create_room(user_id)["room_key"] | ||
|
||
if not room_key: | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to create room") | ||
|
||
for question in questions: | ||
answers_json = {"answers": question.answers} | ||
supabase.table("questions").insert({ | ||
"room_key": room_key, | ||
"question": question.question, | ||
"answers": answers_json, | ||
"correct_answer": question.correct_answer | ||
}).execute() | ||
|
||
print("Questions added successfully") | ||
return quizEntry_schema.RoomKey(room_key=room_key) | ||
|
||
except Exception as e: | ||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to add questions: {e}") | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from app.schemas import user_schema | ||
from fastapi import HTTPException, status | ||
from app.db.db import supabase | ||
from typing import List | ||
|
||
def get_users() -> List[user_schema.UserResponse]: | ||
try: | ||
users = supabase.table("users").select("*").execute() | ||
return users.data | ||
except Exception as e: | ||
return{"error": f"Failed to retrieve users: {str(e)}"} | ||
|
||
def create_user(user: user_schema.UserCreate) -> user_schema.UserResponse: | ||
try: | ||
new_user = {"name": user.name, "email": user.email, "is_active": user.is_active, "img_url": user.img_url} | ||
response = supabase.table("users").insert(new_user).execute() | ||
return response.data[0] | ||
except Exception as e: | ||
return{"error": f"Failed to create user: {str(e)}"} | ||
|
||
def update_user(user: user_schema.UserUpdate) -> user_schema.UserResponse: | ||
try: | ||
updated_user = {"name": user.name, "email": user.email, "is_active": user.is_active, "img_url": user.img_url} | ||
response = supabase.table("users").update(updated_user).eq("id", user.id).execute() | ||
return response.data[0] | ||
except Exception as e: | ||
return{"error": f"Failed to update user: {str(e)}"} | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from supabase import create_client, Client | ||
from app.core.config import SUPABASE_URL, SUPABASE_KEY, SUPABASE_BUCKET | ||
|
||
|
||
if not all([SUPABASE_URL, SUPABASE_KEY, SUPABASE_BUCKET]): | ||
raise EnvironmentError("One or more Supabase environment variables are missing") | ||
|
||
# Initialize the Supabase client | ||
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from fastapi import FastAPI | ||
from fastapi.middleware.cors import CORSMiddleware | ||
from app.api.endpoints import users, quizEntry | ||
from app.db.db import supabase | ||
|
||
|
||
app = FastAPI() | ||
|
||
origins = [ | ||
"http://localhost", | ||
"http://localhost:8080", | ||
"http://localhost:3000", | ||
"http://localhost:8000", | ||
] | ||
|
||
app.add_middleware( | ||
CORSMiddleware, | ||
allow_origins=origins, | ||
allow_credentials=True, | ||
allow_methods=["*"], | ||
allow_headers=["*"], | ||
) | ||
|
||
app.include_router(users.router) | ||
app.include_router(quizEntry.router) | ||
|
||
|
||
@app.get("/") | ||
def read_root(): | ||
return {"Message": "Welcome to Supabase Hackathon!"} |
Oops, something went wrong.