Skip to content

Commit aa3fe1e

Browse files
authored
Merge pull request #22 from fga-eps-mds/feature/ranking
feat(ranking): orquestracao do ranking (geral, amigos, turma, lista)
2 parents ab0062b + b04c326 commit aa3fe1e

6 files changed

Lines changed: 1144 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import type { NextFunction, Request, Response } from "express";
2+
3+
import { CodigoDeErro } from "@/shared/errors/codigos-de-erro";
4+
import { ErroAplicacao } from "@/shared/errors/erro-aplicacao";
5+
6+
import type { RankingService } from "./ranking.service";
7+
8+
type RequisicaoAutenticada = Pick<Request, "usuario" | "headers">;
9+
10+
const LIMITE_MAXIMO_GERAL = 200;
11+
12+
export class RankingController {
13+
constructor(private readonly rankingService: RankingService) {}
14+
15+
geral = async (request: Request, response: Response, next: NextFunction) => {
16+
try {
17+
const usuario = this.obterUsuario(request);
18+
const authorization = this.obterAuthorization(request);
19+
const limite = this.obterLimite(request);
20+
21+
const resultado = await this.rankingService.rankingGeral(usuario, authorization, limite);
22+
23+
return response.status(200).json(resultado);
24+
} catch (error) {
25+
return next(error);
26+
}
27+
};
28+
29+
amigos = async (request: Request, response: Response, next: NextFunction) => {
30+
try {
31+
const usuario = this.obterUsuario(request);
32+
const authorization = this.obterAuthorization(request);
33+
34+
const resultado = await this.rankingService.rankingAmigos(usuario, authorization);
35+
36+
return response.status(200).json(resultado);
37+
} catch (error) {
38+
return next(error);
39+
}
40+
};
41+
42+
turma = async (
43+
request: Request<{ turmaId: string }>,
44+
response: Response,
45+
next: NextFunction,
46+
) => {
47+
try {
48+
const usuario = this.obterUsuario(request);
49+
const authorization = this.obterAuthorization(request);
50+
51+
const resultado = await this.rankingService.rankingTurma(
52+
usuario,
53+
authorization,
54+
request.params.turmaId,
55+
);
56+
57+
return response.status(200).json(resultado);
58+
} catch (error) {
59+
return next(error);
60+
}
61+
};
62+
63+
lista = async (
64+
request: Request<{ turmaId: string; listaId: string }>,
65+
response: Response,
66+
next: NextFunction,
67+
) => {
68+
try {
69+
const usuario = this.obterUsuario(request);
70+
const authorization = this.obterAuthorization(request);
71+
72+
const resultado = await this.rankingService.rankingLista(
73+
usuario,
74+
authorization,
75+
request.params.turmaId,
76+
request.params.listaId,
77+
);
78+
79+
return response.status(200).json(resultado);
80+
} catch (error) {
81+
return next(error);
82+
}
83+
};
84+
85+
private obterLimite(request: Request): number | undefined {
86+
const bruto = request.query.limite;
87+
88+
if (typeof bruto !== "string") {
89+
return undefined;
90+
}
91+
92+
const numero = Number.parseInt(bruto, 10);
93+
94+
if (!Number.isFinite(numero) || numero <= 0) {
95+
return undefined;
96+
}
97+
98+
return Math.min(numero, LIMITE_MAXIMO_GERAL);
99+
}
100+
101+
private obterUsuario(request: RequisicaoAutenticada) {
102+
if (!request.usuario?.id) {
103+
throw new ErroAplicacao({
104+
codigoStatus: 401,
105+
codigo: CodigoDeErro.NAO_AUTORIZADO,
106+
mensagem: "Usuario nao autenticado.",
107+
});
108+
}
109+
110+
return request.usuario;
111+
}
112+
113+
private obterAuthorization(request: RequisicaoAutenticada): string {
114+
const authorization = request.headers.authorization;
115+
116+
if (!authorization) {
117+
throw new ErroAplicacao({
118+
codigoStatus: 401,
119+
codigo: CodigoDeErro.NAO_AUTORIZADO,
120+
mensagem: "Token de acesso ausente.",
121+
});
122+
}
123+
124+
return authorization;
125+
}
126+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Router } from "express";
2+
3+
import { middlewareAutenticacao } from "@/shared/middlewares/autenticacao.middleware";
4+
5+
import { RankingController } from "./ranking.controller";
6+
import { RankingService } from "./ranking.service";
7+
8+
const rankingService = new RankingService();
9+
const rankingController = new RankingController(rankingService);
10+
11+
const rankingRouter = Router();
12+
13+
rankingRouter.use(middlewareAutenticacao);
14+
15+
// Aluno (e professor/admin): ranking geral de todos os alunos visiveis.
16+
rankingRouter.get("/geral", rankingController.geral);
17+
18+
// Aluno: ranking entre os amigos confirmados + ele mesmo.
19+
rankingRouter.get("/amigos", rankingController.amigos);
20+
21+
// Professor/Admin: ranking dos alunos de uma turma (desempenho geral no AnatoQuiz).
22+
// A autorizacao por papel e garantida pelo Quiz-Service (apenasGestao).
23+
rankingRouter.get("/turmas/:turmaId", rankingController.turma);
24+
25+
// Professor/Admin: ranking dos alunos em uma lista especifica da turma.
26+
rankingRouter.get("/listas/:turmaId/:listaId", rankingController.lista);
27+
28+
export { rankingRouter };

0 commit comments

Comments
 (0)