Compare commits

22 Commits

Author SHA1 Message Date
VLADIMIR 7585e84fad update qr 2025-07-15 02:05:18 +07:00
VLADIMIR 6707967fb5 add embed ui 2025-07-15 01:41:18 +07:00
VLADIMIR 88de56c140 rm editor 2025-07-13 04:46:02 +07:00
VLADIMIR d56f7ec990 up 2025-07-13 03:33:40 +07:00
VLADIMIR fc944329a5 up 2025-07-13 03:23:39 +07:00
VLADIMIR 52108d17bb fix 2025-06-17 03:17:45 +07:00
VLADIMIR 9cc6646fe3 add pdf 2025-06-17 03:10:31 +07:00
VLADIMIR be8e7fa482 add pdf 2025-06-17 01:40:55 +07:00
VLADIMIR b17599eb39 add time 2025-06-15 01:02:46 +07:00
VLADIMIR 36aaa49273 fix double applications 2025-06-15 00:28:48 +07:00
VLADIMIR b6e3fb8596 add teams tests 2025-06-14 23:18:05 +07:00
VLADIMIR 54706f0aba add db filepath 2025-06-14 21:40:38 +07:00
VLADIMIR 3a2980e9d0 add test story 2025-06-14 21:28:46 +07:00
VLADIMIR 77854681a0 add launch.json 2025-06-13 21:51:29 +07:00
VLADIMIR b852bebd63 add tests 2025-06-13 13:01:18 +07:00
VLADIMIR 2fa0be8bcb fix 2025-06-07 22:24:14 +07:00
VLADIMIR c5c9f22f69 fix 2025-06-07 22:23:07 +07:00
VLADIMIR ba0f0caecf fix 2025-06-07 22:21:42 +07:00
VLADIMIR 2e510b22a4 update folders 2025-06-07 22:20:14 +07:00
VLADIMIR e7668754fd update 2025-06-06 18:33:52 +07:00
VLADIMIR 94833338f9 update 2025-06-05 00:22:32 +07:00
VLADIMIR 3c1514a144 add qr 2025-06-04 02:38:01 +07:00
51 changed files with 1406 additions and 457 deletions
Vendored
BIN
View File
Binary file not shown.
+4
View File
@@ -17,6 +17,7 @@
# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ # vendor/
bin/
# Go workspace file # Go workspace file
go.work go.work
@@ -25,3 +26,6 @@ go.work
go.sum go.sum
store.db store.db
cmd/text_to_story/*.txt
cmd/text_to_story/*.json
+36
View File
@@ -0,0 +1,36 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/evening_detective",
"args": [
"--local"
],
"cwd": "${workspaceFolder}",
"buildFlags": "-tags local"
},
{
"name": "Local Launch",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/evening_detective",
"args": [
"--local"
],
"cwd": "${workspaceFolder}",
"buildFlags": "-tags local",
"env": {
"STORY_FILENAME": "./internal/tests/story.json",
"DB_FILENAME": "./internal/tests/store.db"
}
}
]
}
+9 -1
View File
@@ -1,7 +1,15 @@
{ {
"cSpell.words": [ "cSpell.words": [
"Приложение",
"Текст",
"Точка",
"точки",
"AUTOINCREMENT", "AUTOINCREMENT",
"gopdf",
"gwmux", "gwmux",
"palces" "localtime",
"palces",
"qrcode",
"signintech"
] ]
} }
+13 -1
View File
@@ -13,4 +13,16 @@ run:
go run ./cmd/evening_detective/main.go go run ./cmd/evening_detective/main.go
build: build:
go build -o bin/evening_detective cmd/evening_detective/main.go rm -rf bin
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -o bin/evening_detective_macos_arm64 cmd/evening_detective/main.go
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o bin/evening_detective_macos_amd64 cmd/evening_detective/main.go
text_to_story:
rm -f ./cmd/text_to_story/story.json
go run ./cmd/text_to_story/main.go
clear:
rm ./internal/tests/store.db
test:
DB_FILENAME=store.db go test -count=1 ./...
+14
View File
@@ -71,6 +71,12 @@ service EveningDetective {
body: "*" body: "*"
}; };
} }
rpc DownloadTeamsQrCodesFile(DownloadTeamsQrCodesFileReq) returns (DownloadTeamsQrCodesFileRsp) {
option (google.api.http) = {
get: "/teams/pdf"
};
}
} }
message PingReq {} message PingReq {}
@@ -147,6 +153,8 @@ message GetGameReq {}
message GetGameRsp { message GetGameRsp {
string state = 1; string state = 1;
string startAt = 2;
string endAt = 3;
} }
message GameStartReq {} message GameStartReq {}
@@ -165,3 +173,9 @@ message GiveApplicationsReq {
} }
message GiveApplicationsRsp {} message GiveApplicationsRsp {}
message DownloadTeamsQrCodesFileReq {}
message DownloadTeamsQrCodesFileRsp {
bytes result = 1;
}
+4
View File
@@ -57,3 +57,7 @@ POST http://localhost:8090/teams/1/applications
} }
] ]
} }
### Qr коды команд в pdf
GET http://localhost:8090/teams/pdf
Binary file not shown.
+25 -5
View File
@@ -2,10 +2,13 @@ package main
import ( import (
"context" "context"
"embed"
"evening_detective/internal/app" "evening_detective/internal/app"
"evening_detective/internal/config"
"evening_detective/internal/services" "evening_detective/internal/services"
"evening_detective/internal/services/story_service" "evening_detective/internal/services/story_service"
proto "evening_detective/proto" proto "evening_detective/proto"
"io/fs"
"log" "log"
"net" "net"
"net/http" "net/http"
@@ -16,6 +19,12 @@ import (
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
) )
//go:embed static/user/*
var userFS embed.FS
//go:embed static/admin/*
var adminFS embed.FS
func main() { func main() {
// Create a listener on TCP port // Create a listener on TCP port
lis, err := net.Listen("tcp", ":8080") lis, err := net.Listen("tcp", ":8080")
@@ -26,13 +35,16 @@ func main() {
// Create a gRPC server object // Create a gRPC server object
s := grpc.NewServer() s := grpc.NewServer()
// Attach the Greeter service to the server // Attach the Greeter service to the server
repository, err := services.NewRepository() dbFilepath := config.GetDBFilepath()
repository, err := services.NewRepository(dbFilepath)
if err != nil { if err != nil {
panic(err) panic(err)
} }
storyService, err := story_service.NewStoryService()
storyFilepath := config.GetStoryFilepath()
storyService, err := story_service.NewStoryService(storyFilepath)
if err != nil { if err != nil {
panic(err) log.Fatalln(err)
} }
proto.RegisterEveningDetectiveServer( proto.RegisterEveningDetectiveServer(
s, s,
@@ -87,7 +99,11 @@ func main() {
}() }()
muxUser := http.NewServeMux() muxUser := http.NewServeMux()
fileServerUser := http.FileServer(http.Dir("./static/user")) subUserFS, err := fs.Sub(userFS, "static/user")
if err != nil {
log.Fatalln(err)
}
fileServerUser := http.FileServer(http.FS(subUserFS))
muxUser.Handle("/", fileServerUser) muxUser.Handle("/", fileServerUser)
// Serve user web server // Serve user web server
@@ -97,7 +113,11 @@ func main() {
}() }()
muxAdmin := http.NewServeMux() muxAdmin := http.NewServeMux()
fileServerAdmin := http.FileServer(http.Dir("./static/admin")) subAdminFS, err := fs.Sub(adminFS, "static/admin")
if err != nil {
log.Fatalln(err)
}
fileServerAdmin := http.FileServer(http.FS(subAdminFS))
muxAdmin.Handle("/", fileServerAdmin) muxAdmin.Handle("/", fileServerAdmin)
// Serve admin web server // Serve admin web server
@@ -0,0 +1 @@
:root{--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, .29);--vt-c-divider-light-2: rgba(60, 60, 60, .12);--vt-c-divider-dark-1: rgba(84, 84, 84, .65);--vt-c-divider-dark-2: rgba(84, 84, 84, .48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, .66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, .64);--main-color: rgba(34, 50, 60, 1);--second-color: rgb(136, 105, 31);--main-back-color: rgba(240, 240, 240, 1);--main-back-item-color: rgba(254, 254, 254, 1)}:root{--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px}*,*:before,*:after{box-sizing:border-box;margin:0;font-weight:400}body{min-height:100dvh;color:var(--color-text);background:var(--main-back-color);transition:color .5s,background-color .5s;line-height:1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:15px;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.input-custom{width:100%;box-sizing:border-box;margin-bottom:15px}.button-custom{margin-left:auto;background-color:var(--main-color);font-weight:600;color:#fff}.button-custom-inline{margin:10px;background-color:var(--main-color);font-weight:600;color:#fff;padding:6px 8px;border:1px solid #ddd;border-radius:15px;font-size:14px}.button-custom:hover,.button-custom-inline:hover{background-color:var(--second-color)}.input-custom,.button-custom{padding:12px 16px;border:1px solid #ddd;border-radius:15px;font-size:16px}.button-container{display:flex}.center-message{display:flex;justify-content:center;align-items:center;height:calc(100dvh - 100px);text-align:center}.qr[data-v-666b8d35]{position:absolute;top:130px;right:30px;text-align:center;width:120px}.header-block[data-v-5b6894ef]{background-color:var(--main-color);font-size:large;color:#fff;vertical-align:middle;padding:10px 0 10px 16px;font-weight:700}.buttons-block[data-v-4d8d73b6]{padding-top:5px}.button-menu[data-v-4d8d73b6]{margin:5px 10px 5px 0}table[data-v-4d8d73b6]{width:700px;border-collapse:collapse;margin:30px auto;border:1px solid #444444}th[data-v-4d8d73b6],td[data-v-4d8d73b6]{padding:12px;text-align:left}th[data-v-4d8d73b6]{background-color:var(--main-color);color:#fff;font-weight:700}tr[data-v-4d8d73b6]:nth-child(odd){background-color:#efefef}tr[data-v-4d8d73b6]:nth-child(2n){background-color:#fff}tr[data-v-4d8d73b6]:hover{background-color:#cfcfcf}.time[data-v-4d8d73b6]{white-space:nowrap}.team-name[data-v-4d8d73b6]{font-weight:600}.link-button[data-v-4d8d73b6]{display:inline;border:none;background:none;padding:0;margin:0;font:inherit;cursor:pointer;color:var(--main-color);text-decoration:underline;font-weight:600;-webkit-appearance:none;-moz-appearance:none;appearance:none;line-height:inherit;text-align:left}.link-button[data-v-4d8d73b6]:hover{color:var(--second-color);text-decoration:none}.link-button[data-v-4d8d73b6]:active{color:#036}.link-button[data-v-4d8d73b6]:focus{outline:none;text-decoration:none;box-shadow:0 0 0 2px #0066cc4d}.form-block[data-v-4d8d73b6]{width:700px;margin:0 auto}a[data-v-4d8d73b6]{color:var(--second-color);text-decoration:none;transition:all .2s ease;cursor:pointer}a[data-v-4d8d73b6]:hover{text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px}a[data-v-4d8d73b6]:focus-visible{outline:2px solid #3182ce;outline-offset:2px;border-radius:2px}a[disabled][data-v-4d8d73b6]{color:#a0aec0;pointer-events:none;cursor:not-allowed}.button-container[data-v-4d8d73b6]{margin-bottom:30px}.cell-center[data-v-4d8d73b6]{text-align:center}.three-columns[data-v-1112068b]{display:grid;grid-template-columns:1fr 2fr 1fr;gap:20px;height:100%}.column[data-v-1112068b]{border:1px solid #e0e0e0;padding:20px;margin:5px}
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

@@ -5,8 +5,8 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ВД Админка</title> <title>ВД Админка</title>
<script type="module" crossorigin src="/assets/index-CdxbIVaR.js"></script> <script type="module" crossorigin src="/assets/index-Tp3gHO58.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-C3dpn_mY.css"> <link rel="stylesheet" crossorigin href="/assets/index-JqNLMpQx.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
@@ -1 +1 @@
import{_ as o,c as s,a as t,o as a}from"./index-C99bTfI6.js";const n={},c={class:"about"};function r(_,e){return a(),s("div",c,e[0]||(e[0]=[t("h1",null,"This is an about page",-1)]))}const l=o(n,[["render",r]]);export{l as default}; import{_ as o,c as s,a as t,o as a}from"./index-DkrD2ASU.js";const n={},c={class:"about"};function r(_,e){return a(),s("div",c,e[0]||(e[0]=[t("h1",null,"This is an about page",-1)]))}const l=o(n,[["render",r]]);export{l as default};
@@ -1 +1 @@
:root{--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, .29);--vt-c-divider-light-2: rgba(60, 60, 60, .12);--vt-c-divider-dark-1: rgba(84, 84, 84, .65);--vt-c-divider-dark-2: rgba(84, 84, 84, .48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, .66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, .64);--main-color: rgba(34, 50, 60, 1);--second-color: rgb(136, 105, 31);--main-back-color: rgba(240, 240, 240, 1);--main-back-item-color: rgba(254, 254, 254, 1)}:root{--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px}*,*:before,*:after{box-sizing:border-box;margin:0;font-weight:400}body{min-height:100dvh;color:var(--color-text);background:var(--main-back-color);transition:color .5s,background-color .5s;line-height:1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:15px;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.header-block{height:60px;background-color:var(--main-color);font-size:large;color:#fff;vertical-align:middle;padding:15px 0 10px 16px;font-weight:700}.input-custom{width:100%;box-sizing:border-box;margin-bottom:15px}.button-custom{margin-left:auto;background-color:var(--main-color);font-weight:600;color:#fff}.button-custom:hover{background-color:var(--main-color);opacity:.9}.button-custom:disabled{opacity:.5}.input-custom,.button-custom{padding:12px 16px;border:1px solid #ddd;border-radius:15px;font-size:16px}.button-container{display:flex}.center-message{display:flex;justify-content:center;align-items:center;height:calc(100dvh - 100px);text-align:center}header[data-v-913ef6b1]{line-height:1.5;max-height:100vh}.logo[data-v-913ef6b1]{display:block;margin:0 auto 2rem}nav[data-v-913ef6b1]{width:100%;font-size:12px;text-align:center;margin-top:2rem}nav a.router-link-exact-active[data-v-913ef6b1]{color:var(--color-text)}nav a.router-link-exact-active[data-v-913ef6b1]:hover{background-color:transparent}nav a[data-v-913ef6b1]{display:inline-block;padding:0 1rem;border-left:1px solid var(--color-border)}nav a[data-v-913ef6b1]:first-of-type{border:0}@media (min-width: 1024px){header[data-v-913ef6b1]{display:flex;place-items:center;padding-right:calc(var(--section-gap) / 2)}.logo[data-v-913ef6b1]{margin:0 2rem 0 0}header .wrapper[data-v-913ef6b1]{display:flex;place-items:flex-start;flex-wrap:wrap}nav[data-v-913ef6b1]{text-align:left;margin-left:-1rem;font-size:1rem;padding:1rem 0;margin-top:1rem}}body[data-v-a43a0f9c]{overflow:hidden}.hr[data-v-a43a0f9c]{margin:7px 0}.body-custom[data-v-a43a0f9c]{font-size:medium}.info-custom[data-v-a43a0f9c]{padding-left:15px}.logo[data-v-a43a0f9c]{float:left;margin:10px}.second-color[data-v-a43a0f9c]{color:var(--second-color)}.form-custom[data-v-a43a0f9c]{border:1px solid #444444;background-color:var(--main-back-color);position:fixed;bottom:0;left:0;width:100%;padding:20px;color:#fff}.message-cloud[data-v-a43a0f9c]{border:1px solid #444444;border-radius:15px;margin:12px 10px;padding:16px;background-color:var(--main-back-item-color)}.message-header[data-v-a43a0f9c]{font-size:large;font-weight:200}.message-content[data-v-a43a0f9c]{font-weight:500;white-space:pre-line}.message-footer[data-v-a43a0f9c]{font-weight:400;color:var(--second-color)}.form-block[data-v-a43a0f9c]{height:140px}.messages-block[data-v-a43a0f9c]{height:calc(100dvh - 200px);overflow-y:auto;scrollbar-width:none}@media (min-width: 1025px){.center-block-custom[data-v-a43a0f9c]{width:700px;margin:0 auto}}.center-message[data-v-a43a0f9c]{height:calc(100dvh - 140px)}.error-message[data-v-13746d20]{color:brown;margin:16px 0} :root{--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, .29);--vt-c-divider-light-2: rgba(60, 60, 60, .12);--vt-c-divider-dark-1: rgba(84, 84, 84, .65);--vt-c-divider-dark-2: rgba(84, 84, 84, .48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, .66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, .64);--main-color: rgba(34, 50, 60, 1);--second-color: rgb(136, 105, 31);--main-back-color: rgba(240, 240, 240, 1);--main-back-item-color: rgba(254, 254, 254, 1)}:root{--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px}*,*:before,*:after{box-sizing:border-box;margin:0;font-weight:400}body{min-height:100dvh;color:var(--color-text);background:var(--main-back-color);transition:color .5s,background-color .5s;line-height:1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:15px;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.header-block{height:60px;background-color:var(--main-color);font-size:large;color:#fff;vertical-align:middle;padding:15px 0 10px 16px;font-weight:700}.input-custom{width:100%;box-sizing:border-box;margin-bottom:15px}.button-custom{margin-left:auto;background-color:var(--main-color);font-weight:600;color:#fff}.button-custom:hover{background-color:var(--main-color);opacity:.9}.button-custom:disabled{opacity:.5}.input-custom,.button-custom{padding:12px 16px;border:1px solid #ddd;border-radius:15px;font-size:16px}.button-container{display:flex}.center-message{display:flex;justify-content:center;align-items:center;height:calc(100dvh - 100px);text-align:center}header[data-v-913ef6b1]{line-height:1.5;max-height:100vh}.logo[data-v-913ef6b1]{display:block;margin:0 auto 2rem}nav[data-v-913ef6b1]{width:100%;font-size:12px;text-align:center;margin-top:2rem}nav a.router-link-exact-active[data-v-913ef6b1]{color:var(--color-text)}nav a.router-link-exact-active[data-v-913ef6b1]:hover{background-color:transparent}nav a[data-v-913ef6b1]{display:inline-block;padding:0 1rem;border-left:1px solid var(--color-border)}nav a[data-v-913ef6b1]:first-of-type{border:0}@media (min-width: 1024px){header[data-v-913ef6b1]{display:flex;place-items:center;padding-right:calc(var(--section-gap) / 2)}.logo[data-v-913ef6b1]{margin:0 2rem 0 0}header .wrapper[data-v-913ef6b1]{display:flex;place-items:flex-start;flex-wrap:wrap}nav[data-v-913ef6b1]{text-align:left;margin-left:-1rem;font-size:1rem;padding:1rem 0;margin-top:1rem}}body[data-v-5146ce3d]{overflow:hidden}.hr[data-v-5146ce3d]{margin:7px 0}.body-custom[data-v-5146ce3d]{font-size:medium}.info-custom[data-v-5146ce3d]{padding-left:15px}.logo[data-v-5146ce3d]{float:left;margin:10px}.logo-right[data-v-5146ce3d]{float:right;margin:12px}.second-color[data-v-5146ce3d]{color:var(--second-color)}.form-custom[data-v-5146ce3d]{border:1px solid #444444;background-color:var(--main-back-color);position:fixed;bottom:0;left:0;width:100%;padding:20px;color:#fff}.message-cloud[data-v-5146ce3d]{border:1px solid #444444;border-radius:15px;margin:12px 10px;padding:16px;background-color:var(--main-back-item-color)}.message-header[data-v-5146ce3d]{font-size:large;font-weight:200}.message-content[data-v-5146ce3d]{font-weight:500;white-space:pre-line}.message-footer[data-v-5146ce3d]{font-weight:400;color:var(--second-color)}.form-block[data-v-5146ce3d]{height:140px}.messages-block[data-v-5146ce3d]{height:calc(100dvh - 200px);overflow-y:auto;scrollbar-width:none}@media (min-width: 1025px){.center-block-custom[data-v-5146ce3d]{width:700px;margin:0 auto}}.center-message[data-v-5146ce3d]{height:calc(100dvh - 140px)}.qr[data-v-5146ce3d]{text-align:center;width:200px}.error-message[data-v-13746d20]{color:brown;margin:16px 0}
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

@@ -5,8 +5,8 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Вечерний детектив</title> <title>Вечерний детектив</title>
<script type="module" crossorigin src="/assets/index-C99bTfI6.js"></script> <script type="module" crossorigin src="/assets/index-DkrD2ASU.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DCF9Sqnk.css"> <link rel="stylesheet" crossorigin href="/assets/index-BJbIgyMb.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
+68
View File
@@ -0,0 +1,68 @@
package main
import (
"encoding/json"
"os"
"strings"
)
type story struct {
Places []placeBlock `json:"places"`
}
type placeBlock struct {
Code string `json:"code"`
Name string `json:"name"`
Text string `json:"text"`
Applications []application `json:"applications,omitempty"`
}
type application struct {
Name string `json:"name"`
}
func main() {
b, err := os.ReadFile("./cmd/text_to_story/text.txt")
if err != nil {
panic(err)
}
story := &story{}
lines := strings.Split(string(b), "\n")
var place *placeBlock
text := ""
for _, line := range lines {
if strings.HasPrefix(line, "[") {
if place != nil {
place.Text = strings.TrimSpace(text)
story.Places = append(story.Places, *place)
text = ""
}
place = &placeBlock{}
codeAndName := strings.Split(line, " ")
place.Code = strings.Trim(codeAndName[0], "[]")
place.Name = strings.TrimSpace(strings.TrimPrefix(strings.Join(codeAndName[1:], " "), "-"))
continue
}
if strings.HasPrefix(line, "Приложение:") {
place.Applications = append(
place.Applications,
application{
Name: strings.TrimSpace(strings.TrimPrefix(line, "Приложение:")),
},
)
continue
}
text += line + "\n"
}
place.Text = strings.TrimSpace(text)
story.Places = append(story.Places, *place)
res, err := json.Marshal(story)
if err != nil {
panic(err)
}
if err := os.WriteFile("./cmd/text_to_story/story.json", res, 0x777); err != nil {
panic(err)
}
}
Binary file not shown.
+163
View File
@@ -0,0 +1,163 @@
{
"places": [
{
"code": "А",
"name": "Администрация",
"text": "Тут работают директор и старший вожатый. На столе Лехи вы находите расписание на 23 августа. Стопку книг по педагогике и какие-то записки от детей — похоже они очень любили Лёху.",
"applications": [{ "name": "Расписание дня" }]
},
{
"code": "В-1",
"name": "Вход",
"text": "Ржавые ворота с выцветшей табличкой «Добро пожаловать в «Сосновый Бор» скрипят на ветру. За ними — узкая дорога, уходящая вглубь соснового леса. На покосившемся стенде у проходной — пожелтевший плакат с информацией:\n\n\"Лагерь «Сосновый Бор» - Место, где рождаются характеры.\"\n\n«Орлы» — спортивные, загорелые, с грамотами за победы в эстафетах.\n\n«Лисы» — те, кто вместо костра сидит с книгами. Их шепотом называют «ботанами», но именно они всегда знают ответ.\n\n«Волки» — вечные нарушители. Их следы находят то на крыше столовой, то у водонапорной вышки.\n\n«Совы» — тихие художники и поэты. Их рисунки иногда находят даже в лесу.\n\nВ самом низу подпись: Директор лагеря - Виктор Сергеевич Громов."
},
{
"code": "В-2",
"name": "Водонапорная вышка",
"text": "Труп лежит на земле с разбитой головой, рядом лежит окровавленный камень, судя по всему от него и погиб старший вожатый. Помимо следов погибшего рядом с трупом вы находите отпечатки кроссовок. Они глубокие, будто кто-то бежал или резко разворачивался. Подошва – с характерным рисунком в виде зигзагов. Также вы находите другие следы двух пар ботинок. Первые – массивные, с грубым протектором. Следы ведут к телу, затем резко обрываются – будто человек замер на месте. Вторые – аккуратные, с узким носком. Они подходят к камню, а затем удаляются в сторону вышки."
},
{
"code": "Д",
"name": "Душ",
"text": "Вы дергаете дверь душа, она закрыта. Завхоз и повариха, сидящие на лавочке рассказали, что душ не работает – у кочегара голова болит уже вторые сутки, – и почему-то громко расхохотались. Поговорив с женщинами вы узнаете, что кормят в лагере очень плохо, даже 2 проверки приезжали – нарушений не нашли, но дети жалуются и почти не едят. Лёша сам ругаться приходил несколько раз, уж очень он за детей волновался."
},
{
"code": "К-1",
"name": "Клуб",
"text": "В клубе вас встречает диджей Пётр.\n“Концерт как всегда душевный, все плакали обнимались, вроде все здесь были, хотя награждение “Лучший ребенок” в этот раз Лёха проводил, а не броненосец, вот его то я вчера и не видел”.\nОн рассказывает, что дискотека прошла на ура, танцевали и пели под все самые лучшие песни. Кажется он почти не общался с Лехой и до сих пор не знает, что произошло: «А какие медляки, танцевал весь лагерь, правда Макса и Даши не было. Они у нас главные знаменитости, танцуют медляки каждый вечер, а днем делают вид что противны друг другу, думают что дети верят в их притворство»"
},
{
"code": "К-2",
"name": "Костровище",
"text": "В глубине лагеря, за последним отрядом расчищена круглая площадка, окруженная полукругом пеньков-сидушек, сколоченных из толстых спилов сосны. В центре — огромный костровой круг, выложенный из камней, почерневших от бесчисленных костров."
},
{
"code": "К-3",
"name": "Коморка физрука",
"text": "Тесное помещение, забитое спортинвентарем до самого потолка. В углу валяется порванный мат, из которого торчит пожелтевший поролон. На полках вперемешку лежат мячи разных видов – футбольные, волейбольные, баскетбольные, – половина из которых явно спущена. Воняет резиной, потом и старыми кроссовками."
},
{
"code": "Л",
"name": "Лавки",
"text": "Пара покосившихся деревянных скамеек, выкрашенных когда-то в зелёную краску, но теперь облезлых до серой древесины. Сиденья испещрены выцарапанными именами, сердечками и нецензурными словами – кто-то старательно выводил их гвоздём или кончиком ключа."
},
{
"code": "М",
"name": "Медпункт",
"text": "Небольшое побелено-голубое здание в тени сосен. Внутри – приемная с выцветшими плакатами про “чистые руки” и “опасность клещей”, изолятор с двумя койками за занавеской, а дальше – общий душ и туалет. На столе стоят 3 кружки из-под чая. Печенье “Юбилейное” в открытой пачке. Медицинская карта с последней записью: “22:30 23.08.99 – Волкова С. (отряд “Орлы”) – жалобы на температуру и тошноту. Диагноз: пищевое отравление?” В мусорном ведре вы замечаете упаковку от таблетки, 3 пакетика чая и использованный презерватив. Слабый аромат духов – дешевый, сладкий, явно не медицинский."
},
{
"code": "O-1",
"name": "Отряд 1",
"text": "Белое кирпичное здание, с выложенными кирпичом “1970”. Сбоку нарисован Чебурашка, коричневой и красной краской. Отряд опрятный, но сильно пахнет потом. Койки заправлены с армейской аккуратностью. На стене – газета с детскими стихами, где кто-то красной ручкой исправил рифмы на похабные."
},
{
"code": "O-2",
"name": "Отряд 2",
"text": "Тени от сосен за окном рисуют на стенах полосатые узоры. Зайдя внутрь здания, вы замечаете одного из вожатых — Кирилла. Заведя разговор о произошедшем, вы по секрету узнаете, что его напарница Даша бегает на свиданки с вожатым первого отряда Максимом. Больше ничего необычного вы не заметили."
},
{
"code": "O-3",
"name": "Отряд 3",
"text": "Приближаясь, Вы осматриваете кирпичное здание с нарисованным сбоку здания мультяшным героем. Переводя взгляд в окно, вы видите детей, разбившихся на группки: кто-то рисует, кто-то бегает, а кто-то просто сидит в сторонке. \n«Вы тоже за тем, что пропало?» — раздаётся голос за спиной. Обернувшись, вы видите мальчика лет 12 с слишком взрослым взглядом. «Лёха говорит, что если что — искать надо в лисах. Только он не договорил... что именно.» Он нервно оглядывается и исчезает за углом, оставив вас с новой загадкой и ощущением, что за вами уже наблюдают."
},
{
"code": "O-4",
"name": "Отряд 4",
"text": "У входа в отряд вы видите десятки пар обуви, аккуратно выставленных в ряд. Среди них вы сразу замечаете кроссовки с характерным зигзагообразным протектором, слегка запачканные грязью и... чем-то тёмным у носка. «Это Катины!» — оживляется девочка с косичками, тыча пальцем в обувь. — «Она их всегда носит, даже когда дождь!»"
},
{
"code": "П",
"name": "Площадь",
"text": "Площадь в лагере, развивается флаг России и флаг лагеря — зелёное полотно с белой сосной. Чисто выметен асфальт. Музыку здесь почти не слышно, хотя граммофон висит на ближайшем столбе."
},
{
"code": "С-1",
"name": "Столовая",
"text": "В столовой пахнет хлоркой, висит плакат чистоты. Там вы никого не нашли."
},
{
"code": "С-2",
"name": "Стадион",
"text": "На стадионе вы встречаете детей 3 и 4 отрядов. Вы интересуетесь, почему они не собирают вещи. Вам рассказывают, что их вожатые самые классные на земле, они приучили их к спорту — каждое утро они даже бегали с Катей вокруг стадиона и водонапорной вышки. Но сегодня последний день и Катя почему-то отправила их играть в волейбол, а бегать запретила."
},
{
"code": "Т",
"name": "Туалет",
"text": "За туалетом вы находите пачку сигарет и записку как у Лехи, размер и бумага совпадают. На ней написано «Сегодня вам сильно повезет, не сдавайся и все получится!» Похоже кто-то раздавал печенье с предсказанием.",
"applications": [{ "name": "Газета" }]
},
{
"code": "Ц",
"name": "Цветы",
"text": "Неровный овал, огороженный потрёпанными синими бордюрами, которые когда-то были яркими, но теперь выцвели под солнцем и покрылись трещинами. Земля в одних местах усыпана мелкими камушками, в других – потрескалась от жары, будто жаждет воды. Но вопреки всему здесь цветут бархатцы – жёлтые и оранжевые, как маленькие огоньки."
},
{
"code": "МК",
"name": "Макс Крутов",
"text": "Перед вами парень в рваных джинсах и черной футболке, похожий на музыканта. Говорит, что был в душе вчера во время дискотеки: «Тёма был на дискотеке, а наши все вчера на медляках отжигали. Ну, я и решил помыться. Пока в душ шёл у администрации у Лехи сигарету и стрельнул. Поговорили немного, о чем я вам не могу сказать. Потом мы заметили за туалетом какие-то шорохи, Леха решил проверить, сказал, что за одно и обход сделает, якобы лишним не будет, ответственный наш» — Пока он это рассказывал мимо проходил директор — «Смотрите наш броненосец пиджак скинул, а я думал это его кожа!»."
},
{
"code": "АК",
"name": "Артём Ковалёв",
"text": "«Я следил за детьми в клубе, даже драку девочек разнял — ребята утром подслушали ссору Лехи с Алиной и поддерживали разные стороны, как видите очень яро. Макс отпросился в душ, с парнями вчера спортом был занят весь день»."
},
{
"code": "ДО",
"name": "Даша Орлова",
"text": "«Вчера весь вечер я сидела с детьми которые не пошли на дискотеку. Но те ребята, которые могли это подтвердить, уже уехали домой»."
},
{
"code": "КЛ",
"name": "Кирилл Лебедев",
"text": "«Леху на втором ужине только видел, да и то он мимо прошел. Мы вчера с Аней, Катей и Темой дежурили на дискотеке. Потом сразу пошли на костер, это могла быть самая лучшая смена. Я рассказывал много историй вчера на костре и про историю лагеря и легенды разные. На свечку мы ушли в отряды — вспоминали смену, делились впечатлениями. На улицу больше не выходили, там похолодало, да и не видно уже ничего было — слишком поздно»."
},
{
"code": "АГ",
"name": "Артём Глушко",
"text": "Артём сидит и читает книгу в своем отряде, попутно помогает ребятам собирать чемоданы. Он интересуется, удалось ли что-то узнать, рассказывает, что они с Лехой как-то застали Макса за кражей денег из кассы, и с тех пор в их отношениях была напряженность. Артем предложил вам печенье и пошел дальше помогать ребятам."
},
{
"code": "АС",
"name": "Анна Соколова",
"text": "«Лёха был ответственным человеком и всегда помогал, иногда он делал больше чем от него требовалось. Он мог и веселые старты провести, когда физрук ленится, вёл все мероприятия лагеря со сцены, встречал проверки. Мне кажется, он некоторые проверки даже устраивал сам, чтобы лагерь лучше делать. Директор даже на него скидывал какие-то бумажные дела. Лёха был очень начитанный хоть и учился на математика, любила с ним поболтать»."
},
{
"code": "КС",
"name": "Катя Светлова",
"text": "На диване в центре общей комнаты отряда вы встречаете молодую девушку в яркой оранжевой футболке с принтами, шортах и белых носках. Длинные волосы, собранные в небрежный хвост или косу, минимум макияжа. Она сидит в обнимку со старшими мальчиками отряда, смеётся и рассказывает им какую-то историю."
},
{
"code": "АЗ",
"name": "Алина Зайцева",
"text": "Вы находите ее рядом с турниками. Девушка спортивного телосложения сидит на траве, прикрыв лицо капюшоном. Слезы бегут по ее лицу. “Мы встречались, хотели даже пожениться, он последнее время очень злой ходил, эта смена его совсем из колеи выбила. Рассказывать он не хотел, знаю что долго за документами засиживался уже когда все спали”."
},
{
"code": "ВСГ",
"name": "Виктор Сергеевич Громов",
"text": "«Труп обнаружил охранник Виктор Петрович на ночном обходе, позвал меня. Я проверил пульс и позвонил в полицию. Вот вам список работников лагеря. Страшно осознавать что кто-то из них может быть убийцей».",
"applications": [{ "name": "Список работников лагеря" }]
},
{
"code": "ЕО",
"name": "Елена Орлова",
"text": "Очень красивая статная девушка в белом халате встречает вас нежной улыбкой. \n«Во время дискотеки я была в приемной, королевская ночь по статистике самая травмоопасная. Хотя на удивление только одна девочка с температурой, я выдала таблетку и вожатая увела её обратно в отряд»."
},
{
"code": "СС",
"name": "Сергей Смирнов",
"text": "Вы подошли к мужчине среднего роста в спортивном костюме: «Вечером телевизор смотрел, музыка долбила спать не давала. Петрович заходил, мы досмотрели “музыкальный ринг” да и побёг он. На дискотеки я не ходок, да и Лёха сказал помощь не нужна. За день набегался, дел много и не только своих, там помоги, сям помоги, никто ничего не может, вот и помогаю. Устаю, возраст как никак. Петрович попросил, вчера помочь с вывозом мусора, с тех пор в коморке и сидел. Лёху видел последний раз в воскресенье, он сказал зарядку не проводить пущай дети поспят»."
},
{
"code": "ВПБ",
"name": "Виктор Петрович Белов",
"text": "«У меня свой режим: завтрак в 9 утра, вынос мусора в 9 вечера, в 11 вечера обход. Всю дискотеку Лёха сидел в администрации, как с концерта пришел, так и не выходил. В пол десятого я до клуба отходил проверить все ли спокойно во время дискотеки, проверил все и за клубом, площадь посмотрел — минут 30 заняло. Фонари давно у клуба не работают, пришлось с фонариком везде лазить. Тело обнаружил уже на обходе — очень перепугался и сразу в администрацию побежал».",
"applications": [{ "name": "Карта лагеря" }]
},
{
"code": "ВД",
"name": "Вечерний детектив",
"text": "Дело №1 “Последний костёр”\n\nАвтор сценария: \nВладимир Фёдоров\n\nРедакторы:\nДарья Лисовая\nЕкатерина Бокова\nЕкатерина Бутина\nАнастасия Пушкарёва\n\nОзвучка:\nАлексей Демченко\n\nХудожники:\nВладимир Фёдоров\nАлина Заугольникова\n\nРазработчик:\nВладимир Фёдоров\n\nМы желаем вам приятной игры!"
}
]
}
+8
View File
@@ -7,5 +7,13 @@ services:
dockerfile: Dockerfile dockerfile: Dockerfile
ports: ports:
- "8080:8080" - "8080:8080"
- "8090:8090"
- "8100:8100"
- "8110:8110"
volumes:
- data:/data
# environment: # environment:
# - ENV_VAR_NAME=env_var_value # - ENV_VAR_NAME=env_var_value
volumes:
data:
+26 -8
View File
@@ -1,6 +1,8 @@
module evening_detective module evening_detective
go 1.22 go 1.23
toolchain go1.23.10
require ( require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0
@@ -8,11 +10,27 @@ require (
) )
require ( require (
github.com/mattn/go-sqlite3 v1.14.28 github.com/phpdave11/gofpdi v1.0.14-0.20211212211723-1f10f9844311 // indirect
golang.org/x/net v0.23.0 // indirect github.com/pkg/errors v0.8.1 // indirect
golang.org/x/sys v0.18.0 // indirect )
golang.org/x/text v0.15.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
google.golang.org/protobuf v1.34.1 // indirect github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/stretchr/testify v1.10.0
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require (
github.com/mattn/go-sqlite3 v1.14.28
github.com/signintech/gopdf v0.32.0
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect
google.golang.org/protobuf v1.34.1
) )
+4
View File
@@ -59,3 +59,7 @@ func (s *Server) GameStop(ctx context.Context, req *proto.GameStopReq) (*proto.G
func (s *Server) GiveApplications(ctx context.Context, req *proto.GiveApplicationsReq) (*proto.GiveApplicationsRsp, error) { func (s *Server) GiveApplications(ctx context.Context, req *proto.GiveApplicationsReq) (*proto.GiveApplicationsRsp, error) {
return s.services.GiveApplications(ctx, req) return s.services.GiveApplications(ctx, req)
} }
func (s *Server) DownloadTeamsQrCodesFile(ctx context.Context, req *proto.DownloadTeamsQrCodesFileReq) (*proto.DownloadTeamsQrCodesFileRsp, error) {
return s.services.DownloadTeamsQrCodesFile(ctx, req)
}
+19
View File
@@ -0,0 +1,19 @@
package config
import "os"
func GetStoryFilepath() string {
storyFilename := os.Getenv("STORY_FILENAME")
if storyFilename != "" {
return storyFilename
}
return "./data/story/story.json"
}
func GetDBFilepath() string {
storyFilename := os.Getenv("DB_FILENAME")
if storyFilename != "" {
return storyFilename
}
return "data/db/store.db"
}
+2 -2
View File
@@ -1,7 +1,7 @@
package models package models
type Game struct { type Game struct {
StartTime int64
EndTime int64
State string State string
StartTime string
EndTime string
} }
+42
View File
@@ -1,7 +1,49 @@
package models package models
import (
"fmt"
"net"
"net/url"
)
type Team struct { type Team struct {
ID int64 ID int64
Name string Name string
Password string Password string
} }
func (t *Team) GetTeamUrl() (string, error) {
ips, err := getLocalIPs()
if err != nil {
return "", err
}
ip := ips[0]
u := fmt.Sprintf("http://%s:8100?name=%s&password=%s", ip, url.PathEscape(t.Name), t.Password)
return u, nil
}
func getLocalIPs() ([]string, error) {
var ips []string
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok {
continue
}
ip := ipNet.IP
if ip.IsLoopback() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() {
continue
}
if ipv4 := ip.To4(); ipv4 != nil {
ips = append(ips, ipv4.String())
}
}
return ips, nil
}
+6 -1
View File
@@ -4,6 +4,7 @@ import (
"evening_detective/internal/models" "evening_detective/internal/models"
"evening_detective/internal/services/story_service" "evening_detective/internal/services/story_service"
"evening_detective/proto" "evening_detective/proto"
"strings"
) )
func mapTeamsToTeamAdvanced(team *models.Team) *proto.TeamAdvanced { func mapTeamsToTeamAdvanced(team *models.Team) *proto.TeamAdvanced {
@@ -24,7 +25,7 @@ func mapTeamsToTeamFull(team *models.Team) *proto.TeamFull {
func mapProtoTeamsToTeam(team *proto.Team) *models.Team { func mapProtoTeamsToTeam(team *proto.Team) *models.Team {
return &models.Team{ return &models.Team{
Name: team.Name, Name: clearTeamName(team.Name),
} }
} }
@@ -85,3 +86,7 @@ func mapProtoApplicationToApplication(items *proto.Application) *models.Applicat
ID: items.Id, ID: items.Id,
} }
} }
func clearTeamName(code string) string {
return strings.TrimSpace(code)
}
+134
View File
@@ -0,0 +1,134 @@
package pdf_service
import (
"bytes"
"evening_detective/internal/models"
"strings"
"embed"
"github.com/signintech/gopdf"
"github.com/skip2/go-qrcode"
)
//go:embed JetBrainsMono-Medium.ttf
var f embed.FS
func CreateTeamsPdf(teams []*models.Team) ([]byte, error) {
pdf := &gopdf.GoPdf{}
pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4}) // W: 595, H: 842
file, err := f.Open("JetBrainsMono-Medium.ttf")
if err != nil {
return nil, err
}
if err := pdf.AddTTFFontByReader("main", file); err != nil {
return nil, err
}
if err := pdf.SetFont("main", "", 10); err != nil {
return nil, err
}
countOnPage := 9
padding := 17.
xDelta := 187.
yDelta := 260.
for i, team := range teams {
if i%countOnPage == 0 {
pdf.AddPage()
pdf.SetPage(1 + i/countOnPage)
}
y := (padding + 15) + yDelta*float64(i%countOnPage/3)
x := padding + xDelta*float64(i%3)
url, err := team.GetTeamUrl()
if err != nil {
return nil, err
}
if err := printTextCenter(pdf, "Подключите Wi-Fi", xDelta-6, x+3, y); err != nil {
return nil, err
}
if err := printTextCenter(pdf, "Имя: evening_detective", xDelta-6, x+3, 15+y); err != nil {
return nil, err
}
if err := printTextCenter(pdf, "Пароль: 12345678", xDelta-6, x+3, 30+y); err != nil {
return nil, err
}
if err := printQR(pdf, url, x+21, 65+y); err != nil {
return nil, err
}
if err := printTextCenter(pdf, "Войдите в приложение по qr", xDelta-6, x+3, 55+y); err != nil {
return nil, err
}
if err := printTextCenter(pdf, team.Name, xDelta-6, x+3, 55+y+150); err != nil {
return nil, err
}
}
buffer := &bytes.Buffer{}
_, err = pdf.WriteTo(buffer)
return buffer.Bytes(), err
}
func printQR(pdf *gopdf.GoPdf, url string, x, y float64) error {
png, err := qrcode.Encode(url, qrcode.Medium, 256)
if err != nil {
return err
}
imgHolder, err := gopdf.ImageHolderByBytes(png)
if err != nil {
return err
}
err = pdf.ImageByHolder(imgHolder, x, y, &gopdf.Rect{W: 145, H: 145})
if err != nil {
return err
}
return nil
}
func printTextCenter(pdf *gopdf.GoPdf, text string, pageWidth, x, y float64) error {
lines := splitTextByWords(pdf, text, pageWidth)
for i, line := range lines {
lineWidth, err := pdf.MeasureTextWidth(line)
if err != nil {
return err
}
xLine := x + (pageWidth-lineWidth)/2
yLine := y + 15*float64(i)
pdf.SetXY(xLine, yLine)
pdf.Cell(nil, line)
}
return nil
}
func splitTextByWords(pdf *gopdf.GoPdf, text string, maxWidth float64) []string {
words := strings.Fields(text)
var lines []string
var currentLine string
for _, word := range words {
testLine := currentLine
if testLine != "" {
testLine += " " + word
} else {
testLine = word
}
width, _ := pdf.MeasureTextWidth(testLine)
if width <= maxWidth {
currentLine = testLine
} else {
if currentLine != "" {
lines = append(lines, currentLine)
}
currentLine = word
}
}
if currentLine != "" {
lines = append(lines, currentLine)
}
return lines
}
+67 -23
View File
@@ -5,6 +5,7 @@ import (
"database/sql" "database/sql"
"errors" "errors"
"evening_detective/internal/models" "evening_detective/internal/models"
"log"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
@@ -13,30 +14,35 @@ type Repository struct {
db *sql.DB db *sql.DB
} }
func NewRepository() (*Repository, error) { func NewRepository(filepath string) (*Repository, error) {
db, err := sql.Open("sqlite3", "store.db") db, err := sql.Open("sqlite3", filepath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = db.Exec("CREATE TABLE IF NOT EXISTS teams (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password TEXT);") log.Printf("load db from: %s", filepath)
_, err = db.Exec("CREATE TABLE IF NOT EXISTS teams (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL CHECK(length(trim(name)) > 0), password TEXT);")
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = db.Exec("CREATE TABLE IF NOT EXISTS actions (id INTEGER PRIMARY KEY AUTOINCREMENT, place TEXT, teamId INTEGER);") _, err = db.Exec("CREATE TABLE IF NOT EXISTS actions (id INTEGER PRIMARY KEY AUTOINCREMENT, place TEXT, teamId INTEGER, FOREIGN KEY (teamId) REFERENCES teams(id) ON DELETE CASCADE);")
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = db.Exec("CREATE TABLE IF NOT EXISTS applications (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, teamId INTEGER, state TEXT);") _, err = db.Exec("CREATE TABLE IF NOT EXISTS applications (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, teamId INTEGER, state TEXT, FOREIGN KEY (teamId) REFERENCES teams(id) ON DELETE CASCADE);")
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = db.Exec("CREATE TABLE IF NOT EXISTS games (id INTEGER PRIMARY KEY AUTOINCREMENT, state TEXT, startAt TIMESTAMP, endAt TIMESTAMP);") _, err = db.Exec("CREATE TABLE IF NOT EXISTS games (id INTEGER PRIMARY KEY AUTOINCREMENT, state TEXT, startAt TEXT, endAt TEXT);")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Repository{db: db}, nil return &Repository{db: db}, nil
} }
func (r *Repository) Close() {
r.db.Close()
}
func (r *Repository) GetTeams(ctx context.Context) ([]*models.Team, error) { func (r *Repository) GetTeams(ctx context.Context) ([]*models.Team, error) {
rows, err := r.db.Query("select id, name, password from teams") rows, err := r.db.Query("select id, name, password from teams")
if err != nil { if err != nil {
@@ -121,19 +127,36 @@ func (r *Repository) GetTeam(ctx context.Context, teamId any, password any) (*mo
return teams[0], nil return teams[0], nil
} }
func (r *Repository) AddApplications(ctx context.Context, actions []*models.Action) error { func (r *Repository) AddApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
for _, action := range actions { for _, application := range applications {
for _, application := range action.Applications { _, err := r.db.Exec("insert into applications (name, teamId, state) values ($1, $2, $3)", application.Name, teamId, application.State)
_, err := r.db.Exec("insert into applications (name, teamId, state) values ($1, $2, $3)", application.Name, action.TeamID, application.State)
if err != nil { if err != nil {
return err return err
} }
} }
}
return nil return nil
} }
func (r *Repository) GetApplications(ctx context.Context, teamId int64, state string) ([]*models.Application, error) { func (r *Repository) GetApplications(ctx context.Context, teamId int64) ([]*models.Application, error) {
rows, err := r.db.Query("select id, name from applications where teamId = $1", teamId)
if err != nil {
return nil, err
}
defer rows.Close()
applications := []*models.Application{}
for rows.Next() {
item := &models.Application{}
err := rows.Scan(&item.ID, &item.Name)
if err != nil {
return nil, err
}
applications = append(applications, item)
}
return applications, nil
}
func (r *Repository) GetApplicationsByState(ctx context.Context, teamId int64, state string) ([]*models.Application, error) {
rows, err := r.db.Query("select id, name from applications where teamId = $1 and state = $2", teamId, state) rows, err := r.db.Query("select id, name from applications where teamId = $1 and state = $2", teamId, state)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -162,31 +185,52 @@ func (r *Repository) GiveApplications(ctx context.Context, teamId int64, applica
return nil return nil
} }
func (r *Repository) GetGame(ctx context.Context) (string, error) { func (r *Repository) GetGame(ctx context.Context) (*models.Game, error) {
rows, err := r.db.Query("select state from games limit 1") rows, err := r.db.Query("select state, startAt, endAt from games limit 1")
if err != nil { if err != nil {
return "", err return nil, err
} }
defer rows.Close() defer rows.Close()
state := "" game := &models.Game{}
if rows.Next() { if rows.Next() {
err := rows.Scan(&state) err := rows.Scan(&game.State, &game.StartTime, &game.EndTime)
if err != nil { if err != nil {
return "", err return nil, err
} }
return state, nil return game, nil
} }
state = "NEW" state := "NEW"
_, err = r.db.Exec("insert into games (state) values ($1)", state) _, err = r.db.Exec("insert into games (state, startAt, endAt) values ($1, '', '')", state)
if err != nil { if err != nil {
return "", err return nil, err
} }
return state, nil game.State = state
return game, nil
} }
func (r *Repository) GameUpdateState(ctx context.Context, state string) error { func (r *Repository) GameUpdateState(ctx context.Context, state string) error {
game, err := r.GetGame(ctx)
if err != nil {
return err
}
switch state {
case "RUN":
if game.StartTime == "" {
_, err := r.db.Exec("update games set state = $1, startAt = datetime('now', 'localtime')", state)
return err
}
_, err := r.db.Exec("update games set state = $1", state) _, err := r.db.Exec("update games set state = $1", state)
return err return err
case "STOP":
_, err := r.db.Exec("update games set state = $1, endAt = datetime('now', 'localtime')", state)
return err
}
return nil
}
func (r *Repository) DeleteAllTeams(ctx context.Context) error {
_, err := r.db.Exec("delete from teams where 1")
return err
} }
+48 -46
View File
@@ -6,11 +6,11 @@ import (
"encoding/json" "encoding/json"
"evening_detective/internal/models" "evening_detective/internal/models"
"evening_detective/internal/modules/password" "evening_detective/internal/modules/password"
"evening_detective/internal/services/pdf_service"
"evening_detective/internal/services/story_service" "evening_detective/internal/services/story_service"
"evening_detective/proto" "evening_detective/proto"
"fmt" "fmt"
"net" "time"
"net/url"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
@@ -41,11 +41,15 @@ func (s *Services) GiveApplications(ctx context.Context, req *proto.GiveApplicat
} }
func (s *Services) GetGame(ctx context.Context, _ *proto.GetGameReq) (*proto.GetGameRsp, error) { func (s *Services) GetGame(ctx context.Context, _ *proto.GetGameReq) (*proto.GetGameRsp, error) {
state, err := s.repository.GetGame(ctx) game, err := s.repository.GetGame(ctx)
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, err.Error()) return nil, status.Errorf(codes.Internal, err.Error())
} }
return &proto.GetGameRsp{State: state}, nil return &proto.GetGameRsp{
State: game.State,
StartAt: game.StartTime,
EndAt: game.EndTime,
}, nil
} }
func (s *Services) GameStart(ctx context.Context, _ *proto.GameStartReq) (*proto.GameStartRsp, error) { func (s *Services) GameStart(ctx context.Context, _ *proto.GameStartReq) (*proto.GameStartRsp, error) {
@@ -78,10 +82,30 @@ func (s *Services) AddAction(ctx context.Context, req *proto.AddActionReq) (*pro
if err := s.repository.AddActions(ctx, team.ID, actions); err != nil { if err := s.repository.AddActions(ctx, team.ID, actions); err != nil {
return nil, status.Errorf(codes.Internal, err.Error()) return nil, status.Errorf(codes.Internal, err.Error())
} }
if err := s.repository.AddApplications(ctx, actions); err != nil { currentApplications, err := s.repository.GetApplications(ctx, team.ID)
if err != nil {
return nil, err
}
newApplications := make([]*models.Application, 0, len(actions))
for _, action := range actions {
for _, actionApplication := range action.Applications {
f := false
for _, currentApplication := range currentApplications {
if currentApplication.Name == actionApplication.Name {
f = true
}
}
if !f {
newApplications = append(newApplications, actionApplication)
}
}
}
if err := s.repository.AddApplications(ctx, team.ID, newApplications); err != nil {
return nil, status.Errorf(codes.Internal, err.Error()) return nil, status.Errorf(codes.Internal, err.Error())
} }
log(team, "add action", actions) addLog(team, "add action", actions)
return &proto.AddActionRsp{}, nil return &proto.AddActionRsp{}, nil
} }
@@ -129,16 +153,16 @@ func (s *Services) GetTeams(ctx context.Context, _ *proto.GetTeamsReq) (*proto.G
if err != nil { if err != nil {
return nil, err return nil, err
} }
newTeam.Url, err = getTeamUrl(team) newTeam.Url, err = team.GetTeamUrl()
if err != nil { if err != nil {
return nil, err return nil, err
} }
newTeam.SpendTime = int64(len(actions)) newTeam.SpendTime = int64(len(actions))
applications, err := s.repository.GetApplications(ctx, team.ID, "NEW") currentApplications, err := s.repository.GetApplicationsByState(ctx, team.ID, "NEW")
if err != nil { if err != nil {
return nil, err return nil, err
} }
newTeam.Applications = mapApplicationsToProtoApplications(applications) newTeam.Applications = mapApplicationsToProtoApplications(currentApplications)
res = append(res, newTeam) res = append(res, newTeam)
} }
return &proto.GetTeamsRsp{Teams: res}, err return &proto.GetTeamsRsp{Teams: res}, err
@@ -162,6 +186,20 @@ func (s *Services) AddTeams(ctx context.Context, req *proto.AddTeamsReq) (*proto
return &proto.AddTeamsRsp{Teams: res}, err return &proto.AddTeamsRsp{Teams: res}, err
} }
func (s *Services) DownloadTeamsQrCodesFile(ctx context.Context, req *proto.DownloadTeamsQrCodesFileReq) (*proto.DownloadTeamsQrCodesFileRsp, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
teams, err := s.repository.GetTeams(ctx)
if err != nil {
return nil, err
}
b, err := pdf_service.CreateTeamsPdf(teams)
if err != nil {
return nil, err
}
return &proto.DownloadTeamsQrCodesFileRsp{Result: b}, nil
}
func (s *Services) getTeam(ctx context.Context) (*models.Team, error) { func (s *Services) getTeam(ctx context.Context) (*models.Team, error) {
md, ok := metadata.FromIncomingContext(ctx) md, ok := metadata.FromIncomingContext(ctx)
if !ok { if !ok {
@@ -190,45 +228,9 @@ func (s *Services) getTeam(ctx context.Context) (*models.Team, error) {
return team, nil return team, nil
} }
func log(team *models.Team, action string, v any) { func addLog(team *models.Team, action string, v any) {
vJson, err := json.Marshal(v) vJson, err := json.Marshal(v)
if err == nil { if err == nil {
fmt.Printf("Team %s: %s %s\n", team.Name, action, string(vJson)) fmt.Printf("Team %s: %s %s\n", team.Name, action, string(vJson))
} }
} }
func getTeamUrl(team *models.Team) (string, error) {
ips, err := getLocalIPs()
if err != nil {
return "", err
}
ip := ips[0]
u := fmt.Sprintf("http://%s:8100?name=%s&password=%s", ip, url.PathEscape(team.Name), team.Password)
return u, nil
}
func getLocalIPs() ([]string, error) {
var ips []string
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok {
continue
}
ip := ipNet.IP
if ip.IsLoopback() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() {
continue
}
if ipv4 := ip.To4(); ipv4 != nil {
ips = append(ips, ipv4.String())
}
}
return ips, nil
}
+6 -3
View File
@@ -2,6 +2,8 @@ package story_service
import ( import (
"encoding/json" "encoding/json"
"fmt"
"log"
"os" "os"
"strings" "strings"
) )
@@ -43,11 +45,12 @@ type StoryService struct {
story *Story story *Story
} }
func NewStoryService() (*StoryService, error) { func NewStoryService(filepath string) (*StoryService, error) {
data, err := os.ReadFile("./story/story.json") data, err := os.ReadFile(filepath)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("story file %s not found", filepath)
} }
log.Printf("load story from: %s", filepath)
story := &Story{} story := &Story{}
if err := json.Unmarshal(data, story); err != nil { if err := json.Unmarshal(data, story); err != nil {
return nil, err return nil, err
+33
View File
@@ -0,0 +1,33 @@
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetApplication(t *testing.T) {
defer deleteTeams(t)
client, close := getClient()
defer close()
createTeamResp, err := createTeam(client, "Тестовая команда")
assert.Nil(t, err, "запрос отправлену спешно")
team := createTeamResp.Teams[0]
addAction(t, client, team.Name, team.Password, "Т-1")
getTeamsResp, err := getTeams(client)
assert.Nil(t, err, "запрос отправлен успешно")
applications := getTeamsResp.Teams[0].Applications
assert.Equal(t, 1, len(applications), "выдать 1 приложение")
addAction(t, client, team.Name, team.Password, "Т-1")
getTeamsResp, err = getTeams(client)
assert.Nil(t, err, "запрос отправлен успешно")
applications = getTeamsResp.Teams[0].Applications
assert.Equal(t, 1, len(applications), "выдать 1 приложение")
}
+81
View File
@@ -0,0 +1,81 @@
package tests
import (
"context"
"encoding/base64"
"log"
"testing"
"time"
"evening_detective/internal/config"
"evening_detective/internal/services"
pb "evening_detective/proto"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func getClient() (pb.EveningDetectiveClient, func() error) {
conn, err := grpc.Dial("localhost:8080", grpc.WithInsecure())
if err != nil {
log.Fatalf("Не удалось подключиться к серверу: %v", err)
}
return pb.NewEveningDetectiveClient(conn), conn.Close
}
func getContext() (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), time.Second)
}
func deleteTeams(t *testing.T) {
dbFilepath := config.GetDBFilepath()
repository, err := services.NewRepository(dbFilepath)
if err != nil {
assert.Nil(t, err, "подключение к базе")
}
defer repository.Close()
err = repository.DeleteAllTeams(context.Background())
assert.Nil(t, err, "команды удалены")
}
func createTeam(client pb.EveningDetectiveClient, name string) (*pb.AddTeamsRsp, error) {
ctx, cancel := getContext()
defer cancel()
req := &pb.AddTeamsReq{
Teams: []*pb.Team{
{Name: name},
},
}
return client.AddTeams(ctx, req)
}
func getTeams(client pb.EveningDetectiveClient) (*pb.GetTeamsRsp, error) {
ctx, cancel := getContext()
defer cancel()
req := &pb.GetTeamsReq{}
return client.GetTeams(ctx, req)
}
func addAction(
t *testing.T,
client pb.EveningDetectiveClient,
name string,
password string,
place string,
) {
ctx, cancel := getContext()
defer cancel()
md := metadata.Pairs(
"team-id", base64.StdEncoding.EncodeToString([]byte(name)),
"password", password,
)
ctx = metadata.NewOutgoingContext(ctx, md)
req := &pb.AddActionReq{
Place: place,
}
_, err := client.AddAction(ctx, req)
assert.Nil(t, err, "запрос отправлен успешно")
}
+23
View File
@@ -0,0 +1,23 @@
package tests
import (
"log"
"testing"
pb "evening_detective/proto"
)
func TestPing(t *testing.T) {
client, close := getClient()
defer close()
ctx, cancel := getContext()
defer cancel()
req := &pb.PingReq{}
_, err := client.Ping(ctx, req)
if err != nil {
log.Fatalf("Ошибка выполнения запроса: %v", err)
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"places": [
{
"code": "Т-1",
"name": "Точка 1",
"text": "Текст точки 1",
"applications": [{ "name": "application 1" }]
}
]
}
+79
View File
@@ -0,0 +1,79 @@
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCreateTeam(t *testing.T) {
defer deleteTeams(t)
client, close := getClient()
defer close()
createTeamResp, err := createTeam(client, "Тестовая команда")
assert.Nil(t, err, "запрос отправлен успешно")
assert.Equal(t, len(createTeamResp.Teams), 1, "количество команд равно 1")
assert.Equal(t, createTeamResp.Teams[0].Name, "Тестовая команда")
getTeamsResp, err := getTeams(client)
assert.Nil(t, err, "запрос отправлен успешно")
assert.Equal(t, len(getTeamsResp.Teams), 1, "количество команд равно 1")
assert.Equal(t, getTeamsResp.Teams[0].Name, "Тестовая команда")
}
func TestCreateTeamWithEmptyName(t *testing.T) {
defer deleteTeams(t)
client, close := getClient()
defer close()
_, err := createTeam(client, "")
assert.NotNil(t, err, "запрос не удался")
}
func TestCreateTwoTeam(t *testing.T) {
defer deleteTeams(t)
client, close := getClient()
defer close()
_, err := createTeam(client, "Тестовая команда 1")
assert.Nil(t, err, "запрос отправлен успешно")
_, err = createTeam(client, "Тестовая команда 2")
assert.Nil(t, err, "запрос отправлен успешно")
getTeamsResp, err := getTeams(client)
assert.Nil(t, err, "запрос отправлен успешно")
assert.Equal(t, len(getTeamsResp.Teams), 2, "количество команд равно 2")
assert.Equal(t, getTeamsResp.Teams[0].Name, "Тестовая команда 1")
assert.Equal(t, getTeamsResp.Teams[1].Name, "Тестовая команда 2")
}
func TestCreateTwoEqTeam(t *testing.T) {
defer deleteTeams(t)
client, close := getClient()
defer close()
_, err := createTeam(client, "Тестовая команда")
assert.Nil(t, err, "запрос отправлен успешно")
_, err = createTeam(client, "Тестовая команда")
assert.NotNil(t, err, "запрос не удался")
}
func TestCreateTwoBadTeam(t *testing.T) {
defer deleteTeams(t)
client, close := getClient()
defer close()
_, err := createTeam(client, "Тестовая команда")
assert.Nil(t, err, "запрос отправлен успешно")
_, err = createTeam(client, "Тестовая команда ")
assert.NotNil(t, err, "запрос не удался")
}
+228 -81
View File
@@ -922,6 +922,8 @@ type GetGameRsp struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
State string `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` State string `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"`
StartAt string `protobuf:"bytes,2,opt,name=startAt,proto3" json:"startAt,omitempty"`
EndAt string `protobuf:"bytes,3,opt,name=endAt,proto3" json:"endAt,omitempty"`
} }
func (x *GetGameRsp) Reset() { func (x *GetGameRsp) Reset() {
@@ -963,6 +965,20 @@ func (x *GetGameRsp) GetState() string {
return "" return ""
} }
func (x *GetGameRsp) GetStartAt() string {
if x != nil {
return x.StartAt
}
return ""
}
func (x *GetGameRsp) GetEndAt() string {
if x != nil {
return x.EndAt
}
return ""
}
type GameStartReq struct { type GameStartReq struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -1217,6 +1233,91 @@ func (*GiveApplicationsRsp) Descriptor() ([]byte, []int) {
return file_main_proto_rawDescGZIP(), []int{24} return file_main_proto_rawDescGZIP(), []int{24}
} }
type DownloadTeamsQrCodesFileReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DownloadTeamsQrCodesFileReq) Reset() {
*x = DownloadTeamsQrCodesFileReq{}
if protoimpl.UnsafeEnabled {
mi := &file_main_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DownloadTeamsQrCodesFileReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DownloadTeamsQrCodesFileReq) ProtoMessage() {}
func (x *DownloadTeamsQrCodesFileReq) ProtoReflect() protoreflect.Message {
mi := &file_main_proto_msgTypes[25]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DownloadTeamsQrCodesFileReq.ProtoReflect.Descriptor instead.
func (*DownloadTeamsQrCodesFileReq) Descriptor() ([]byte, []int) {
return file_main_proto_rawDescGZIP(), []int{25}
}
type DownloadTeamsQrCodesFileRsp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Result []byte `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"`
}
func (x *DownloadTeamsQrCodesFileRsp) Reset() {
*x = DownloadTeamsQrCodesFileRsp{}
if protoimpl.UnsafeEnabled {
mi := &file_main_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DownloadTeamsQrCodesFileRsp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DownloadTeamsQrCodesFileRsp) ProtoMessage() {}
func (x *DownloadTeamsQrCodesFileRsp) ProtoReflect() protoreflect.Message {
mi := &file_main_proto_msgTypes[26]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DownloadTeamsQrCodesFileRsp.ProtoReflect.Descriptor instead.
func (*DownloadTeamsQrCodesFileRsp) Descriptor() ([]byte, []int) {
return file_main_proto_rawDescGZIP(), []int{26}
}
func (x *DownloadTeamsQrCodesFileRsp) GetResult() []byte {
if x != nil {
return x.Result
}
return nil
}
var File_main_proto protoreflect.FileDescriptor var File_main_proto protoreflect.FileDescriptor
var file_main_proto_rawDesc = []byte{ var file_main_proto_rawDesc = []byte{
@@ -1288,9 +1389,12 @@ var file_main_proto_rawDesc = []byte{
0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41,
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x70, 0x70, 0x6c, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x70, 0x70, 0x6c,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x0c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x47, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x0c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x47,
0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x22, 0x22, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x22, 0x52, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x47, 0x61, 0x6d,
0x65, 0x52, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x65, 0x52, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x0e, 0x0a, 0x0c, 0x47, 0x61, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x74,
0x61, 0x72, 0x74, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x74, 0x61,
0x72, 0x74, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x22, 0x0e, 0x0a, 0x0c, 0x47, 0x61,
0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x22, 0x0e, 0x0a, 0x0c, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x22, 0x0e, 0x0a, 0x0c, 0x47, 0x61,
0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x73, 0x70, 0x22, 0x2f, 0x0a, 0x0b, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x73, 0x70, 0x22, 0x2f, 0x0a, 0x0b, 0x47, 0x61,
0x6d, 0x65, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x69, 0x6d, 0x6d, 0x65, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x69, 0x6d,
@@ -1305,79 +1409,94 @@ var file_main_proto_rawDesc = []byte{
0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x69, 0x76, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x69, 0x76, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x73, 0x70, 0x32, 0xe8, 0x08, 0x0a, 0x10, 0x45, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x73, 0x70, 0x22, 0x1d, 0x0a, 0x1b, 0x44, 0x6f,
0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x51, 0x72, 0x43, 0x6f, 0x64,
0x59, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x20, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x22, 0x35, 0x0a, 0x1b, 0x44, 0x6f, 0x77,
0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x51, 0x72, 0x43, 0x6f, 0x64, 0x65,
0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75,
0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x69, 0x76, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x73, 0x70, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x32, 0x85, 0x0a, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x74, 0x65,
0x93, 0x02, 0x07, 0x12, 0x05, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x69, 0x0a, 0x08, 0x41, 0x64, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x59, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x20, 0x2e,
0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65,
0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x1a,
0x2e, 0x41, 0x64, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x63, 0x20, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f,
0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x73,
0x70, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x07, 0x12, 0x05, 0x2f, 0x70, 0x69, 0x6e, 0x67,
0x12, 0x69, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x2e, 0x63,
0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74,
0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x52,
0x73, 0x70, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69,
0x74, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x66, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x64, 0x64,
0x73, 0x12, 0x24, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x52, 0x73, 0x70, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b,
0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x66, 0x0a, 0x08, 0x47,
0x65, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e,
0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76,
0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x52, 0x73, 0x70, 0x22, 0x0e, 0x82, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e,
0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x6d, 0x0a,
0x0b, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x43, 0x53, 0x56, 0x12, 0x27, 0x2e, 0x63,
0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74,
0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x43,
0x53, 0x56, 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76,
0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e,
0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x43, 0x53, 0x56, 0x52, 0x73, 0x70, 0x22, 0x0c,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x06, 0x12, 0x04, 0x2f, 0x63, 0x73, 0x76, 0x12, 0x62, 0x0a, 0x07,
0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x12, 0x23, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e,
0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76,
0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x63,
0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74,
0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x73,
0x70, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x07, 0x12, 0x05, 0x2f, 0x74, 0x65, 0x61, 0x6d,
0x12, 0x73, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e,
0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65,
0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73,
0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x52, 0x73, 0x70, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f, 0x74, 0x65,
0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x61, 0x6d, 0x73, 0x12, 0x6d, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x43,
0x64, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x73, 0x70, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x53, 0x56, 0x12, 0x27, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69,
0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x61, 0x63, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x62, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x43, 0x53, 0x56, 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x63, 0x72,
0x12, 0x23, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65,
0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x43, 0x53,
0x6d, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x56, 0x52, 0x73, 0x70, 0x22, 0x0c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x06, 0x12, 0x04, 0x2f, 0x63,
0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x73, 0x76, 0x12, 0x62, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x12, 0x23, 0x2e,
0x47, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x73, 0x70, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65,
0x02, 0x07, 0x12, 0x05, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x12, 0x71, 0x0a, 0x09, 0x47, 0x61, 0x6d, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x52,
0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x25, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69,
0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74,
0x54, 0x65, 0x61, 0x6d, 0x52, 0x73, 0x70, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x07, 0x12,
0x05, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x73, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x41, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e,
0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x64,
0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x61,
0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63,
0x74, 0x69, 0x76, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x73,
0x70, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x74,
0x65, 0x61, 0x6d, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x62, 0x0a, 0x07, 0x47,
0x65, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65,
0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65,
0x2e, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x63, 0x72,
0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65,
0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x65, 0x52, 0x73, 0x70,
0x74, 0x52, 0x73, 0x70, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x07, 0x12, 0x05, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x12,
0x0b, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x6d, 0x0a, 0x08, 0x71, 0x0a, 0x09, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x25, 0x2e, 0x63,
0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x24, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74,
0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74,
0x76, 0x65, 0x2e, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e,
0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x61,
0x6d, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x73, 0x70, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x10, 0x3a, 0x01, 0x2a, 0x22, 0x0b, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x73, 0x74, 0x61,
0x72, 0x74, 0x12, 0x6d, 0x0a, 0x08, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x24,
0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64,
0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x6f, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x6f,
0x70, 0x52, 0x73, 0x70, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65,
0x0a, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x12, 0x97, 0x01, 0x0a, 0x10, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47,
0x47, 0x69, 0x76, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x73, 0x70, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93,
0x12, 0x2c, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x73, 0x74, 0x6f,
0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x69, 0x76, 0x65, 0x41, 0x70, 0x12, 0x97, 0x01, 0x0a, 0x10, 0x47, 0x69, 0x76, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x2c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65,
0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65,
0x2e, 0x47, 0x69, 0x76, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x52, 0x65, 0x71, 0x1a, 0x2c, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65,
0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47,
0x69, 0x76, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52,
0x73, 0x70, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x3a, 0x01, 0x2a, 0x22, 0x1c, 0x2f,
0x74, 0x65, 0x61, 0x6d, 0x73, 0x2f, 0x7b, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x7d, 0x2f, 0x61,
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x9a, 0x01, 0x0a, 0x18,
0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x51, 0x72, 0x43,
0x6f, 0x64, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x34, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73,
0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69,
0x76, 0x65, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73,
0x51, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x34,
0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x2e, 0x63, 0x72, 0x61, 0x62, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64,
0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x47, 0x69, 0x76, 0x65, 0x41, 0x70, 0x70, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61,
0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x73, 0x70, 0x22, 0x27, 0x82, 0xd3, 0x64, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x51, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x46, 0x69, 0x6c,
0xe4, 0x93, 0x02, 0x21, 0x3a, 0x01, 0x2a, 0x22, 0x1c, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x2f, 0x65, 0x52, 0x73, 0x70, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x74,
0x7b, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x7d, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x65, 0x61, 0x6d, 0x73, 0x2f, 0x70, 0x64, 0x66, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x6b, 0x67, 0x2f,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -1392,7 +1511,7 @@ func file_main_proto_rawDescGZIP() []byte {
return file_main_proto_rawDescData return file_main_proto_rawDescData
} }
var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 27)
var file_main_proto_goTypes = []interface{}{ var file_main_proto_goTypes = []interface{}{
(*PingReq)(nil), // 0: crabs.evening_detective.PingReq (*PingReq)(nil), // 0: crabs.evening_detective.PingReq
(*PingRsp)(nil), // 1: crabs.evening_detective.PingRsp (*PingRsp)(nil), // 1: crabs.evening_detective.PingRsp
@@ -1419,6 +1538,8 @@ var file_main_proto_goTypes = []interface{}{
(*GameStopRsp)(nil), // 22: crabs.evening_detective.GameStopRsp (*GameStopRsp)(nil), // 22: crabs.evening_detective.GameStopRsp
(*GiveApplicationsReq)(nil), // 23: crabs.evening_detective.GiveApplicationsReq (*GiveApplicationsReq)(nil), // 23: crabs.evening_detective.GiveApplicationsReq
(*GiveApplicationsRsp)(nil), // 24: crabs.evening_detective.GiveApplicationsRsp (*GiveApplicationsRsp)(nil), // 24: crabs.evening_detective.GiveApplicationsRsp
(*DownloadTeamsQrCodesFileReq)(nil), // 25: crabs.evening_detective.DownloadTeamsQrCodesFileReq
(*DownloadTeamsQrCodesFileRsp)(nil), // 26: crabs.evening_detective.DownloadTeamsQrCodesFileRsp
} }
var file_main_proto_depIdxs = []int32{ var file_main_proto_depIdxs = []int32{
3, // 0: crabs.evening_detective.AddTeamsReq.teams:type_name -> crabs.evening_detective.Team 3, // 0: crabs.evening_detective.AddTeamsReq.teams:type_name -> crabs.evening_detective.Team
@@ -1438,18 +1559,20 @@ var file_main_proto_depIdxs = []int32{
19, // 14: crabs.evening_detective.EveningDetective.GameStart:input_type -> crabs.evening_detective.GameStartReq 19, // 14: crabs.evening_detective.EveningDetective.GameStart:input_type -> crabs.evening_detective.GameStartReq
21, // 15: crabs.evening_detective.EveningDetective.GameStop:input_type -> crabs.evening_detective.GameStopReq 21, // 15: crabs.evening_detective.EveningDetective.GameStop:input_type -> crabs.evening_detective.GameStopReq
23, // 16: crabs.evening_detective.EveningDetective.GiveApplications:input_type -> crabs.evening_detective.GiveApplicationsReq 23, // 16: crabs.evening_detective.EveningDetective.GiveApplications:input_type -> crabs.evening_detective.GiveApplicationsReq
1, // 17: crabs.evening_detective.EveningDetective.Ping:output_type -> crabs.evening_detective.PingRsp 25, // 17: crabs.evening_detective.EveningDetective.DownloadTeamsQrCodesFile:input_type -> crabs.evening_detective.DownloadTeamsQrCodesFileReq
4, // 18: crabs.evening_detective.EveningDetective.AddTeams:output_type -> crabs.evening_detective.AddTeamsRsp 1, // 18: crabs.evening_detective.EveningDetective.Ping:output_type -> crabs.evening_detective.PingRsp
7, // 19: crabs.evening_detective.EveningDetective.GetTeams:output_type -> crabs.evening_detective.GetTeamsRsp 4, // 19: crabs.evening_detective.EveningDetective.AddTeams:output_type -> crabs.evening_detective.AddTeamsRsp
9, // 20: crabs.evening_detective.EveningDetective.GetTeamsCSV:output_type -> crabs.evening_detective.GetTeamsCSVRsp 7, // 20: crabs.evening_detective.EveningDetective.GetTeams:output_type -> crabs.evening_detective.GetTeamsRsp
13, // 21: crabs.evening_detective.EveningDetective.GetTeam:output_type -> crabs.evening_detective.GetTeamRsp 9, // 21: crabs.evening_detective.EveningDetective.GetTeamsCSV:output_type -> crabs.evening_detective.GetTeamsCSVRsp
15, // 22: crabs.evening_detective.EveningDetective.AddAction:output_type -> crabs.evening_detective.AddActionRsp 13, // 22: crabs.evening_detective.EveningDetective.GetTeam:output_type -> crabs.evening_detective.GetTeamRsp
18, // 23: crabs.evening_detective.EveningDetective.GetGame:output_type -> crabs.evening_detective.GetGameRsp 15, // 23: crabs.evening_detective.EveningDetective.AddAction:output_type -> crabs.evening_detective.AddActionRsp
20, // 24: crabs.evening_detective.EveningDetective.GameStart:output_type -> crabs.evening_detective.GameStartRsp 18, // 24: crabs.evening_detective.EveningDetective.GetGame:output_type -> crabs.evening_detective.GetGameRsp
22, // 25: crabs.evening_detective.EveningDetective.GameStop:output_type -> crabs.evening_detective.GameStopRsp 20, // 25: crabs.evening_detective.EveningDetective.GameStart:output_type -> crabs.evening_detective.GameStartRsp
24, // 26: crabs.evening_detective.EveningDetective.GiveApplications:output_type -> crabs.evening_detective.GiveApplicationsRsp 22, // 26: crabs.evening_detective.EveningDetective.GameStop:output_type -> crabs.evening_detective.GameStopRsp
17, // [17:27] is the sub-list for method output_type 24, // 27: crabs.evening_detective.EveningDetective.GiveApplications:output_type -> crabs.evening_detective.GiveApplicationsRsp
7, // [7:17] is the sub-list for method input_type 26, // 28: crabs.evening_detective.EveningDetective.DownloadTeamsQrCodesFile:output_type -> crabs.evening_detective.DownloadTeamsQrCodesFileRsp
18, // [18:29] is the sub-list for method output_type
7, // [7:18] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name 7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee 7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name 0, // [0:7] is the sub-list for field type_name
@@ -1761,6 +1884,30 @@ func file_main_proto_init() {
return nil return nil
} }
} }
file_main_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DownloadTeamsQrCodesFileReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_main_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DownloadTeamsQrCodesFileRsp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
@@ -1768,7 +1915,7 @@ func file_main_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_main_proto_rawDesc, RawDescriptor: file_main_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 25, NumMessages: 27,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
}, },
+69
View File
@@ -285,6 +285,24 @@ func local_request_EveningDetective_GiveApplications_0(ctx context.Context, mars
} }
func request_EveningDetective_DownloadTeamsQrCodesFile_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DownloadTeamsQrCodesFileReq
var metadata runtime.ServerMetadata
msg, err := client.DownloadTeamsQrCodesFile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_EveningDetective_DownloadTeamsQrCodesFile_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DownloadTeamsQrCodesFileReq
var metadata runtime.ServerMetadata
msg, err := server.DownloadTeamsQrCodesFile(ctx, &protoReq)
return msg, metadata, err
}
// RegisterEveningDetectiveHandlerServer registers the http handlers for service EveningDetective to "mux". // RegisterEveningDetectiveHandlerServer registers the http handlers for service EveningDetective to "mux".
// UnaryRPC :call EveningDetectiveServer directly. // UnaryRPC :call EveningDetectiveServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
@@ -541,6 +559,31 @@ func RegisterEveningDetectiveHandlerServer(ctx context.Context, mux *runtime.Ser
}) })
mux.Handle("GET", pattern_EveningDetective_DownloadTeamsQrCodesFile_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)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective.EveningDetective/DownloadTeamsQrCodesFile", runtime.WithHTTPPathPattern("/teams/pdf"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_EveningDetective_DownloadTeamsQrCodesFile_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_EveningDetective_DownloadTeamsQrCodesFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil return nil
} }
@@ -802,6 +845,28 @@ func RegisterEveningDetectiveHandlerClient(ctx context.Context, mux *runtime.Ser
}) })
mux.Handle("GET", pattern_EveningDetective_DownloadTeamsQrCodesFile_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)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective.EveningDetective/DownloadTeamsQrCodesFile", runtime.WithHTTPPathPattern("/teams/pdf"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_EveningDetective_DownloadTeamsQrCodesFile_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_EveningDetective_DownloadTeamsQrCodesFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil return nil
} }
@@ -825,6 +890,8 @@ var (
pattern_EveningDetective_GameStop_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"game", "stop"}, "")) pattern_EveningDetective_GameStop_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"game", "stop"}, ""))
pattern_EveningDetective_GiveApplications_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"teams", "teamId", "applications"}, "")) pattern_EveningDetective_GiveApplications_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"teams", "teamId", "applications"}, ""))
pattern_EveningDetective_DownloadTeamsQrCodesFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"teams", "pdf"}, ""))
) )
var ( var (
@@ -847,4 +914,6 @@ var (
forward_EveningDetective_GameStop_0 = runtime.ForwardResponseMessage forward_EveningDetective_GameStop_0 = runtime.ForwardResponseMessage
forward_EveningDetective_GiveApplications_0 = runtime.ForwardResponseMessage forward_EveningDetective_GiveApplications_0 = runtime.ForwardResponseMessage
forward_EveningDetective_DownloadTeamsQrCodesFile_0 = runtime.ForwardResponseMessage
) )
+37
View File
@@ -247,6 +247,28 @@
] ]
} }
}, },
"/teams/pdf": {
"get": {
"operationId": "EveningDetective_DownloadTeamsQrCodesFile",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/evening_detectiveDownloadTeamsQrCodesFileRsp"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
},
"tags": [
"EveningDetective"
]
}
},
"/teams/{teamId}/applications": { "/teams/{teamId}/applications": {
"post": { "post": {
"operationId": "EveningDetective_GiveApplications", "operationId": "EveningDetective_GiveApplications",
@@ -360,6 +382,15 @@
} }
} }
}, },
"evening_detectiveDownloadTeamsQrCodesFileRsp": {
"type": "object",
"properties": {
"result": {
"type": "string",
"format": "byte"
}
}
},
"evening_detectiveGameStartReq": { "evening_detectiveGameStartReq": {
"type": "object" "type": "object"
}, },
@@ -383,6 +414,12 @@
"properties": { "properties": {
"state": { "state": {
"type": "string" "type": "string"
},
"startAt": {
"type": "string"
},
"endAt": {
"type": "string"
} }
} }
}, },
+37
View File
@@ -29,6 +29,7 @@ const (
EveningDetective_GameStart_FullMethodName = "/crabs.evening_detective.EveningDetective/GameStart" EveningDetective_GameStart_FullMethodName = "/crabs.evening_detective.EveningDetective/GameStart"
EveningDetective_GameStop_FullMethodName = "/crabs.evening_detective.EveningDetective/GameStop" EveningDetective_GameStop_FullMethodName = "/crabs.evening_detective.EveningDetective/GameStop"
EveningDetective_GiveApplications_FullMethodName = "/crabs.evening_detective.EveningDetective/GiveApplications" EveningDetective_GiveApplications_FullMethodName = "/crabs.evening_detective.EveningDetective/GiveApplications"
EveningDetective_DownloadTeamsQrCodesFile_FullMethodName = "/crabs.evening_detective.EveningDetective/DownloadTeamsQrCodesFile"
) )
// EveningDetectiveClient is the client API for EveningDetective service. // EveningDetectiveClient is the client API for EveningDetective service.
@@ -45,6 +46,7 @@ type EveningDetectiveClient interface {
GameStart(ctx context.Context, in *GameStartReq, opts ...grpc.CallOption) (*GameStartRsp, error) GameStart(ctx context.Context, in *GameStartReq, opts ...grpc.CallOption) (*GameStartRsp, error)
GameStop(ctx context.Context, in *GameStopReq, opts ...grpc.CallOption) (*GameStopRsp, error) GameStop(ctx context.Context, in *GameStopReq, opts ...grpc.CallOption) (*GameStopRsp, error)
GiveApplications(ctx context.Context, in *GiveApplicationsReq, opts ...grpc.CallOption) (*GiveApplicationsRsp, error) GiveApplications(ctx context.Context, in *GiveApplicationsReq, opts ...grpc.CallOption) (*GiveApplicationsRsp, error)
DownloadTeamsQrCodesFile(ctx context.Context, in *DownloadTeamsQrCodesFileReq, opts ...grpc.CallOption) (*DownloadTeamsQrCodesFileRsp, error)
} }
type eveningDetectiveClient struct { type eveningDetectiveClient struct {
@@ -145,6 +147,15 @@ func (c *eveningDetectiveClient) GiveApplications(ctx context.Context, in *GiveA
return out, nil return out, nil
} }
func (c *eveningDetectiveClient) DownloadTeamsQrCodesFile(ctx context.Context, in *DownloadTeamsQrCodesFileReq, opts ...grpc.CallOption) (*DownloadTeamsQrCodesFileRsp, error) {
out := new(DownloadTeamsQrCodesFileRsp)
err := c.cc.Invoke(ctx, EveningDetective_DownloadTeamsQrCodesFile_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// EveningDetectiveServer is the server API for EveningDetective service. // EveningDetectiveServer is the server API for EveningDetective service.
// All implementations must embed UnimplementedEveningDetectiveServer // All implementations must embed UnimplementedEveningDetectiveServer
// for forward compatibility // for forward compatibility
@@ -159,6 +170,7 @@ type EveningDetectiveServer interface {
GameStart(context.Context, *GameStartReq) (*GameStartRsp, error) GameStart(context.Context, *GameStartReq) (*GameStartRsp, error)
GameStop(context.Context, *GameStopReq) (*GameStopRsp, error) GameStop(context.Context, *GameStopReq) (*GameStopRsp, error)
GiveApplications(context.Context, *GiveApplicationsReq) (*GiveApplicationsRsp, error) GiveApplications(context.Context, *GiveApplicationsReq) (*GiveApplicationsRsp, error)
DownloadTeamsQrCodesFile(context.Context, *DownloadTeamsQrCodesFileReq) (*DownloadTeamsQrCodesFileRsp, error)
mustEmbedUnimplementedEveningDetectiveServer() mustEmbedUnimplementedEveningDetectiveServer()
} }
@@ -196,6 +208,9 @@ func (UnimplementedEveningDetectiveServer) GameStop(context.Context, *GameStopRe
func (UnimplementedEveningDetectiveServer) GiveApplications(context.Context, *GiveApplicationsReq) (*GiveApplicationsRsp, error) { func (UnimplementedEveningDetectiveServer) GiveApplications(context.Context, *GiveApplicationsReq) (*GiveApplicationsRsp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GiveApplications not implemented") return nil, status.Errorf(codes.Unimplemented, "method GiveApplications not implemented")
} }
func (UnimplementedEveningDetectiveServer) DownloadTeamsQrCodesFile(context.Context, *DownloadTeamsQrCodesFileReq) (*DownloadTeamsQrCodesFileRsp, error) {
return nil, status.Errorf(codes.Unimplemented, "method DownloadTeamsQrCodesFile not implemented")
}
func (UnimplementedEveningDetectiveServer) mustEmbedUnimplementedEveningDetectiveServer() {} func (UnimplementedEveningDetectiveServer) mustEmbedUnimplementedEveningDetectiveServer() {}
// UnsafeEveningDetectiveServer may be embedded to opt out of forward compatibility for this service. // UnsafeEveningDetectiveServer may be embedded to opt out of forward compatibility for this service.
@@ -389,6 +404,24 @@ func _EveningDetective_GiveApplications_Handler(srv interface{}, ctx context.Con
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _EveningDetective_DownloadTeamsQrCodesFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DownloadTeamsQrCodesFileReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EveningDetectiveServer).DownloadTeamsQrCodesFile(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: EveningDetective_DownloadTeamsQrCodesFile_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EveningDetectiveServer).DownloadTeamsQrCodesFile(ctx, req.(*DownloadTeamsQrCodesFileReq))
}
return interceptor(ctx, in, info, handler)
}
// EveningDetective_ServiceDesc is the grpc.ServiceDesc for EveningDetective service. // EveningDetective_ServiceDesc is the grpc.ServiceDesc for EveningDetective service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@@ -436,6 +469,10 @@ var EveningDetective_ServiceDesc = grpc.ServiceDesc{
MethodName: "GiveApplications", MethodName: "GiveApplications",
Handler: _EveningDetective_GiveApplications_Handler, Handler: _EveningDetective_GiveApplications_Handler,
}, },
{
MethodName: "DownloadTeamsQrCodesFile",
Handler: _EveningDetective_DownloadTeamsQrCodesFile_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "main.proto", Metadata: "main.proto",
BIN
View File
Binary file not shown.
@@ -1 +0,0 @@
import{_ as o,c as s,a as t,o as a}from"./index-CdxbIVaR.js";const n={},c={class:"about"};function r(_,e){return a(),s("div",c,e[0]||(e[0]=[t("h1",null,"This is an about page",-1)]))}const l=o(n,[["render",r]]);export{l as default};
-1
View File
@@ -1 +0,0 @@
:root{--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, .29);--vt-c-divider-light-2: rgba(60, 60, 60, .12);--vt-c-divider-dark-1: rgba(84, 84, 84, .65);--vt-c-divider-dark-2: rgba(84, 84, 84, .48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, .66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, .64);--main-color: rgba(34, 50, 60, 1);--second-color: rgb(136, 105, 31);--main-back-color: rgba(240, 240, 240, 1);--main-back-item-color: rgba(254, 254, 254, 1)}:root{--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px}*,*:before,*:after{box-sizing:border-box;margin:0;font-weight:400}body{min-height:100dvh;color:var(--color-text);background:var(--main-back-color);transition:color .5s,background-color .5s;line-height:1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:15px;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.header-block{height:50px;background-color:var(--main-color);font-size:large;color:#fff;vertical-align:middle;padding:10px 0 10px 16px;font-weight:700}.input-custom{width:100%;box-sizing:border-box;margin-bottom:15px}.button-custom{margin-left:auto;background-color:var(--main-color);font-weight:600;color:#fff}.button-custom:hover{background-color:var(--second-color)}.input-custom,.button-custom{padding:12px 16px;border:1px solid #ddd;border-radius:15px;font-size:16px}.button-container{display:flex}.center-message{display:flex;justify-content:center;align-items:center;height:calc(100dvh - 100px);text-align:center}header[data-v-e5db0c22]{line-height:1.5;max-height:100vh}.logo[data-v-e5db0c22]{display:block;margin:0 auto 2rem}nav[data-v-e5db0c22]{width:100%;font-size:12px;text-align:center;margin-top:2rem}nav a.router-link-exact-active[data-v-e5db0c22]{color:var(--color-text)}nav a.router-link-exact-active[data-v-e5db0c22]:hover{background-color:transparent}nav a[data-v-e5db0c22]{display:inline-block;padding:0 1rem;border-left:1px solid var(--color-border)}nav a[data-v-e5db0c22]:first-of-type{border:0}@media (min-width: 1024px){header[data-v-e5db0c22]{display:flex;place-items:center;padding-right:calc(var(--section-gap) / 2)}.logo[data-v-e5db0c22]{margin:0 2rem 0 0}header .wrapper[data-v-e5db0c22]{display:flex;place-items:flex-start;flex-wrap:wrap}nav[data-v-e5db0c22]{text-align:left;margin-left:-1rem;font-size:1rem;padding:1rem 0;margin-top:1rem}}body[data-v-8c48c65f]{font-family:Arial,sans-serif;margin:20px}.buttons-block[data-v-8c48c65f]{padding-top:20px}.button-menu[data-v-8c48c65f]{margin:5px}table[data-v-8c48c65f]{width:700px;border-collapse:collapse;margin:30px auto;border:1px solid #444444}th[data-v-8c48c65f],td[data-v-8c48c65f]{padding:12px;text-align:left}th[data-v-8c48c65f]{background-color:var(--main-color);color:#fff;font-weight:700}tr[data-v-8c48c65f]:nth-child(odd){background-color:#efefef}tr[data-v-8c48c65f]:nth-child(2n){background-color:#fff}tr[data-v-8c48c65f]:hover{background-color:#cfcfcf}.time[data-v-8c48c65f]{white-space:nowrap}.team-name[data-v-8c48c65f]{font-weight:600}.link-button[data-v-8c48c65f]{display:inline;border:none;background:none;padding:0;margin:0;font:inherit;cursor:pointer;color:var(--main-color);text-decoration:underline;font-weight:600;-webkit-appearance:none;-moz-appearance:none;appearance:none;line-height:inherit;text-align:left}.link-button[data-v-8c48c65f]:hover{color:var(--second-color);text-decoration:none}.link-button[data-v-8c48c65f]:active{color:#036}.link-button[data-v-8c48c65f]:focus{outline:none;text-decoration:none;box-shadow:0 0 0 2px #0066cc4d}.form-block[data-v-8c48c65f]{width:700px;margin:0 auto}a[data-v-8c48c65f]{color:var(--second-color);text-decoration:none;transition:all .2s ease;cursor:pointer}a[data-v-8c48c65f]:hover{text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px}a[data-v-8c48c65f]:focus-visible{outline:2px solid #3182ce;outline-offset:2px;border-radius:2px}a[disabled][data-v-8c48c65f]{color:#a0aec0;pointer-events:none;cursor:not-allowed}.qr[data-v-8c48c65f]{position:absolute;top:80px;right:30px;text-align:center;width:120px}.button-container[data-v-8c48c65f]{margin-bottom:30px}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
@media (min-width: 1024px){.about{min-height:100vh;display:flex;align-items:center}}
File diff suppressed because one or more lines are too long
-179
View File
@@ -1,179 +0,0 @@
{
"places": [
{
"code": "ВД",
"name": "Вечерний детектив",
"text": "Дело №1 “Последний костёр”\nАвторы: Фёдоров Владимир, Лисовая Дарья\n Желают вам приятной игры."
},
{
"code": "А",
"name": "Администрация",
"text": "Тут работают директор и старший вожатый. На столе Лехи вы находите расписание на 23 августа. Стопку книг по педагогике и какие-то записки от детей — похоже они очень любили Лёху.",
"applications": [
{
"name": "Расписание дня"
}
]
},
{
"code": "В-1",
"name": "Вход",
"text": "Ржавые ворота с выцветшей табличкой «Добро пожаловать в «Сосновый Бор» скрипят на ветру. За ними — узкая дорога, уходящая вглубь соснового леса. На покосившемся стенде у проходной — пожелтевший плакат с информацией:\n\n\"Лагерь «Сосновый Бор» - Место, где рождаются характеры.\"\n\n«Орлы» — спортивные, загорелые, с грамотами за победы в эстафетах.\n\n«Лисы» — те, кто вместо костра сидит с книгами. Их шепотом называют «ботанами», но именно они всегда знают ответ.\n\n«Волки» — вечные нарушители. Их следы находят то на крыше столовой, то у водонапорной вышки.\n\n«Совы» — тихие художники и поэты. Их рисунки иногда находят дааже в лесу.\n\nВ самом низу подпись: Директор лагеря - Виктор Сергеевич Громов."
},
{
"code": "В-2",
"name": "Водонапорная вышка",
"text": "Труп лежит на земле с разбитой головой, рядом лежит окровавленный камень, судя по всему от него и погиб старший вожатый. Рядом с трупом вы видите отпечатки кроссовок свежие, глубокие, будто кто-то бежал или резко разворачивался. Подошва – с характерным рисунком в виде зигзагов. И еще следы двух пар ботинок: Первые – массивные, с грубым протектором. Следы ведут к телу, затем резко обрываются – будто человек замер на месте. Вторые – аккуратные, с узким носком. Они подходят к камню, а затем удаляются в сторону вышки."
},
{
"code": "Д",
"name": "Душ",
"text": "Вы дергаете дверь душа, она закрыта. Завхоз и повариха, сидящие на лавочке рассказали, что душ не работает, что у кочегара голова болит уже вторые сутки, и почему-то громко расхохотались. Поговорив с женщинами вы узнаете что кормят в лагере очень плохо, даже 2 проверки приезжали – нарушений не нашли, но дети жалуются и почти не едят. Лёша сам ругаться приходил несколько раз, уж очень он за детей волновался."
},
{
"code": "К-1",
"name": "Клуб",
"text": "В клубе вас встречает диджей Пётр. “Концерт как всегда душевный, все плакали обнимались, вроде все здесь были, хотя награждение лучший ребенок в этот раз Лёха проводил, а не броненосец, вот его то я вчера и не видел”. Он рассказывает что дискотека прошла на ура, танцевали и пели под все самые лучшие песни. Кажется он почти не общался с Лехой и до сих пор не знает что произошло: «А какие медляки, танцевал весь лагерь, правда Макса и Даши не было. Они у нас главные знаменитости, танцуют медляки каждый вечер, а днем делают вид что противны друг другу, думают что дети верят в их притворство»"
},
{
"code": "К-2",
"name": "Костровище",
"text": "В глубине лагеря, за последним отрядом расчищена круглая площадка, окруженная полукругом пеньков-сидушек, сколоченных из толстых спилов сосны. В центре — огромный костровой круг, выложенный из камней, почерневших от бесчисленных огней."
},
{
"code": "К-3",
"name": "Коморка физрука",
"text": "Тесное помещение, забитое спортинвентарём до самого потолка. В углу валяется порванный мат, из которого торчит пожелтевший поролон. На полках вперемешку лежат мячи разных видов – футбольные, волейбольные, баскетбольные, – половина из которых явно спущена. Воняет резиной, потом и старыми кроссовками."
},
{
"code": "Л",
"name": "Лавки",
"text": "Пара покосившихся деревянных скамеек, выкрашенных когда-то в зелёную краску, но теперь облезлых до серой древесины. Сиденья испещрены выцарапанными именами, сердечками и нецензурными словами – кто-то старательно выводил их гвоздём или кончиком ключа."
},
{
"code": "М",
"name": "Медпункт",
"text": "Небольшое побелено-голубое здание в тени сосен. Внутри – приемная с выцветшими плакатами про “чистые руки” и “опасность клещей”, изолятор с двумя койками за занавеской, а дальше – общий душ и туалет. На столе стоят 3 кружки из под чая. Печенье “Юбилейное” в открытой пачке. Медицинская карта с последней записью: “22:30 23.08.99 – Волкова С. (отряд “Орлы”) – жалобы на температуру и тошноту. Диагноз: пищевое отравление?” В мусорном ведре вы замечаете упаковку от таблетки, 3 пакетика чая и использованный презерватив. Слабый аромат духов – дешевый, сладкий, явно не медицинский."
},
{
"code": "О-1",
"name": "Отряд 1",
"text": "Белое кирпичное здание, с выложенными кирпичом “1970”. Сбоку нарисован Чебурашка, коричневой и красной краской. Отряд опрятный но сильно пахнет потом. Койки заправлены с армейской аккуратностью. На стене – газета с детскими стихами, где кто-то красной ручкой исправил рифмы на похабные."
},
{
"code": "О-2",
"name": "Отряд 2",
"text": "Тени от сосен за окном рисуют на стенах полосатые узоры. Зайдя внутрь здания, вы замечаете одного из вожатых — Кирилла. Заведя разговор о произошедшем, вы по секрету узнаёте, что его напарница Даша бегает на свиданки с вожатым первого отряда Максимом. Больше ничего необычного вы не заметили."
},
{
"code": "О-3",
"name": "Отряд 3",
"text": "Приближаясь, Вы осматриваете кирпичное здание с нарисованным сбоку здания мультяшным героем. Переводя взгляд в окно, вы видите детей, разбившихся на группки: кто-то рисует, кто-то бегает, а кто-то просто сидит в сторонке. «Вы тоже за тем, что пропало?» — раздаётся голос за спиной. Обернувшись, вы видите мальчика лет 12 с слишком взрослым взглядом. «Лёха говорит, что если что — искать надо в «лисах». Только он не договорил... что именно. Он нервно оглядывается и исчезает за углом, оставив вас с новой загадкой и ощущением, что за вами уже наблюдают."
},
{
"code": "О-4",
"name": "Отряд 4",
"text": "У входа в отряд вы десятки пар обуви, аккуратно выставленных в ряд. Среди них вы сразу замечаете те самые кроссовки с характерным зигзагообразным протектором, слегка запачканные грязью и... чем-то тёмным у носка. «Это Катины!» — оживляется девочка с косичками, тыча пальцем в обувь. — «Она их всегда носит, даже когда дождь!»"
},
{
"code": "П",
"name": "Площадь",
"text": "Площадь в лагере, развивается флаг России и флаг лагеря — зелёное полотно с белой сосной. Чисто выметен асфальт. Музыку здесь почти не слышно хотя граммофон висит на ближайшем столбе."
},
{
"code": "С-1",
"name": "Столовая",
"text": "В столовой пахнет хлоркой, висит плакат чистоты. Там вы никого не нашли."
},
{
"code": "С-2",
"name": "Стадион",
"text": "На стадионе вы встречаете детей 3 и 4 отрядов. Вы интересуетесь, почему они не собирают вещи. Вам рассказывают, что их вожатые самые классные на земле, они приучили их к спорту — каждое утро они даже бегали с Катей вокруг стадиона и водонапорной вышки. Но сегодня последний день и Катя почему-то отправила их играть в волейбол, а бегать запретила."
},
{
"code": "Т",
"name": "Туалет",
"text": "За туалетом вы находите пачку сигарет и записку как у Лехи, размер и бумага совпадают. На ней написано «Сегодня вам сильно повезет, не сдавайся и все получится!» Похоже кто-то раздавал печенье с предсказанием.",
"applications": [
{
"name": "Газета"
}
]
},
{
"code": "Ц",
"name": "Цветы",
"text": "Неровный овал, огороженный потрёпанными синими бордюрами, которые когда-то были яркими, но теперь выцвели под солнцем и покрылись трещинами. Земля в одних местах усыпана мелкими камушками, в других – потрескалась от жары, будто жаждет воды. Но вопреки всему здесь цветут бархатцы – жёлтые и оранжевые, как маленькие огоньки."
},
{
"code": "МК",
"name": "Макс Крутов",
"text": "Перед вами парень в рваных джинсах и черной футболке, похожий на музыканта. Говорит что был в душе вчера во время дискотеки: «Тёма был на дискотеке, а наши все вчера на медляках отжигали. Ну, я и решил помыться. Пока в душ шёл у администрации у Лехи сигарету и стрельнул. Поговорили немного, о чем я вам не могу сказать. Потом мы заметили за туалетом какие-то шорохи, Леха решил проверить, сказал что за одно и обход сделает, якобы лишним не будет, ответственный наш» — Пока он это рассказывал мимо проходил директор — «Смотрите наш броненосец пиджак скинул, а я думал это его кожа!»."
},
{
"code": "АК",
"name": "Артём Ковалёв",
"text": "«Я следил за детьми в клубе, даже драку девочек разнял — ребята подслушали ссору Лехи с Алиной и поддерживали разные стороны, как видите очень яро. Макс отпросился в душ, с парнями вчера спортом был занят весь день»."
},
{
"code": "ДО",
"name": "Даша Орлова",
"text": "«Вчера весь вечер я сидела с детьми которые не пошли на дискотеку. Но те ребята которые могли это подтвердить уже уехали домой»."
},
{
"code": "КЛ",
"name": "Кирилл Лебедев",
"text": "«Леху на втором ужине только видел, да и то он мимо прошел. Мы вчера с Аней, Катей и Темой дежурили на дискотеке. Потом сразу пошли на костер, это могла быть самая лучшая смена. Я рассказывал много историй вчера на костре и про историю лагеря и легенды разные. На свечку мы ушли в отряды зашли — вспоминали смену, делились впечатлениями. На улицу больше не выходили, там похолодало, да и не видно уже ничего было — слишком поздно»."
},
{
"code": "АГ",
"name": "Артём Глушко",
"text": "Артём сидит и читает книгу в своем отряде, попутно помогает ребятам собирать чемоданы. Он интересуется, удалось ли что-то узнать, рассказывает, что они с Лехой как-то застали Макса за кражей денег из кассы, и с тех пор в их отношениях была напряженность. Артем предложил вам печенье и пошел дальше помогать ребятам."
},
{
"code": "АС",
"name": "Анна Соколова",
"text": "«Лёха был ответственным человеком и всегда помогал, иногда он делал больше чем от него требовалось. Он мог и веселые старты провести, когда физрук ленится, вёл все мероприятия лагеря со сцены, встречал проверки. Мне кажется, он некоторые проверки даже устраивал сам, чтобы лагерь лучше делать. Директор даже на него скидывал какие-то бумажные дела. Лёха был очень начитанный хоть и учился на математика, любила с ним поболтать»."
},
{
"code": "КС",
"name": "Катя Светлова",
"text": "На диване в центре общей комнаты отряда вы встречаете молодую девушку, лет 20-22, в яркой оранжевой футболке с принтами, шортах и белых носках. Длинные волосы, собранные в небрежный хвост или косу, минимум макияжа. Она сидит в обнимку со старшими мальчиками отряда, смеётся и рассказывает им какую-то историю."
},
{
"code": "АЗ",
"name": "Алина Зайцева",
"text": "Вы находите ее рядом с турниками. Девушка спортивного телосложения сидит на траве прикрыв лицо капюшоном. Слезы бегут по ее лицу. “Мы встречались, хотели даже пожениться, он последнее время очень злой ходил, эта смена его совсем из колеи выбила. Рассказывать он не хотел, знаю что долго за документами засиживался уже когда все спали”."
},
{
"code": "ВСГ",
"name": "Виктор Сергеевич Громов",
"text": "«Труп обнаружил охранник Виктор Петрович на ночном обходе, позвал меня. Я проверил пульс и позвонил в полицию. Вот вам список работников лагеря. Страшно осознавать что кто-то из них может быть убийцей».",
"applications": [
{
"name": "Список работников лагеря"
}
]
},
{
"code": "ЕО",
"name": "Елена Орлова",
"text": "Очень красивая статная девушка в белом халате встречает вас нежной улыбкой. «Во время дискотеки я была в приемной, королевская ночь по статистике самая травмоопасная. Хотя на удивление только одна девочка с температурой, я выдала таблетку и вожатая увела её обратно в отряд»."
},
{
"code": "СС",
"name": "Сергей Смирнов",
"text": "Вы подошли к мужчине среднего роста в спортивном костюме: «Вечером телевизор смотрел, музыка долбила спать не давала. Петрович заходил, мы досмотрели “музыкальный ринг” да и побёг он. На дискотеки я не ходок, да и Лёха сказал помощь не нужна. За день набегался, дел много и не только своих, там помоги, сям помоги, никто ничего не может, вот и помогаю. Устаю, возраст как никак. Петрович попросил, вчера помочь с вывозом мусора с тех пор в коморке и сидел. Лёху видел последний раз в воскресенье, он сказал зарядку не проводить пущай дети поспят»."
},
{
"code": "ВПБ",
"name": "Виктор Петрович Белов",
"text": "«У меня свой режим: завтрак в 9 утра, вынос мусора в 9 вечера, в 11 вечера обход. Всю дискотеку Лёха сидел в администрации, как с концерта пришел так и не выходил. В пол десятого я до клуба отходил проверить все ли спокойно пока дискотека, проверил все и за клубом, площадь посмотрел — минут 30 заняло. Фонари давно у клуба не работают, пришлось с фонариком везде лазить. Тело обнаружил уже на обходе — очень перепугался и сразу в администрацию побежал».",
"applications": [
{
"name": "Карта лагеря"
}
]
}
]
}