This commit is contained in:
2026-09-17 13:04:44 +07:00
parent e3cbf18220
commit 5ba640bfe4
12 changed files with 19 additions and 60 deletions
+1 -2
View File
@@ -12,7 +12,6 @@ import (
"evening_detective_server/internal/modules/processor_jwt" "evening_detective_server/internal/modules/processor_jwt"
"evening_detective_server/internal/modules/scenario_archive" "evening_detective_server/internal/modules/scenario_archive"
"evening_detective_server/internal/modules/storytelling" "evening_detective_server/internal/modules/storytelling"
"evening_detective_server/internal/modules/string_tools"
"evening_detective_server/internal/modules/team_qr_pdf" "evening_detective_server/internal/modules/team_qr_pdf"
"evening_detective_server/internal/repos/actions_repo" "evening_detective_server/internal/repos/actions_repo"
"evening_detective_server/internal/repos/applications_repo" "evening_detective_server/internal/repos/applications_repo"
@@ -118,7 +117,7 @@ func main() {
if err != nil { if err != nil {
log.Fatalf("Unable to create connection rustfs: %v\n", err) log.Fatalf("Unable to create connection rustfs: %v\n", err)
} }
fileService := file_service.NewFileService(fileStorage, string_tools.NewStringTools(), maxFileSize) fileService := file_service.NewFileService(fileStorage, maxFileSize)
scenariosRepo := scenarios_repo.NewScenariosRepo(dbpool) scenariosRepo := scenarios_repo.NewScenariosRepo(dbpool)
cleaner := cleaner.NewCleaner() cleaner := cleaner.NewCleaner()
scenarioService := scenarios_service.NewScenarioService( scenarioService := scenarios_service.NewScenarioService(
+1 -2
View File
@@ -7,7 +7,6 @@ import (
"evening_detective_server/internal/modules/file_storage" "evening_detective_server/internal/modules/file_storage"
"evening_detective_server/internal/modules/processor_jwt" "evening_detective_server/internal/modules/processor_jwt"
"evening_detective_server/internal/modules/string_tools"
"evening_detective_server/internal/services/file_service" "evening_detective_server/internal/services/file_service"
proto "evening_detective_server/proto" proto "evening_detective_server/proto"
@@ -63,7 +62,7 @@ func newTestFileServer(storage *fakeStorage, maxSize int) *server {
storage = newFakeStorage() storage = newFakeStorage()
} }
return &server{ return &server{
fileService: file_service.NewFileService(storage, string_tools.NewStringTools(), maxSize), fileService: file_service.NewFileService(storage, maxSize),
} }
} }
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"evening_detective_server/internal/modules/processor_jwt" "evening_detective_server/internal/modules/processor_jwt"
"evening_detective_server/internal/modules/roles" "evening_detective_server/internal/modules/roles"
"evening_detective_server/internal/modules/scenario_archive" "evening_detective_server/internal/modules/scenario_archive"
"evening_detective_server/internal/modules/string_tools"
"evening_detective_server/internal/repos/scenarios_repo" "evening_detective_server/internal/repos/scenarios_repo"
"evening_detective_server/internal/services/scenarios_service" "evening_detective_server/internal/services/scenarios_service"
proto "evening_detective_server/proto" proto "evening_detective_server/proto"
@@ -45,7 +46,7 @@ func (s *server) DownloadScenarioArchive(ctx context.Context, req *proto.Downloa
// Имя файла транслитерируется (заголовки HTTP — только ASCII) и // Имя файла транслитерируется (заголовки HTTP — только ASCII) и
// санитайзится от header injection; заголовок пробрасывается gateway. // санитайзится от header injection; заголовок пробрасывается gateway.
transliterated := sanitizeFilename(stringTools.Transliterate(name)) transliterated := sanitizeFilename(string_tools.Transliterate(name))
if transliterated == "" { if transliterated == "" {
transliterated = "scenario" transliterated = "scenario"
} }
-4
View File
@@ -1,7 +1,6 @@
package app package app
import ( import (
"evening_detective_server/internal/modules/string_tools"
"evening_detective_server/internal/repos/game_map_repo" "evening_detective_server/internal/repos/game_map_repo"
"evening_detective_server/internal/repos/screen_sessions_repo" "evening_detective_server/internal/repos/screen_sessions_repo"
"evening_detective_server/internal/services/answer_service" "evening_detective_server/internal/services/answer_service"
@@ -16,9 +15,6 @@ import (
proto "evening_detective_server/proto" proto "evening_detective_server/proto"
) )
// stringTools — транслитерация имён файлов для HTTP-заголовков.
var stringTools = string_tools.NewStringTools()
type server struct { type server struct {
proto.UnsafeEveningDetectiveServerServer proto.UnsafeEveningDetectiveServerServer
+9 -12
View File
@@ -9,9 +9,6 @@ import (
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
) )
// textFormatter — форматирование текста при конвертации входящих данных.
var textFormatter = formatter_utils.NewFormatter()
func mapScenarios(o []*scenarios_service.Scenario) []*proto.Scenario { func mapScenarios(o []*scenarios_service.Scenario) []*proto.Scenario {
res := make([]*proto.Scenario, 0, len(o)) res := make([]*proto.Scenario, 0, len(o))
for _, item := range o { for _, item := range o {
@@ -66,7 +63,7 @@ func convertConclusion(o *proto.Conclusion) *storytelling.Conclusion {
if o == nil || (o.Text == "" && o.Video == "") { if o == nil || (o.Text == "" && o.Video == "") {
return nil return nil
} }
return &storytelling.Conclusion{Text: textFormatter.FormatText(o.Text), Video: o.Video} return &storytelling.Conclusion{Text: formatter_utils.FormatText(o.Text), Video: o.Video}
} }
func mapIntroduction(o *storytelling.Introduction) *proto.Introduction { func mapIntroduction(o *storytelling.Introduction) *proto.Introduction {
@@ -149,8 +146,8 @@ func mapKey(o *storytelling.Key) *proto.Key {
func convertPlace(o *proto.Place) *storytelling.Place { func convertPlace(o *proto.Place) *storytelling.Place {
return &storytelling.Place{ return &storytelling.Place{
Code: o.Code, Code: o.Code,
Name: textFormatter.FormatString(o.Name), Name: formatter_utils.FormatString(o.Name),
Text: textFormatter.FormatText(o.Text), Text: formatter_utils.FormatText(o.Text),
Image: o.Image, Image: o.Image,
Hidden: o.Hidden, Hidden: o.Hidden,
Applications: convertApplications(o.Applications), Applications: convertApplications(o.Applications),
@@ -185,7 +182,7 @@ func convertKeys(o []*proto.Key) []*storytelling.Key {
func convertApplication(o *proto.Application) *storytelling.Application { func convertApplication(o *proto.Application) *storytelling.Application {
return &storytelling.Application{ return &storytelling.Application{
Name: textFormatter.FormatString(o.Name), Name: formatter_utils.FormatString(o.Name),
Image: o.Image, Image: o.Image,
FileType: o.FileType, FileType: o.FileType,
} }
@@ -194,14 +191,14 @@ func convertApplication(o *proto.Application) *storytelling.Application {
func convertDoor(o *proto.Door) *storytelling.Door { func convertDoor(o *proto.Door) *storytelling.Door {
return &storytelling.Door{ return &storytelling.Door{
Code: o.Code, Code: o.Code,
Name: textFormatter.FormatString(o.Name), Name: formatter_utils.FormatString(o.Name),
Keys: convertKeys(o.Keys), Keys: convertKeys(o.Keys),
} }
} }
func convertKey(o *proto.Key) *storytelling.Key { func convertKey(o *proto.Key) *storytelling.Key {
return &storytelling.Key{ return &storytelling.Key{
Name: textFormatter.FormatString(o.Name), Name: formatter_utils.FormatString(o.Name),
} }
} }
@@ -210,7 +207,7 @@ func convertIntroduction(o *proto.Introduction) *storytelling.Introduction {
return nil return nil
} }
return &storytelling.Introduction{ return &storytelling.Introduction{
Text: textFormatter.FormatText(o.Text), Text: formatter_utils.FormatText(o.Text),
Audio: o.Audio, Audio: o.Audio,
} }
} }
@@ -240,7 +237,7 @@ func convertQuestion(o *proto.Question) *storytelling.Question {
} }
return &storytelling.Question{ return &storytelling.Question{
Code: o.Code, Code: o.Code,
Text: textFormatter.FormatText(o.Text), Text: formatter_utils.FormatText(o.Text),
Answer: textFormatter.FormatText(o.Answer), Answer: formatter_utils.FormatText(o.Answer),
} }
} }
@@ -1,7 +0,0 @@
package formatter_utils
// IFormatter — форматирование текста сценария для отображения.
type IFormatter interface {
FormatText(text string) string
FormatString(text string) string
}
+2 -9
View File
@@ -5,16 +5,9 @@ import (
"strings" "strings"
) )
type formatter struct{}
// NewFormatter создаёт реализацию IFormatter.
func NewFormatter() IFormatter {
return &formatter{}
}
// FormatText форматирует многострочный текст: обрезает пробелы по краям // FormatText форматирует многострочный текст: обрезает пробелы по краям
// строк, превращает "--" в тире и добавляет отступ абзаца. // строк, превращает "--" в тире и добавляет отступ абзаца.
func (f *formatter) FormatText(text string) string { func FormatText(text string) string {
scanner := bufio.NewScanner(strings.NewReader(text)) scanner := bufio.NewScanner(strings.NewReader(text))
scanner.Split(bufio.ScanLines) scanner.Split(bufio.ScanLines)
@@ -46,7 +39,7 @@ func (f *formatter) FormatText(text string) string {
// FormatString форматирует одиночную строку: обрезает пробелы и заменяет // FormatString форматирует одиночную строку: обрезает пробелы и заменяет
// "--" на тире. // "--" на тире.
func (f *formatter) FormatString(text string) string { func FormatString(text string) string {
l := strings.TrimSpace(text) l := strings.TrimSpace(text)
if strings.HasPrefix(l, "--") { if strings.HasPrefix(l, "--") {
l = strings.Replace(l, "--", "—", 1) l = strings.Replace(l, "--", "—", 1)
@@ -29,10 +29,9 @@ func Test_service_FormatText(t *testing.T) {
want: " — Привет", want: " — Привет",
}, },
} }
formatter := NewFormatter()
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got := formatter.FormatText(tt.text) got := FormatText(tt.text)
if got != tt.want { if got != tt.want {
t.Errorf("FormatText() = %v, want %v", got, tt.want) t.Errorf("FormatText() = %v, want %v", got, tt.want)
} }
@@ -1,7 +0,0 @@
package string_tools
// IStringTools — утилиты работы со строками.
type IStringTools interface {
// Transliterate выполняет транслитерацию русского текста в латиницу.
Transliterate(text string) string
}
@@ -44,16 +44,9 @@ var (
) )
) )
type stringTools struct{}
// NewStringTools создаёт реализацию IStringTools.
func NewStringTools() IStringTools {
return &stringTools{}
}
// Transliterate выполняет транслитерацию русского текста в латиницу, // Transliterate выполняет транслитерацию русского текста в латиницу,
// заменяет пробелы на _, удаляет все остальные символы, кроме цифр (знаки препинания и т.д.) // заменяет пробелы на _, удаляет все остальные символы, кроме цифр (знаки препинания и т.д.)
func (s *stringTools) Transliterate(text string) string { func Transliterate(text string) string {
// Приводим к нижнему регистру и транслитерируем // Приводим к нижнему регистру и транслитерируем
result := replacer.Replace(strings.ToLower(text)) result := replacer.Replace(strings.ToLower(text))
+1 -4
View File
@@ -40,18 +40,15 @@ var allowedExtensions = map[string]struct{}{
type FileService struct { type FileService struct {
fileStorage file_storage.IFileStorage fileStorage file_storage.IFileStorage
stringTools string_tools.IStringTools
maxFileSize int maxFileSize int
} }
func NewFileService( func NewFileService(
fileStorage file_storage.IFileStorage, fileStorage file_storage.IFileStorage,
stringTools string_tools.IStringTools,
maxFileSize int, maxFileSize int,
) *FileService { ) *FileService {
return &FileService{ return &FileService{
fileStorage: fileStorage, fileStorage: fileStorage,
stringTools: stringTools,
maxFileSize: maxFileSize, maxFileSize: maxFileSize,
} }
} }
@@ -86,7 +83,7 @@ func (s *FileService) UploadFile(
// Транслитерация может обнулить base (например, «!!!.pdf»): хранимое // Транслитерация может обнулить base (например, «!!!.pdf»): хранимое
// имя без base недопустимо — проверяем до размера и содержимого. // имя без base недопустимо — проверяем до размера и содержимого.
transliterated := s.stringTools.Transliterate(base) transliterated := string_tools.Transliterate(base)
if transliterated == "" { if transliterated == "" {
return "", "", ErrEmptyName return "", "", ErrEmptyName
} }
@@ -7,7 +7,6 @@ import (
"testing" "testing"
"evening_detective_server/internal/modules/file_storage" "evening_detective_server/internal/modules/file_storage"
"evening_detective_server/internal/modules/string_tools"
) )
// fakeStorage — in-memory реализация IFileStorage для тестов. // fakeStorage — in-memory реализация IFileStorage для тестов.
@@ -44,7 +43,7 @@ func (s *fakeStorage) MimeType(filename string) string {
} }
func newService(maxFileSize int) *FileService { func newService(maxFileSize int) *FileService {
return NewFileService(newFakeStorage(), string_tools.NewStringTools(), maxFileSize) return NewFileService(newFakeStorage(), maxFileSize)
} }
func mustUpload(t *testing.T, svc *FileService, filename string, data []byte) (string, string) { func mustUpload(t *testing.T, svc *FileService, filename string, data []byte) (string, string) {