362 lines
10 KiB
Go
362 lines
10 KiB
Go
package equipment
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"jannex/admin-dashboard-backend/modules/config"
|
|
"jannex/admin-dashboard-backend/modules/database"
|
|
"jannex/admin-dashboard-backend/modules/logger"
|
|
"jannex/admin-dashboard-backend/modules/structs"
|
|
"jannex/admin-dashboard-backend/modules/utils"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/google/uuid"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
const Base = "https://inv.ex.umbach.dev"
|
|
const apiBase = Base + "/api"
|
|
const ApiToken = "1367f15d21935e4eb540f897946fb5cd98485c3f"
|
|
|
|
func InvexApiRequestClient(requestMethod string, url string) (statusCode int, body []byte, err error) {
|
|
a := fiber.AcquireAgent()
|
|
|
|
a.Add("Authorization", "Token "+ApiToken)
|
|
|
|
req := a.Request()
|
|
req.Header.SetMethod(requestMethod)
|
|
req.SetRequestURI(url)
|
|
|
|
if err := a.Parse(); err != nil {
|
|
log.Error().Msgf("Failed to parse request, err: %s", err)
|
|
return 0, nil, err
|
|
}
|
|
|
|
code, body, _ := a.Bytes()
|
|
|
|
if code == 401 {
|
|
log.Error().Msgf("invex not authorized, code: %d", code)
|
|
|
|
logger.AddSystemLog(structs.LogMessage{
|
|
Id: 29,
|
|
Type: utils.LogTypeInfo,
|
|
Messages: []structs.LogData{
|
|
{Type: "error", Value: "invex not authorized"},
|
|
{Type: "statusCode", Value: strconv.Itoa(code)},
|
|
},
|
|
})
|
|
|
|
return code, nil, err
|
|
}
|
|
|
|
if code == 404 {
|
|
log.Error().Msgf("Invex stock item not found, code: %d", code)
|
|
|
|
logger.AddSystemLog(structs.LogMessage{
|
|
Id: 29,
|
|
Type: utils.LogTypeInfo,
|
|
Messages: []structs.LogData{
|
|
{Type: "error", Value: "invex stock item not found"},
|
|
{Type: "statusCode", Value: strconv.Itoa(code)},
|
|
},
|
|
})
|
|
return code, nil, err
|
|
}
|
|
|
|
return code, body, nil
|
|
}
|
|
|
|
type Notes struct {
|
|
Image string
|
|
Description string
|
|
}
|
|
|
|
func getImageType(data string) string {
|
|
switch data {
|
|
case "data:image/png;base64":
|
|
return "png"
|
|
default:
|
|
return "jpeg"
|
|
}
|
|
}
|
|
|
|
func CreateEquipmentDocumentation(c *fiber.Ctx, body structs.CreateEquipmentDocumentationRequest) error {
|
|
var bodyNotes []map[string]string
|
|
|
|
err := json.Unmarshal(body.Notes, &bodyNotes)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to unmarshal json, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
userId := c.Locals("userId").(string)
|
|
|
|
newEquipmentDocumentation := structs.EquipmentDocumentation{
|
|
Id: uuid.New().String(),
|
|
StockItemId: body.StockItemId,
|
|
Type: body.Type,
|
|
Title: body.Title,
|
|
CreatedByUserId: userId,
|
|
}
|
|
|
|
if err := os.Mkdir(config.Cfg.FolderPaths.PublicStatic+"/equipmentdocumentation/"+newEquipmentDocumentation.Id, os.ModePerm); err != nil {
|
|
log.Error().Msgf("Failed to create folder, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
var notes []Notes
|
|
|
|
// loop throught bodyNotes and save image to static folder under random name
|
|
for _, bodyNote := range bodyNotes {
|
|
var newFileName string
|
|
|
|
if bodyNote["Image"] != "" {
|
|
// image is sent as base64 string
|
|
// decode it and save it to the static folder
|
|
|
|
// encoded base64 image structure is: data:image/jpeg;base64,/9j/4AA...
|
|
splittedImageData := strings.Split(bodyNote["Image"], ",")
|
|
|
|
decodedImage, err := base64.StdEncoding.DecodeString(splittedImageData[1])
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to decode base64 string, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
newFileName = uuid.New().String() + "." + getImageType(splittedImageData[0])
|
|
|
|
err = os.WriteFile(config.Cfg.FolderPaths.PublicStatic+"/equipmentdocumentation/"+newEquipmentDocumentation.Id+"/"+newFileName, decodedImage, 0644)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to save image, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
notes = append(notes, Notes{
|
|
Image: newFileName,
|
|
Description: bodyNote["Description"],
|
|
})
|
|
}
|
|
|
|
marshaledNotes, err := json.Marshal(notes)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to marshal notes, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
newEquipmentDocumentation.Notes = string(marshaledNotes)
|
|
|
|
database.DB.Create(&newEquipmentDocumentation)
|
|
|
|
logger.AddSystemLog(structs.LogMessage{
|
|
Id: 27,
|
|
Type: utils.LogTypeInfo,
|
|
Messages: []structs.LogData{
|
|
{Type: "userId", Value: userId},
|
|
{Type: "equipmentDocumentationId", Value: newEquipmentDocumentation.Id},
|
|
{Type: "stockItemId", Value: newEquipmentDocumentation.StockItemId},
|
|
{Type: "type", Value: strconv.Itoa(int(body.Type))},
|
|
{Type: "title", Value: body.Title},
|
|
{Type: "description", Value: string(marshaledNotes)},
|
|
},
|
|
})
|
|
|
|
return c.JSON(fiber.Map{"message": "ok"})
|
|
}
|
|
|
|
func GetEquipmentDocumentations(stockItemId string, c *fiber.Ctx) error {
|
|
var documentations []structs.EquipmentDocumentation
|
|
|
|
database.DB.Where("stock_item_id = ?", stockItemId).Find(&documentations)
|
|
|
|
var err error
|
|
statusCode := 200
|
|
|
|
if len(documentations) == 0 {
|
|
// there are no documentations for this equipment on the our database
|
|
// so there will be checked on invex if the stock item exists
|
|
statusCode, _, err = InvexApiRequestClient(fiber.MethodGet, apiBase+"/stock/"+stockItemId+"/")
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Invex api request error: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
logger.AddSystemLog(structs.LogMessage{
|
|
Id: 30,
|
|
Type: utils.LogTypeInfo,
|
|
Messages: []structs.LogData{
|
|
{Type: "userId", Value: c.Locals("userId").(string)},
|
|
{Type: "stockItemId", Value: stockItemId},
|
|
{Type: "statusCode", Value: strconv.Itoa(statusCode)},
|
|
},
|
|
})
|
|
|
|
return c.JSON(structs.EquipmentDocumentationResponse{
|
|
Status: statusCode,
|
|
Documentations: documentations})
|
|
}
|
|
|
|
func GetEquipmentDocumentation(stockItemId string, documentationId string, c *fiber.Ctx) error {
|
|
var documentation structs.EquipmentDocumentation
|
|
|
|
database.DB.Where("id = ? AND stock_item_id = ?", documentationId, stockItemId).Find(&documentation)
|
|
|
|
return c.JSON(documentation)
|
|
}
|
|
|
|
func EditEquipmentDocumentation(c *fiber.Ctx, body structs.EditEquipmentDocumentationRequest) error {
|
|
var bodyNotes []map[string]string
|
|
|
|
err := json.Unmarshal(body.Notes, &bodyNotes)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to unmarshal json, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
var notes []Notes
|
|
|
|
// loop throught bodyNotes and save image to static folder under random name
|
|
for _, bodyNote := range bodyNotes {
|
|
newFileName := bodyNote["Image"]
|
|
|
|
if bodyNote["Image"] != "" {
|
|
// check if image starts with base64 string
|
|
if strings.HasPrefix(bodyNote["Image"], "data:") {
|
|
// image is sent as base64 string
|
|
// decode it and save it to the static folder
|
|
|
|
// encoded base64 image structure is: data:image/jpeg;base64,/9j/4AA...
|
|
splittedImageData := strings.Split(bodyNote["Image"], ",")
|
|
|
|
decodedImage, err := base64.StdEncoding.DecodeString(splittedImageData[1])
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to decode base64 string, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
newFileName = uuid.New().String() + "." + getImageType(splittedImageData[0])
|
|
|
|
err = os.WriteFile(config.Cfg.FolderPaths.PublicStatic+"/equipmentdocumentation/"+body.DocumentationId+"/"+newFileName, decodedImage, 0644)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to save image, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
}
|
|
}
|
|
|
|
notes = append(notes, Notes{
|
|
Image: newFileName,
|
|
Description: bodyNote["Description"],
|
|
})
|
|
}
|
|
|
|
// read all images on the folder and delete images that are not longer used in notes
|
|
files, err := os.ReadDir(config.Cfg.FolderPaths.PublicStatic + "/equipmentdocumentation/" + body.DocumentationId)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to read directory, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
for _, file := range files {
|
|
if file.IsDir() {
|
|
continue
|
|
}
|
|
|
|
if !isInList(file.Name(), notes) {
|
|
err := os.Remove(config.Cfg.FolderPaths.PublicStatic + "/equipmentdocumentation/" + body.DocumentationId + "/" + file.Name())
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to remove file, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
}
|
|
}
|
|
|
|
// marshal notes to json
|
|
marshaledNotes, err := json.Marshal(notes)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to marshal notes, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
database.DB.Model(&structs.EquipmentDocumentation{}).Where("id = ?", body.DocumentationId).Updates(structs.EquipmentDocumentation{
|
|
Type: body.Type,
|
|
Title: body.Title,
|
|
Notes: string(marshaledNotes),
|
|
})
|
|
|
|
logger.AddSystemLog(structs.LogMessage{
|
|
Id: 28,
|
|
Type: utils.LogTypeInfo,
|
|
Messages: []structs.LogData{
|
|
{Type: "userId", Value: c.Locals("userId").(string)},
|
|
{Type: "equipmentDocumentationId", Value: body.DocumentationId},
|
|
{Type: "title", Value: body.Title},
|
|
{Type: "type", Value: strconv.Itoa(int(body.Type))},
|
|
{Type: "description", Value: string(marshaledNotes)},
|
|
},
|
|
})
|
|
|
|
return c.JSON(fiber.Map{"message": "ok"})
|
|
}
|
|
|
|
func isInList(fileName string, notes []Notes) bool {
|
|
for _, note := range notes {
|
|
if note.Image == fileName {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// fetching the thumbnail from the invex server and sending it back to the client
|
|
func GetEquipmentInvexThumbnail(c *fiber.Ctx, stockItemId string) error {
|
|
// first request to /api/stock/:stockItemId/ to get the thumbnail url
|
|
_, body, err := InvexApiRequestClient(fiber.MethodGet, apiBase+"/stock/"+stockItemId+"/")
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Invex api request error: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
// parse body as json
|
|
var data map[string]interface{}
|
|
|
|
if err := json.Unmarshal(body, &data); err != nil {
|
|
log.Error().Msgf("Failed to unmarshal json, err: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
partDetail := data["part_detail"].(map[string]interface{})
|
|
thumbnail := partDetail["thumbnail"].(string)
|
|
|
|
// second request to /media/part_images/:thumbnail to get the thumbnail image
|
|
_, body, err = InvexApiRequestClient(fiber.MethodGet, Base+"/"+thumbnail)
|
|
|
|
if err != nil {
|
|
log.Error().Msgf("Invex api request error: %s", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
c.Set("Content-Type", "image/png")
|
|
|
|
return c.Send(body)
|
|
}
|