ОБТ
This commit is contained in:
parent
a1dc96088c
commit
1ad012b8fa
14 changed files with 136 additions and 52 deletions
19
Caddyfile
Normal file
19
Caddyfile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
debug
|
||||||
|
}
|
||||||
|
|
||||||
|
http:// {
|
||||||
|
handle_path /file/* {
|
||||||
|
root * /app/store
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
handle /api* {
|
||||||
|
reverse_proxy http://app:8000
|
||||||
|
}
|
||||||
|
handle {
|
||||||
|
root * /app/frontend/dist
|
||||||
|
file_server
|
||||||
|
try_files {path} /index.html
|
||||||
|
encode gzip zstd
|
||||||
|
}
|
||||||
|
}
|
|
@ -377,6 +377,19 @@ paths:
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: '#/components/responses/taskResponse'
|
$ref: '#/components/responses/taskResponse'
|
||||||
|
/file/{uid}:
|
||||||
|
get:
|
||||||
|
operationId: getFile
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: uuid
|
||||||
|
type: string
|
||||||
|
response:
|
||||||
|
307:
|
||||||
|
description: redirect
|
||||||
/games:
|
/games:
|
||||||
get:
|
get:
|
||||||
responses:
|
responses:
|
||||||
|
|
|
@ -40,4 +40,17 @@ paths:
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: "#/components/responses/taskResponse"
|
$ref: "#/components/responses/taskResponse"
|
||||||
|
/file/{uid}:
|
||||||
|
get:
|
||||||
|
operationId: getFile
|
||||||
|
parameters:
|
||||||
|
- name: uid
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
response:
|
||||||
|
307:
|
||||||
|
description: redirect
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,9 @@ type ServerInterface interface {
|
||||||
// (POST /engine/{uid}/code)
|
// (POST /engine/{uid}/code)
|
||||||
EnterCode(ctx echo.Context, uid openapi_types.UUID) error
|
EnterCode(ctx echo.Context, uid openapi_types.UUID) error
|
||||||
|
|
||||||
|
// (GET /file/{uid})
|
||||||
|
GetFile(ctx echo.Context, uid openapi_types.UUID) error
|
||||||
|
|
||||||
// (GET /games)
|
// (GET /games)
|
||||||
GetGames(ctx echo.Context) error
|
GetGames(ctx echo.Context) error
|
||||||
|
|
||||||
|
@ -176,6 +179,24 @@ func (w *ServerInterfaceWrapper) EnterCode(ctx echo.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFile converts echo context to params.
|
||||||
|
func (w *ServerInterfaceWrapper) GetFile(ctx echo.Context) error {
|
||||||
|
var err error
|
||||||
|
// ------------- Path parameter "uid" -------------
|
||||||
|
var uid openapi_types.UUID
|
||||||
|
|
||||||
|
err = runtime.BindStyledParameterWithOptions("simple", "uid", ctx.Param("uid"), &uid, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter uid: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Set(CookieAuthScopes, []string{})
|
||||||
|
|
||||||
|
// Invoke the callback with all the unmarshaled arguments
|
||||||
|
err = w.Handler.GetFile(ctx, uid)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// GetGames converts echo context to params.
|
// GetGames converts echo context to params.
|
||||||
func (w *ServerInterfaceWrapper) GetGames(ctx echo.Context) error {
|
func (w *ServerInterfaceWrapper) GetGames(ctx echo.Context) error {
|
||||||
var err error
|
var err error
|
||||||
|
@ -262,6 +283,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||||
router.GET(baseURL+"/admin/games/:uid", wrapper.AdminGetGame)
|
router.GET(baseURL+"/admin/games/:uid", wrapper.AdminGetGame)
|
||||||
router.GET(baseURL+"/engine/:uid", wrapper.GameEngine)
|
router.GET(baseURL+"/engine/:uid", wrapper.GameEngine)
|
||||||
router.POST(baseURL+"/engine/:uid/code", wrapper.EnterCode)
|
router.POST(baseURL+"/engine/:uid/code", wrapper.EnterCode)
|
||||||
|
router.GET(baseURL+"/file/:uid", wrapper.GetFile)
|
||||||
router.GET(baseURL+"/games", wrapper.GetGames)
|
router.GET(baseURL+"/games", wrapper.GetGames)
|
||||||
router.GET(baseURL+"/user", wrapper.GetUser)
|
router.GET(baseURL+"/user", wrapper.GetUser)
|
||||||
router.POST(baseURL+"/user/login", wrapper.PostUserLogin)
|
router.POST(baseURL+"/user/login", wrapper.PostUserLogin)
|
||||||
|
@ -273,26 +295,27 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||||
var swaggerSpec = []string{
|
var swaggerSpec = []string{
|
||||||
|
|
||||||
"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",
|
||||||
|
"0I910y50yiIW0sJWrst/AwAA//8rjKvDLRwAAA==",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSwagger returns the content of the embedded swagger specification file
|
// GetSwagger returns the content of the embedded swagger specification file
|
||||||
|
|
|
@ -14,7 +14,6 @@ RUN apk update --no-cache && apk add --no-cache tzdata
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download && go mod verify
|
RUN go mod download && go mod verify
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY --from=frontend /app/dist /app/frontend/dist
|
|
||||||
RUN go build -ldflags="-X gitrepo.ru/neonxp/nquest.Version=${VERSION}" -o nquest *.go
|
RUN go build -ldflags="-X gitrepo.ru/neonxp/nquest.Version=${VERSION}" -o nquest *.go
|
||||||
|
|
||||||
# Runtime container
|
# Runtime container
|
||||||
|
@ -24,6 +23,7 @@ RUN apk update --no-cache && apk add --no-cache ca-certificates
|
||||||
|
|
||||||
COPY --from=backend /usr/share/zoneinfo/Europe/Moscow /usr/share/zoneinfo/Europe/Moscow
|
COPY --from=backend /usr/share/zoneinfo/Europe/Moscow /usr/share/zoneinfo/Europe/Moscow
|
||||||
COPY --from=backend /app/nquest /app/nquest
|
COPY --from=backend /app/nquest /app/nquest
|
||||||
|
COPY --from=frontend /app/dist /app/frontend/dist
|
||||||
|
|
||||||
ENV TZ Europe/Moscow
|
ENV TZ Europe/Moscow
|
||||||
|
|
3
build/caddy/Dockerfile
Normal file
3
build/caddy/Dockerfile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
FROM caddy:2.8-alpine
|
||||||
|
|
||||||
|
COPY Caddyfile /etc/caddy/Caddyfile
|
|
@ -3,19 +3,30 @@ version: '3.8'
|
||||||
volumes:
|
volumes:
|
||||||
postgres-data:
|
postgres-data:
|
||||||
storage:
|
storage:
|
||||||
|
frontend:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
caddy:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: build/caddy/Dockerfile
|
||||||
|
volumes:
|
||||||
|
- frontend:/app/frontend/dist:ro
|
||||||
|
- storage:/app/store:ro
|
||||||
|
ports:
|
||||||
|
- 8989:80
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
app:
|
app:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: build/api/Dockerfile
|
||||||
ports:
|
|
||||||
- 8989:8989
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
volumes:
|
volumes:
|
||||||
|
- frontend:/app/frontend/dist:rw
|
||||||
- storage:/app/store:rw
|
- storage:/app/store:rw
|
||||||
db:
|
db:
|
||||||
image: postgres:15-alpine3.17
|
image: postgres:15-alpine3.17
|
||||||
|
|
17
embeds.go
17
embeds.go
|
@ -1,17 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
//go:embed all:frontend/dist
|
|
||||||
dist embed.FS
|
|
||||||
//go:embed frontend/dist/index.html
|
|
||||||
indexHTML embed.FS
|
|
||||||
|
|
||||||
distDirFS = echo.MustSubFS(dist, "frontend/dist")
|
|
||||||
distIndexHtml = echo.MustSubFS(indexHTML, "frontend/dist")
|
|
||||||
)
|
|
|
@ -4,7 +4,7 @@ import { UserProvider } from '../store/user'
|
||||||
import { ajax } from '../utils/fetch'
|
import { ajax } from '../utils/fetch'
|
||||||
import { Layout, Menu } from 'antd'
|
import { Layout, Menu } from 'antd'
|
||||||
import { MenuOutlined } from '@ant-design/icons'
|
import { MenuOutlined } from '@ant-design/icons'
|
||||||
import { Content, Header } from 'antd/es/layout/layout'
|
import { Content, Footer, Header } from 'antd/es/layout/layout'
|
||||||
import { useRole } from '../utils/roles'
|
import { useRole } from '../utils/roles'
|
||||||
|
|
||||||
const AppLayout = () => {
|
const AppLayout = () => {
|
||||||
|
@ -80,9 +80,12 @@ const AppLayout = () => {
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
/>
|
/>
|
||||||
</Header>
|
</Header>
|
||||||
<Content style={{ padding: '0 24px' }}>
|
<Content style={{ padding: '0 24px', minHeight: '80vh' }}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</Content>
|
</Content>
|
||||||
|
<Footer>
|
||||||
|
Сделал <a href="https://neonxp.ru">NeonXP</a> в 2024.
|
||||||
|
</Footer>
|
||||||
</Layout>)
|
</Layout>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,16 @@ const Index = () => {
|
||||||
const { user } = UserProvider.useContainer()
|
const { user } = UserProvider.useContainer()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
return (<>
|
return (<>
|
||||||
<Title>NQuest</Title>
|
<Title><img src="/assets/logo.png" />uest</Title>
|
||||||
<Paragraph>Привет! Это платформа для ARG игр.</Paragraph>
|
<Paragraph>Привет! Это платформа для ARG игр.</Paragraph>
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
Если ты попал сюда случайно, то скорее всего, для тебя здесь нет ничего интересного.
|
Если ты попал сюда случайно, то скорее всего, для тебя здесь нет ничего интересного.<br />
|
||||||
А если ты знаешь зачем пришёл, то добро пожаловать!
|
А если ты знаешь зачем пришёл, то добро пожаловать!
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
|
<Paragraph>
|
||||||
|
Телеграм-канал с новостями проекта: <a href="https://t.me/nquest_ru">nquest_ru</a>, рекомендую подписаться.<br />
|
||||||
|
Там будут как roadmap проекта, так и анонсы новых квестов.
|
||||||
|
</Paragraph>
|
||||||
{!user
|
{!user
|
||||||
? (<Button.Group>
|
? (<Button.Group>
|
||||||
<Button type="primary" onClick={() => navigate('/login')}>Вход</Button>
|
<Button type="primary" onClick={() => navigate('/login')}>Вход</Button>
|
||||||
|
|
|
@ -38,16 +38,14 @@ const renderItem = (user, navigate, item) => {
|
||||||
</Popover>,
|
</Popover>,
|
||||||
<Popover key='taskCount' content={`Этот квест состоит из ${item.taskCount} уровней`} title='Количество уровней в квесте'>
|
<Popover key='taskCount' content={`Этот квест состоит из ${item.taskCount} уровней`} title='Количество уровней в квесте'>
|
||||||
<Space>{item.taskCount} ур</Space>
|
<Space>{item.taskCount} ур</Space>
|
||||||
</Popover>,
|
</Popover>
|
||||||
<>{moment(item.createdAt).fromNow()}</>,
|
|
||||||
<>Автор {item.authors.map(a => a.username)}</>
|
|
||||||
]
|
]
|
||||||
|
|
||||||
let questAction = (<span>Необходимо войти</span>)
|
let questAction = (<span>Необходимо войти</span>)
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
questAction = (user.games.find(x => x.id === item.id)
|
questAction = (user.games.find(x => x.id === item.id)
|
||||||
? <span>Вы уже прошли этот квест</span>
|
? <b>Вы уже прошли этот квест</b>
|
||||||
: <Button onClick={() => navigate(`/go/${item.id}`)} type="primary">Начать квест</Button>
|
: <Button onClick={() => navigate(`/go/${item.id}`)} type="primary">Начать квест</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
3
main.go
3
main.go
|
@ -130,9 +130,6 @@ func main() {
|
||||||
// --[ System ]--
|
// --[ System ]--
|
||||||
e.GET("/metrics", echoprometheus.NewHandler())
|
e.GET("/metrics", echoprometheus.NewHandler())
|
||||||
|
|
||||||
e.StaticFS("/file", afero.NewIOFS(storage))
|
|
||||||
e.StaticFS("/*", distDirFS)
|
|
||||||
|
|
||||||
e.Logger.Debugf("backend version %s", Version)
|
e.Logger.Debugf("backend version %s", Version)
|
||||||
e.Logger.Fatal(e.Start(cfg.Listen))
|
e.Logger.Fatal(e.Start(cfg.Listen))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"gitrepo.ru/neonxp/nquest/api"
|
"gitrepo.ru/neonxp/nquest/api"
|
||||||
|
@ -57,3 +59,12 @@ func (u *File) AdminListFiles(c echo.Context, quest uuid.UUID) error {
|
||||||
|
|
||||||
return c.JSON(200, list)
|
return c.JSON(200, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *File) GetFile(c echo.Context, uid uuid.UUID) error {
|
||||||
|
f, err := u.FileService.GetFilesByID(c.Request().Context(), uid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect(307, fmt.Sprintf(`/file/%s/%s`, f.QuestID, f.Filename))
|
||||||
|
}
|
||||||
|
|
|
@ -57,3 +57,9 @@ func (u *File) GetFilesByQuest(ctx context.Context, quest uuid.UUID) ([]*models.
|
||||||
|
|
||||||
return list, u.DB.WithContext(ctx).Find(&list, `quest_id = ?`, quest.String()).Error
|
return list, u.DB.WithContext(ctx).Find(&list, `quest_id = ?`, quest.String()).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *File) GetFilesByID(ctx context.Context, fileID uuid.UUID) (*models.File, error) {
|
||||||
|
file := &models.File{}
|
||||||
|
|
||||||
|
return file, u.DB.WithContext(ctx).First(file, fileID).Error
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue