Advertisement
bruimafia

template service

Mar 27th, 2025
291
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 8.56 KB | None | 0 0
  1. package services
  2.  
  3. import (
  4.     "document-flow-server/internal/apperrors"
  5.     "document-flow-server/internal/constants"
  6.     "document-flow-server/internal/models"
  7.     "document-flow-server/internal/repositories"
  8.     "document-flow-server/internal/storage"
  9.     "document-flow-server/internal/utils"
  10.     "encoding/json"
  11.     "fmt"
  12.     "mime/multipart"
  13.     "os"
  14.     "path/filepath"
  15. )
  16.  
  17. type FileInfo struct {
  18.     OldFilePath         string
  19.     OldDirPath          string
  20.     NewDirPath          string
  21.     NewFileName         string
  22.     OldJSONName         string
  23.     NewFilePathInOldDir string
  24.     NewFilePath         string
  25.     OldJSONInNewPath    string
  26.     NewJSONFileName     string
  27. }
  28.  
  29. // GetTemplates получает список шаблонов: либо всех, либо с пагинацией
  30. func GetTemplates(page, limit *int) (models.TemplatesResponse, error) {
  31.     if page == nil || limit == nil {
  32.         return repositories.GetAllTemplates()
  33.     }
  34.  
  35.     return repositories.GetTemplatesPaginated(*page, *limit)
  36. }
  37.  
  38. // CreateTemplate создаёт новый шаблон и возвращает его с предзагруженными данными
  39. func CreateTemplate(fieldsJSON string, file *multipart.File, fileHeader *multipart.FileHeader, user *models.User) (*models.Template, error) {
  40.     if !user.HasRole("admin") {
  41.         return nil, apperrors.ErrForbidden
  42.     }
  43.  
  44.     var template models.Template
  45.     err := json.Unmarshal([]byte(fieldsJSON), &template)
  46.     if err != nil {
  47.         return nil, fmt.Errorf("недопустимый формат JSON в полях: %w", err)
  48.     }
  49.     template.Creator = nil
  50.  
  51.     // проверка на существование шаблона с таким же именем
  52.     exists, err := repositories.TemplateExistsByName(template.Name)
  53.     if err != nil {
  54.         return nil, fmt.Errorf("ошибка при проверке существования шаблона: %w", err)
  55.     }
  56.     if exists {
  57.         return nil, apperrors.ErrTemplateAlreadyExists
  58.     }
  59.  
  60.     savedName := utils.ToSnakeCase(template.Name) + filepath.Ext(fileHeader.Filename)
  61.     savedPath, err := storage.SaveFile(*file, savedName, filepath.Join(constants.TEMPLATES_FOLDER, utils.ToSnakeCase(template.Name)))
  62.     if err != nil {
  63.         return nil, err
  64.     }
  65.     template.FileName = savedName
  66.     template.Path = savedPath
  67.  
  68.     createdTemplate, err := repositories.CreateTemplate(&template)
  69.     if err != nil {
  70.         return nil, fmt.Errorf("ошибка при сохранении шаблона в базу данных: %w", err)
  71.     }
  72.  
  73.     fileNameJson := utils.ToSnakeCase(template.Name) + ".json"
  74.     savePath := filepath.Join(constants.TEMPLATES_FOLDER, utils.ToSnakeCase(template.Name))
  75.  
  76.     templateJson, err := json.MarshalIndent(template, "", "  ")
  77.     if err != nil {
  78.         return nil, fmt.Errorf("не удалось сериализовать шаблон в JSON: %v", err)
  79.     }
  80.  
  81.     _, err = storage.SaveFileFromBytes(templateJson, fileNameJson, savePath)
  82.     if err != nil {
  83.         return nil, fmt.Errorf("не удалось сохранить файл JSON: %v", err)
  84.     }
  85.  
  86.     return createdTemplate, nil
  87. }
  88.  
  89. // GetTemplateById получает шаблон по его идентификатору
  90. func GetTemplateById(id uint64) (*models.Template, error) {
  91.     return repositories.GetTemplateById(id)
  92. }
  93.  
  94. // UpdateTemplateById обновляет шаблон по его идентификатору
  95. func UpdateTemplateById(id uint64, fieldsJSON string, file *multipart.File, fileHeader *multipart.FileHeader, user *models.User) (*models.Template, error) {
  96.     if !user.HasRole("admin") {
  97.         return nil, apperrors.ErrForbidden
  98.     }
  99.  
  100.     currentTemplate, err := repositories.GetTemplateById(id)
  101.     if err != nil {
  102.         return nil, err
  103.     }
  104.  
  105.     updates := make(map[string]interface{})
  106.     // парсим JSON только если он не пустой
  107.     if fieldsJSON != "" {
  108.         if err := json.Unmarshal([]byte(fieldsJSON), &updates); err != nil {
  109.             return nil, fmt.Errorf("неверный формат JSON: %v", err)
  110.         }
  111.  
  112.         if markers, ok := updates["markers"].([]interface{}); ok {
  113.             var strArr models.StringArray
  114.             for _, m := range markers {
  115.                 if s, ok := m.(string); ok {
  116.                     strArr = append(strArr, s)
  117.                 }
  118.             }
  119.             updates["markers"] = strArr
  120.         }
  121.     }
  122.  
  123.     newName, nameUpdated := updates["name"].(string)
  124.     if nameUpdated && newName != currentTemplate.Name {
  125.         exists, err := repositories.TemplateExistsByName(newName)
  126.         if err != nil {
  127.             return nil, fmt.Errorf("ошибка проверки имени: %v", err)
  128.         }
  129.         if exists {
  130.             return nil, apperrors.ErrTemplateAlreadyExists
  131.         }
  132.     } else {
  133.         newName = currentTemplate.Name
  134.     }
  135.  
  136.     var newDir, newFileName, newFilePath string
  137.     if nameUpdated || file != nil {
  138.         if nameUpdated {
  139.             newDir = utils.ToSnakeCase(newName)
  140.         } else {
  141.             newDir = utils.ToSnakeCase(currentTemplate.Name)
  142.         }
  143.  
  144.         if file != nil {
  145.             newFileName = utils.ToSnakeCase(newName) + filepath.Ext(fileHeader.Filename)
  146.         } else {
  147.             newFileName = utils.ToSnakeCase(newName) + filepath.Ext(currentTemplate.FileName)
  148.         }
  149.  
  150.         newFilePath = filepath.Join(constants.TEMPLATES_FOLDER, newDir, newFileName)
  151.  
  152.         if nameUpdated {
  153.             os.MkdirAll(filepath.Join(constants.TEMPLATES_FOLDER, newDir), os.ModePerm)
  154.             oldDir := filepath.Dir(currentTemplate.Path)
  155.  
  156.             if file != nil {
  157.                 savedPath, err := storage.SaveFile(*file, newFileName, filepath.Join(constants.TEMPLATES_FOLDER, newDir))
  158.                 if err != nil {
  159.                     return nil, err
  160.                 }
  161.                 newFilePath = savedPath
  162.             } else {
  163.                 os.Rename(currentTemplate.Path, newFilePath)
  164.                 oldJsonPath := filepath.Join(oldDir, utils.ToSnakeCase(currentTemplate.Name)+".json")
  165.                 newJsonPath := filepath.Join(constants.TEMPLATES_FOLDER, newDir, utils.ToSnakeCase(newName)+".json")
  166.                 os.Rename(oldJsonPath, newJsonPath)
  167.                 os.Remove(oldDir)
  168.             }
  169.         } else if file != nil {
  170.             savedPath, err := storage.SaveFile(*file, newFileName, filepath.Join(constants.TEMPLATES_FOLDER, newDir))
  171.             if err != nil {
  172.                 return nil, err
  173.             }
  174.             newFilePath = savedPath
  175.         }
  176.  
  177.         updates["path"] = newFilePath
  178.         updates["file_name"] = newFileName
  179.     }
  180.  
  181.     allowedFields := map[string]bool{"name": true, "description": true, "color": true, "markers": true, "path": true, "file_name": true}
  182.     filteredUpdates := make(map[string]interface{})
  183.     for key, val := range updates {
  184.         if allowedFields[key] {
  185.             filteredUpdates[key] = val
  186.         }
  187.     }
  188.  
  189.     // если есть что обновлять в БД
  190.     var updatedTemplate *models.Template
  191.     if len(filteredUpdates) > 0 || nameUpdated || file != nil {
  192.         updatedTemplate, err = repositories.UpdateTemplateById(id, filteredUpdates)
  193.         if err != nil {
  194.             return nil, err
  195.         }
  196.     } else {
  197.         return currentTemplate, nil
  198.     }
  199.  
  200.     jsonData, _ := json.MarshalIndent(updatedTemplate, "", "  ")
  201.     jsonFileName := utils.ToSnakeCase(updatedTemplate.Name) + ".json"
  202.     jsonDir := filepath.Join(constants.TEMPLATES_FOLDER, utils.ToSnakeCase(updatedTemplate.Name))
  203.     storage.SaveFileFromBytes(jsonData, jsonFileName, jsonDir)
  204.  
  205.     return updatedTemplate, nil
  206. }
  207.  
  208. // DeleteTemplateById удаляет шаблон по его идентификатору
  209. func DeleteTemplateById(id uint64, user *models.User) error {
  210.     if !user.HasRole("admin") {
  211.         return apperrors.ErrForbidden
  212.     }
  213.  
  214.     // получение данных шаблона перед удалением (чтобы удалить файлы)
  215.     //template, err := repositories.GetTemplateById(id)
  216.     //if err != nil {
  217.     //  fmt.Printf("Шаблон с ID %d не найден", id)
  218.     //  return err
  219.     //}
  220.  
  221.     if err := repositories.DeleteTemplateById(id); err != nil {
  222.         return fmt.Errorf("ошибка при удалении шаблона из базы данных: %w", err)
  223.     }
  224.  
  225.     // удаление директории шаблона с сервера
  226.     // пока временно убрано, чтобы можно было редактировать шаблоны, основанные на удаленных шаблонах
  227.     //dirPath := filepath.Join(constants.TEMPLATES_FOLDER, utils.ToSnakeCase(template.Name))
  228.     //err = storage.DeleteDir(dirPath, 0)
  229.     //if err != nil {
  230.     //  fmt.Printf("Ошибка при удалении директории шаблона %s\n", err.Error())
  231.     //}
  232.  
  233.     return nil
  234. }
  235.  
  236. // SearchTemplates универсально ищет по разным полям
  237. func SearchTemplates(query string, page, limit *int) (models.TemplatesResponse, error) {
  238.     if page != nil && *page < 1 || limit != nil && *limit < 1 {
  239.         return models.TemplatesResponse{},
  240.             apperrors.ErrInvalidParams.WithCustomMessage("неверные параметры пагинации. page и limit должны быть больше 0")
  241.     }
  242.     return repositories.SearchTemplates(query, *page, *limit)
  243. }
  244.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement