diff --git a/api/main.proto b/api/main.proto index 86e9a93..d70a1e7 100644 --- a/api/main.proto +++ b/api/main.proto @@ -1045,19 +1045,19 @@ message DeleteAccountRsp { message GetTermsReq {} message GetTermsRsp { - string text = 1; + string text = 1; } message GetPrivacyReq {} message GetPrivacyRsp { - string text = 1; + string text = 1; } message GetConsentReq {} message GetConsentRsp { - string text = 1; + string text = 1; } message GetUsersReq {} @@ -1080,13 +1080,13 @@ message GetUserByIDReq { } message GetUserByIDRsp { - User user = 1; + User user = 1; } message GetMeReq {} message GetMeRsp { - User user = 1; + User user = 1; } message ChangeUserPasswordReq { @@ -1139,7 +1139,7 @@ message AddScenarioReq { } message AddScenarioRsp { - int32 ID = 1; + int32 ID = 1; } message GetMyScenariosReq {} @@ -1175,14 +1175,15 @@ message Scenario { google.protobuf.Timestamp published_at = 10; double average_rating = 11; int32 reviews_count = 12; + string difficulty = 13; } message Story { - repeated Place places = 1; - Introduction introduction = 2; - repeated Question questions = 3; - string background = 4; - Conclusion conclusion = 5; // Только в полном сценарии, игрокам не передаётся. + repeated Place places = 1; + Introduction introduction = 2; + repeated Question questions = 3; + string background = 4; + Conclusion conclusion = 5; // Только в полном сценарии, игрокам не передаётся. } message Conclusion { @@ -1364,20 +1365,20 @@ message DownloadScenarioArchiveReq { } message UploadScenarioArchiveRsp { - int32 ID = 1; + int32 ID = 1; } message AddGameReq { string name = 1; string description = 2; google.protobuf.Timestamp start_at = 3; - int32 scenarioID = 4; + int32 scenarioID = 4; string format = 5; string location = 6; } message AddGameRsp { - int32 ID = 1; + int32 ID = 1; } message GetGamesReq {} @@ -1437,7 +1438,7 @@ enum ScreenCommand { message ScreenState { string ID = 1; string status = 2; - optional int32 gameID = 3; + optional int32 gameID = 3; ScreenMode mode = 4; bool sound_enabled = 5; string error = 6; @@ -1459,7 +1460,7 @@ message ScreenState { message CreateScreenSessionReq {} message CreateScreenSessionRsp { - string screenID = 1; + string screenID = 1; string access_token = 2; } @@ -1507,7 +1508,7 @@ message SetScreenSoundRsp { message MapItem { string kind = 1; - int32 itemID = 2; + int32 itemID = 2; string label = 3; int32 x = 4; int32 y = 5; @@ -1601,22 +1602,22 @@ message ParticipationRsp { } message Team { - int32 ID = 1; - string name = 2; - string status = 3; - string password = 4; - int32 actions_count = 5; - repeated Application applications = 6; - string captain_email = 7; - int32 participants_count = 8; + int32 ID = 1; + string name = 2; + string status = 3; + string password = 4; + int32 actions_count = 5; + repeated Application applications = 6; + string captain_email = 7; + int32 participants_count = 8; // Статус участия: pending, confirmed или cancelled. Поле панели организатора. - string participation_status = 9; + string participation_status = 9; // Источник решения: captain, automatic либо пустая строка до ответа. string participation_source = 10; // Последняя ошибка отправки; пустая строка, если ошибки нет. string participation_email_error = 11; // Письмо принято SMTP-сервером; не означает прочтение или доставку во входящие. - bool participation_email_sent = 12; + bool participation_email_sent = 12; } message GetGameReq { @@ -1624,7 +1625,7 @@ message GetGameReq { } message GetGameRsp { - Game game = 1; + Game game = 1; } message GetGameAnswersReq { @@ -1668,22 +1669,24 @@ message GetGameResultsRsp { message GameReview { int32 ID = 1; - int32 gameID = 2; - int32 teamID = 3; + int32 gameID = 2; + int32 teamID = 3; string team_name = 4; int32 rating = 5; string text = 6; string status = 7; google.protobuf.Timestamp created_at = 8; string game_name = 9; + int32 difficulty = 10; } message CreateGameReviewReq { - int32 gameID = 1; - int32 teamID = 2; - string password = 3; - int32 rating = 4; - string text = 5; + int32 gameID = 1; + int32 teamID = 2; + string password = 3; + int32 rating = 4; + string text = 5; + int32 difficulty = 6; } message CreateGameReviewRsp { @@ -1720,7 +1723,7 @@ message UpdateGameReq { string name = 2; string description = 3; google.protobuf.Timestamp start_at = 4; - int32 scenarioID = 5; + int32 scenarioID = 5; string format = 6; string location = 7; } @@ -1771,7 +1774,7 @@ message DeleteGameRsp { } message AddTeamReq { - int32 gameID = 1; + int32 gameID = 1; string name = 2; string captain_email = 3; } diff --git a/bin/evening_detective_server b/bin/evening_detective_server index 57dbac0..e1e2c56 100755 Binary files a/bin/evening_detective_server and b/bin/evening_detective_server differ diff --git a/cmd/evening_detective_server/main.swagger.json b/cmd/evening_detective_server/main.swagger.json index 7ddee40..86ee02e 100644 --- a/cmd/evening_detective_server/main.swagger.json +++ b/cmd/evening_detective_server/main.swagger.json @@ -3118,6 +3118,10 @@ }, "text": { "type": "string" + }, + "difficulty": { + "type": "integer", + "format": "int32" } } }, @@ -3710,6 +3714,10 @@ }, "gameName": { "type": "string" + }, + "difficulty": { + "type": "integer", + "format": "int32" } } }, @@ -4293,6 +4301,9 @@ "reviewsCount": { "type": "integer", "format": "int32" + }, + "difficulty": { + "type": "string" } } }, diff --git a/internal/app/game_reviews.go b/internal/app/game_reviews.go index a06552c..63cd060 100644 --- a/internal/app/game_reviews.go +++ b/internal/app/game_reviews.go @@ -13,15 +13,16 @@ import ( func mapGameReview(r *game_review_service.Review) *proto.GameReview { return &proto.GameReview{ - ID: int32(r.ID), - GameID: int32(r.GameID), - TeamID: int32(r.TeamID), - TeamName: r.TeamName, - Rating: r.Rating, - Text: r.Text, - Status: r.Status, - CreatedAt: timestamppb.New(r.CreatedAt), - GameName: r.GameName, + ID: int32(r.ID), + GameID: int32(r.GameID), + TeamID: int32(r.TeamID), + TeamName: r.TeamName, + Rating: r.Rating, + Difficulty: r.Difficulty, + Text: r.Text, + Status: r.Status, + CreatedAt: timestamppb.New(r.CreatedAt), + GameName: r.GameName, } } @@ -34,7 +35,7 @@ func mapGameReviews(reviews []*game_review_service.Review) []*proto.GameReview { } func (s *server) CreateGameReview(ctx context.Context, req *proto.CreateGameReviewReq) (*proto.CreateGameReviewRsp, error) { - review, err := s.reviewService.Create(ctx, int(req.GameID), int(req.TeamID), req.Password, req.Rating, req.Text) + review, err := s.reviewService.Create(ctx, int(req.GameID), int(req.TeamID), req.Password, req.Rating, req.Difficulty, req.Text) if err != nil { return nil, reviewErrorStatus(err, "не удалось создать отзыв") } diff --git a/internal/app/scenarios.go b/internal/app/scenarios.go index 8858944..8ff8ab7 100644 --- a/internal/app/scenarios.go +++ b/internal/app/scenarios.go @@ -97,12 +97,13 @@ func (s *server) GetScenario(ctx context.Context, req *proto.GetScenarioReq) (*p func (s *server) addScenarioRatings(ctx context.Context, scenarios []*scenarios_service.Scenario) error { for _, scenario := range scenarios { - average, count, err := s.reviewService.ScenarioRating(ctx, scenario.ID) + average, count, difficulty, err := s.reviewService.ScenarioRating(ctx, scenario.ID) if err != nil { return err } scenario.AverageRating = average scenario.ReviewsCount = count + scenario.Difficulty = difficulty } return nil } diff --git a/internal/app/story_mapper.go b/internal/app/story_mapper.go index 520d88c..3b4683a 100644 --- a/internal/app/story_mapper.go +++ b/internal/app/story_mapper.go @@ -40,6 +40,7 @@ func mapScenario(o *scenarios_service.Scenario) *proto.Scenario { PublishedAt: publishedAt, AverageRating: o.AverageRating, ReviewsCount: o.ReviewsCount, + Difficulty: o.Difficulty, } } diff --git a/internal/repos/game_reviews_repo/repo.go b/internal/repos/game_reviews_repo/repo.go index ed36c64..33bfe36 100644 --- a/internal/repos/game_reviews_repo/repo.go +++ b/internal/repos/game_reviews_repo/repo.go @@ -23,15 +23,16 @@ var ( // Review describes a game review. type Review struct { - ID int - GameID int - GameName string - TeamID int - TeamName string - Rating int32 - Text string - Status string - CreatedAt time.Time + ID int + GameID int + GameName string + TeamID int + TeamName string + Rating int32 + Difficulty int32 + Text string + Status string + CreatedAt time.Time } // Repo persists game reviews. @@ -41,13 +42,13 @@ type Repo struct{ pool *pgxpool.Pool } func NewGameReviewsRepo(pool *pgxpool.Pool) *Repo { return &Repo{pool: pool} } // Create stores a review. -func (r *Repo) Create(ctx context.Context, gameID, teamID int, rating int32, text string) (*Review, error) { +func (r *Repo) Create(ctx context.Context, gameID, teamID int, rating, difficulty int32, text string) (*Review, error) { review := &Review{} err := r.pool.QueryRow( ctx, ` - INSERT INTO game_reviews (game_id, team_id, rating, text) - SELECT $1, t.id, $3, $4 + INSERT INTO game_reviews (game_id, team_id, rating, difficulty, text) + SELECT $1, t.id, $3, $4, $5 FROM teams t WHERE t.id = $2 AND t.game_id = $1 ON CONFLICT (game_id, team_id) DO NOTHING @@ -55,9 +56,10 @@ func (r *Repo) Create(ctx context.Context, gameID, teamID int, rating int32, tex gameID, teamID, rating, + difficulty, text, ).Scan( - &review.ID, &review.GameID, &review.TeamID, &review.Rating, &review.Text, &review.Status, &review.CreatedAt) + &review.ID, &review.GameID, &review.TeamID, &review.Rating, &review.Difficulty, &review.Text, &review.Status, &review.CreatedAt) if errors.Is(err, pgx.ErrNoRows) { var exists bool if err := r.pool.QueryRow( @@ -89,7 +91,7 @@ func (r *Repo) GetByID(ctx context.Context, id int) (*Review, error) { func (r *Repo) List(ctx context.Context, gameID int, all bool) ([]*Review, float64, int32, error) { rows, err := r.pool.Query( ctx, - `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.text, r.status, r.created_at + `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.difficulty, r.text, r.status, r.created_at FROM game_reviews r JOIN teams t ON t.id = r.team_id JOIN games g ON g.id = r.game_id @@ -105,7 +107,7 @@ func (r *Repo) List(ctx context.Context, gameID int, all bool) ([]*Review, float var reviews []*Review for rows.Next() { review := &Review{} - if err := rows.Scan(&review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Text, &review.Status, &review.CreatedAt); err != nil { + if err := rows.Scan(&review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Difficulty, &review.Text, &review.Status, &review.CreatedAt); err != nil { return nil, 0, 0, err } reviews = append(reviews, review) @@ -131,7 +133,7 @@ func (r *Repo) List(ctx context.Context, gameID int, all bool) ([]*Review, float func (r *Repo) ListForModeration(ctx context.Context) ([]*Review, error) { rows, err := r.pool.Query( ctx, - `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.text, r.status, r.created_at + `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.difficulty, r.text, r.status, r.created_at FROM game_reviews r JOIN teams t ON t.id = r.team_id JOIN games g ON g.id = r.game_id @@ -144,7 +146,7 @@ func (r *Repo) ListForModeration(ctx context.Context) ([]*Review, error) { var reviews []*Review for rows.Next() { review := &Review{} - if err := rows.Scan(&review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Text, &review.Status, &review.CreatedAt); err != nil { + if err := rows.Scan(&review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Difficulty, &review.Text, &review.Status, &review.CreatedAt); err != nil { return nil, err } reviews = append(reviews, review) @@ -175,25 +177,26 @@ func (r *Repo) Moderate(ctx context.Context, id int, status string) (*Review, er } // ScenarioRating returns aggregate ratings for a scenario. -func (r *Repo) ScenarioRating(ctx context.Context, scenarioID int) (float64, int32, error) { +func (r *Repo) ScenarioRating(ctx context.Context, scenarioID int) (float64, int32, float64, error) { var average float64 + var averageDifficulty float64 var count int64 err := r.pool.QueryRow( ctx, - `SELECT COALESCE(AVG(r.rating), 0), COUNT(*) + `SELECT COALESCE(AVG(r.rating), 0), COUNT(*), COALESCE(AVG(r.difficulty), 0) FROM game_reviews r JOIN games g ON g.id = r.game_id WHERE g.scenario_id = $1 AND g.status = 'finish' AND r.status = 'approved'`, scenarioID, - ).Scan(&average, &count) - return average, int32(count), err + ).Scan(&average, &count, &averageDifficulty) + return average, int32(count), averageDifficulty, err } // ListByScenario returns reviews and aggregate ratings for a scenario. func (r *Repo) ListByScenario(ctx context.Context, scenarioID int) ([]*Review, float64, int32, error) { rows, err := r.pool.Query( ctx, - `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.text, r.status, r.created_at + `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.difficulty, r.text, r.status, r.created_at FROM game_reviews r JOIN teams t ON t.id = r.team_id JOIN games g ON g.id = r.game_id @@ -208,7 +211,7 @@ func (r *Repo) ListByScenario(ctx context.Context, scenarioID int) ([]*Review, f var reviews []*Review for rows.Next() { review := &Review{} - if err := rows.Scan(&review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Text, &review.Status, &review.CreatedAt); err != nil { + if err := rows.Scan(&review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Difficulty, &review.Text, &review.Status, &review.CreatedAt); err != nil { return nil, 0, 0, err } reviews = append(reviews, review) @@ -216,7 +219,7 @@ func (r *Repo) ListByScenario(ctx context.Context, scenarioID int) ([]*Review, f if err := rows.Err(); err != nil { return nil, 0, 0, err } - average, count, err := r.ScenarioRating(ctx, scenarioID) + average, count, _, err := r.ScenarioRating(ctx, scenarioID) return reviews, average, count, err } @@ -224,14 +227,14 @@ func (r *Repo) queryOne(ctx context.Context, id int) (*Review, error) { review := &Review{} err := r.pool.QueryRow( ctx, - `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.text, r.status, r.created_at + `SELECT r.id, r.game_id, r.team_id, t.name, g.name, r.rating, r.difficulty, r.text, r.status, r.created_at FROM game_reviews r JOIN teams t ON t.id = r.team_id JOIN games g ON g.id = r.game_id WHERE r.id = $1`, id, ).Scan( - &review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Text, &review.Status, &review.CreatedAt) + &review.ID, &review.GameID, &review.TeamID, &review.TeamName, &review.GameName, &review.Rating, &review.Difficulty, &review.Text, &review.Status, &review.CreatedAt) if errors.Is(err, pgx.ErrNoRows) { return nil, ErrReviewNotFound } diff --git a/internal/services/game_review_service/mapper.go b/internal/services/game_review_service/mapper.go index 10d0df1..dc4b4cc 100644 --- a/internal/services/game_review_service/mapper.go +++ b/internal/services/game_review_service/mapper.go @@ -9,15 +9,16 @@ import ( // Review describes a game review exposed by the service layer. type Review struct { - ID int - GameID int - GameName string - TeamID int - TeamName string - Rating int32 - Text string - Status string - CreatedAt time.Time + ID int + GameID int + GameName string + TeamID int + TeamName string + Rating int32 + Difficulty int32 + Text string + Status string + CreatedAt time.Time } func mapReview(review *game_reviews_repo.Review) *Review { @@ -25,15 +26,16 @@ func mapReview(review *game_reviews_repo.Review) *Review { return nil } return &Review{ - ID: review.ID, - GameID: review.GameID, - GameName: review.GameName, - TeamID: review.TeamID, - TeamName: review.TeamName, - Rating: review.Rating, - Text: review.Text, - Status: review.Status, - CreatedAt: review.CreatedAt, + ID: review.ID, + GameID: review.GameID, + GameName: review.GameName, + TeamID: review.TeamID, + TeamName: review.TeamName, + Rating: review.Rating, + Difficulty: review.Difficulty, + Text: review.Text, + Status: review.Status, + CreatedAt: review.CreatedAt, } } diff --git a/internal/services/game_review_service/service.go b/internal/services/game_review_service/service.go index 2fda60b..72b7706 100644 --- a/internal/services/game_review_service/service.go +++ b/internal/services/game_review_service/service.go @@ -31,7 +31,7 @@ var ( // ErrGameNotFinished indicates that the game is not finished. ErrGameNotFinished = errors.New("оценить можно только завершённую игру") // ErrInvalidReview indicates that review data is invalid. - ErrInvalidReview = errors.New("оценка должна быть от 1 до 5, текст обязателен") + ErrInvalidReview = errors.New("оценка должна быть от 1 до 5, сложность от 1 до 3, текст обязателен") ) // GameReviewService handles game reviews. @@ -49,8 +49,8 @@ func NewGameReviewService(reviews *game_reviews_repo.Repo, games *games_repo.Gam } // Create stores a game review. -func (s *GameReviewService) Create(ctx context.Context, gameID, teamID int, password string, rating int32, text string) (*Review, error) { - if rating < 1 || rating > 5 || strings.TrimSpace(text) == "" { +func (s *GameReviewService) Create(ctx context.Context, gameID, teamID int, password string, rating, difficulty int32, text string) (*Review, error) { + if rating < 1 || rating > 5 || difficulty < 1 || difficulty > 3 || strings.TrimSpace(text) == "" { return nil, ErrInvalidReview } team, err := s.teams.GetTeamByID(ctx, teamID) @@ -73,7 +73,7 @@ func (s *GameReviewService) Create(ctx context.Context, gameID, teamID int, pass if game.Status != "finish" { return nil, ErrGameNotFinished } - review, err := s.reviews.Create(ctx, gameID, teamID, rating, strings.TrimSpace(text)) + review, err := s.reviews.Create(ctx, gameID, teamID, rating, difficulty, strings.TrimSpace(text)) if err != nil { if errors.Is(err, game_reviews_repo.ErrReviewExists) { return nil, ErrReviewExists @@ -117,8 +117,25 @@ func (s *GameReviewService) Moderate(ctx context.Context, id int, status string) } // ScenarioRating returns aggregate ratings for a scenario. -func (s *GameReviewService) ScenarioRating(ctx context.Context, scenarioID int) (float64, int32, error) { - return s.reviews.ScenarioRating(ctx, scenarioID) +func (s *GameReviewService) ScenarioRating(ctx context.Context, scenarioID int) (float64, int32, string, error) { + average, count, averageDifficulty, err := s.reviews.ScenarioRating(ctx, scenarioID) + if err != nil { + return 0, 0, "", err + } + return average, count, difficultyCategory(averageDifficulty, count), nil +} + +func difficultyCategory(average float64, count int32) string { + if count == 0 { + return "" + } + if average <= 1.66 { + return "лёгкая" + } + if average <= 2.33 { + return "средняя" + } + return "тяжёлая" } // ListByScenario returns reviews for a scenario. diff --git a/internal/services/game_review_service/service_test.go b/internal/services/game_review_service/service_test.go index 3ae8b05..0d9c78a 100644 --- a/internal/services/game_review_service/service_test.go +++ b/internal/services/game_review_service/service_test.go @@ -33,3 +33,20 @@ func TestReviewReminderEmail(t *testing.T) { }) } } + +func TestDifficultyCategory(t *testing.T) { + for _, test := range []struct { + average float64 + count int32 + want string + }{ + {average: 0, count: 0, want: ""}, + {average: 1.66, count: 1, want: "лёгкая"}, + {average: 2, count: 1, want: "средняя"}, + {average: 2.34, count: 1, want: "тяжёлая"}, + } { + if got := difficultyCategory(test.average, test.count); got != test.want { + t.Errorf("difficultyCategory(%v, %d) = %q, want %q", test.average, test.count, got, test.want) + } + } +} diff --git a/internal/services/scenarios_service/scenario.go b/internal/services/scenarios_service/scenario.go index 425ab2a..2882deb 100644 --- a/internal/services/scenarios_service/scenario.go +++ b/internal/services/scenarios_service/scenario.go @@ -21,5 +21,6 @@ type Scenario struct { PublishedAt *time.Time AverageRating float64 ReviewsCount int32 + Difficulty string IsDeleted bool } diff --git a/migrations/20261003090000_add_review_difficulty.sql b/migrations/20261003090000_add_review_difficulty.sql new file mode 100644 index 0000000..b58de49 --- /dev/null +++ b/migrations/20261003090000_add_review_difficulty.sql @@ -0,0 +1,6 @@ +-- +goose Up +ALTER TABLE game_reviews + ADD COLUMN difficulty INTEGER NOT NULL DEFAULT 2 CHECK (difficulty BETWEEN 1 AND 3); + +-- +goose Down +ALTER TABLE game_reviews DROP COLUMN difficulty; diff --git a/proto/main.pb.go b/proto/main.pb.go index 096963c..5d2e0a4 100644 --- a/proto/main.pb.go +++ b/proto/main.pb.go @@ -2264,6 +2264,7 @@ type Scenario struct { PublishedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=published_at,json=publishedAt,proto3" json:"published_at,omitempty"` AverageRating float64 `protobuf:"fixed64,11,opt,name=average_rating,json=averageRating,proto3" json:"average_rating,omitempty"` ReviewsCount int32 `protobuf:"varint,12,opt,name=reviews_count,json=reviewsCount,proto3" json:"reviews_count,omitempty"` + Difficulty string `protobuf:"bytes,13,opt,name=difficulty,proto3" json:"difficulty,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2382,6 +2383,13 @@ func (x *Scenario) GetReviewsCount() int32 { return 0 } +func (x *Scenario) GetDifficulty() string { + if x != nil { + return x.Difficulty + } + return "" +} + type Story struct { state protoimpl.MessageState `protogen:"open.v1"` Places []*Place `protobuf:"bytes,1,rep,name=places,proto3" json:"places,omitempty"` @@ -6734,6 +6742,7 @@ type GameReview struct { Status string `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` GameName string `protobuf:"bytes,9,opt,name=game_name,json=gameName,proto3" json:"game_name,omitempty"` + Difficulty int32 `protobuf:"varint,10,opt,name=difficulty,proto3" json:"difficulty,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -6831,6 +6840,13 @@ func (x *GameReview) GetGameName() string { return "" } +func (x *GameReview) GetDifficulty() int32 { + if x != nil { + return x.Difficulty + } + return 0 +} + type CreateGameReviewReq struct { state protoimpl.MessageState `protogen:"open.v1"` GameID int32 `protobuf:"varint,1,opt,name=gameID,proto3" json:"gameID,omitempty"` @@ -6838,6 +6854,7 @@ type CreateGameReviewReq struct { Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` Rating int32 `protobuf:"varint,4,opt,name=rating,proto3" json:"rating,omitempty"` Text string `protobuf:"bytes,5,opt,name=text,proto3" json:"text,omitempty"` + Difficulty int32 `protobuf:"varint,6,opt,name=difficulty,proto3" json:"difficulty,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -6907,6 +6924,13 @@ func (x *CreateGameReviewReq) GetText() string { return "" } +func (x *CreateGameReviewReq) GetDifficulty() int32 { + if x != nil { + return x.Difficulty + } + return 0 +} + type CreateGameReviewRsp struct { state protoimpl.MessageState `protogen:"open.v1"` Review *GameReview `protobuf:"bytes,1,opt,name=review,proto3" json:"review,omitempty"` @@ -9448,7 +9472,7 @@ const file_main_proto_rawDesc = "" + "\x0eGetScenarioReq\x12\x0e\n" + "\x02ID\x18\x01 \x01(\x05R\x02ID\"V\n" + "\x0eGetScenarioRsp\x12D\n" + - "\bscenario\x18\x01 \x01(\v2(.crabs.evening_detective_server.ScenarioR\bscenario\"\x9e\x04\n" + + "\bscenario\x18\x01 \x01(\v2(.crabs.evening_detective_server.ScenarioR\bscenario\"\xbe\x04\n" + "\bScenario\x12\x0e\n" + "\x02ID\x18\x01 \x01(\x05R\x02ID\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12%\n" + @@ -9464,7 +9488,10 @@ const file_main_proto_rawDesc = "" + "\fpublished_at\x18\n" + " \x01(\v2\x1a.google.protobuf.TimestampR\vpublishedAt\x12%\n" + "\x0eaverage_rating\x18\v \x01(\x01R\raverageRating\x12#\n" + - "\rreviews_count\x18\f \x01(\x05R\freviewsCountB\x0e\n" + + "\rreviews_count\x18\f \x01(\x05R\freviewsCount\x12\x1e\n" + + "\n" + + "difficulty\x18\r \x01(\tR\n" + + "difficultyB\x0e\n" + "\f_descriptionB\b\n" + "\x06_image\"\xcc\x02\n" + "\x05Story\x12=\n" + @@ -9753,7 +9780,7 @@ const file_main_proto_rawDesc = "" + "\ractions_count\x18\x05 \x01(\x05R\factionsCount\"\xa4\x01\n" + "\x11GetGameResultsRsp\x12M\n" + "\tquestions\x18\x01 \x03(\v2/.crabs.evening_detective_server.ResultsQuestionR\tquestions\x12@\n" + - "\x05teams\x18\x02 \x03(\v2*.crabs.evening_detective_server.TeamResultR\x05teams\"\x85\x02\n" + + "\x05teams\x18\x02 \x03(\v2*.crabs.evening_detective_server.TeamResultR\x05teams\"\xa5\x02\n" + "\n" + "GameReview\x12\x0e\n" + "\x02ID\x18\x01 \x01(\x05R\x02ID\x12\x16\n" + @@ -9765,13 +9792,20 @@ const file_main_proto_rawDesc = "" + "\x06status\x18\a \x01(\tR\x06status\x129\n" + "\n" + "created_at\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x12\x1b\n" + - "\tgame_name\x18\t \x01(\tR\bgameName\"\x8d\x01\n" + + "\tgame_name\x18\t \x01(\tR\bgameName\x12\x1e\n" + + "\n" + + "difficulty\x18\n" + + " \x01(\x05R\n" + + "difficulty\"\xad\x01\n" + "\x13CreateGameReviewReq\x12\x16\n" + "\x06gameID\x18\x01 \x01(\x05R\x06gameID\x12\x16\n" + "\x06teamID\x18\x02 \x01(\x05R\x06teamID\x12\x1a\n" + "\bpassword\x18\x03 \x01(\tR\bpassword\x12\x16\n" + "\x06rating\x18\x04 \x01(\x05R\x06rating\x12\x12\n" + - "\x04text\x18\x05 \x01(\tR\x04text\"Y\n" + + "\x04text\x18\x05 \x01(\tR\x04text\x12\x1e\n" + + "\n" + + "difficulty\x18\x06 \x01(\x05R\n" + + "difficulty\"Y\n" + "\x13CreateGameReviewRsp\x12B\n" + "\x06review\x18\x01 \x01(\v2*.crabs.evening_detective_server.GameReviewR\x06review\"+\n" + "\x11GetGameReviewsReq\x12\x16\n" +