diff --git a/proto/main.proto b/proto/main.proto index ac6f7f4..6d7a34e 100644 --- a/proto/main.proto +++ b/proto/main.proto @@ -365,6 +365,38 @@ service EveningDetectiveServer { }; } + rpc AddScenarioQuestion(AddScenarioQuestionReq) returns (AddScenarioQuestionRsp) { + option (google.api.http) = { + post: "/api/scenarios/{id}/questions" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Вопросы сценария"; + summary: "Создать вопрос дела"; + }; + } + + rpc UpdateScenarioQuestion(UpdateScenarioQuestionReq) returns (UpdateScenarioQuestionRsp) { + option (google.api.http) = { + put : "/api/scenarios/{id}/questions/{code}" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Вопросы сценария"; + summary: "Обновить вопрос дела"; + }; + } + + rpc DeleteScenarioQuestion(DeleteScenarioQuestionReq) returns (DeleteScenarioQuestionRsp) { + option (google.api.http) = { + delete: "/api/scenarios/{id}/questions/{code}" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Вопросы сценария"; + summary: "Удалить вопрос дела"; + }; + } + rpc UpdateScenarioIntro(UpdateScenarioIntroReq) returns (UpdateScenarioIntroRsp) { option (google.api.http) = { put : "/api/scenarios/{id}/introduction" @@ -428,6 +460,16 @@ service EveningDetectiveServer { }; } + rpc GetGameAnswers(GetGameAnswersReq) returns (GetGameAnswersRsp) { + option (google.api.http) = { + get: "/api/games/{gameId}/answers" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Игры"; + summary: "Получить ответы команд на вопросы дела (для оценки организатором)"; + }; + } + rpc UpdateGame(UpdateGameReq) returns (UpdateGameRsp) { option (google.api.http) = { put : "/api/games/{id}" @@ -583,6 +625,44 @@ service EveningDetectiveServer { summary: "Удалить последний ход"; }; } + + rpc GetTeamAnswers(GetTeamAnswersReq) returns (GetTeamAnswersRsp) { + option (google.api.http) = { + get: "/api/teams/{id}/answers" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + security: { + security_requirement: {} + } + tags : "Ходы"; + summary: "Получить ответы команды на вопросы дела"; + }; + } + + rpc SubmitTeamAnswers(SubmitTeamAnswersReq) returns (SubmitTeamAnswersRsp) { + option (google.api.http) = { + post: "/api/teams/{id}/answers" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + security: { + security_requirement: {} + } + tags : "Ходы"; + summary: "Отправить ответы команды на вопросы дела"; + }; + } + + rpc SetTeamAnswerScore(SetTeamAnswerScoreReq) returns (SetTeamAnswerScoreRsp) { + option (google.api.http) = { + put : "/api/teams/{id}/answers/{questionCode}/score" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Игры"; + summary: "Выставить балл команде за ответ на вопрос дела"; + }; + } } message PingReq {} @@ -792,6 +872,7 @@ message Scenario { message Story { Introduction introduction = 2; repeated Place places = 1; + repeated Question questions = 3; } message Introduction { @@ -829,6 +910,43 @@ message Key { string name = 1; } +// Вопрос дела - вопрос, на который команда должна ответить в конце игры. +// Правильный ответ (answer) виден только автору сценария и организаторам +// (при оценке ответов команд), команде не передаётся. +message Question { + // Код вопроса - используется при отправке ответов командой + string code = 1; + + // Текст вопроса + string text = 2; + + // Правильный ответ (справка для организатора при оценке) + string answer = 3; +} + +// Ответ команды на вопрос дела +message Answer { + // Код вопроса + string questionCode = 1; + + // Текст ответа команды + string answer = 2; +} + +// Ответ команды с баллом (для панели организатора) +message AnswerScore { + string questionCode = 1; + string answer = 2; + // Балл, выставленный организатором; отсутствует, если ещё не оценено + optional int32 score = 3; +} + +// Ответы одной команды на вопросы дела +message TeamAnswers { + Team team = 1; + repeated AnswerScore answers = 2; +} + message UpdateScenarioReq { int32 id = 1; string name = 2; @@ -901,6 +1019,34 @@ message UpdateScenarioIntroRsp { string error = 1; } +message AddScenarioQuestionReq { + int32 id = 1; + Question question = 2; +} + +message AddScenarioQuestionRsp { + string error = 1; +} + +message UpdateScenarioQuestionReq { + int32 id = 1; + string code = 2; + Question question = 3; +} + +message UpdateScenarioQuestionRsp { + string error = 1; +} + +message DeleteScenarioQuestionReq { + int32 id = 1; + string code = 2; +} + +message DeleteScenarioQuestionRsp { + string error = 1; +} + message DownloadScenarioArchiveReq { int32 id = 1; } @@ -959,6 +1105,16 @@ message GetGameRsp { Game game = 2; } +message GetGameAnswersReq { + int32 gameId = 1; +} + +message GetGameAnswersRsp { + string error = 1; + repeated Question questions = 2; + repeated TeamAnswers teams = 3; +} + message UpdateGameReq { int32 id = 1; string name = 2; @@ -1084,3 +1240,34 @@ message DeleteLastTeamActionReq { message DeleteLastTeamActionRsp { string error = 1; } + +message GetTeamAnswersReq { + int64 id = 1; + string password = 2; +} + +message GetTeamAnswersRsp { + string error = 1; + repeated Answer answers = 2; +} + +message SubmitTeamAnswersReq { + int64 id = 1; + string password = 2; + repeated Answer answers = 3; +} + +message SubmitTeamAnswersRsp { + string error = 1; +} + +message SetTeamAnswerScoreReq { + int64 id = 1; + string questionCode = 2; + // Балл; отсутствует — сбросить выставленный балл + optional int32 score = 3; +} + +message SetTeamAnswerScoreRsp { + string error = 1; +} diff --git a/src/api/generated/crabs/evening_detective_server/index.ts b/src/api/generated/crabs/evening_detective_server/index.ts index 960d3c6..ffffeb4 100644 --- a/src/api/generated/crabs/evening_detective_server/index.ts +++ b/src/api/generated/crabs/evening_detective_server/index.ts @@ -208,6 +208,7 @@ export type Scenario = { export type Story = { introduction: Introduction | undefined; places: Place[] | undefined; + questions: Question[] | undefined; }; export type Introduction = { @@ -245,6 +246,18 @@ export type Key = { name: string | undefined; }; +// Вопрос дела - вопрос, на который команда должна ответить в конце игры. +// Правильный ответ (answer) виден только автору сценария и организаторам +// (при оценке ответов команд), команде не передаётся. +export type Question = { + // Код вопроса - используется при отправке ответов командой + code: string | undefined; + // Текст вопроса + text: string | undefined; + // Правильный ответ (справка для организатора при оценке) + answer: string | undefined; +}; + export type GetScenariosCatalogReq = { }; @@ -262,6 +275,37 @@ export type GetScenarioRsp = { scenario: Scenario | undefined; }; +// Ответ команды на вопрос дела +export type Answer = { + // Код вопроса + questionCode: string | undefined; + // Текст ответа команды + answer: string | undefined; +}; + +// Ответ команды с баллом (для панели организатора) +export type AnswerScore = { + questionCode: string | undefined; + answer: string | undefined; + // Балл, выставленный организатором; отсутствует, если ещё не оценено + score?: number; +}; + +// Ответы одной команды на вопросы дела +export type TeamAnswers = { + team: Team | undefined; + answers: AnswerScore[] | undefined; +}; + +export type Team = { + id: number | undefined; + name: string | undefined; + status: string | undefined; + password: string | undefined; + actionsCount: number | undefined; + applications: Application[] | undefined; +}; + export type UpdateScenarioReq = { id: number | undefined; name: string | undefined; @@ -334,6 +378,34 @@ export type UpdateScenarioIntroRsp = { error: string | undefined; }; +export type AddScenarioQuestionReq = { + id: number | undefined; + question: Question | undefined; +}; + +export type AddScenarioQuestionRsp = { + error: string | undefined; +}; + +export type UpdateScenarioQuestionReq = { + id: number | undefined; + code: string | undefined; + question: Question | undefined; +}; + +export type UpdateScenarioQuestionRsp = { + error: string | undefined; +}; + +export type DeleteScenarioQuestionReq = { + id: number | undefined; + code: string | undefined; +}; + +export type DeleteScenarioQuestionRsp = { + error: string | undefined; +}; + export type DownloadScenarioArchiveReq = { id: number | undefined; }; @@ -375,15 +447,6 @@ export type Game = { endedAt?: wellKnownTimestamp; }; -export type Team = { - id: number | undefined; - name: string | undefined; - status: string | undefined; - password: string | undefined; - actionsCount: number | undefined; - applications: Application[] | undefined; -}; - export type GetGameReq = { id: number | undefined; }; @@ -393,6 +456,16 @@ export type GetGameRsp = { game: Game | undefined; }; +export type GetGameAnswersReq = { + gameId: number | undefined; +}; + +export type GetGameAnswersRsp = { + error: string | undefined; + questions: Question[] | undefined; + teams: TeamAnswers[] | undefined; +}; + export type UpdateGameReq = { id: number | undefined; name: string | undefined; @@ -519,6 +592,37 @@ export type DeleteLastTeamActionRsp = { error: string | undefined; }; +export type GetTeamAnswersReq = { + id: number | undefined; + password: string | undefined; +}; + +export type GetTeamAnswersRsp = { + error: string | undefined; + answers: Answer[] | undefined; +}; + +export type SubmitTeamAnswersReq = { + id: number | undefined; + password: string | undefined; + answers: Answer[] | undefined; +}; + +export type SubmitTeamAnswersRsp = { + error: string | undefined; +}; + +export type SetTeamAnswerScoreReq = { + id: number | undefined; + questionCode: string | undefined; + // Балл; отсутствует — сбросить выставленный балл + score?: number; +}; + +export type SetTeamAnswerScoreRsp = { + error: string | undefined; +}; + export interface EveningDetectiveServer { Ping(request: PingReq): Promise; Echo(request: EchoReq): Promise; @@ -550,12 +654,16 @@ export interface EveningDetectiveServer { AddScenarioPlace(request: AddScenarioPlaceReq): Promise; UpdateScenarioPlace(request: UpdateScenarioPlaceReq): Promise; DeleteScenarioPlace(request: DeleteScenarioPlaceReq): Promise; + AddScenarioQuestion(request: AddScenarioQuestionReq): Promise; + UpdateScenarioQuestion(request: UpdateScenarioQuestionReq): Promise; + DeleteScenarioQuestion(request: DeleteScenarioQuestionReq): Promise; UpdateScenarioIntro(request: UpdateScenarioIntroReq): Promise; DownloadScenarioArchive(request: DownloadScenarioArchiveReq): Promise; UploadScenarioArchive(request: googleapi_HttpBody): Promise; AddGame(request: AddGameReq): Promise; GetGames(request: GetGamesReq): Promise; GetGame(request: GetGameReq): Promise; + GetGameAnswers(request: GetGameAnswersReq): Promise; UpdateGame(request: UpdateGameReq): Promise; StartGame(request: StartGameReq): Promise; PauseGame(request: PauseGameReq): Promise; @@ -570,6 +678,9 @@ export interface EveningDetectiveServer { GetTeamStory(request: GetTeamStoryReq): Promise; AddTeamAction(request: AddTeamActionReq): Promise; DeleteLastTeamAction(request: DeleteLastTeamActionReq): Promise; + GetTeamAnswers(request: GetTeamAnswersReq): Promise; + SubmitTeamAnswers(request: SubmitTeamAnswersReq): Promise; + SetTeamAnswerScore(request: SetTeamAnswerScoreReq): Promise; } type RequestType = { @@ -1142,6 +1253,72 @@ export function createEveningDetectiveServerClient( method: "DeleteScenarioPlace", }) as Promise; }, + AddScenarioQuestion(request) { // eslint-disable-line @typescript-eslint/no-unused-vars + if (!request.id) { + throw new Error("missing required field request.id"); + } + const path = `api/scenarios/${request.id}/questions`; // eslint-disable-line quotes + const body = JSON.stringify(request); + const queryParams: string[] = []; + let uri = path; + if (queryParams.length > 0) { + uri += `?${queryParams.join("&")}` + } + return handler({ + path: uri, + method: "POST", + body, + }, { + service: "EveningDetectiveServer", + method: "AddScenarioQuestion", + }) as Promise; + }, + UpdateScenarioQuestion(request) { // eslint-disable-line @typescript-eslint/no-unused-vars + if (!request.id) { + throw new Error("missing required field request.id"); + } + if (!request.code) { + throw new Error("missing required field request.code"); + } + const path = `api/scenarios/${request.id}/questions/${request.code}`; // eslint-disable-line quotes + const body = JSON.stringify(request); + const queryParams: string[] = []; + let uri = path; + if (queryParams.length > 0) { + uri += `?${queryParams.join("&")}` + } + return handler({ + path: uri, + method: "PUT", + body, + }, { + service: "EveningDetectiveServer", + method: "UpdateScenarioQuestion", + }) as Promise; + }, + DeleteScenarioQuestion(request) { // eslint-disable-line @typescript-eslint/no-unused-vars + if (!request.id) { + throw new Error("missing required field request.id"); + } + if (!request.code) { + throw new Error("missing required field request.code"); + } + const path = `api/scenarios/${request.id}/questions/${request.code}`; // eslint-disable-line quotes + const body = null; + const queryParams: string[] = []; + let uri = path; + if (queryParams.length > 0) { + uri += `?${queryParams.join("&")}` + } + return handler({ + path: uri, + method: "DELETE", + body, + }, { + service: "EveningDetectiveServer", + method: "DeleteScenarioQuestion", + }) as Promise; + }, UpdateScenarioIntro(request) { // eslint-disable-line @typescript-eslint/no-unused-vars if (!request.id) { throw new Error("missing required field request.id"); @@ -1253,6 +1430,26 @@ export function createEveningDetectiveServerClient( method: "GetGame", }) as Promise; }, + GetGameAnswers(request) { // eslint-disable-line @typescript-eslint/no-unused-vars + if (!request.gameId) { + throw new Error("missing required field request.gameId"); + } + const path = `api/games/${request.gameId}/answers`; // eslint-disable-line quotes + const body = null; + const queryParams: string[] = []; + let uri = path; + if (queryParams.length > 0) { + uri += `?${queryParams.join("&")}` + } + return handler({ + path: uri, + method: "GET", + body, + }, { + service: "EveningDetectiveServer", + method: "GetGameAnswers", + }) as Promise; + }, UpdateGame(request) { // eslint-disable-line @typescript-eslint/no-unused-vars if (!request.id) { throw new Error("missing required field request.id"); @@ -1533,6 +1730,72 @@ export function createEveningDetectiveServerClient( method: "DeleteLastTeamAction", }) as Promise; }, + GetTeamAnswers(request) { // eslint-disable-line @typescript-eslint/no-unused-vars + if (!request.id) { + throw new Error("missing required field request.id"); + } + const path = `api/teams/${request.id}/answers`; // eslint-disable-line quotes + const body = null; + const queryParams: string[] = []; + if (request.password) { + queryParams.push(`password=${encodeURIComponent(request.password.toString())}`) + } + let uri = path; + if (queryParams.length > 0) { + uri += `?${queryParams.join("&")}` + } + return handler({ + path: uri, + method: "GET", + body, + }, { + service: "EveningDetectiveServer", + method: "GetTeamAnswers", + }) as Promise; + }, + SubmitTeamAnswers(request) { // eslint-disable-line @typescript-eslint/no-unused-vars + if (!request.id) { + throw new Error("missing required field request.id"); + } + const path = `api/teams/${request.id}/answers`; // eslint-disable-line quotes + const body = JSON.stringify(request); + const queryParams: string[] = []; + let uri = path; + if (queryParams.length > 0) { + uri += `?${queryParams.join("&")}` + } + return handler({ + path: uri, + method: "POST", + body, + }, { + service: "EveningDetectiveServer", + method: "SubmitTeamAnswers", + }) as Promise; + }, + SetTeamAnswerScore(request) { // eslint-disable-line @typescript-eslint/no-unused-vars + if (!request.id) { + throw new Error("missing required field request.id"); + } + if (!request.questionCode) { + throw new Error("missing required field request.questionCode"); + } + const path = `api/teams/${request.id}/answers/${request.questionCode}/score`; // eslint-disable-line quotes + const body = JSON.stringify(request); + const queryParams: string[] = []; + let uri = path; + if (queryParams.length > 0) { + uri += `?${queryParams.join("&")}` + } + return handler({ + path: uri, + method: "PUT", + body, + }, { + service: "EveningDetectiveServer", + method: "SetTeamAnswerScore", + }) as Promise; + }, }; } // Message that represents an arbitrary HTTP body. It should only be used for