feat: update article files upload and setup ci/cd

This commit is contained in:
hanif salafi 2024-03-06 21:00:43 +07:00
parent 07064f13ce
commit c5563655a9
11 changed files with 295 additions and 32 deletions

22
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,22 @@
stages:
- build
- deploy
build:
stage: build
image: golang:alpine
script:
- go build -o main .
artifacts:
paths:
- main
deploy:
stage: deploy
image: docker:stable
services:
- docker:dind
script:
- docker login -u $DEPLOY_USERNAME -p $DEPLOY_TOKEN registry.gitlab.com
- docker build -t registry.gitlab.com/hanifsalafi/web-humas-be:dev .
- docker push registry.gitlab.com/hanifsalafi/web-humas-be:dev

24
Dockerfile Normal file
View File

@ -0,0 +1,24 @@
# Menggunakan Go image resmi dari Docker Hub sebagai base image
FROM golang:alpine AS builder
# Menentukan direktori kerja
WORKDIR /app
# Menyalin file Go mod dan Go sum untuk mendownload dependensi
COPY go.mod ./
COPY go.sum ./
# Mendownload dependensi menggunakan Go module
RUN go mod download
# Menyalin seluruh file ke dalam image
COPY build .
# Mengcompile aplikasi Go
RUN go build -o main .
# Memindahkan binary hasil compile ke direktori yang lebih kecil
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]

View File

