From a097f10bb640595ae7f4ad59849ee33633914677 Mon Sep 17 00:00:00 2001 From: Luckaskl Date: Mon, 18 May 2026 18:57:25 -0500 Subject: [PATCH] =?UTF-8?q?implementa=C3=A7=C3=A3o=20de=20funcionalidades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/__pycache__/main.cpython-311.pyc | Bin 0 -> 1058 bytes app/api/v1/__pycache__/api.cpython-311.pyc | Bin 0 -> 448 bytes .../__pycache__/games.cpython-311.pyc | Bin 0 -> 7159 bytes app/api/v1/endpoints/games.py | 83 ++++++++++++++++-- app/core/__pycache__/config.cpython-311.pyc | Bin 0 -> 939 bytes app/db/__pycache__/database.cpython-311.pyc | Bin 0 -> 916 bytes app/models/__pycache__/game.cpython-311.pyc | Bin 0 -> 1423 bytes app/schemas/__pycache__/game.cpython-311.pyc | Bin 0 -> 3536 bytes 8 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 app/__pycache__/main.cpython-311.pyc create mode 100644 app/api/v1/__pycache__/api.cpython-311.pyc create mode 100644 app/api/v1/endpoints/__pycache__/games.cpython-311.pyc create mode 100644 app/core/__pycache__/config.cpython-311.pyc create mode 100644 app/db/__pycache__/database.cpython-311.pyc create mode 100644 app/models/__pycache__/game.cpython-311.pyc create mode 100644 app/schemas/__pycache__/game.cpython-311.pyc diff --git a/app/__pycache__/main.cpython-311.pyc b/app/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5572d011815c171a12b29b8673e3127f2a55cea5 GIT binary patch literal 1058 zcmZuv%}X0m5TCan*|^DSj1*IpHiuT4Ln9tMG?aphEiD*D#X~M(&Ay}?_9MLANZXSw zLVN7ZLMfydrPcq!e_)k>VNXI&y+!QFQ|E2mVxW(i_kQ!6d9(9o_E6JQ!1Z%K)x0YJ z{NhHuyT z=9_CWTl-f90^S7?^@=wb=R^#_Bv_eP4i%evp5CDCd2}sO`|%Eb&duv?e#NXY*Yhab zF;5QNyg~Czx_|QBavNy4`4_rPwYkkn8evp&hj?w%<+Tq zKX4FgY!?mP*SE2IEP*UjxGQN>U*~+N))>`&TGcHpOs}o4zFJ<|td Ufsi%Q2fkm5AdC)E14q<~zuH0nF8}}l literal 0 HcmV?d00001 diff --git a/app/api/v1/__pycache__/api.cpython-311.pyc b/app/api/v1/__pycache__/api.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe45d93324af204c5c1e21c5dd2541f47ffb9945 GIT binary patch literal 448 zcmZ3^%ge<81S_X=XKet|k3k$5V1+V1=K&eh8B!Qh7;_kM8KW2(L2RZRrd;MIW<~}k zhE&F7KozTD`WT{EQdt(jbi+kKj8x_v90epk zFf%eT-e8cufQoJ~s9ius4|v5oB0Hmdq8qqwFmPRGki5hoIYV`h&INt@1LX%YFEB`6 RWC*yz5O4v8ig0{|wsb2b0~ literal 0 HcmV?d00001 diff --git a/app/api/v1/endpoints/__pycache__/games.cpython-311.pyc b/app/api/v1/endpoints/__pycache__/games.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..488cfb63190cbab564aba980d2b9ac242c42f0ac GIT binary patch literal 7159 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 Uu~#o6_MO0DnJSFad$36V58v9`ivR!s literal 0 HcmV?d00001 diff --git a/app/api/v1/endpoints/games.py b/app/api/v1/endpoints/games.py index b3633cb..fdeaa56 100644 --- a/app/api/v1/endpoints/games.py +++ b/app/api/v1/endpoints/games.py @@ -1,28 +1,95 @@ from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session +from sqlalchemy import or_, String from typing import List, Optional +import re +import unicodedata from app.schemas.game import GameCreate, GameUpdate, GameResponse, StandardResponse +from app.models.game import Game from app.db.database import get_db router = APIRouter() +def generate_slug(title: str) -> str: + # Remove acentos + text = unicodedata.normalize('NFKD', title).encode('ASCII', 'ignore').decode('utf-8') + # Transforma para lowercase e substitui espaços por hifens + text = text.lower() + # Remove caracteres especiais + text = re.sub(r'[^a-z0-9\-]', '-', text) + # Remove hifens duplicados + text = re.sub(r'-+', '-', text).strip('-') + return text + @router.get("/", response_model=StandardResponse) def read_games(skip: int = 0, limit: int = 100, genre: Optional[str] = None, platform: Optional[str] = None, db: Session = Depends(get_db)): - # Lógica de listagem e filtragem será implementada aqui - return {"success": True, "message": "Lista de jogos", "data": []} + query = db.query(Game) + + if genre: + query = query.filter(Game.genres.cast(String).ilike(f'%"{genre}"%')) + + if platform: + query = query.filter(Game.platforms.cast(String).ilike(f'%"{platform}"%')) + + games = query.offset(skip).limit(limit).all() + data = [GameResponse.model_validate(g).model_dump() for g in games] + + return {"success": True, "message": "Lista de jogos", "data": data} @router.post("/", response_model=StandardResponse, status_code=status.HTTP_201_CREATED) def create_game(game: GameCreate, db: Session = Depends(get_db)): - # Lógica de criação será implementada aqui - return {"success": True, "message": "Jogo criado com sucesso", "data": {}} + slug = generate_slug(game.title) + + # Verifica se já existe um jogo com esse slug + db_game = db.query(Game).filter(Game.slug == slug).first() + if db_game: + raise HTTPException(status_code=400, detail="Um jogo com este título/slug já existe.") + + # Cria o modelo no DB + game_data = game.model_dump() + db_game = Game(**game_data, slug=slug) + + db.add(db_game) + db.commit() + db.refresh(db_game) + + data = GameResponse.model_validate(db_game).model_dump() + return {"success": True, "message": "Jogo criado com sucesso", "data": data} @router.get("/{id_ou_slug}", response_model=StandardResponse) def read_game(id_ou_slug: str, db: Session = Depends(get_db)): - # Lógica de leitura de um único jogo será implementada aqui - return {"success": True, "message": "Detalhes do jogo", "data": {}} + db_game = db.query(Game).filter(or_(Game.id == id_ou_slug, Game.slug == id_ou_slug)).first() + + if not db_game: + raise HTTPException(status_code=404, detail="Jogo não encontrado.") + + data = GameResponse.model_validate(db_game).model_dump() + return {"success": True, "message": "Detalhes do jogo", "data": data} @router.patch("/{id}", response_model=StandardResponse) def update_game(id: str, game: GameUpdate, db: Session = Depends(get_db)): - # Lógica de atualização parcial será implementada aqui - return {"success": True, "message": "Jogo atualizado com sucesso", "data": {}} + db_game = db.query(Game).filter(Game.id == id).first() + + if not db_game: + raise HTTPException(status_code=404, detail="Jogo não encontrado.") + + update_data = game.model_dump(exclude_unset=True) + + if "title" in update_data: + new_slug = generate_slug(update_data["title"]) + # Verifica se o novo slug conflita com outro jogo existente + existing_slug = db.query(Game).filter(Game.slug == new_slug, Game.id != id).first() + if existing_slug: + raise HTTPException(status_code=400, detail="Um jogo com este título/slug já existe.") + db_game.slug = new_slug + + for key, value in update_data.items(): + setattr(db_game, key, value) + + db.add(db_game) + db.commit() + db.refresh(db_game) + + data = GameResponse.model_validate(db_game).model_dump() + return {"success": True, "message": "Jogo atualizado com sucesso", "data": data} diff --git a/app/core/__pycache__/config.cpython-311.pyc b/app/core/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..066ba769529145ea2c04708b3e46630503c630d0 GIT binary patch literal 939 zcmZuvzfaph6h7OR#0>^YC=`Yks&+|-L~Ip8k&-m3iXcTv=-}mK<&MZGu~XZL1nQ8X zLn?J(%UE>@s`xYb2f`NJ+NoPmn3(#WLx>Q4ckjFR(CD1F*3 zx3^?Gd+?Ec-eToSNgD67m256sF0jMW-h=Z%OG6p2!ZJG#o`$O? zC5POh%;6m}4~rV=~TI!{x0y+6H4^T2}ooqr+x)WY>jU zs6u0zFC5(^NMDMs~er&Gi^XOU|!LUVPa)KabD4t5mh5EN8~YFW9;TX zi3ts4P)t&})I8yq6WCSg-Q-nz$SEWz_50XE{Ds8{;}QBafD?50R*_;DgXcg literal 0 HcmV?d00001 diff --git a/app/db/__pycache__/database.cpython-311.pyc b/app/db/__pycache__/database.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23246f18afc77153b6c543fa44f66959e829e45f GIT binary patch literal 916 zcma)4PiqrF6o0e-vb#;2Lb0)kMNp7nn|=WiQ?!?q9*hd^C2V%4>DJwBoZZ+KBIMv9 zEd@o8UOW^J6=^?!M?XReIfMnF;6-nNTtZL2N!r@bOW(|U{NC@)pZDI(xAAckP`>Vs zt$!u}zlC!y>KW+mBG>~8lz8A1ix7b&Px56;9$*=s1cQ~^nR%Dg3 zTVY5{Qs#IzwmiFGw^9z5GIDI%wJ2}`-*=u~d#jP4M z78PlUr*PRAYWNt<9~=$%W!%`F-JNYLb|qPz>P$>FbumtK^Mk&lZ=1Vjb1?c%=`zvp z_d^2@`J~Lj(R5CdS2D@i4BvRR=d3Y*i;H)TC;k)Jfcspumx~`4r!dp36L5y6vg($( zCfMYY-1FRGuJE+@;@NVn4Ii9~jALaHYZ(;q9ePLrpFne}KlB4y^VlPP6J61U@C%x* zObF?~z1HaLz=PK4?7;oj=)Ah?#F%d0{+2Eof;!Jt8x2a_fU6&`e^x6= zT&=nxsqGA>4_^APbCH)sU#7hmSXS(O#&%)96R@GznCLAGyhSXZ=DQ&23D|JFIbf_St4vMwPEYjCO!UrT10*eQ zbCgKP#J_LZHl%jDK2?K+itTtFu#Eb4R4DG%gxry{QK1Px3PQY zktISekGf*P@NIwurSEP2sXida zj;4~2`qs7fW@qhqBej;!tfii{l&qfT(bPP6SH8Lb?fqmm8y_8-N9Jh!h50rr1}}tr)TKKQiQoE9@PUq*e$#Nt%6PksT{s%}XRw@5#1b&j=CWRJ z_p-CS!%8qjd;;MCz_}txQXeg+ud01?J-uA}sF)0%b9GvJ=N$bX+RJ|n?>`f$L8|`( D9Rgq+ literal 0 HcmV?d00001 diff --git a/app/schemas/__pycache__/game.cpython-311.pyc b/app/schemas/__pycache__/game.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f47806998a83073dc4af34f22d89f69dfe359c0 GIT binary patch literal 3536 zcmbtW%}*Og6yNoZ*Xu9LR~nNP2oNCdM^d$o#DPX?p(RjotB|Pb9%^m86XMEiJG1Mk z94akR4;(o7P&FKKPE_@u=%27Faahf@r{17&sB-Fivw-bg`n`;Q%)Z}zym{|8v-2{a z&q(mRe3t$C2O>$o;LF*QJgpr629;-$DVcIzvSeMh5_&?$_e5Q>h)%4ep0re5wNiRY zmJ-s6WGdfDCZX~RMUsAkU-;;n;F7?pF)l5*6mVLM%LpzFT!v;MV`c@H1uhrsmlIqb zxPe%|yx!pVBgcDVLg%c(UR zMxB%8TGipohmGy(>3YS#v(+Cj!|OANO1f-Hdg1{@Q&%XV$+7d+R5cTe@CHmO#wZ~J zei5EoF)X@j8C%pY^R)B0Z9QxlwK`WHQ^TaJq;aiMX+WDwg=Z=it7*3DSkF}|PufO3 zWLOraVk!b;UgCvH#b`8|j)Cj3D;1Ul>yOegp!BME%V@R4&#peEmSNx8g5htrwi)V2 z01jfKlWxynFf;G2?tZhMIw)N8$UGFE%m>%5yPxdd?R;^N8~4a{D84|bu;H`eE)L>X zK>zRK$k}>(%cG|Q2nB@K5HOlt zu^q++@%1u75n%{HtZf8qm(DzO)b(!gZ;7)>x~Jxg=o zK_+Ym8qabKHI5sPC!Ly8r#x#?yUJ=}yK!}kHW;;ex>YxvM@?oy)uc~pz1gCy%+;FM z9DKwUnXIs$RNm*RQFUrhX(=DgA-Wc34$nR|g&;PF5cxE|ipL%0Gz`)7b|eqAZJI_ZAAy8!b2z$24Td@>nK&AOjhTaU~@@yX1; z+7IJX;f#A_k4!=F1wthhBrd5>kOU0)9Nz)x734)nrMOCnE6#n#fJ1apZ@2}MFkA_{8iqP z@TmzeTFM0Rq%Uya_*h0iZ8l`5|}1-PqX(@`LWWyS}pyIdYeGZ*<<UQW;Gy9!hc8-9AF=NtYUx