Skip to content

Commit d14af5f

Browse files
authored
Merge pull request #189 from Pseudo-Lab/feat/start-challenge
feat(getcloser): start challenge by assigning a question
2 parents 1ff5f2a + e73cdd3 commit d14af5f

13 files changed

Lines changed: 195 additions & 27 deletions

File tree

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from api.v1.users import users
2+
from api.v1.challenge import assign_challenge
23
from api.v1.teams import teams
3-
from api.v1.challenges import challenges
44
from fastapi import APIRouter
55

66
api_router = APIRouter()
77
api_router.include_router(users.router, prefix="/users", tags=["users"])
8+
api_router.include_router(assign_challenge.router, prefix="/challenge", tags=["challenge"])
89
api_router.include_router(teams.router, prefix="/teams", tags=["teams"])
9-
api_router.include_router(challenges.router, prefix="/challenges", tags=["challenges"])
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from fastapi import APIRouter, HTTPException, Depends
2+
from sqlalchemy.orm import Session
3+
from schemas.challenge_schema import ChallengeRequest, ChallengeResponse
4+
from services.challenge_service import assign_challenges_logic
5+
from services.user_service import parse_user_id
6+
from core.database import get_db
7+
8+
router = APIRouter()
9+
10+
@router.post("/assign-challenges", response_model=ChallengeResponse)
11+
def assign_challenges(request: ChallengeRequest, db: Session = Depends(get_db)):
12+
try:
13+
# my_id = parse_user_id(request.my_id).get("id")
14+
# if not my_id:
15+
# raise HTTPException(status_code=400, detail="μ˜¬λ°”λ₯Έ ν˜•μ‹μ˜ μœ μ € νƒœκ·Έκ°€ μ•„λ‹™λ‹ˆλ‹€. 예: κΉ€λ―Όμ€€#0001")
16+
17+
# members_ids = [request.my_id] # νŒ€μ›μ— 자기 μžμ‹  포함
18+
# for tag in request.members_ids:
19+
# parsed = parse_user_id(tag)
20+
# if "error" in parsed:
21+
# raise HTTPException(status_code=400, detail=parsed["error"])
22+
# members_ids.append(parsed["id"])
23+
24+
members_ids = [request.my_id] + request.members_ids
25+
assigned = assign_challenges_logic(request.my_id, members_ids, db)
26+
return ChallengeResponse(team_id=request.team_id, my_assigned=assigned)
27+
28+
except ValueError as e:
29+
raise HTTPException(status_code=400, detail=str(e))

β€Žgetcloser/backend/app/api/v1/users/users.pyβ€Ž

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from core.database import get_db
22
from fastapi import APIRouter, Depends
3-
from services.user_service import auth_user, get_user
3+
from services.user_service import auth_user, get_user, parse_user_id
44
from sqlalchemy.orm import Session
55
from schemas.user_schema import UserAuth, UserResponse
66

@@ -16,3 +16,12 @@ def auth(user_auth: UserAuth, db: Session = Depends(get_db)):
1616
def get_user_name(id: int, db: Session = Depends(get_db)):
1717
user = get_user(db, id)
1818
return {"data": f"{user.name}#{str(user.id).zfill(4)}"}
19+
20+
21+
@router.get("/user_id/{tag}")
22+
def get_user_id(tag: str):
23+
"""
24+
'이름#0001' ν˜•μ‹μ˜ λ¬Έμžμ—΄μ„ λ°›μ•„μ„œ ID(int)둜 λ³€ν™˜ν•©λ‹ˆλ‹€.
25+
"""
26+
response = parse_user_id(tag)
27+
return response

β€Žgetcloser/backend/app/main.pyβ€Ž

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
from routers import test_db
88
from api.v1 import api_router
99

10+
from scripts.users import seed_users_from_csv
11+
from scripts.challenge_question import seed_challenge_questions_from_csv
12+
1013

1114
# .env 파일 λ‘œλ“œ
1215
load_dotenv()
@@ -50,3 +53,10 @@ async def read_root():
5053
async def health_check():
5154
"""ν—¬μŠ€ 체크 μ—”λ“œν¬μΈνŠΈ"""
5255
return {"status": "healthy"}
56+
57+
# μ„œλ²„ μ‹œμž‘ μ‹œ μ‹€ν–‰
58+
@app.on_event("startup")
59+
def on_startup():
60+
print("πŸš€ Server starting, seeding challenge questions...")
61+
seed_users_from_csv("./scripts/user_data.csv")
62+
seed_challenge_questions_from_csv("./scripts/challenge_question.csv")
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from core.database import Base
2+
from sqlalchemy import Column, Integer, String
3+
4+
class ChallengeQuestion(Base):
5+
__tablename__ = 'challenge_questions'
6+
id = Column(Integer, primary_key=True, index=True)
7+
user_id = Column(Integer)
8+
category = Column(String)
9+
answer = Column(String)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from core.database import Base
2+
from sqlalchemy import Column, Integer, String, DateTime, Boolean, ForeignKey
3+
from sqlalchemy.orm import relationship
4+
5+
class UserChallengeStatus(Base):
6+
__tablename__ = "user_challenge_status"
7+
8+
id = Column(Integer, primary_key=True, index=True)
9+
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
10+
challenge_id = Column(Integer, ForeignKey("challenge_questions.id"), nullable=False)
11+
is_correct = Column(Boolean, default=False)
12+
submitted_at = Column(DateTime, nullable=True)
13+
is_redeemed = Column(Boolean, default=False)
14+
redeemed_at = Column(DateTime, nullable=True)

β€Žgetcloser/backend/app/schemas/challenge_schema.pyβ€Ž

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
11
from pydantic import BaseModel
2+
from typing import List
3+
4+
class ChallengeRequest(BaseModel):
5+
team_id: int
6+
my_id: int
7+
members_ids: List[int]
8+
9+
class AssignedChallenge(BaseModel):
10+
user_id: int
11+
assigned_challenge_id: int
12+
from_user_id: int
13+
category: str
14+
answer: str
15+
16+
class ChallengeResponse(BaseModel):
17+
team_id: int
18+
my_assigned: AssignedChallenge
219
from datetime import datetime
320
from typing import Optional
421

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import csv
2+
from sqlalchemy.orm import Session
3+
from core.database import SessionLocal, engine, Base
4+
from models.challenge_question import ChallengeQuestion
5+
6+
def seed_challenge_questions_from_csv(file_path: str):
7+
# ν…Œμ΄λΈ” 생성 (μ—†μœΌλ©΄)
8+
Base.metadata.create_all(bind=engine)
9+
10+
db: Session = SessionLocal()
11+
try:
12+
with open(file_path, mode='r', encoding='utf-8') as csvfile:
13+
reader = csv.DictReader(csvfile)
14+
for row in reader:
15+
challenge = ChallengeQuestion(
16+
id=int(row["challenge_id"]),
17+
user_id=int(row["user_id"]),
18+
category=row["category"],
19+
answer=row["answer"]
20+
)
21+
# 이미 같은 challenge_idκ°€ μžˆλŠ”μ§€ 확인
22+
existing = db.query(ChallengeQuestion).filter_by(id=challenge.id).first()
23+
if not existing:
24+
db.add(challenge)
25+
26+
db.commit()
27+
print("βœ… Challenge questions seeded successfully!")
28+
29+
except Exception as e:
30+
print("❌ Error while seeding data:", e)
31+
32+
finally:
33+
db.close()
34+
35+
36+
# if __name__ == "__main__":
37+
# seed_challenge_questions_from_csv("./scripts/challenge_question.csv")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
user_id,name,email
2+
1,κΉ€λ―Όμ€€,minjun_kim@gmail.com
3+
2,μ΄μ„œμ—°,seoyeon_lee@naver.com
4+
3,λ°•λ„μœ€,doyoon2025@daum.net
5+
4,μ΅œμ§€μš°,jiwoo_choi@gmail.com
6+
5,μ •ν•˜μ€,haeun_jeong@naver.com
7+
6,κ°•μ‹œμš°,siwoo12@daum.net
8+
7,μ‘°μ„œμ•„,seoa_jo@gmail.com
9+
8,μœ€μ˜ˆμ€€,yejun_yoon@naver.com
10+
9,μž₯μœ λ‚˜,yuna_jang@daum.net
11+
10,μž„μ§€ν˜Έ,jiho_im10@gmail.com
12+
11,κΉ€ν•˜μœ€,hayoon_kim@naver.com
13+
12,μ΄μ€μš°,eunwoo_lee33@daum.net
14+
13,λ°•μ„œμ€€,seojun_park@gmail.com
15+
14,μ΅œμ•„λ¦°,arin_choi@naver.com
16+
15,μ •μˆ˜μ•„,sua_jeong@daum.net
17+
16,κ°•μ§€μ•ˆ,jiankang@gmail.com
18+
17,μ‘°ν•˜μ€€,hajun_jo2@naver.com
19+
18,μœ€λ‹€μ€,daeun_yoon@daum.net
20+
19,μž₯μ„ μš°,sunwoo_jang19@gmail.com
21+
20,μž„μ±„μ›,chaewon_im@naver.com

β€Žgetcloser/backend/app/scripts/user_dummy_data.csvβ€Ž

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
Β (0)