@ -181,17 +181,19 @@ func (_i *articleFilesController) Delete(c *fiber.Ctx) error {
})
}
// Upload create ArticleFiles
// @Summary Create ArticleFiles
// Uploader upload ArticleFiles
// @Summary Upload ArticleFiles
// @Description API for create ArticleFiles
// @Tags Task
// @Security Bearer
// @Produce json
// @Param files formData file true "Upload file"
// @Success 200 {object} response.Response
// @Failure 401 {object} response.Response
// @Failure 404 {object} response.Response
// @Failure 422 {object} response.Response
// @Failure 500 {object} response.Response
// @Router /article-files [post]
// @Router /article-files/uploader [post]
func (_i *articleFilesController) Uploader(c *fiber.Ctx) error {
err := _i.articleFilesService.Uploader(c, 1)
@ -209,12 +211,13 @@ func (_i *articleFilesController) Uploader(c *fiber.Ctx) error {
// @Description API for create ArticleFiles
// @Tags Task
// @Security Bearer
// @Param id path string true "Filename"
// @Success 200 {object} response.Response
// @Failure 401 {object} response.Response
// @Failure 404 {object} response.Response
// @Failure 422 {object} response.Response
// @Failure 500 {object} response.Response
// @Router /article-files/viewer [get]
// @Router /article-files/viewer/{id} [get]
func (_i *articleFilesController) Viewer(c *fiber.Ctx) error {
return _i.articleFilesService.Viewer(c, c.Params("id"))

View File

@ -9,7 +9,7 @@ import (
"go-humas-be/app/module/article_files/repository"
"go-humas-be/app/module/article_files/request"
"go-humas-be/app/module/article_files/response"
minioUpload "go-humas-be/utils/minio"
minioStorage "go-humas-be/config/config"
"go-humas-be/utils/paginator"
"io"
"log"
@ -22,6 +22,7 @@ import (
type articleFilesService struct {
Repo repository.ArticleFilesRepository
Log zerolog.Logger
MinioStorage *minioStorage.MinioStorage
}
// ArticleFilesService define interface of IArticleFilesService
@ -36,11 +37,12 @@ type ArticleFilesService interface {
}
// NewArticleFilesService init ArticleFilesService
func NewArticleFilesService(repo repository.ArticleFilesRepository, log zerolog.Logger) ArticleFilesService {
func NewArticleFilesService(repo repository.ArticleFilesRepository, log zerolog.Logger, minioStorage *minioStorage.MinioStorage) ArticleFilesService {
return &articleFilesService{
Repo: repo,
Log: log,
MinioStorage: minioStorage,
}
}
@ -83,7 +85,7 @@ func (_i *articleFilesService) Delete(id uint) error {
}
func (_i *articleFilesService) Uploader(c *fiber.Ctx, id uint) (err error) {
bucketName := "humas"
bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
form, err := c.MultipartForm()
if err != nil {
@ -92,7 +94,7 @@ func (_i *articleFilesService) Uploader(c *fiber.Ctx, id uint) (err error) {
files := form.File["files"]
// Create minio connection.
minioClient, err := minioUpload.MinioConnection()
minioClient, err := _i.MinioStorage.ConnectMinio()
if err != nil {
// Return status 500 and minio connection error.
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
@ -130,15 +132,15 @@ func (_i *articleFilesService) Uploader(c *fiber.Ctx, id uint) (err error) {
func (_i *articleFilesService) Viewer(c *fiber.Ctx, id string) (err error) {
ctx := context.Background()
bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
objectName := id
bucketName := "humas"
_i.Log.Info().Str("timestamp", time.Now().
Format(time.RFC3339)).Str("Service:Resource", "Article:Uploads").
Interface("data", objectName).Msg("")
// Create minio connection.
minioClient, err := minioUpload.MinioConnection()
minioClient, err := _i.MinioStorage.ConnectMinio()
if err != nil {
// Return status 500 and minio connection error.
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{

View File

@ -65,11 +65,24 @@ type middleware = struct {
}
}
// minio struct config
type objectStorage = struct {
MinioStorage struct {
Endpoint string `toml:"endpoint"`
AccessKeyID string `toml:"access-key-id"`
SecretAccessKey string `toml:"secret-access-key"`
UseSSL bool `toml:"use-ssl"`
BucketName string `toml:"bucket-name"`
Location string `toml:"location"`
}
}
type Config struct {
App app
DB db
Logger logger
Middleware middleware
ObjectStorage objectStorage
}
// NewConfig : initialize config

View File

@ -1,4 +1,4 @@
package minio
package config
import (
"context"
@ -7,13 +7,29 @@ import (
"log"
)
// MinioConnection membuka koneksi ke Minio.
func MinioConnection() (*minio.Client, error) {
// MinioSetup struct
type MinioStorage struct {
Cfg *Config
}
func NewMinio(cfg *Config) *MinioStorage {
minioSetup := &MinioStorage{
Cfg: cfg,
}
return minioSetup
}
func (_minio *MinioStorage) ConnectMinio() (*minio.Client, error) {
ctx := context.Background()
endpoint := "localhost:9004"
accessKeyID := "sc6ZiC6dpWMZWmfwukSF"
secretAccessKey := "Q6MsoOhYFmRctWJLMrPXdV0vwKns8d9tgUJyu1ec"
useSSL := false
endpoint := _minio.Cfg.ObjectStorage.MinioStorage.Endpoint
accessKeyID := _minio.Cfg.ObjectStorage.MinioStorage.AccessKeyID
secretAccessKey := _minio.Cfg.ObjectStorage.MinioStorage.SecretAccessKey
useSSL := _minio.Cfg.ObjectStorage.MinioStorage.UseSSL
bucketName := _minio.Cfg.ObjectStorage.MinioStorage.BucketName
location := _minio.Cfg.ObjectStorage.MinioStorage.Location
// Initialize minio client object.
minioClient, errInit := minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
@ -23,10 +39,6 @@ func MinioConnection() (*minio.Client, error) {
log.Fatalln(errInit)
}
// Make a new bucket called dev-minio.
bucketName := "humas"
location := "us-east-1"
err := minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location})
if err != nil {
// Check to see if we already own this bucket (which happens if you run this twice)

View File

@ -18,6 +18,14 @@ time-format = "" # https://pkg.go.dev/time#pkg-constants, https://github.com/rs/
level = 0 # panic -> 5, fatal -> 4, error -> 3, warn -> 2, info -> 1, debug -> 0, trace -> -1
prettier = true
[objectstorage.miniostorage]
endpoint = "103.37.125.216:9009"
access-key-id = "mnwWy87WrNiY4V7n63Nt"
secret-access-key = "OXG4Pzy5QaTJCbQmmA2aXt2jakxQVNfHA34kWzp5"
use-ssl = false
bucket-name = "humas"
location = "us-east-1"
[middleware.compress]
enable = true
level = 1

View File

@ -627,7 +627,65 @@ const docTemplate = `{
}
}
},
"/article-files/viewer": {
"/article-files/uploader": {
"post": {
"security": [
{
"Bearer": []
}
],
"description": "API for create ArticleFiles",
"produces": [
"application/json"
],
"tags": [
"Task"
],
"summary": "Upload ArticleFiles",
"parameters": [
{
"type": "file",
"description": "Upload file",
"name": "files",
"in": "formData",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"422": {
"description": "Unprocessable Entity",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/article-files/viewer/{id}": {
"get": {
"security": [
{
@ -639,6 +697,15 @@ const docTemplate = `{
"Task"
],
"summary": "Create ArticleFiles",
"parameters": [
{
"type": "string",
"description": "Filename",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",

View File

@ -616,7 +616,65 @@
}
}
},
"/article-files/viewer": {
"/article-files/uploader": {
"post": {
"security": [
{
"Bearer": []
}
],
"description": "API for create ArticleFiles",
"produces": [
"application/json"
],
"tags": [
"Task"
],
"summary": "Upload ArticleFiles",
"parameters": [
{
"type": "file",
"description": "Upload file",
"name": "files",
"in": "formData",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"422": {
"description": "Unprocessable Entity",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/article-files/viewer/{id}": {
"get": {
"security": [
{
@ -628,6 +686,15 @@
"Task"
],
"summary": "Create ArticleFiles",
"parameters": [
{
"type": "string",
"description": "Filename",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",

View File

@ -567,9 +567,52 @@ paths:
summary: update ArticleFiles
tags:
- Task
/article-files/viewer:
/article-files/uploader:
post:
description: API for create ArticleFiles
parameters:
- description: Upload file
in: formData
name: files
required: true
type: file
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/response.Response'
"422":
description: Unprocessable Entity
schema:
$ref: '#/definitions/response.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- Bearer: []
summary: Upload ArticleFiles
tags:
- Task
/article-files/viewer/{id}:
get:
description: API for create ArticleFiles
parameters:
- description: Filename
in: path
name: id
required: true
type: string
responses:
"200":
description: OK

View File

@ -42,6 +42,8 @@ func main() {
fx.Provide(database.NewDatabase),
// middleware
fx.Provide(middleware.NewMiddleware),
// data storage
fx.Provide(config.NewMinio),
// router
fx.Provide(router.NewRouter),