diff --git a/app/database/entity/ppid_data_categories.entity.go b/app/database/entity/ppid_data_categories.entity.go index c09e1cd..4a04685 100644 --- a/app/database/entity/ppid_data_categories.entity.go +++ b/app/database/entity/ppid_data_categories.entity.go @@ -10,6 +10,7 @@ type PpidDataCategories struct { ParentId *uint `json:"parent_id" gorm:"type:int4"` Position *int `json:"position" gorm:"type:int4"` ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"` + ThumbnailUrl *string `json:"thumbnail_url" gorm:"type:varchar"` IsActive *bool `json:"is_active" gorm:"type:bool;default:true"` CreatedAt time.Time `json:"created_at" gorm:"default:now()"` UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"` diff --git a/app/database/entity/ppid_data_files.entity.go b/app/database/entity/ppid_data_files.entity.go index 71ae48a..6c66a31 100644 --- a/app/database/entity/ppid_data_files.entity.go +++ b/app/database/entity/ppid_data_files.entity.go @@ -6,6 +6,7 @@ type PpidDataFiles struct { ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"` PpidDataId int `json:"ppid_data_id" gorm:"type:int4"` Title *string `json:"title" gorm:"type:varchar"` + Type *string `json:"type" gorm:"type:varchar"` FileType *string `json:"file_type" gorm:"type:varchar"` FileName *string `json:"file_name" gorm:"type:varchar"` FilePath *string `json:"file_path" gorm:"type:varchar"` diff --git a/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go b/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go index 6d3a54b..ce8787f 100644 --- a/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go +++ b/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go @@ -12,7 +12,6 @@ import ( "go-humas-be/app/module/ppid_datas/response" usersRepository "go-humas-be/app/module/users/repository" "go-humas-be/utils/paginator" - "strconv" ) func PpidDataCategoriesResponseMapper(ppidDataCategoriesReq *entity.PpidDataCategories, childPpidDataCategoriesReq []*entity.PpidDataCategories) (ppidDataCategoriesRes *res.PpidDataCategoriesResponse) { @@ -31,7 +30,7 @@ func PpidDataCategoriesResponseMapper(ppidDataCategoriesReq *entity.PpidDataCate Slug: ppidDataCategoriesReq.Slug, ParentId: ppidDataCategoriesReq.ParentId, Position: ppidDataCategoriesReq.Position, - ThumbnailUrl: "/ppid-data-categories/thumbnail/viewer/" + strconv.Itoa(int(ppidDataCategoriesReq.ID)), + ThumbnailUrl: ppidDataCategoriesReq.ThumbnailUrl, IsActive: ppidDataCategoriesReq.IsActive, CreatedAt: ppidDataCategoriesReq.CreatedAt, UpdatedAt: ppidDataCategoriesReq.UpdatedAt, @@ -76,7 +75,7 @@ func PpidDataCategoriesWithPpidDataResponseMapper( Slug: ppidDataCategoriesReq.Slug, ParentId: ppidDataCategoriesReq.ParentId, Position: ppidDataCategoriesReq.Position, - ThumbnailUrl: "/ppid-data-categories/thumbnail/viewer/" + strconv.Itoa(int(ppidDataCategoriesReq.ID)), + ThumbnailUrl: ppidDataCategoriesReq.ThumbnailUrl, IsActive: ppidDataCategoriesReq.IsActive, CreatedAt: ppidDataCategoriesReq.CreatedAt, UpdatedAt: ppidDataCategoriesReq.UpdatedAt, diff --git a/app/module/ppid_data_categories/response/ppid_data_categories.response.go b/app/module/ppid_data_categories/response/ppid_data_categories.response.go index 75e241b..2b58af6 100644 --- a/app/module/ppid_data_categories/response/ppid_data_categories.response.go +++ b/app/module/ppid_data_categories/response/ppid_data_categories.response.go @@ -12,7 +12,7 @@ type PpidDataCategoriesResponse struct { Slug string `json:"slug"` ParentId *uint `json:"parentId"` Position *int `json:"position"` - ThumbnailUrl string `json:"thumbnailUrl"` + ThumbnailUrl *string `json:"thumbnailUrl"` IsActive *bool `json:"isActive"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` @@ -27,7 +27,7 @@ type PpidDataCategoriesWithPpidDataResponse struct { Slug string `json:"slug"` ParentId *uint `json:"parentId"` Position *int `json:"position"` - ThumbnailUrl string `json:"thumbnailUrl"` + ThumbnailUrl *string `json:"thumbnailUrl"` IsActive *bool `json:"isActive"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` diff --git a/app/module/ppid_data_categories/service/ppid_data_categories.service.go b/app/module/ppid_data_categories/service/ppid_data_categories.service.go index ce01cd9..ef0f746 100644 --- a/app/module/ppid_data_categories/service/ppid_data_categories.service.go +++ b/app/module/ppid_data_categories/service/ppid_data_categories.service.go @@ -13,7 +13,7 @@ import ( ppidDataFilesRepository "go-humas-be/app/module/ppid_data_files/repository" ppidDatasRepository "go-humas-be/app/module/ppid_datas/repository" usersRepository "go-humas-be/app/module/users/repository" - minioStorage "go-humas-be/config/config" + config "go-humas-be/config/config" "go-humas-be/utils/paginator" "io" "log" @@ -31,8 +31,9 @@ type ppidDataCategoriesService struct { PpidDatasRepo ppidDatasRepository.PpidDatasRepository PpidDataFilesRepo ppidDataFilesRepository.PpidDataFilesRepository UsersRepo usersRepository.UsersRepository - MinioStorage *minioStorage.MinioStorage + MinioStorage *config.MinioStorage Log zerolog.Logger + Cfg *config.Config } // PpidDataCategoriesService define interface of IPpidDataCategoriesService @@ -55,8 +56,9 @@ func NewPpidDataCategoriesService( ppidDatasRepo ppidDatasRepository.PpidDatasRepository, ppidDataFilesRepo ppidDataFilesRepository.PpidDataFilesRepository, usersRepo usersRepository.UsersRepository, - minioStorage *minioStorage.MinioStorage, + minioStorage *config.MinioStorage, log zerolog.Logger, + cfg *config.Config, ) PpidDataCategoriesService { return &ppidDataCategoriesService{ @@ -66,6 +68,7 @@ func NewPpidDataCategoriesService( UsersRepo: usersRepo, MinioStorage: minioStorage, Log: log, + Cfg: cfg, } } @@ -159,6 +162,9 @@ func (_i *ppidDataCategoriesService) SaveThumbnail(c *fiber.Ctx) (err error) { return err } + host := _i.Cfg.App.Host + port := _i.Cfg.App.ExternalPort + _i.Log.Info().Str("timestamp", time.Now(). Format(time.RFC3339)).Str("Service:SaveThumbnail", "Categories:SaveThumbnail"). Interface("id", id).Msg("") @@ -207,7 +213,12 @@ func (_i *ppidDataCategoriesService) SaveThumbnail(c *fiber.Ctx) (err error) { objectName := "ppid/category/thumbnail/" + newFilename findCategory, err := _i.Repo.FindOne(uint(id)) + + thumbnailUrl := host + port + "/ppid-data-categories/thumbnail/viewer/" + strconv.Itoa(int(id)) + findCategory.ThumbnailPath = &objectName + findCategory.ThumbnailUrl = &thumbnailUrl + err = _i.Repo.Update(uint(id), findCategory) if err != nil { return err diff --git a/app/module/ppid_data_files/controller/ppid_data_files.controller.go b/app/module/ppid_data_files/controller/ppid_data_files.controller.go index 7d7ba90..4992103 100644 --- a/app/module/ppid_data_files/controller/ppid_data_files.controller.go +++ b/app/module/ppid_data_files/controller/ppid_data_files.controller.go @@ -111,7 +111,10 @@ func (_i *ppidDataFilesController) Show(c *fiber.Ctx) error { // @Tags PPID Files // @Security Bearer // @Produce json -// @Param files formData file true "Upload file" +// @Param types formData string false "Types" +// @Param positions formData string false "Positions" +// @Param urls formData string false "Upload Url" +// @Param files formData file false "Upload File" // @Param ppidDataId path int true "Ppid Data ID" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError diff --git a/app/module/ppid_data_files/mapper/ppid_data_files.mapper.go b/app/module/ppid_data_files/mapper/ppid_data_files.mapper.go index 1610bd3..c2f4824 100644 --- a/app/module/ppid_data_files/mapper/ppid_data_files.mapper.go +++ b/app/module/ppid_data_files/mapper/ppid_data_files.mapper.go @@ -6,16 +6,14 @@ import ( ) func PpidDataFilesResponseMapper(ppidDataFilesReq *entity.PpidDataFiles) (ppidDataFilesRes *res.PpidDataFilesResponse) { - fileUrl := "/ppid-data-files/viewer/" - if ppidDataFilesReq.FileName != nil { - fileUrl += *ppidDataFilesReq.FileName - } if ppidDataFilesReq != nil { ppidDataFilesRes = &res.PpidDataFilesResponse{ ID: ppidDataFilesReq.ID, Title: ppidDataFilesReq.Title, + Type: ppidDataFilesReq.Type, PpidDataId: ppidDataFilesReq.PpidDataId, - FileUrl: fileUrl, + FileName: ppidDataFilesReq.FileName, + FileUrl: ppidDataFilesReq.FileUrl, FileType: ppidDataFilesReq.FileType, DownloadCount: ppidDataFilesReq.DownloadCount, Position: ppidDataFilesReq.Position, diff --git a/app/module/ppid_data_files/request/ppid_data_files.request.go b/app/module/ppid_data_files/request/ppid_data_files.request.go index 7684d2b..d9831eb 100644 --- a/app/module/ppid_data_files/request/ppid_data_files.request.go +++ b/app/module/ppid_data_files/request/ppid_data_files.request.go @@ -24,10 +24,13 @@ type PpidDataFilesQueryRequest struct { type PpidDataFilesCreateRequest struct { PpidDataId int `json:"ppidDataId" validate:"required"` - Title *string `json:"title" validate:"required"` + Title *string `json:"title"` + Type *string `json:"type"` + Position *int `json:"position"` FileType *string `json:"fileType"` FileName *string `json:"fileName"` FilePath *string `json:"filePath"` + FileUrl *string `json:"fileUrl"` Size *string `json:"size"` CreatedById *int `json:"createdById"` StatusId *int `json:"statusId"` @@ -36,10 +39,13 @@ type PpidDataFilesCreateRequest struct { func (req PpidDataFilesCreateRequest) ToEntity() *entity.PpidDataFiles { return &entity.PpidDataFiles{ Title: req.Title, + Type: req.Type, + Position: req.Position, PpidDataId: req.PpidDataId, FileType: req.FileType, FileName: req.FileName, FilePath: req.FilePath, + FileUrl: req.FileUrl, Size: req.Size, CreatedById: req.CreatedById, StatusId: req.StatusId, diff --git a/app/module/ppid_data_files/response/ppid_data_files.response.go b/app/module/ppid_data_files/response/ppid_data_files.response.go index 5deb365..a3f8ded 100644 --- a/app/module/ppid_data_files/response/ppid_data_files.response.go +++ b/app/module/ppid_data_files/response/ppid_data_files.response.go @@ -5,10 +5,11 @@ import "time" type PpidDataFilesResponse struct { ID uint `json:"id"` Title *string `json:"title"` + Type *string `json:"type"` PpidDataId int `json:"ppidDataId"` - FileName uint `json:"fileName"` + FileName *string `json:"fileName"` FileType *string `json:"fileType"` - FileUrl string `json:"fileUrl"` + FileUrl *string `json:"fileUrl"` DownloadCount *int `json:"downloadCount"` CreatedById *int `json:"createdById"` Position *int `json:"position"` diff --git a/app/module/ppid_data_files/service/ppid_data_files.service.go b/app/module/ppid_data_files/service/ppid_data_files.service.go index 9601e39..fb89a0b 100644 --- a/app/module/ppid_data_files/service/ppid_data_files.service.go +++ b/app/module/ppid_data_files/service/ppid_data_files.service.go @@ -10,12 +10,13 @@ import ( "go-humas-be/app/module/ppid_data_files/repository" "go-humas-be/app/module/ppid_data_files/request" "go-humas-be/app/module/ppid_data_files/response" - minioStorage "go-humas-be/config/config" + config "go-humas-be/config/config" "go-humas-be/utils/paginator" "io" "log" "math/rand" "mime" + "path" "path/filepath" "strconv" "strings" @@ -26,7 +27,8 @@ import ( type ppidDataFilesService struct { Repo repository.PpidDataFilesRepository Log zerolog.Logger - MinioStorage *minioStorage.MinioStorage + MinioStorage *config.MinioStorage + Cfg *config.Config } // PpidDataFilesService define interface of IPpidDataFilesService @@ -41,12 +43,13 @@ type PpidDataFilesService interface { } // NewPpidDataFilesService init PpidDataFilesService -func NewPpidDataFilesService(repo repository.PpidDataFilesRepository, log zerolog.Logger, minioStorage *minioStorage.MinioStorage) PpidDataFilesService { +func NewPpidDataFilesService(repo repository.PpidDataFilesRepository, log zerolog.Logger, minioStorage *config.MinioStorage, cfg *config.Config) PpidDataFilesService { return &ppidDataFilesService{ Repo: repo, Log: log, MinioStorage: minioStorage, + Cfg: cfg, } } @@ -80,69 +83,121 @@ func (_i *ppidDataFilesService) Save(c *fiber.Ctx) (err error) { return err } - bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName + host := _i.Cfg.App.Host + port := _i.Cfg.App.ExternalPort form, err := c.MultipartForm() - if err != nil { - return err - } + + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service", "Save"). + Interface("form", form).Msg("") + + typesString := form.Value["types"] + types := strings.Split(typesString[0], ",") + positionsString := form.Value["positions"] + positions := strings.Split(positionsString[0], ",") + urlsString := form.Value["urls"] + urls := strings.Split(urlsString[0], ",") files := form.File["files"] - // Create minio connection. - minioClient, err := _i.MinioStorage.ConnectMinio() - if err != nil { - // Return status 500 and minio connection error. - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": true, - "msg": err.Error(), - }) - } + fileCounter := 0 + urlCounter := 0 - // Iterasi semua file yang diunggah - for _, file := range files { + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service", "Save"). + Interface("form", types).Msg("") - _i.Log.Info().Str("timestamp", time.Now(). - Format(time.RFC3339)).Str("Service:Resource", "Uploader:: loop1"). - Interface("data", file).Msg("") - - src, err := file.Open() + for index, fileType := range types { + position := &positions[index] + positionInt64, err := strconv.ParseInt(*position, 10, 0) if err != nil { return err } - defer src.Close() - - filename := filepath.Base(file.Filename) - filename = strings.ReplaceAll(filename, " ", "") - filenameWithoutExt := filepath.Clean(filename[:len(filename)-len(filepath.Ext(filename))]) - extension := filepath.Ext(file.Filename)[1:] - - rand.New(rand.NewSource(time.Now().UnixNano())) - randUniqueId := rand.Intn(1000000) - - newFilenameWithoutExt := filenameWithoutExt + "_" + strconv.Itoa(randUniqueId) - newFilename := newFilenameWithoutExt + "." + extension - objectName := "ppid/upload/" + newFilename - - size := strconv.FormatInt(file.Size, 10) + positionInt := int(positionInt64) statusId := 1 - req := request.PpidDataFilesCreateRequest{ PpidDataId: int(id), - Title: &newFilenameWithoutExt, - FileType: &extension, - FileName: &newFilename, - FilePath: &objectName, - Size: &size, + Type: &fileType, + Position: &positionInt, StatusId: &statusId, } - err = _i.Repo.Create(req.ToEntity()) - if err != nil { - return err + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service", "Save"). + Interface("request", req).Msg("") + + if fileType == "url" { + url := urls[urlCounter] + filename := path.Base(url) + filenameWithoutExt := filepath.Clean(filename[:len(filename)-len(filepath.Ext(filename))]) + extension := filepath.Ext(filename)[1:] + title := strings.ReplaceAll(filenameWithoutExt, "-", " ") + + req.Title = &title + req.FileType = &extension + req.FileName = &filename + req.FileUrl = &url + + urlCounter += 1 + } else { + bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName + + // Create minio connection. + minioClient, err := _i.MinioStorage.ConnectMinio() + if err != nil { + // Return status 500 and minio connection error. + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": true, + "msg": err.Error(), + }) + } + + // Iterasi semua file yang diunggah + file := files[fileCounter] + + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service:Resource", "Uploader:: loop1"). + Interface("data", file).Msg("") + + src, err := file.Open() + if err != nil { + return err + } + defer src.Close() + + filename := filepath.Base(file.Filename) + filename = strings.ReplaceAll(filename, " ", "") + filenameWithoutExt := filepath.Clean(filename[:len(filename)-len(filepath.Ext(filename))]) + extension := filepath.Ext(file.Filename)[1:] + + rand.New(rand.NewSource(time.Now().UnixNano())) + randUniqueId := rand.Intn(1000000) + + newFilenameWithoutExt := filenameWithoutExt + "_" + strconv.Itoa(randUniqueId) + newFilename := newFilenameWithoutExt + "." + extension + objectName := "ppid/upload/" + newFilename + + size := strconv.FormatInt(file.Size, 10) + fileUrl := "/ppid-data-files/viewer/" + fileUrl += host + port + newFilename + + req.Title = &newFilenameWithoutExt + req.FileType = &extension + req.FileName = &newFilename + req.FilePath = &objectName + req.FileUrl = &fileUrl + req.Size = &size + + // Upload file to MinIO + _, err = minioClient.PutObject(context.Background(), bucketName, objectName, src, file.Size, minio.PutObjectOptions{}) + if err != nil { + return err + } + + fileCounter += 1 } - // Upload file ke MinIO - _, err = minioClient.PutObject(context.Background(), bucketName, objectName, src, file.Size, minio.PutObjectOptions{}) + err = _i.Repo.Create(req.ToEntity()) if err != nil { return err } diff --git a/app/module/ppid_datas/controller/ppid_datas.controller.go b/app/module/ppid_datas/controller/ppid_datas.controller.go index a958008..41d0902 100644 --- a/app/module/ppid_datas/controller/ppid_datas.controller.go +++ b/app/module/ppid_datas/controller/ppid_datas.controller.go @@ -112,7 +112,7 @@ func (_i *ppidDatasController) Show(c *fiber.Ctx) error { // @Description API for create PpidDatas // @Tags PPID Data // @Security Bearer -// @Param Authorization header string true "Insert your access token" default(Bearer ) +// @Param Authorization header string true "Insert your access token" default (Bearer ) // @Param payload body request.PpidDatasCreateRequest true "Required payload" // @Success 200 {object} response.Response // @Failure 400 {object} response.BadRequestError diff --git a/config/config/index.config.go b/config/config/index.config.go index b414765..b030dd7 100644 --- a/config/config/index.config.go +++ b/config/config/index.config.go @@ -14,13 +14,15 @@ import ( ) type app = struct { - Name string `toml:"name"` - Port string `toml:"port"` - PrintRoutes bool `toml:"print-routes"` - Prefork bool `toml:"prefork"` - Production bool `toml:"production"` - IdleTimeout time.Duration `toml:"idle-timeout"` - BodyLimit int `toml:"body-limit"` + Name string `toml:"name"` + Host string `toml:"host"` + Port string `toml:"port"` + ExternalPort string `toml:"external-port"` + PrintRoutes bool `toml:"print-routes"` + Prefork bool `toml:"prefork"` + Production bool `toml:"production"` + IdleTimeout time.Duration `toml:"idle-timeout"` + BodyLimit int `toml:"body-limit"` } // db struct config diff --git a/config/toml/config.toml b/config/toml/config.toml index 44cdf3a..41b35ce 100644 --- a/config/toml/config.toml +++ b/config/toml/config.toml @@ -1,7 +1,9 @@ # Configuration vars for cmd/app [app] name = "Fiber starter" +host = "http://103.82.242.92" port = ":8800" +external-port = ":8888" idle-timeout = 5 # As seconds print-routes = false prefork = true @@ -10,7 +12,7 @@ body-limit = 104857600 # "100 * 1024 * 1024" [db.postgres] dsn = "postgresql://humas_polri:P@ssw0rd.1@103.82.242.92:5432/humas_polri" # ://:@:/ -migrate = false +migrate = true seed = false [logger] diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index 61bd204..a4d8c5d 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -4521,12 +4521,29 @@ const docTemplate = `{ ], "summary": "Create PpidDataFiles", "parameters": [ + { + "type": "string", + "description": "Types", + "name": "types", + "in": "formData" + }, + { + "type": "string", + "description": "Positions", + "name": "positions", + "in": "formData" + }, + { + "type": "string", + "description": "Upload Url", + "name": "urls", + "in": "formData" + }, { "type": "file", - "description": "Upload file", + "description": "Upload File", "name": "files", - "in": "formData", - "required": true + "in": "formData" }, { "type": "integer", @@ -4717,7 +4734,6 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "default": "Bearer \u003cAdd access token here\u003e", "description": "Insert your access token", "name": "Authorization", "in": "header", diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index 2e4b615..bab2b12 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -4510,12 +4510,29 @@ ], "summary": "Create PpidDataFiles", "parameters": [ + { + "type": "string", + "description": "Types", + "name": "types", + "in": "formData" + }, + { + "type": "string", + "description": "Positions", + "name": "positions", + "in": "formData" + }, + { + "type": "string", + "description": "Upload Url", + "name": "urls", + "in": "formData" + }, { "type": "file", - "description": "Upload file", + "description": "Upload File", "name": "files", - "in": "formData", - "required": true + "in": "formData" }, { "type": "integer", @@ -4706,7 +4723,6 @@ "parameters": [ { "type": "string", - "default": "Bearer \u003cAdd access token here\u003e", "description": "Insert your access token", "name": "Authorization", "in": "header", diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 42b8843..40b1f2f 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -3445,10 +3445,21 @@ paths: post: description: API for create PpidDataFiles parameters: - - description: Upload file + - description: Types + in: formData + name: types + type: string + - description: Positions + in: formData + name: positions + type: string + - description: Upload Url + in: formData + name: urls + type: string + - description: Upload File in: formData name: files - required: true type: file - description: Ppid Data ID in: path @@ -3631,8 +3642,7 @@ paths: post: description: API for create PpidDatas parameters: - - default: Bearer - description: Insert your access token + - description: Insert your access token in: header name: Authorization required: true