generated from VLADIMIR/template
fix
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
// Package email_sender sends email messages over SMTP.
|
||||
package email_sender
|
||||
|
||||
import "context"
|
||||
|
||||
// Message describes an email message.
|
||||
type Message struct {
|
||||
To string
|
||||
Subject string
|
||||
@@ -9,6 +11,7 @@ type Message struct {
|
||||
HTML string
|
||||
}
|
||||
|
||||
// IEmailSender sends email messages.
|
||||
type IEmailSender interface {
|
||||
Send(ctx context.Context, message Message) error
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ type sender struct {
|
||||
tlsConfig *tls.Config
|
||||
}
|
||||
|
||||
// NewSender creates an SMTP email sender.
|
||||
func NewSender(
|
||||
smtpHost string,
|
||||
smtpPort string,
|
||||
|
||||
@@ -2,6 +2,7 @@ package email_sender
|
||||
|
||||
import "html"
|
||||
|
||||
// ButtonHTML returns an HTML button linking to link.
|
||||
func ButtonHTML(link, label string) string {
|
||||
return `<table role="presentation" cellpadding="0" cellspacing="0" style="margin:20px 0;">
|
||||
<tr><td class="email-button" bgcolor="#342a22" style="border-radius:5px; background-color:#342a22;">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package file_storage stores files in object storage.
|
||||
package file_storage
|
||||
|
||||
import (
|
||||
@@ -12,12 +13,14 @@ import (
|
||||
// отсутствующих объектов (маппинг smithy-ошибок NoSuchKey/NotFound).
|
||||
var ErrFileNotFound = errors.New("файл не найден")
|
||||
|
||||
// File describes a stored file.
|
||||
type File struct {
|
||||
Name string
|
||||
Data []byte
|
||||
Mime string
|
||||
}
|
||||
|
||||
// IFileStorage stores and retrieves files.
|
||||
type IFileStorage interface {
|
||||
Put(ctx context.Context, file *File) error
|
||||
Get(ctx context.Context, filename string) (*File, error)
|
||||
|
||||
@@ -18,6 +18,7 @@ type storage struct {
|
||||
bucket string
|
||||
}
|
||||
|
||||
// NewRustFSStorage creates a RustFS-backed file storage.
|
||||
func NewRustFSStorage(
|
||||
ctx context.Context,
|
||||
endpoint string,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package network_utils provides network-related helpers.
|
||||
package network_utils
|
||||
|
||||
import "net"
|
||||
|
||||
@@ -13,6 +13,7 @@ type generator struct {
|
||||
length int
|
||||
}
|
||||
|
||||
// NewGenerator creates a password generator.
|
||||
func NewGenerator(length int) IPasswordGenerator {
|
||||
return &generator{
|
||||
length: length,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Package password_generator generates passwords.
|
||||
package password_generator
|
||||
|
||||
// IPasswordGenerator generates passwords.
|
||||
type IPasswordGenerator interface {
|
||||
Generate() (string, error)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package processor_jwt processes JSON Web Tokens.
|
||||
package processor_jwt
|
||||
|
||||
import "context"
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// NewAuthorizationInterceptor creates a gRPC JWT authorization interceptor.
|
||||
func NewAuthorizationInterceptor(
|
||||
publicMethods map[string]bool,
|
||||
processorJWT IProcessorJWT,
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// JWTClaims contains claims extracted from a JSON Web Token.
|
||||
type JWTClaims struct {
|
||||
UserID int `json:"user_id"`
|
||||
UserEmail string `json:"user_email"`
|
||||
@@ -13,10 +14,12 @@ type JWTClaims struct {
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// HasRole reports whether the claims contain role.
|
||||
func (c *JWTClaims) HasRole(role string) bool {
|
||||
return slices.Contains(c.Roles, role)
|
||||
}
|
||||
|
||||
// IProcessorJWT validates and creates JSON Web Tokens.
|
||||
type IProcessorJWT interface {
|
||||
GenerateAccessToken(userID int, userEmail string, userRoles []string) (string, error)
|
||||
GenerateRefreshToken(userID int) (string, error)
|
||||
|
||||
@@ -12,6 +12,7 @@ type processor struct {
|
||||
secret []byte
|
||||
}
|
||||
|
||||
// NewProcessor creates a JWT processor.
|
||||
func NewProcessor(secret string) IProcessorJWT {
|
||||
return &processor{
|
||||
secret: []byte(secret),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package roles defines application roles and role checks.
|
||||
package roles
|
||||
|
||||
// Роли пользователей системы.
|
||||
|
||||
@@ -7,6 +7,7 @@ type subject struct {
|
||||
roles []string
|
||||
}
|
||||
|
||||
// NewSubject creates a role-bearing subject.
|
||||
func NewSubject(roles ...string) IHasRole {
|
||||
return &subject{roles: roles}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"evening_detective_server/internal/modules/storytelling"
|
||||
)
|
||||
|
||||
// Имя файла с описанием сценария внутри архива.
|
||||
// FileName is the name of the scenario description inside an archive.
|
||||
const FileName = "scenario.json"
|
||||
|
||||
// Текущая версия формата scenario.json.
|
||||
// Version is the current scenario.json format version.
|
||||
const Version = 1
|
||||
|
||||
// ScenarioJSON — описание сценария в архиве; Story — в формате колонки
|
||||
@@ -30,6 +30,7 @@ type Scenario struct {
|
||||
Story string
|
||||
}
|
||||
|
||||
// Bundle contains an archived scenario and its metadata.
|
||||
type Bundle struct {
|
||||
Scenario *ScenarioJSON
|
||||
Files map[string][]byte
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Package storytelling models scenario stories and their elements.
|
||||
package storytelling
|
||||
|
||||
// ICleaner cleans text used by a story.
|
||||
type ICleaner interface {
|
||||
ClearCode(code string) string
|
||||
ClearText(text string) string
|
||||
|
||||
@@ -1,53 +1,49 @@
|
||||
package storytelling
|
||||
|
||||
// IStory provides access to a scenario story.
|
||||
type IStory interface {
|
||||
GetStory(scenario *Story, codes []string) *Story
|
||||
}
|
||||
|
||||
// История - это введение, набор точек и вопросы дела
|
||||
// Story describes a scenario story.
|
||||
type Story struct {
|
||||
Background string `json:"background,omitempty"`
|
||||
|
||||
Introduction *Introduction `json:"introduction,omitempty"`
|
||||
|
||||
// Закрывашка доступна в редакторе сценария, игрокам не передаётся.
|
||||
// Conclusion is available in the scenario editor and is not sent to players.
|
||||
Conclusion *Conclusion `json:"conclusion,omitempty"`
|
||||
|
||||
Places []*Place `json:"places"`
|
||||
|
||||
// Вопросы дела - список вопросов, на которые команда должна ответить
|
||||
// Questions are the questions the team must answer.
|
||||
Questions []*Question `json:"questions,omitempty"`
|
||||
}
|
||||
|
||||
// Вопрос дела - вопрос, который автор сценария добавляет вместе с
|
||||
// правильным ответом; команда отвечает на вопросы в конце игры
|
||||
// Question describes a question and its correct answer.
|
||||
type Question struct {
|
||||
Code string `json:"code"`
|
||||
|
||||
Text string `json:"text"`
|
||||
|
||||
// Правильный ответ - виден только автору и организаторам,
|
||||
// команде не передаётся
|
||||
// Answer is visible only to the author and organizers.
|
||||
Answer string `json:"answer"`
|
||||
}
|
||||
|
||||
// Закрывашка - текст и видео для редактора сценария.
|
||||
// Conclusion describes text and video for the scenario editor.
|
||||
type Conclusion struct {
|
||||
Text string `json:"text"`
|
||||
Video string `json:"video,omitempty"`
|
||||
}
|
||||
|
||||
// Введение - текст и аудио, которые игрок получает в начале игры.
|
||||
// Introduction describes the text and audio shown at the start of the game.
|
||||
type Introduction struct {
|
||||
Text string `json:"text"`
|
||||
|
||||
Audio string `json:"audio,omitempty"`
|
||||
}
|
||||
|
||||
// Точка - что-то куда можно сходить
|
||||
// Это может быть место - аптека, остановка, площадь...
|
||||
// Это может быть персонаж - пострадавший, продавец, полицейский...
|
||||
// Это может быть описание действия игрока - ответ на вопрос, реакция на выбитую дверь...
|
||||
// Place describes a location, character, or player action in the story.
|
||||
type Place struct {
|
||||
Code string `json:"code"`
|
||||
|
||||
@@ -57,42 +53,39 @@ type Place struct {
|
||||
|
||||
Image string `json:"image"`
|
||||
|
||||
// Признак скрытой карточки - некоторые места изначально не доступны
|
||||
// Hidden reports whether the place is initially unavailable.
|
||||
Hidden bool `json:"hidden"`
|
||||
|
||||
Applications []*Application `json:"applications,omitempty"`
|
||||
|
||||
// Двери к другим точкам - действия или диалоги, открывающие другие точки
|
||||
// Doors are actions or dialogues that open other places.
|
||||
Doors []*Door `json:"doors"`
|
||||
|
||||
// Получаемые ключи - ключи используются для получения доступа к скрытым дверям
|
||||
// Keys are used to access hidden doors.
|
||||
Keys []*Key `json:"keys"`
|
||||
}
|
||||
|
||||
// Приложение - улика
|
||||
// Это может быть оружие, отпечатки, фотография...
|
||||
// Application describes evidence such as a weapon, fingerprint, or photo.
|
||||
type Application struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
Image string `json:"image"`
|
||||
|
||||
// Тип файла улики: image | pdf | audio.
|
||||
// FileType is the evidence file type: image, pdf, or audio.
|
||||
FileType string `json:"file_type,omitempty"`
|
||||
}
|
||||
|
||||
// Дверь - действие или диалог
|
||||
// Door describes an action or dialogue.
|
||||
type Door struct {
|
||||
Code string `json:"code"`
|
||||
|
||||
Name string `json:"name"`
|
||||
|
||||
// Некоторые двери изначально не доступны
|
||||
// Ключи требуемые для получения доступа к скрытым дверям
|
||||
// Если указаны ключи то дверь считается скрытой
|
||||
// Keys are required to access a hidden door.
|
||||
Keys []*Key `json:"keys"`
|
||||
}
|
||||
|
||||
// Аналог карт допуска в "Тайны Аркхема"
|
||||
// Key describes an item that grants access to a door.
|
||||
type Key struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ type story struct {
|
||||
cleaner ICleaner
|
||||
}
|
||||
|
||||
// NewStory creates a story from a cleaner.
|
||||
func NewStory(
|
||||
cleaner ICleaner,
|
||||
) IStory {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package string_tools provides string transformation helpers.
|
||||
package string_tools
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package team_qr_pdf generates team QR-code PDFs.
|
||||
package team_qr_pdf
|
||||
|
||||
import (
|
||||
@@ -12,8 +13,10 @@ import (
|
||||
"github.com/skip2/go-qrcode"
|
||||
)
|
||||
|
||||
// ErrNoCards indicates that no cards were provided for generation.
|
||||
var ErrNoCards = errors.New("нет карточек")
|
||||
|
||||
// Card contains the data rendered on a team QR-code card.
|
||||
type Card struct {
|
||||
Name string
|
||||
URL string
|
||||
@@ -22,6 +25,7 @@ type Card struct {
|
||||
//go:embed fonts/DejaVuSansCondensed.ttf
|
||||
var font []byte
|
||||
|
||||
// Generate returns a PDF containing team QR-code cards.
|
||||
func Generate(cards []Card) ([]byte, error) {
|
||||
if len(cards) == 0 {
|
||||
return nil, ErrNoCards
|
||||
|
||||
Reference in New Issue
Block a user