generated from VLADIMIR/template
add intro
This commit is contained in:
+27
-1
@@ -365,6 +365,17 @@ service EveningDetectiveServer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc UpdateScenarioIntro(UpdateScenarioIntroReq) returns (UpdateScenarioIntroRsp) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
put : "/api/scenarios/{id}/introduction"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
tags : "Сценарии";
|
||||||
|
summary: "Обновить введение сценария";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
rpc DownloadScenarioArchive(DownloadScenarioArchiveReq) returns (google.api.HttpBody) {
|
rpc DownloadScenarioArchive(DownloadScenarioArchiveReq) returns (google.api.HttpBody) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/api/scenarios/{id}/archive"
|
get: "/api/scenarios/{id}/archive"
|
||||||
@@ -776,7 +787,13 @@ message Scenario {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message Story {
|
message Story {
|
||||||
repeated Place places = 1;
|
Introduction introduction = 2;
|
||||||
|
repeated Place places = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Introduction {
|
||||||
|
string text = 1;
|
||||||
|
string audio = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Place {
|
message Place {
|
||||||
@@ -868,6 +885,15 @@ message DeleteScenarioPlaceRsp {
|
|||||||
string error = 1;
|
string error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message UpdateScenarioIntroReq {
|
||||||
|
int32 id = 1;
|
||||||
|
Introduction introduction = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateScenarioIntroRsp {
|
||||||
|
string error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message DownloadScenarioArchiveReq {
|
message DownloadScenarioArchiveReq {
|
||||||
int32 id = 1;
|
int32 id = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -973,6 +973,46 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/scenarios/{id}/introduction": {
|
||||||
|
"put": {
|
||||||
|
"summary": "Обновить введение сценария",
|
||||||
|
"operationId": "EveningDetectiveServer_UpdateScenarioIntro",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/evening_detective_serverUpdateScenarioIntroRsp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/EveningDetectiveServerUpdateScenarioIntroBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Сценарии"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/scenarios/{id}/places": {
|
"/api/scenarios/{id}/places": {
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "Создать точку сценария",
|
"summary": "Создать точку сценария",
|
||||||
@@ -1765,6 +1805,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"EveningDetectiveServerUpdateScenarioIntroBody": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"introduction": {
|
||||||
|
"$ref": "#/definitions/evening_detective_serverIntroduction"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"EveningDetectiveServerUpdateScenarioPlaceBody": {
|
"EveningDetectiveServerUpdateScenarioPlaceBody": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -2228,6 +2276,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"evening_detective_serverIntroduction": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"text": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"audio": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"evening_detective_serverKey": {
|
"evening_detective_serverKey": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -2450,6 +2509,9 @@
|
|||||||
"evening_detective_serverStory": {
|
"evening_detective_serverStory": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"introduction": {
|
||||||
|
"$ref": "#/definitions/evening_detective_serverIntroduction"
|
||||||
|
},
|
||||||
"places": {
|
"places": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -2496,6 +2558,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"evening_detective_serverUpdateScenarioIntroRsp": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"error": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"evening_detective_serverUpdateScenarioPlaceRsp": {
|
"evening_detective_serverUpdateScenarioPlaceRsp": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -580,6 +580,28 @@ func (s *server) DeleteScenarioPlace(ctx context.Context, req *proto.DeleteScena
|
|||||||
return &proto.DeleteScenarioPlaceRsp{}, nil
|
return &proto.DeleteScenarioPlaceRsp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *server) UpdateScenarioIntro(ctx context.Context, req *proto.UpdateScenarioIntroReq) (*proto.UpdateScenarioIntroRsp, 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.UpdateScenarioIntro(
|
||||||
|
ctx,
|
||||||
|
int(req.Id),
|
||||||
|
convertIntroduction(req.Introduction),
|
||||||
|
claims.UserID,
|
||||||
|
roles.HasRole(claims, roles.Admin),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return &proto.UpdateScenarioIntroRsp{
|
||||||
|
Error: err.Error(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &proto.UpdateScenarioIntroRsp{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DownloadScenarioArchive отдаёт ZIP-архив сценария; ошибки — gRPC-статусами.
|
// DownloadScenarioArchive отдаёт ZIP-архив сценария; ошибки — gRPC-статусами.
|
||||||
func (s *server) DownloadScenarioArchive(ctx context.Context, req *proto.DownloadScenarioArchiveReq) (*httpbody.HttpBody, error) {
|
func (s *server) DownloadScenarioArchive(ctx context.Context, req *proto.DownloadScenarioArchiveReq) (*httpbody.HttpBody, error) {
|
||||||
claims := ctx.Value("claims").(*processor_jwt.JWTClaims)
|
claims := ctx.Value("claims").(*processor_jwt.JWTClaims)
|
||||||
|
|||||||
@@ -47,7 +47,18 @@ func mapStory(o *storytelling.Story) *proto.Story {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &proto.Story{
|
return &proto.Story{
|
||||||
Places: mapPlaces(o.Places),
|
Introduction: mapIntroduction(o.Introduction),
|
||||||
|
Places: mapPlaces(o.Places),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapIntroduction(o *storytelling.Introduction) *proto.Introduction {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &proto.Introduction{
|
||||||
|
Text: o.Text,
|
||||||
|
Audio: o.Audio,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,3 +185,13 @@ func convertKey(o *proto.Key) *storytelling.Key {
|
|||||||
Name: textFormatter.FormatString(o.Name),
|
Name: textFormatter.FormatString(o.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertIntroduction(o *proto.Introduction) *storytelling.Introduction {
|
||||||
|
if o == nil || (o.Text == "" && o.Audio == "") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &storytelling.Introduction{
|
||||||
|
Text: textFormatter.FormatText(o.Text),
|
||||||
|
Audio: o.Audio,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ func (a *scenarioArchive) Pack(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if story.Introduction != nil {
|
||||||
|
if err := addRef(story.Introduction.Audio); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, place := range story.Places {
|
for _, place := range story.Places {
|
||||||
if err := addRef(place.Image); err != nil {
|
if err := addRef(place.Image); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -137,6 +142,9 @@ func (a *scenarioArchive) Pack(
|
|||||||
application.Image = rewriteRef(application.Image, archivePathOf)
|
application.Image = rewriteRef(application.Image, archivePathOf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if story.Introduction != nil {
|
||||||
|
story.Introduction.Audio = rewriteRef(story.Introduction.Audio, archivePathOf)
|
||||||
|
}
|
||||||
|
|
||||||
doc := ScenarioJSON{
|
doc := ScenarioJSON{
|
||||||
Version: Version,
|
Version: Version,
|
||||||
|
|||||||
@@ -101,6 +101,48 @@ func TestPackUnpackRoundTrip(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPackUnpackIntroAudioRoundTrip(t *testing.T) {
|
||||||
|
description := "desc"
|
||||||
|
image := "cover.png"
|
||||||
|
scenario := &repos.Scenario{
|
||||||
|
ID: 1,
|
||||||
|
Name: "С введением",
|
||||||
|
Description: &description,
|
||||||
|
Image: &image,
|
||||||
|
Scenario: `{"introduction":{"text":"Введение","audio":"intro.mp3"},"places":[
|
||||||
|
{"code":"club","name":"Клуб","text":"Тёмный зал","image":"club.png"}
|
||||||
|
]}`,
|
||||||
|
}
|
||||||
|
files := memoryFiles{
|
||||||
|
"cover.png": []byte("cover-bytes"),
|
||||||
|
"club.png": []byte("club-bytes"),
|
||||||
|
"intro.mp3": []byte("intro-audio-bytes"),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := testArchive.Pack(context.Background(), scenario, testDomain, files.get)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Pack: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle, err := testArchive.Unpack(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unpack: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Scenario.Story.Introduction == nil {
|
||||||
|
t.Fatal("Story.Introduction = nil, want введение")
|
||||||
|
}
|
||||||
|
if bundle.Scenario.Story.Introduction.Text != "Введение" {
|
||||||
|
t.Errorf("Introduction.Text = %q, want %q", bundle.Scenario.Story.Introduction.Text, "Введение")
|
||||||
|
}
|
||||||
|
if bundle.Scenario.Story.Introduction.Audio != "images/intro.mp3" {
|
||||||
|
t.Errorf("Introduction.Audio = %q, want %q", bundle.Scenario.Story.Introduction.Audio, "images/intro.mp3")
|
||||||
|
}
|
||||||
|
if _, ok := bundle.Files["images/intro.mp3"]; !ok {
|
||||||
|
t.Errorf("в архиве нет аудиофайла %q", "images/intro.mp3")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPackExternalURLsKeptAndNotFetched(t *testing.T) {
|
func TestPackExternalURLsKeptAndNotFetched(t *testing.T) {
|
||||||
description := "desc"
|
description := "desc"
|
||||||
scenario := &repos.Scenario{
|
scenario := &repos.Scenario{
|
||||||
|
|||||||
@@ -4,13 +4,26 @@ type IStory interface {
|
|||||||
GetStory(scenario *Story, codes []string) *Story
|
GetStory(scenario *Story, codes []string) *Story
|
||||||
}
|
}
|
||||||
|
|
||||||
// История - это набор точек
|
// История - это введение и набор точек
|
||||||
type Story struct {
|
type Story struct {
|
||||||
|
|
||||||
|
// Введение - то, что игрок получает в начале игры
|
||||||
|
Introduction *Introduction `json:"introduction,omitempty"`
|
||||||
|
|
||||||
// Список точек
|
// Список точек
|
||||||
Places []*Place `json:"places"`
|
Places []*Place `json:"places"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Введение - текст и аудио, которые игрок получает в начале игры
|
||||||
|
type Introduction struct {
|
||||||
|
|
||||||
|
// Текст введения
|
||||||
|
Text string `json:"text"`
|
||||||
|
|
||||||
|
// Аудио введения
|
||||||
|
Audio string `json:"audio,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Точка - что-то куда можно сходить
|
// Точка - что-то куда можно сходить
|
||||||
// Это может быть место - аптека, остановка, площадь...
|
// Это может быть место - аптека, остановка, площадь...
|
||||||
// Это может быть персонаж - пострадавший, продавец, полицейский...
|
// Это может быть персонаж - пострадавший, продавец, полицейский...
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ func (s *story) GetStory(
|
|||||||
codesWithUseActions := map[string]struct{}{}
|
codesWithUseActions := map[string]struct{}{}
|
||||||
codesHidden := map[string]struct{}{}
|
codesHidden := map[string]struct{}{}
|
||||||
givenApplications := map[string]struct{}{}
|
givenApplications := map[string]struct{}{}
|
||||||
|
// Введение передаётся игроку всегда — и до первого хода (начало игры),
|
||||||
|
// и в дальнейшем (как заголовок истории).
|
||||||
|
if scenario.Introduction != nil {
|
||||||
|
story.Introduction = &Introduction{
|
||||||
|
Text: s.cleaner.ClearText(scenario.Introduction.Text),
|
||||||
|
Audio: scenario.Introduction.Audio,
|
||||||
|
}
|
||||||
|
}
|
||||||
for i, code := range codes {
|
for i, code := range codes {
|
||||||
var prevPlace *Place
|
var prevPlace *Place
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
|||||||
@@ -28,6 +28,52 @@ func Test_story_GetStory(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Введение передаётся в начале игры (без действий)",
|
||||||
|
scenario: &Story{
|
||||||
|
Introduction: &Introduction{
|
||||||
|
Text: "Текст введения.([Ы])",
|
||||||
|
Audio: "intro.mp3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
codes: []string{},
|
||||||
|
want: &Story{
|
||||||
|
Introduction: &Introduction{
|
||||||
|
Text: "Текст введения.",
|
||||||
|
Audio: "intro.mp3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Введение передаётся вместе с точками",
|
||||||
|
scenario: &Story{
|
||||||
|
Introduction: &Introduction{
|
||||||
|
Text: "Текст введения.",
|
||||||
|
Audio: "intro.mp3",
|
||||||
|
},
|
||||||
|
Places: []*Place{
|
||||||
|
{
|
||||||
|
Code: "Ы",
|
||||||
|
Name: "Название точки",
|
||||||
|
Text: "Текст точки.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
codes: []string{"Ы"},
|
||||||
|
want: &Story{
|
||||||
|
Introduction: &Introduction{
|
||||||
|
Text: "Текст введения.",
|
||||||
|
Audio: "intro.mp3",
|
||||||
|
},
|
||||||
|
Places: []*Place{
|
||||||
|
{
|
||||||
|
Code: "Ы",
|
||||||
|
Name: "Название точки",
|
||||||
|
Text: "Текст точки.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Получение точки",
|
name: "Получение точки",
|
||||||
scenario: &Story{
|
scenario: &Story{
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func (s *MCPService) Server() *server.MCPServer {
|
|||||||
srv.AddTool(
|
srv.AddTool(
|
||||||
mcp.NewTool(
|
mcp.NewTool(
|
||||||
"get_team_story",
|
"get_team_story",
|
||||||
mcp.WithDescription("Получить текущую историю команды: видимые точки сценария (текст, двери, улики) и информацию об игре. Команда идентифицируется паролем."),
|
mcp.WithDescription("Получить текущую историю команды: введение сценария (текст и аудио), видимые точки сценария (текст, двери, улики) и информацию об игре. Команда идентифицируется паролем."),
|
||||||
mcp.WithNumber("team_id", mcp.Required(), mcp.Description("ID команды")),
|
mcp.WithNumber("team_id", mcp.Required(), mcp.Description("ID команды")),
|
||||||
mcp.WithString("password", mcp.Required(), mcp.Description("Пароль команды")),
|
mcp.WithString("password", mcp.Required(), mcp.Description("Пароль команды")),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ func (f *fakeGamePlayer) AddTeamAction(_ context.Context, teamID int, password,
|
|||||||
|
|
||||||
func defaultStory() *storytelling.Story {
|
func defaultStory() *storytelling.Story {
|
||||||
return &storytelling.Story{
|
return &storytelling.Story{
|
||||||
|
Introduction: &storytelling.Introduction{
|
||||||
|
Text: "Добро пожаловать в особняк.",
|
||||||
|
Audio: "http://storage.test/api/files/intro.mp3",
|
||||||
|
},
|
||||||
Places: []*storytelling.Place{
|
Places: []*storytelling.Place{
|
||||||
{
|
{
|
||||||
Code: "entrance",
|
Code: "entrance",
|
||||||
@@ -254,6 +258,9 @@ func TestGetTeamStory(t *testing.T) {
|
|||||||
if !strings.Contains(got, "entrance") {
|
if !strings.Contains(got, "entrance") {
|
||||||
t.Fatalf("get_team_story: %q; want story JSON", got)
|
t.Fatalf("get_team_story: %q; want story JSON", got)
|
||||||
}
|
}
|
||||||
|
if !strings.Contains(got, `"introduction"`) || !strings.Contains(got, "Добро пожаловать в особняк.") {
|
||||||
|
t.Fatalf("get_team_story: %q; want introduction in story JSON", got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTeamStoryBusinessError(t *testing.T) {
|
func TestGetTeamStoryBusinessError(t *testing.T) {
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ func mapStory(o string, domain string) (*storytelling.Story, error) {
|
|||||||
place.Image = domain + place.Image
|
place.Image = domain + place.Image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if res.Introduction != nil && res.Introduction.Audio != "" {
|
||||||
|
res.Introduction.Audio = domain + res.Introduction.Audio
|
||||||
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -278,6 +278,25 @@ func (s *ScenarioService) DeleteScenarioPlace(
|
|||||||
return s.updateStory(ctx, id, story)
|
return s.updateStory(ctx, id, story)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateScenarioIntro сохраняет введение сценария (текст и аудио).
|
||||||
|
func (s *ScenarioService) UpdateScenarioIntro(
|
||||||
|
ctx context.Context,
|
||||||
|
id int,
|
||||||
|
introduction *storytelling.Introduction,
|
||||||
|
actorId int,
|
||||||
|
isAdmin bool,
|
||||||
|
) error {
|
||||||
|
if _, err := s.getScenarioForChange(ctx, id, actorId, isAdmin); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
story, err := s.getStory(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
story.Introduction = introduction
|
||||||
|
return s.updateStory(ctx, id, story)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ScenarioService) getStory(ctx context.Context, id int) (*storytelling.Story, error) {
|
func (s *ScenarioService) getStory(ctx context.Context, id int) (*storytelling.Story, error) {
|
||||||
storyString, err := s.scenariosRepo.GetStoryByScenarioID(ctx, id)
|
storyString, err := s.scenariosRepo.GetStoryByScenarioID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -385,6 +404,12 @@ func (s *ScenarioService) UploadArchive(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if scenario.Story.Introduction != nil {
|
||||||
|
scenario.Story.Introduction.Audio, err = rewrite(scenario.Story.Introduction.Audio)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
storyJSON, err := normalizeStory(scenario.Story)
|
storyJSON, err := normalizeStory(scenario.Story)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -423,6 +448,9 @@ func (s *ScenarioService) updateStory(ctx context.Context, id int, story *storyt
|
|||||||
for _, place := range story.Places {
|
for _, place := range story.Places {
|
||||||
place.Image = strings.TrimPrefix(place.Image, s.domain)
|
place.Image = strings.TrimPrefix(place.Image, s.domain)
|
||||||
}
|
}
|
||||||
|
if story.Introduction != nil {
|
||||||
|
story.Introduction.Audio = strings.TrimPrefix(story.Introduction.Audio, s.domain)
|
||||||
|
}
|
||||||
storyString, err := normalizeStory(story)
|
storyString, err := normalizeStory(story)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -338,6 +338,76 @@ func TestUploadArchive(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUploadArchiveWithIntro(t *testing.T) {
|
||||||
|
repo := newFakeScenariosRepo()
|
||||||
|
srcStorage := newFakeStorage()
|
||||||
|
description := "Детективная история"
|
||||||
|
image := "cover.png"
|
||||||
|
scenario := &repos.Scenario{
|
||||||
|
ID: 1,
|
||||||
|
Name: "Ночной клуб",
|
||||||
|
Description: &description,
|
||||||
|
Image: &image,
|
||||||
|
Author: &repos.User{ID: 7},
|
||||||
|
Status: "draft",
|
||||||
|
Scenario: `{"introduction":{"text":"Введение","audio":"intro.mp3"},"places":[
|
||||||
|
{"code":"club","name":"Клуб","text":"Тёмный зал","image":"club.png"}
|
||||||
|
]}`,
|
||||||
|
}
|
||||||
|
repo.byID[scenario.ID] = scenario
|
||||||
|
_ = srcStorage.Put(context.Background(), &file_storage.File{Name: "cover.png", Data: []byte("cover-bytes")})
|
||||||
|
_ = srcStorage.Put(context.Background(), &file_storage.File{Name: "club.png", Data: []byte("club-bytes")})
|
||||||
|
_ = srcStorage.Put(context.Background(), &file_storage.File{Name: "intro.mp3", Data: []byte("intro-audio-bytes")})
|
||||||
|
|
||||||
|
// Экспорт (Pack кладёт аудио введения в архив), затем импорт в «чистые»
|
||||||
|
// repo и storage: ссылки должны быть переписаны на новые имена.
|
||||||
|
svc := newTestService(repo, srcStorage)
|
||||||
|
archive, _, err := svc.DownloadArchive(context.Background(), 1, 7, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DownloadArchive: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
importRepo := newFakeScenariosRepo()
|
||||||
|
importStorage := newFakeStorage()
|
||||||
|
importSvc := newTestService(importRepo, importStorage)
|
||||||
|
|
||||||
|
id, err := importSvc.UploadArchive(context.Background(), archive, 42)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UploadArchive: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
saved := importRepo.get(id)
|
||||||
|
story := &storytelling.Story{}
|
||||||
|
if err := json.Unmarshal([]byte(saved.Scenario), story); err != nil {
|
||||||
|
t.Fatalf("story не разобрался: %v", err)
|
||||||
|
}
|
||||||
|
if story.Introduction == nil {
|
||||||
|
t.Fatal("Introduction = nil, want введение после импорта")
|
||||||
|
}
|
||||||
|
if story.Introduction.Text != "Введение" {
|
||||||
|
t.Errorf("Introduction.Text = %q, want %q", story.Introduction.Text, "Введение")
|
||||||
|
}
|
||||||
|
if story.Introduction.Audio == "" || strings.HasPrefix(story.Introduction.Audio, "images/") || story.Introduction.Audio == "intro.mp3" {
|
||||||
|
t.Errorf("Introduction.Audio = %q, want новое случайное имя без images/", story.Introduction.Audio)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Аудио введения загружено в storage под новым именем.
|
||||||
|
files := importStorage.names()
|
||||||
|
found := false
|
||||||
|
for _, name := range files {
|
||||||
|
file, err := importStorage.Get(context.Background(), name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Get(%q): %v", name, err)
|
||||||
|
}
|
||||||
|
if string(file.Data) == "intro-audio-bytes" {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("аудио введения не загружено в storage; файлы: %v", files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUploadArchiveMissingImage(t *testing.T) {
|
func TestUploadArchiveMissingImage(t *testing.T) {
|
||||||
repo := newFakeScenariosRepo()
|
repo := newFakeScenariosRepo()
|
||||||
storage := newFakeStorage()
|
storage := newFakeStorage()
|
||||||
@@ -509,6 +579,85 @@ func TestDownloadArchiveMissingImage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateScenarioIntro(t *testing.T) {
|
||||||
|
repo := newFakeScenariosRepo()
|
||||||
|
storage := newFakeStorage()
|
||||||
|
seedScenario(t, repo, storage)
|
||||||
|
svc := newTestService(repo, storage)
|
||||||
|
|
||||||
|
// Установка введения автором.
|
||||||
|
err := svc.UpdateScenarioIntro(context.Background(), 1, &storytelling.Introduction{
|
||||||
|
Text: "Введение",
|
||||||
|
Audio: "intro.mp3",
|
||||||
|
}, 7, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UpdateScenarioIntro: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// В хранилище — голое имя аудио, без домена.
|
||||||
|
parsed := &storytelling.Story{}
|
||||||
|
if err := json.Unmarshal([]byte(repo.get(1).Scenario), parsed); err != nil {
|
||||||
|
t.Fatalf("json.Unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if parsed.Introduction == nil {
|
||||||
|
t.Fatal("Introduction = nil, want введение в сохранённой истории")
|
||||||
|
}
|
||||||
|
if parsed.Introduction.Text != "Введение" {
|
||||||
|
t.Errorf("Introduction.Text = %q, want %q", parsed.Introduction.Text, "Введение")
|
||||||
|
}
|
||||||
|
if parsed.Introduction.Audio != "intro.mp3" {
|
||||||
|
t.Errorf("Introduction.Audio = %q, want %q (без домена)", parsed.Introduction.Audio, "intro.mp3")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Наружу — аудио с доменом.
|
||||||
|
full, err := svc.GetFullScenarioByID(context.Background(), 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetFullScenarioByID: %v", err)
|
||||||
|
}
|
||||||
|
if full.Story.Introduction == nil {
|
||||||
|
t.Fatal("Story.Introduction = nil, want введение в полном сценарии")
|
||||||
|
}
|
||||||
|
if full.Story.Introduction.Audio != testDomain+"intro.mp3" {
|
||||||
|
t.Errorf("Introduction.Audio = %q, want %q", full.Story.Introduction.Audio, testDomain+"intro.mp3")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Редактирование точки не должно затрагивать введение и голое имя аудио.
|
||||||
|
err = svc.UpdateScenarioPlace(context.Background(), 1, "club", &storytelling.Place{
|
||||||
|
Code: "club",
|
||||||
|
Name: "Клуб",
|
||||||
|
Text: "Обновлённый текст.",
|
||||||
|
}, 7, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UpdateScenarioPlace: %v", err)
|
||||||
|
}
|
||||||
|
parsed = &storytelling.Story{}
|
||||||
|
if err := json.Unmarshal([]byte(repo.get(1).Scenario), parsed); err != nil {
|
||||||
|
t.Fatalf("json.Unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if parsed.Introduction == nil || parsed.Introduction.Text != "Введение" || parsed.Introduction.Audio != "intro.mp3" {
|
||||||
|
t.Errorf("введение повреждено после UpdateScenarioPlace: %+v", parsed.Introduction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очистка введения (nil) — поле исчезает из истории.
|
||||||
|
err = svc.UpdateScenarioIntro(context.Background(), 1, nil, 7, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UpdateScenarioIntro(nil): %v", err)
|
||||||
|
}
|
||||||
|
parsed = &storytelling.Story{}
|
||||||
|
if err := json.Unmarshal([]byte(repo.get(1).Scenario), parsed); err != nil {
|
||||||
|
t.Fatalf("json.Unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if parsed.Introduction != nil {
|
||||||
|
t.Errorf("Introduction = %+v, want nil после очистки", parsed.Introduction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Чужой автор не может менять введение.
|
||||||
|
err = svc.UpdateScenarioIntro(context.Background(), 1, &storytelling.Introduction{Text: "x"}, 99, false)
|
||||||
|
if !errors.Is(err, ErrScenarioNotOwner) {
|
||||||
|
t.Errorf("err = %v, want ErrScenarioNotOwner", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// buildRawArchive собирает zip из произвольных записей (для тестов импорта).
|
// buildRawArchive собирает zip из произвольных записей (для тестов импорта).
|
||||||
func buildRawArchive(t *testing.T, entries map[string][]byte) []byte {
|
func buildRawArchive(t *testing.T, entries map[string][]byte) []byte {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|||||||
+534
-360
File diff suppressed because it is too large
Load Diff
@@ -1024,6 +1024,51 @@ func local_request_EveningDetectiveServer_DeleteScenarioPlace_0(ctx context.Cont
|
|||||||
return msg, metadata, err
|
return msg, metadata, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func request_EveningDetectiveServer_UpdateScenarioIntro_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var (
|
||||||
|
protoReq UpdateScenarioIntroReq
|
||||||
|
metadata runtime.ServerMetadata
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
if req.Body != nil {
|
||||||
|
_, _ = io.Copy(io.Discard, req.Body)
|
||||||
|
}
|
||||||
|
val, ok := pathParams["id"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||||
|
}
|
||||||
|
protoReq.Id, err = runtime.Int32(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||||
|
}
|
||||||
|
msg, err := client.UpdateScenarioIntro(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_EveningDetectiveServer_UpdateScenarioIntro_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var (
|
||||||
|
protoReq UpdateScenarioIntroReq
|
||||||
|
metadata runtime.ServerMetadata
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
val, ok := pathParams["id"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||||
|
}
|
||||||
|
protoReq.Id, err = runtime.Int32(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||||
|
}
|
||||||
|
msg, err := server.UpdateScenarioIntro(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
}
|
||||||
|
|
||||||
func request_EveningDetectiveServer_DownloadScenarioArchive_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_EveningDetectiveServer_DownloadScenarioArchive_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var (
|
var (
|
||||||
protoReq DownloadScenarioArchiveReq
|
protoReq DownloadScenarioArchiveReq
|
||||||
@@ -2385,6 +2430,26 @@ func RegisterEveningDetectiveServerHandlerServer(ctx context.Context, mux *runti
|
|||||||
}
|
}
|
||||||
forward_EveningDetectiveServer_DeleteScenarioPlace_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
forward_EveningDetectiveServer_DeleteScenarioPlace_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
})
|
})
|
||||||
|
mux.Handle(http.MethodPut, pattern_EveningDetectiveServer_UpdateScenarioIntro_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
var stream runtime.ServerTransportStream
|
||||||
|
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/UpdateScenarioIntro", runtime.WithHTTPPathPattern("/api/scenarios/{id}/introduction"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_EveningDetectiveServer_UpdateScenarioIntro_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
forward_EveningDetectiveServer_UpdateScenarioIntro_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
})
|
||||||
mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadScenarioArchive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadScenarioArchive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -3315,6 +3380,23 @@ func RegisterEveningDetectiveServerHandlerClient(ctx context.Context, mux *runti
|
|||||||
}
|
}
|
||||||
forward_EveningDetectiveServer_DeleteScenarioPlace_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
forward_EveningDetectiveServer_DeleteScenarioPlace_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
})
|
})
|
||||||
|
mux.Handle(http.MethodPut, pattern_EveningDetectiveServer_UpdateScenarioIntro_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/UpdateScenarioIntro", runtime.WithHTTPPathPattern("/api/scenarios/{id}/introduction"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_EveningDetectiveServer_UpdateScenarioIntro_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
forward_EveningDetectiveServer_UpdateScenarioIntro_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
})
|
||||||
mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadScenarioArchive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadScenarioArchive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -3672,6 +3754,7 @@ var (
|
|||||||
pattern_EveningDetectiveServer_AddScenarioPlace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "scenarios", "id", "places"}, ""))
|
pattern_EveningDetectiveServer_AddScenarioPlace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "scenarios", "id", "places"}, ""))
|
||||||
pattern_EveningDetectiveServer_UpdateScenarioPlace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "scenarios", "id", "places", "code"}, ""))
|
pattern_EveningDetectiveServer_UpdateScenarioPlace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "scenarios", "id", "places", "code"}, ""))
|
||||||
pattern_EveningDetectiveServer_DeleteScenarioPlace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "scenarios", "id", "places", "code"}, ""))
|
pattern_EveningDetectiveServer_DeleteScenarioPlace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "scenarios", "id", "places", "code"}, ""))
|
||||||
|
pattern_EveningDetectiveServer_UpdateScenarioIntro_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "scenarios", "id", "introduction"}, ""))
|
||||||
pattern_EveningDetectiveServer_DownloadScenarioArchive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "scenarios", "id", "archive"}, ""))
|
pattern_EveningDetectiveServer_DownloadScenarioArchive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "scenarios", "id", "archive"}, ""))
|
||||||
pattern_EveningDetectiveServer_UploadScenarioArchive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "scenarios", "archive"}, ""))
|
pattern_EveningDetectiveServer_UploadScenarioArchive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "scenarios", "archive"}, ""))
|
||||||
pattern_EveningDetectiveServer_AddGame_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"api", "games"}, ""))
|
pattern_EveningDetectiveServer_AddGame_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"api", "games"}, ""))
|
||||||
@@ -3724,6 +3807,7 @@ var (
|
|||||||
forward_EveningDetectiveServer_AddScenarioPlace_0 = runtime.ForwardResponseMessage
|
forward_EveningDetectiveServer_AddScenarioPlace_0 = runtime.ForwardResponseMessage
|
||||||
forward_EveningDetectiveServer_UpdateScenarioPlace_0 = runtime.ForwardResponseMessage
|
forward_EveningDetectiveServer_UpdateScenarioPlace_0 = runtime.ForwardResponseMessage
|
||||||
forward_EveningDetectiveServer_DeleteScenarioPlace_0 = runtime.ForwardResponseMessage
|
forward_EveningDetectiveServer_DeleteScenarioPlace_0 = runtime.ForwardResponseMessage
|
||||||
|
forward_EveningDetectiveServer_UpdateScenarioIntro_0 = runtime.ForwardResponseMessage
|
||||||
forward_EveningDetectiveServer_DownloadScenarioArchive_0 = runtime.ForwardResponseMessage
|
forward_EveningDetectiveServer_DownloadScenarioArchive_0 = runtime.ForwardResponseMessage
|
||||||
forward_EveningDetectiveServer_UploadScenarioArchive_0 = runtime.ForwardResponseMessage
|
forward_EveningDetectiveServer_UploadScenarioArchive_0 = runtime.ForwardResponseMessage
|
||||||
forward_EveningDetectiveServer_AddGame_0 = runtime.ForwardResponseMessage
|
forward_EveningDetectiveServer_AddGame_0 = runtime.ForwardResponseMessage
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ const (
|
|||||||
EveningDetectiveServer_AddScenarioPlace_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/AddScenarioPlace"
|
EveningDetectiveServer_AddScenarioPlace_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/AddScenarioPlace"
|
||||||
EveningDetectiveServer_UpdateScenarioPlace_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/UpdateScenarioPlace"
|
EveningDetectiveServer_UpdateScenarioPlace_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/UpdateScenarioPlace"
|
||||||
EveningDetectiveServer_DeleteScenarioPlace_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/DeleteScenarioPlace"
|
EveningDetectiveServer_DeleteScenarioPlace_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/DeleteScenarioPlace"
|
||||||
|
EveningDetectiveServer_UpdateScenarioIntro_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/UpdateScenarioIntro"
|
||||||
EveningDetectiveServer_DownloadScenarioArchive_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/DownloadScenarioArchive"
|
EveningDetectiveServer_DownloadScenarioArchive_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/DownloadScenarioArchive"
|
||||||
EveningDetectiveServer_UploadScenarioArchive_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/UploadScenarioArchive"
|
EveningDetectiveServer_UploadScenarioArchive_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/UploadScenarioArchive"
|
||||||
EveningDetectiveServer_AddGame_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/AddGame"
|
EveningDetectiveServer_AddGame_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/AddGame"
|
||||||
@@ -105,6 +106,7 @@ type EveningDetectiveServerClient interface {
|
|||||||
AddScenarioPlace(ctx context.Context, in *AddScenarioPlaceReq, opts ...grpc.CallOption) (*AddScenarioPlaceRsp, error)
|
AddScenarioPlace(ctx context.Context, in *AddScenarioPlaceReq, opts ...grpc.CallOption) (*AddScenarioPlaceRsp, error)
|
||||||
UpdateScenarioPlace(ctx context.Context, in *UpdateScenarioPlaceReq, opts ...grpc.CallOption) (*UpdateScenarioPlaceRsp, error)
|
UpdateScenarioPlace(ctx context.Context, in *UpdateScenarioPlaceReq, opts ...grpc.CallOption) (*UpdateScenarioPlaceRsp, error)
|
||||||
DeleteScenarioPlace(ctx context.Context, in *DeleteScenarioPlaceReq, opts ...grpc.CallOption) (*DeleteScenarioPlaceRsp, error)
|
DeleteScenarioPlace(ctx context.Context, in *DeleteScenarioPlaceReq, opts ...grpc.CallOption) (*DeleteScenarioPlaceRsp, error)
|
||||||
|
UpdateScenarioIntro(ctx context.Context, in *UpdateScenarioIntroReq, opts ...grpc.CallOption) (*UpdateScenarioIntroRsp, error)
|
||||||
DownloadScenarioArchive(ctx context.Context, in *DownloadScenarioArchiveReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error)
|
DownloadScenarioArchive(ctx context.Context, in *DownloadScenarioArchiveReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error)
|
||||||
UploadScenarioArchive(ctx context.Context, in *httpbody.HttpBody, opts ...grpc.CallOption) (*UploadScenarioArchiveRsp, error)
|
UploadScenarioArchive(ctx context.Context, in *httpbody.HttpBody, opts ...grpc.CallOption) (*UploadScenarioArchiveRsp, error)
|
||||||
AddGame(ctx context.Context, in *AddGameReq, opts ...grpc.CallOption) (*AddGameRsp, error)
|
AddGame(ctx context.Context, in *AddGameReq, opts ...grpc.CallOption) (*AddGameRsp, error)
|
||||||
@@ -434,6 +436,16 @@ func (c *eveningDetectiveServerClient) DeleteScenarioPlace(ctx context.Context,
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *eveningDetectiveServerClient) UpdateScenarioIntro(ctx context.Context, in *UpdateScenarioIntroReq, opts ...grpc.CallOption) (*UpdateScenarioIntroRsp, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(UpdateScenarioIntroRsp)
|
||||||
|
err := c.cc.Invoke(ctx, EveningDetectiveServer_UpdateScenarioIntro_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *eveningDetectiveServerClient) DownloadScenarioArchive(ctx context.Context, in *DownloadScenarioArchiveReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error) {
|
func (c *eveningDetectiveServerClient) DownloadScenarioArchive(ctx context.Context, in *DownloadScenarioArchiveReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error) {
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
out := new(httpbody.HttpBody)
|
out := new(httpbody.HttpBody)
|
||||||
@@ -658,6 +670,7 @@ type EveningDetectiveServerServer interface {
|
|||||||
AddScenarioPlace(context.Context, *AddScenarioPlaceReq) (*AddScenarioPlaceRsp, error)
|
AddScenarioPlace(context.Context, *AddScenarioPlaceReq) (*AddScenarioPlaceRsp, error)
|
||||||
UpdateScenarioPlace(context.Context, *UpdateScenarioPlaceReq) (*UpdateScenarioPlaceRsp, error)
|
UpdateScenarioPlace(context.Context, *UpdateScenarioPlaceReq) (*UpdateScenarioPlaceRsp, error)
|
||||||
DeleteScenarioPlace(context.Context, *DeleteScenarioPlaceReq) (*DeleteScenarioPlaceRsp, error)
|
DeleteScenarioPlace(context.Context, *DeleteScenarioPlaceReq) (*DeleteScenarioPlaceRsp, error)
|
||||||
|
UpdateScenarioIntro(context.Context, *UpdateScenarioIntroReq) (*UpdateScenarioIntroRsp, error)
|
||||||
DownloadScenarioArchive(context.Context, *DownloadScenarioArchiveReq) (*httpbody.HttpBody, error)
|
DownloadScenarioArchive(context.Context, *DownloadScenarioArchiveReq) (*httpbody.HttpBody, error)
|
||||||
UploadScenarioArchive(context.Context, *httpbody.HttpBody) (*UploadScenarioArchiveRsp, error)
|
UploadScenarioArchive(context.Context, *httpbody.HttpBody) (*UploadScenarioArchiveRsp, error)
|
||||||
AddGame(context.Context, *AddGameReq) (*AddGameRsp, error)
|
AddGame(context.Context, *AddGameReq) (*AddGameRsp, error)
|
||||||
@@ -777,6 +790,9 @@ func (UnimplementedEveningDetectiveServerServer) UpdateScenarioPlace(context.Con
|
|||||||
func (UnimplementedEveningDetectiveServerServer) DeleteScenarioPlace(context.Context, *DeleteScenarioPlaceReq) (*DeleteScenarioPlaceRsp, error) {
|
func (UnimplementedEveningDetectiveServerServer) DeleteScenarioPlace(context.Context, *DeleteScenarioPlaceReq) (*DeleteScenarioPlaceRsp, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method DeleteScenarioPlace not implemented")
|
return nil, status.Error(codes.Unimplemented, "method DeleteScenarioPlace not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedEveningDetectiveServerServer) UpdateScenarioIntro(context.Context, *UpdateScenarioIntroReq) (*UpdateScenarioIntroRsp, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method UpdateScenarioIntro not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedEveningDetectiveServerServer) DownloadScenarioArchive(context.Context, *DownloadScenarioArchiveReq) (*httpbody.HttpBody, error) {
|
func (UnimplementedEveningDetectiveServerServer) DownloadScenarioArchive(context.Context, *DownloadScenarioArchiveReq) (*httpbody.HttpBody, error) {
|
||||||
return nil, status.Error(codes.Unimplemented, "method DownloadScenarioArchive not implemented")
|
return nil, status.Error(codes.Unimplemented, "method DownloadScenarioArchive not implemented")
|
||||||
}
|
}
|
||||||
@@ -1396,6 +1412,24 @@ func _EveningDetectiveServer_DeleteScenarioPlace_Handler(srv interface{}, ctx co
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _EveningDetectiveServer_UpdateScenarioIntro_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(UpdateScenarioIntroReq)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(EveningDetectiveServerServer).UpdateScenarioIntro(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: EveningDetectiveServer_UpdateScenarioIntro_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(EveningDetectiveServerServer).UpdateScenarioIntro(ctx, req.(*UpdateScenarioIntroReq))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func _EveningDetectiveServer_DownloadScenarioArchive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _EveningDetectiveServer_DownloadScenarioArchive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(DownloadScenarioArchiveReq)
|
in := new(DownloadScenarioArchiveReq)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@@ -1865,6 +1899,10 @@ var EveningDetectiveServer_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "DeleteScenarioPlace",
|
MethodName: "DeleteScenarioPlace",
|
||||||
Handler: _EveningDetectiveServer_DeleteScenarioPlace_Handler,
|
Handler: _EveningDetectiveServer_DeleteScenarioPlace_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "UpdateScenarioIntro",
|
||||||
|
Handler: _EveningDetectiveServer_UpdateScenarioIntro_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "DownloadScenarioArchive",
|
MethodName: "DownloadScenarioArchive",
|
||||||
Handler: _EveningDetectiveServer_DownloadScenarioArchive_Handler,
|
Handler: _EveningDetectiveServer_DownloadScenarioArchive_Handler,
|
||||||
|
|||||||
Reference in New Issue
Block a user