651 lines
21 KiB
Markdown
651 lines
21 KiB
Markdown
# Code Templates for Narasi Ahli Implementation
|
|
|
|
## Database Entity Template
|
|
|
|
### Example: Education History Entity
|
|
```go
|
|
package entity
|
|
|
|
import (
|
|
"narasi-ahli-be/app/database/entity/users"
|
|
"time"
|
|
)
|
|
|
|
type EducationHistory struct {
|
|
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
UserID uint `json:"user_id" gorm:"type:int4;not null;index"`
|
|
SchoolName string `json:"school_name" gorm:"type:varchar(255);not null"`
|
|
Major string `json:"major" gorm:"type:varchar(255);not null"`
|
|
EducationLevel string `json:"education_level" gorm:"type:varchar(100);not null"`
|
|
GraduationYear int `json:"graduation_year" gorm:"type:int4;not null"`
|
|
CertificateImage *string `json:"certificate_image" gorm:"type:varchar(500)"`
|
|
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
|
|
|
// Relationships
|
|
User *users.Users `json:"user" gorm:"foreignKey:UserID;references:ID"`
|
|
}
|
|
|
|
func (EducationHistory) TableName() string {
|
|
return "education_histories"
|
|
}
|
|
```
|
|
|
|
## Module Structure Template
|
|
|
|
### Module File Template
|
|
```go
|
|
package education_history
|
|
|
|
import (
|
|
"narasi-ahli-be/app/module/education_history/controller"
|
|
"narasi-ahli-be/app/module/education_history/repository"
|
|
"narasi-ahli-be/app/module/education_history/service"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
type EducationHistoryRouter struct {
|
|
App fiber.Router
|
|
Controller *controller.Controller
|
|
}
|
|
|
|
var NewEducationHistoryModule = fx.Options(
|
|
fx.Provide(repository.NewEducationHistoryRepository),
|
|
fx.Provide(service.NewEducationHistoryService),
|
|
fx.Provide(controller.NewController),
|
|
fx.Provide(NewEducationHistoryRouter),
|
|
)
|
|
|
|
func NewEducationHistoryRouter(fiber *fiber.App, controller *controller.Controller) *EducationHistoryRouter {
|
|
return &EducationHistoryRouter{
|
|
App: fiber,
|
|
Controller: controller,
|
|
}
|
|
}
|
|
|
|
func (_i *EducationHistoryRouter) RegisterEducationHistoryRoutes() {
|
|
educationController := _i.Controller.EducationHistory
|
|
|
|
_i.App.Route("/education-history", func(router fiber.Router) {
|
|
router.Get("/", educationController.All)
|
|
router.Get("/:id", educationController.Show)
|
|
router.Post("/", educationController.Save)
|
|
router.Put("/:id", educationController.Update)
|
|
router.Delete("/:id", educationController.Delete)
|
|
router.Post("/:id/certificate", educationController.UploadCertificate)
|
|
})
|
|
}
|
|
```
|
|
|
|
### Controller Template
|
|
```go
|
|
package controller
|
|
|
|
import (
|
|
"narasi-ahli-be/app/middleware"
|
|
"narasi-ahli-be/app/module/education_history/request"
|
|
"narasi-ahli-be/app/module/education_history/service"
|
|
"narasi-ahli-be/utils/paginator"
|
|
utilRes "narasi-ahli-be/utils/response"
|
|
utilVal "narasi-ahli-be/utils/validator"
|
|
utilSvc "narasi-ahli-be/utils/service"
|
|
"strconv"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
type educationHistoryController struct {
|
|
educationHistoryService service.EducationHistoryService
|
|
}
|
|
|
|
type EducationHistoryController interface {
|
|
All(c *fiber.Ctx) error
|
|
Show(c *fiber.Ctx) error
|
|
Save(c *fiber.Ctx) error
|
|
Update(c *fiber.Ctx) error
|
|
Delete(c *fiber.Ctx) error
|
|
UploadCertificate(c *fiber.Ctx) error
|
|
}
|
|
|
|
func NewEducationHistoryController(educationHistoryService service.EducationHistoryService) EducationHistoryController {
|
|
return &educationHistoryController{
|
|
educationHistoryService: educationHistoryService,
|
|
}
|
|
}
|
|
|
|
// All Education History
|
|
// @Summary Get all Education History
|
|
// @Description API for getting all Education History for authenticated user
|
|
// @Tags Education History
|
|
// @Security Bearer
|
|
// @Param req query request.EducationHistoryQueryRequest false "query parameters"
|
|
// @Param req query paginator.Pagination false "pagination parameters"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 400 {object} response.BadRequestError
|
|
// @Failure 401 {object} response.UnauthorizedError
|
|
// @Failure 500 {object} response.InternalServerError
|
|
// @Router /education-history [get]
|
|
func (_i *educationHistoryController) All(c *fiber.Ctx) error {
|
|
paginate, err := paginator.Paginate(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get user ID from auth token
|
|
authHeader := c.Get("Authorization")
|
|
userId := utilSvc.GetUserId(authHeader)
|
|
if userId == nil {
|
|
return utilRes.Resp(c, utilRes.Response{
|
|
Success: false,
|
|
Code: 401,
|
|
Messages: utilRes.Messages{"Unauthorized"},
|
|
})
|
|
}
|
|
|
|
reqContext := request.EducationHistoryQueryRequestContext{
|
|
SchoolName: c.Query("schoolName"),
|
|
Major: c.Query("major"),
|
|
EducationLevel: c.Query("educationLevel"),
|
|
GraduationYear: c.Query("graduationYear"),
|
|
}
|
|
req := reqContext.ToParamRequest()
|
|
req.Pagination = paginate
|
|
|
|
clientId := middleware.GetClientID(c)
|
|
educationData, paging, err := _i.educationHistoryService.All(clientId, *userId, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return utilRes.Resp(c, utilRes.Response{
|
|
Success: true,
|
|
Messages: utilRes.Messages{"Education history list successfully retrieved"},
|
|
Data: educationData,
|
|
Meta: paging,
|
|
})
|
|
}
|
|
|
|
// Show Education History
|
|
// @Summary Get one Education History
|
|
// @Description API for getting one Education History
|
|
// @Tags Education History
|
|
// @Security Bearer
|
|
// @Param id path int true "Education History ID"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 400 {object} response.BadRequestError
|
|
// @Failure 401 {object} response.UnauthorizedError
|
|
// @Failure 500 {object} response.InternalServerError
|
|
// @Router /education-history/{id} [get]
|
|
func (_i *educationHistoryController) Show(c *fiber.Ctx) error {
|
|
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
authHeader := c.Get("Authorization")
|
|
userId := utilSvc.GetUserId(authHeader)
|
|
if userId == nil {
|
|
return utilRes.Resp(c, utilRes.Response{
|
|
Success: false,
|
|
Code: 401,
|
|
Messages: utilRes.Messages{"Unauthorized"},
|
|
})
|
|
}
|
|
|
|
clientId := middleware.GetClientID(c)
|
|
educationData, err := _i.educationHistoryService.Show(clientId, *userId, uint(id))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return utilRes.Resp(c, utilRes.Response{
|
|
Success: true,
|
|
Messages: utilRes.Messages{"Education history successfully retrieved"},
|
|
Data: educationData,
|
|
})
|
|
}
|
|
|
|
// Save Education History
|
|
// @Summary Create Education History
|
|
// @Description API for create Education History
|
|
// @Tags Education History
|
|
// @Security Bearer
|
|
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
// @Param payload body request.EducationHistoryCreateRequest true "Required payload"
|
|
// @Success 200 {object} response.Response
|
|
// @Failure 400 {object} response.BadRequestError
|
|
// @Failure 401 {object} response.UnauthorizedError
|
|
// @Failure 500 {object} response.InternalServerError
|
|
// @Router /education-history [post]
|
|
func (_i *educationHistoryController) Save(c *fiber.Ctx) error {
|
|
req := new(request.EducationHistoryCreateRequest)
|
|
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
return err
|
|
}
|
|
|
|
authHeader := c.Get("Authorization")
|
|
userId := utilSvc.GetUserId(authHeader)
|
|
if userId == nil {
|
|
return utilRes.Resp(c, utilRes.Response{
|
|
Success: false,
|
|
Code: 401,
|
|
Messages: utilRes.Messages{"Unauthorized"},
|
|
})
|
|
}
|
|
|
|
clientId := middleware.GetClientID(c)
|
|
dataResult, err := _i.educationHistoryService.Save(clientId, *userId, *req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return utilRes.Resp(c, utilRes.Response{
|
|
Success: true,
|
|
Messages: utilRes.Messages{"Education history successfully created"},
|
|
Data: dataResult,
|
|
})
|
|
}
|
|
|
|
// Additional methods: Update, Delete, UploadCertificate...
|
|
```
|
|
|
|
### Service Template
|
|
```go
|
|
package service
|
|
|
|
import (
|
|
"narasi-ahli-be/app/module/education_history/mapper"
|
|
"narasi-ahli-be/app/module/education_history/repository"
|
|
"narasi-ahli-be/app/module/education_history/request"
|
|
"narasi-ahli-be/app/module/education_history/response"
|
|
"narasi-ahli-be/utils/paginator"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
type educationHistoryService struct {
|
|
Repo repository.EducationHistoryRepository
|
|
Log zerolog.Logger
|
|
}
|
|
|
|
type EducationHistoryService interface {
|
|
All(clientId *uuid.UUID, userId uint, req request.EducationHistoryQueryRequest) (educationHistories []*response.EducationHistoryResponse, paging paginator.Pagination, err error)
|
|
Show(clientId *uuid.UUID, userId uint, id uint) (educationHistory *response.EducationHistoryResponse, err error)
|
|
Save(clientId *uuid.UUID, userId uint, req request.EducationHistoryCreateRequest) (educationHistory *response.EducationHistoryResponse, err error)
|
|
Update(clientId *uuid.UUID, userId uint, id uint, req request.EducationHistoryUpdateRequest) (err error)
|
|
Delete(clientId *uuid.UUID, userId uint, id uint) error
|
|
UploadCertificate(clientId *uuid.UUID, userId uint, id uint, filePath string) error
|
|
}
|
|
|
|
func NewEducationHistoryService(repo repository.EducationHistoryRepository, log zerolog.Logger) EducationHistoryService {
|
|
return &educationHistoryService{
|
|
Repo: repo,
|
|
Log: log,
|
|
}
|
|
}
|
|
|
|
func (_i *educationHistoryService) All(clientId *uuid.UUID, userId uint, req request.EducationHistoryQueryRequest) (educationHistories []*response.EducationHistoryResponse, paging paginator.Pagination, err error) {
|
|
results, paging, err := _i.Repo.GetAll(clientId, userId, req)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, result := range results {
|
|
educationHistories = append(educationHistories, mapper.EducationHistoryResponseMapper(result))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (_i *educationHistoryService) Show(clientId *uuid.UUID, userId uint, id uint) (educationHistory *response.EducationHistoryResponse, err error) {
|
|
result, err := _i.Repo.FindOneByUserAndId(clientId, userId, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return mapper.EducationHistoryResponseMapper(result), nil
|
|
}
|
|
|
|
func (_i *educationHistoryService) Save(clientId *uuid.UUID, userId uint, req request.EducationHistoryCreateRequest) (educationHistory *response.EducationHistoryResponse, err error) {
|
|
_i.Log.Info().Interface("data", req).Msg("Creating education history")
|
|
|
|
entity := req.ToEntity()
|
|
entity.UserID = userId
|
|
|
|
result, err := _i.Repo.Create(clientId, entity)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return mapper.EducationHistoryResponseMapper(result), nil
|
|
}
|
|
|
|
// Additional methods: Update, Delete, UploadCertificate...
|
|
```
|
|
|
|
### Repository Template
|
|
```go
|
|
package repository
|
|
|
|
import (
|
|
"narasi-ahli-be/app/database/entity"
|
|
"narasi-ahli-be/app/module/education_history/request"
|
|
"narasi-ahli-be/utils/paginator"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type educationHistoryRepository struct {
|
|
DB *gorm.DB
|
|
}
|
|
|
|
type EducationHistoryRepository interface {
|
|
GetAll(clientId *uuid.UUID, userId uint, req request.EducationHistoryQueryRequest) (educationHistories []*entity.EducationHistory, paging paginator.Pagination, err error)
|
|
FindOneByUserAndId(clientId *uuid.UUID, userId uint, id uint) (educationHistory *entity.EducationHistory, err error)
|
|
Create(clientId *uuid.UUID, educationHistory *entity.EducationHistory) (result *entity.EducationHistory, err error)
|
|
Update(clientId *uuid.UUID, userId uint, id uint, educationHistory *entity.EducationHistory) (err error)
|
|
Delete(clientId *uuid.UUID, userId uint, id uint) (err error)
|
|
}
|
|
|
|
func NewEducationHistoryRepository(db *gorm.DB) EducationHistoryRepository {
|
|
return &educationHistoryRepository{
|
|
DB: db,
|
|
}
|
|
}
|
|
|
|
func (_i *educationHistoryRepository) GetAll(clientId *uuid.UUID, userId uint, req request.EducationHistoryQueryRequest) (educationHistories []*entity.EducationHistory, paging paginator.Pagination, err error) {
|
|
query := _i.DB.Where("user_id = ?", userId)
|
|
|
|
// Apply filters
|
|
if req.SchoolName != nil {
|
|
query = query.Where("school_name ILIKE ?", "%"+*req.SchoolName+"%")
|
|
}
|
|
if req.Major != nil {
|
|
query = query.Where("major ILIKE ?", "%"+*req.Major+"%")
|
|
}
|
|
if req.EducationLevel != nil {
|
|
query = query.Where("education_level = ?", *req.EducationLevel)
|
|
}
|
|
if req.GraduationYear != nil {
|
|
query = query.Where("graduation_year = ?", *req.GraduationYear)
|
|
}
|
|
|
|
// Include user relationship
|
|
query = query.Preload("User")
|
|
|
|
// Apply pagination
|
|
paging = paginator.Paging(req.Pagination, query, &educationHistories)
|
|
|
|
return
|
|
}
|
|
|
|
func (_i *educationHistoryRepository) FindOneByUserAndId(clientId *uuid.UUID, userId uint, id uint) (educationHistory *entity.EducationHistory, err error) {
|
|
err = _i.DB.Where("user_id = ? AND id = ?", userId, id).Preload("User").First(&educationHistory).Error
|
|
return
|
|
}
|
|
|
|
func (_i *educationHistoryRepository) Create(clientId *uuid.UUID, educationHistory *entity.EducationHistory) (result *entity.EducationHistory, err error) {
|
|
err = _i.DB.Create(educationHistory).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Reload with relationships
|
|
err = _i.DB.Preload("User").First(&result, educationHistory.ID).Error
|
|
return
|
|
}
|
|
|
|
// Additional methods: Update, Delete...
|
|
```
|
|
|
|
### Request DTO Template
|
|
```go
|
|
package request
|
|
|
|
import (
|
|
"narasi-ahli-be/app/database/entity"
|
|
"narasi-ahli-be/utils/paginator"
|
|
"strconv"
|
|
)
|
|
|
|
type EducationHistoryQueryRequest struct {
|
|
SchoolName *string `json:"schoolName"`
|
|
Major *string `json:"major"`
|
|
EducationLevel *string `json:"educationLevel"`
|
|
GraduationYear *int `json:"graduationYear"`
|
|
Pagination *paginator.Pagination `json:"pagination"`
|
|
}
|
|
|
|
type EducationHistoryCreateRequest struct {
|
|
SchoolName string `json:"schoolName" validate:"required,min=2,max=255"`
|
|
Major string `json:"major" validate:"required,min=2,max=255"`
|
|
EducationLevel string `json:"educationLevel" validate:"required,min=2,max=100"`
|
|
GraduationYear int `json:"graduationYear" validate:"required,min=1950,max=2030"`
|
|
CertificateImage string `json:"certificateImage,omitempty"`
|
|
}
|
|
|
|
func (req EducationHistoryCreateRequest) ToEntity() *entity.EducationHistory {
|
|
return &entity.EducationHistory{
|
|
SchoolName: req.SchoolName,
|
|
Major: req.Major,
|
|
EducationLevel: req.EducationLevel,
|
|
GraduationYear: req.GraduationYear,
|
|
CertificateImage: &req.CertificateImage,
|
|
}
|
|
}
|
|
|
|
type EducationHistoryUpdateRequest struct {
|
|
SchoolName string `json:"schoolName" validate:"required,min=2,max=255"`
|
|
Major string `json:"major" validate:"required,min=2,max=255"`
|
|
EducationLevel string `json:"educationLevel" validate:"required,min=2,max=100"`
|
|
GraduationYear int `json:"graduationYear" validate:"required,min=1950,max=2030"`
|
|
CertificateImage string `json:"certificateImage,omitempty"`
|
|
}
|
|
|
|
func (req EducationHistoryUpdateRequest) ToEntity() *entity.EducationHistory {
|
|
return &entity.EducationHistory{
|
|
SchoolName: req.SchoolName,
|
|
Major: req.Major,
|
|
EducationLevel: req.EducationLevel,
|
|
GraduationYear: req.GraduationYear,
|
|
CertificateImage: &req.CertificateImage,
|
|
}
|
|
}
|
|
|
|
type EducationHistoryQueryRequestContext struct {
|
|
SchoolName string `json:"schoolName"`
|
|
Major string `json:"major"`
|
|
EducationLevel string `json:"educationLevel"`
|
|
GraduationYear string `json:"graduationYear"`
|
|
}
|
|
|
|
func (req EducationHistoryQueryRequestContext) ToParamRequest() EducationHistoryQueryRequest {
|
|
var request EducationHistoryQueryRequest
|
|
|
|
if schoolName := req.SchoolName; schoolName != "" {
|
|
request.SchoolName = &schoolName
|
|
}
|
|
if major := req.Major; major != "" {
|
|
request.Major = &major
|
|
}
|
|
if educationLevel := req.EducationLevel; educationLevel != "" {
|
|
request.EducationLevel = &educationLevel
|
|
}
|
|
if graduationYearStr := req.GraduationYear; graduationYearStr != "" {
|
|
graduationYear, err := strconv.Atoi(graduationYearStr)
|
|
if err == nil {
|
|
request.GraduationYear = &graduationYear
|
|
}
|
|
}
|
|
|
|
return request
|
|
}
|
|
```
|
|
|
|
### Response DTO Template
|
|
```go
|
|
package response
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
type EducationHistoryResponse struct {
|
|
ID uint `json:"id"`
|
|
UserID uint `json:"userId"`
|
|
SchoolName string `json:"schoolName"`
|
|
Major string `json:"major"`
|
|
EducationLevel string `json:"educationLevel"`
|
|
GraduationYear int `json:"graduationYear"`
|
|
CertificateImage *string `json:"certificateImage"`
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
|
|
// Nested user info (optional)
|
|
User *UserBasicInfo `json:"user,omitempty"`
|
|
}
|
|
|
|
type UserBasicInfo struct {
|
|
ID uint `json:"id"`
|
|
Username string `json:"username"`
|
|
Fullname string `json:"fullname"`
|
|
Email string `json:"email"`
|
|
}
|
|
```
|
|
|
|
### Mapper Template
|
|
```go
|
|
package mapper
|
|
|
|
import (
|
|
"narasi-ahli-be/app/database/entity"
|
|
"narasi-ahli-be/app/module/education_history/response"
|
|
)
|
|
|
|
func EducationHistoryResponseMapper(educationHistory *entity.EducationHistory) *response.EducationHistoryResponse {
|
|
result := &response.EducationHistoryResponse{
|
|
ID: educationHistory.ID,
|
|
UserID: educationHistory.UserID,
|
|
SchoolName: educationHistory.SchoolName,
|
|
Major: educationHistory.Major,
|
|
EducationLevel: educationHistory.EducationLevel,
|
|
GraduationYear: educationHistory.GraduationYear,
|
|
CertificateImage: educationHistory.CertificateImage,
|
|
CreatedAt: educationHistory.CreatedAt,
|
|
UpdatedAt: educationHistory.UpdatedAt,
|
|
}
|
|
|
|
// Include user info if loaded
|
|
if educationHistory.User != nil {
|
|
result.User = &response.UserBasicInfo{
|
|
ID: educationHistory.User.ID,
|
|
Username: educationHistory.User.Username,
|
|
Fullname: educationHistory.User.Fullname,
|
|
Email: educationHistory.User.Email,
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
```
|
|
|
|
## File Upload Service Template
|
|
|
|
```go
|
|
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"mime/multipart"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/minio/minio-go/v7"
|
|
)
|
|
|
|
type FileUploadService interface {
|
|
UploadCertificate(file *multipart.FileHeader) (string, error)
|
|
UploadChatFile(file *multipart.FileHeader, messageType string) (string, error)
|
|
ValidateFile(file *multipart.FileHeader, allowedTypes []string, maxSize int64) error
|
|
}
|
|
|
|
type fileUploadService struct {
|
|
minioClient *minio.Client
|
|
bucketName string
|
|
}
|
|
|
|
func NewFileUploadService(minioClient *minio.Client, bucketName string) FileUploadService {
|
|
return &fileUploadService{
|
|
minioClient: minioClient,
|
|
bucketName: bucketName,
|
|
}
|
|
}
|
|
|
|
func (s *fileUploadService) UploadCertificate(file *multipart.FileHeader) (string, error) {
|
|
// Validate file
|
|
allowedTypes := []string{".jpg", ".jpeg", ".png", ".pdf"}
|
|
maxSize := int64(5 * 1024 * 1024) // 5MB
|
|
|
|
if err := s.ValidateFile(file, allowedTypes, maxSize); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Generate unique filename
|
|
ext := filepath.Ext(file.Filename)
|
|
filename := fmt.Sprintf("certificates/%s_%d%s", uuid.New().String(), time.Now().Unix(), ext)
|
|
|
|
// Upload to MinIO
|
|
src, err := file.Open()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer src.Close()
|
|
|
|
_, err = s.minioClient.PutObject(
|
|
context.Background(),
|
|
s.bucketName,
|
|
filename,
|
|
src,
|
|
file.Size,
|
|
minio.PutObjectOptions{ContentType: file.Header.Get("Content-Type")},
|
|
)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return filename, nil
|
|
}
|
|
|
|
func (s *fileUploadService) ValidateFile(file *multipart.FileHeader, allowedTypes []string, maxSize int64) error {
|
|
// Check file size
|
|
if file.Size > maxSize {
|
|
return fmt.Errorf("file size exceeds maximum allowed size")
|
|
}
|
|
|
|
// Check file type
|
|
ext := strings.ToLower(filepath.Ext(file.Filename))
|
|
allowed := false
|
|
for _, allowedType := range allowedTypes {
|
|
if ext == allowedType {
|
|
allowed = true
|
|
break
|
|
}
|
|
}
|
|
if !allowed {
|
|
return fmt.Errorf("file type not allowed")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
These templates provide a solid foundation for implementing each module following the existing codebase patterns. Each module can be built by copying and adapting these templates with the specific field requirements for that module.
|