package app import ( "context" "evening_detective_server/internal/modules/file_storage" "evening_detective_server/internal/modules/processor_jwt" "evening_detective_server/internal/modules/roles" "evening_detective_server/internal/services/file_service" "evening_detective_server/internal/services/game_service" "evening_detective_server/internal/services/scenarios_service" "evening_detective_server/internal/services/ui_service" "evening_detective_server/internal/services/users_service" proto "evening_detective_server/proto" "google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) type server struct { proto.UnsafeEveningDetectiveServerServer usersService *users_service.UsersService uiService *ui_service.UiService fileService *file_service.FileService scenarioService *scenarios_service.ScenarioService gameService *game_service.GameService } func NewServer( usersService *users_service.UsersService, uiService *ui_service.UiService, fileService *file_service.FileService, scenarioService *scenarios_service.ScenarioService, gameService *game_service.GameService, ) proto.EveningDetectiveServerServer { return &server{ usersService: usersService, uiService: uiService, fileService: fileService, scenarioService: scenarioService, gameService: gameService, } } func (s *server) Ping(_ context.Context, _ *proto.PingReq) (*proto.PingRsp, error) { return &proto.PingRsp{}, nil } func (s *server) Echo(_ context.Context, req *proto.EchoReq) (*proto.EchoRsp, error) { return &proto.EchoRsp{Text: req.Text}, nil } func (s *server) Signup(ctx context.Context, req *proto.SignupReq) (*proto.SignupRsp, error) { err := s.usersService.AddUser(ctx, req.Username, req.Email) if err != nil { return &proto.SignupRsp{ Error: err.Error(), }, nil } return &proto.SignupRsp{}, nil } func (s *server) RefreshPassword(ctx context.Context, req *proto.RefreshPasswordReq) (*proto.RefreshPasswordRsp, error) { err := s.usersService.RefreshPassword(ctx, req.Email) if err != nil { return &proto.RefreshPasswordRsp{ Error: err.Error(), }, nil } return &proto.RefreshPasswordRsp{}, nil } func (s *server) Login(ctx context.Context, req *proto.LoginReq) (*proto.LoginRsp, error) { accessToken, refreshToken, err := s.usersService.Login(ctx, req.Email, req.Password) if err != nil { return &proto.LoginRsp{ Error: err.Error(), }, nil } return &proto.LoginRsp{ AccessToken: accessToken, RefreshToken: refreshToken, }, nil } func (s *server) Refresh(ctx context.Context, req *proto.RefreshReq) (*proto.RefreshRsp, error) { accessToken, refreshToken, err := s.usersService.Refresh(ctx, req.RefreshToken) if err != nil { return &proto.RefreshRsp{ Error: err.Error(), }, nil } return &proto.RefreshRsp{ AccessToken: accessToken, RefreshToken: refreshToken, }, nil } func (s *server) GetUsers(ctx context.Context, req *proto.GetUsersReq) (*proto.GetUsersRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Admin) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } users, err := s.usersService.GetUsers(ctx) if err != nil { return &proto.GetUsersRsp{ Error: err.Error(), }, nil } resUsers := make([]*proto.User, 0, len(users)) for _, user := range users { resUsers = append(resUsers, mapUser(user)) } return &proto.GetUsersRsp{ Users: resUsers, }, nil } func (s *server) GetUserById(ctx context.Context, req *proto.GetUserByIdReq) (*proto.GetUserByIdRsp, error) { user, err := s.usersService.GetUserByID(ctx, int(req.Id)) if err != nil { return &proto.GetUserByIdRsp{ Error: err.Error(), }, nil } return &proto.GetUserByIdRsp{ User: mapUser(user), }, nil } func (s *server) GetMe(ctx context.Context, req *proto.GetMeReq) (*proto.GetMeRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) user, err := s.usersService.GetUserByID(ctx, claims.UserID) if err != nil { return &proto.GetMeRsp{ Error: err.Error(), }, nil } return &proto.GetMeRsp{ User: mapUser(user), }, nil } func (s *server) AddUserRole(ctx context.Context, req *proto.AddUserRoleReq) (*proto.AddUserRoleRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Admin) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } if err := s.usersService.AddUserRole(ctx, int(req.Id), req.Role); err != nil { return &proto.AddUserRoleRsp{ Error: err.Error(), }, nil } return &proto.AddUserRoleRsp{}, nil } func (s *server) DeleteUserRole(ctx context.Context, req *proto.DeleteUserRoleReq) (*proto.DeleteUserRoleRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Admin) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } if err := s.usersService.DeleteUserRole(ctx, int(req.Id), req.Role); err != nil { return &proto.DeleteUserRoleRsp{ Error: err.Error(), }, nil } return &proto.DeleteUserRoleRsp{}, nil } func (s *server) GetPermissions(ctx context.Context, req *proto.GetPermissionsReq) (*proto.GetPermissionsRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) permissions := s.uiService.GetPermissions(claims.Roles) return &proto.GetPermissionsRsp{ Permissions: permissions, }, nil } func (s *server) UploadFile(ctx context.Context, req *proto.UploadFileReq) (*proto.UploadFileRsp, error) { filename, err := s.fileService.UploadFile( ctx, &file_storage.File{ Name: req.Filename, Data: req.Data, }, ) if err != nil { return &proto.UploadFileRsp{ Error: err.Error(), }, nil } return &proto.UploadFileRsp{ Filename: filename, }, nil } func (s *server) DownloadFile(ctx context.Context, req *proto.DownloadFileReq) (*httpbody.HttpBody, error) { file, err := s.fileService.DownloadFile(ctx, req.Filename) if err != nil { return &httpbody.HttpBody{}, nil } return &httpbody.HttpBody{ Data: file.Data, ContentType: file.Mime, }, nil } func (s *server) AddScenario(ctx context.Context, req *proto.AddScenarioReq) (*proto.AddScenarioRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } id, err := s.scenarioService.AddScenario(ctx, req.Name, claims.UserID) if err != nil { return &proto.AddScenarioRsp{ Error: err.Error(), }, nil } return &proto.AddScenarioRsp{ Id: int32(id), }, nil } func (s *server) GetMyScenarios(ctx context.Context, req *proto.GetMyScenariosReq) (*proto.GetMyScenariosRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } scenarios, err := s.scenarioService.GetScenariosByAuthorID(ctx, claims.UserID) if err != nil { return &proto.GetMyScenariosRsp{ Error: err.Error(), }, nil } return &proto.GetMyScenariosRsp{ Scenarios: mapScenarios(scenarios), }, nil } func (s *server) GetScenariosCatalog(ctx context.Context, req *proto.GetScenariosCatalogReq) (*proto.GetScenariosCatalogRsp, error) { scenarios, err := s.scenarioService.GetScenariosCatalog(ctx) if err != nil { return &proto.GetScenariosCatalogRsp{ Error: err.Error(), }, nil } return &proto.GetScenariosCatalogRsp{ Scenarios: mapScenarios(scenarios), }, nil } func (s *server) GetFullScenario(ctx context.Context, req *proto.GetScenarioReq) (*proto.GetScenarioRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } scenario, err := s.scenarioService.GetFullScenarioByID(ctx, int(req.Id)) if err != nil { return &proto.GetScenarioRsp{ Error: err.Error(), }, nil } return &proto.GetScenarioRsp{ Scenario: mapScenario(scenario), }, nil } func (s *server) GetScenario(ctx context.Context, req *proto.GetScenarioReq) (*proto.GetScenarioRsp, error) { scenario, err := s.scenarioService.GetScenarioByID(ctx, int(req.Id)) if err != nil { return &proto.GetScenarioRsp{ Error: err.Error(), }, nil } return &proto.GetScenarioRsp{ Scenario: mapScenario(scenario), }, nil } func (s *server) UpdateScenario(ctx context.Context, req *proto.UpdateScenarioReq) (*proto.UpdateScenarioRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.scenarioService.UpdateScenarioByID( ctx, int(req.Id), req.Name, req.Description, req.Image, ) if err != nil { return &proto.UpdateScenarioRsp{ Error: err.Error(), }, nil } return &proto.UpdateScenarioRsp{}, nil } func (s *server) PublicScenario(ctx context.Context, req *proto.PublicScenarioReq) (*proto.PublicScenarioRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.scenarioService.UpdateScenarioStatusByID( ctx, int(req.Id), "public", ) if err != nil { return &proto.PublicScenarioRsp{ Error: err.Error(), }, nil } return &proto.PublicScenarioRsp{}, nil } func (s *server) DraftScenario(ctx context.Context, req *proto.DraftScenarioReq) (*proto.DraftScenarioRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.scenarioService.UpdateScenarioStatusByID( ctx, int(req.Id), "draft", ) if err != nil { return &proto.DraftScenarioRsp{ Error: err.Error(), }, nil } return &proto.DraftScenarioRsp{}, nil } func (s *server) DeleteScenario(ctx context.Context, req *proto.DeleteScenarioReq) (*proto.DeleteScenarioRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.scenarioService.DeleteScenarioByID( ctx, int(req.Id), ) if err != nil { return &proto.DeleteScenarioRsp{ Error: err.Error(), }, nil } return &proto.DeleteScenarioRsp{}, nil } func (s *server) AddScenarioPlace(ctx context.Context, req *proto.AddScenarioPlaceReq) (*proto.AddScenarioPlaceRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.scenarioService.AddScenarioPlace( ctx, int(req.Id), convertPlace(req.Place), ) if err != nil { return &proto.AddScenarioPlaceRsp{ Error: err.Error(), }, nil } return &proto.AddScenarioPlaceRsp{}, nil } func (s *server) UpdateScenarioPlace(ctx context.Context, req *proto.UpdateScenarioPlaceReq) (*proto.UpdateScenarioPlaceRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.scenarioService.UpdateScenarioPlace( ctx, int(req.Id), req.Code, convertPlace(req.Place), ) if err != nil { return &proto.UpdateScenarioPlaceRsp{ Error: err.Error(), }, nil } return &proto.UpdateScenarioPlaceRsp{}, nil } func (s *server) DeleteScenarioPlace(ctx context.Context, req *proto.DeleteScenarioPlaceReq) (*proto.DeleteScenarioPlaceRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.scenarioService.DeleteScenarioPlace( ctx, int(req.Id), req.Code, ) if err != nil { return &proto.DeleteScenarioPlaceRsp{ Error: err.Error(), }, nil } return &proto.DeleteScenarioPlaceRsp{}, nil } func (s *server) AddGame(ctx context.Context, req *proto.AddGameReq) (*proto.AddGameRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } if req.StartAt == nil { return nil, status.Errorf(codes.InvalidArgument, "startAt must not be nil") } id, err := s.gameService.AddGame( ctx, req.Name, req.Description, req.StartAt.AsTime(), req.ScenarioId, ) if err != nil { return &proto.AddGameRsp{ Error: err.Error(), }, nil } return &proto.AddGameRsp{ Id: int32(id), }, nil } func (s *server) DeleteGame(ctx context.Context, req *proto.DeleteGameReq) (*proto.DeleteGameRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.gameService.DeleteGame( ctx, int(req.Id), ) if err != nil { return &proto.DeleteGameRsp{ Error: err.Error(), }, nil } return &proto.DeleteGameRsp{}, nil } func (s *server) GetGame(ctx context.Context, req *proto.GetGameReq) (*proto.GetGameRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } game, err := s.gameService.GetGame(ctx, int(req.Id)) if err != nil { return &proto.GetGameRsp{ Error: err.Error(), }, nil } return &proto.GetGameRsp{ Game: mapGame(game), }, nil } func (s *server) GetGames(ctx context.Context, req *proto.GetGamesReq) (*proto.GetGamesRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } games, err := s.gameService.GetGames(ctx) if err != nil { return &proto.GetGamesRsp{ Error: err.Error(), }, nil } return &proto.GetGamesRsp{ Games: mapGames(games), }, nil } func (s *server) UpdateGame(ctx context.Context, req *proto.UpdateGameReq) (*proto.UpdateGameRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } if req.StartAt == nil { return nil, status.Errorf(codes.InvalidArgument, "startAt must not be nil") } err := s.gameService.UpdateGame( ctx, int(req.Id), req.Name, req.Description, req.StartAt.AsTime(), req.ScenarioId, ) if err != nil { return &proto.UpdateGameRsp{ Error: err.Error(), }, nil } return &proto.UpdateGameRsp{}, nil } func (s *server) AddTeam(ctx context.Context, req *proto.AddTeamReq) (*proto.AddTeamRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } team, err := s.gameService.AddTeam( ctx, claims.UserID, int(req.GameId), req.Name, ) if err != nil { return &proto.AddTeamRsp{ Error: err.Error(), }, nil } return &proto.AddTeamRsp{ Id: int32(team.ID), Password: team.Password, }, nil } func (s *server) UpdateTeam(ctx context.Context, req *proto.UpdateTeamReq) (*proto.UpdateTeamRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.gameService.UpdateTeam( ctx, int(req.Id), req.Name, ) if err != nil { return &proto.UpdateTeamRsp{ Error: err.Error(), }, nil } return &proto.UpdateTeamRsp{}, nil } func (s *server) DeleteTeam(ctx context.Context, req *proto.DeleteTeamReq) (*proto.DeleteTeamRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.gameService.DeleteTeam( ctx, int(req.Id), ) if err != nil { return &proto.DeleteTeamRsp{ Error: err.Error(), }, nil } return &proto.DeleteTeamRsp{}, nil } func (s *server) GiveTeamApplications(ctx context.Context, req *proto.GiveTeamApplicationsReq) (*proto.GiveTeamApplicationsRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Organizer) && !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.gameService.GiveTeamApplications( ctx, int(req.Id), req.Name, ) if err != nil { return &proto.GiveTeamApplicationsRsp{ Error: err.Error(), }, nil } return &proto.GiveTeamApplicationsRsp{}, nil } func (s *server) GetTeamStory(ctx context.Context, req *proto.GetTeamStoryReq) (*proto.GetTeamStoryRsp, error) { story, err := s.gameService.GetTeamActions( ctx, int(req.Id), req.Password, ) if err != nil { return &proto.GetTeamStoryRsp{ Error: err.Error(), }, nil } return &proto.GetTeamStoryRsp{ Story: mapStory(story), }, nil } func (s *server) AddTeamAction(ctx context.Context, req *proto.AddTeamActionReq) (*proto.AddTeamActionRsp, error) { err := s.gameService.AddTeamAction( ctx, int(req.Id), req.Password, req.Code, ) if err != nil { return &proto.AddTeamActionRsp{ Error: err.Error(), }, nil } return &proto.AddTeamActionRsp{}, nil } func (s *server) DeleteLastTeamAction(ctx context.Context, req *proto.DeleteLastTeamActionReq) (*proto.DeleteLastTeamActionRsp, error) { claims := ctx.Value("claims").(*processor_jwt.JWTClaims) if !roles.HasRole(claims, roles.Author) { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } err := s.gameService.DeleteLastTeamAction( ctx, int(req.Id), ) if err != nil { return &proto.DeleteLastTeamActionRsp{ Error: err.Error(), }, nil } return &proto.DeleteLastTeamActionRsp{}, nil }