feat: Update project structure and configuration files

This commit is contained in:
rogeecn
2025-03-24 09:29:38 +08:00
parent ea15a51556
commit 8de43c2861
159 changed files with 498 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package admin
import (
"quyun/app/models"
"quyun/app/requests"
"github.com/gofiber/fiber/v3"
)
// @provider
type medias struct{}
// List medias
// @Router /v1/admin/medias [get]
// @Bind pagination query
func (ctl *medias) List(ctx fiber.Ctx, pagination *requests.Pagination) (*requests.Pager, error) {
return models.Medias.List(ctx.Context(), pagination)
}

View File

@@ -0,0 +1,40 @@
package admin
import (
"quyun/app/models"
"quyun/app/requests"
"quyun/database/schemas/public/model"
"github.com/gofiber/fiber/v3"
)
type ListQuery struct {
Key *string `query:"key"`
}
// @provider
type posts struct{}
// List posts
// @Router /v1/admin/posts [get]
// @Bind pagination query
// @Bind query query
func (ctl *posts) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery) (*requests.Pager, error) {
cond := models.Posts.BuildConditionWithKey(query.Key)
return models.Posts.List(ctx.Context(), pagination, cond)
}
// Create
// @Router /v1/admin/posts [post]
// @Bind form body
func (ctl *posts) Create(ctx fiber.Ctx, form *model.Posts) error {
return nil
}
// Update posts
// @Router /v1/admin/posts/:id [put]
// @Bind id path
// @Bind form body
func (ctl *posts) Update(ctx fiber.Ctx, id int64, form *model.Posts) error {
return nil
}

View File

@@ -0,0 +1,57 @@
package admin
import (
"quyun/providers/app"
"go.ipao.vip/atom"
"go.ipao.vip/atom/container"
"go.ipao.vip/atom/contracts"
"go.ipao.vip/atom/opt"
)
func Provide(opts ...opt.Option) error {
if err := container.Container.Provide(func() (*medias, error) {
obj := &medias{}
return obj, nil
}); err != nil {
return err
}
if err := container.Container.Provide(func() (*posts, error) {
obj := &posts{}
return obj, nil
}); err != nil {
return err
}
if err := container.Container.Provide(func(
medias *medias,
posts *posts,
uploads *uploads,
) (contracts.HttpRoute, error) {
obj := &Routes{
medias: medias,
posts: posts,
uploads: uploads,
}
if err := obj.Prepare(); err != nil {
return nil, err
}
return obj, nil
}, atom.GroupRoutes); err != nil {
return err
}
if err := container.Container.Provide(func(
app *app.Config,
) (*uploads, error) {
obj := &uploads{
app: app,
}
return obj, nil
}); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,72 @@
// Code generated by the atomctl ; DO NOT EDIT.
package admin
import (
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
_ "go.ipao.vip/atom"
_ "go.ipao.vip/atom/contracts"
. "go.ipao.vip/atom/fen"
"mime/multipart"
"quyun/app/requests"
"quyun/database/schemas/public/model"
)
// @provider contracts.HttpRoute atom.GroupRoutes
type Routes struct {
log *log.Entry `inject:"false"`
medias *medias
posts *posts
uploads *uploads
}
func (r *Routes) Prepare() error {
r.log = log.WithField("module", "routes.admin")
return nil
}
func (r *Routes) Name() string {
return "admin"
}
func (r *Routes) Register(router fiber.Router) {
// 注册路由组: medias
router.Get("/v1/admin/medias", DataFunc1(
r.medias.List,
Query[requests.Pagination]("pagination"),
))
// 注册路由组: posts
router.Get("/v1/admin/posts", DataFunc2(
r.posts.List,
Query[requests.Pagination]("pagination"),
Query[ListQuery]("query"),
))
router.Post("/v1/admin/posts", Func1(
r.posts.Create,
Body[model.Posts]("form"),
))
router.Put("/v1/admin/posts/:id", Func2(
r.posts.Update,
PathParam[int64]("id"),
Body[model.Posts]("form"),
))
// 注册路由组: uploads
router.Post("/v1/admin/uploads/:md5/chunks/:idx", Func3(
r.uploads.Chunks,
PathParam[string]("md5"),
PathParam[string]("idx"),
File[multipart.FileHeader]("file"),
))
router.Post("/v1/admin/uploads/:md5/complete", Func2(
r.uploads.Complete,
PathParam[string]("md5"),
Body[UploadFileInfo]("body"),
))
}

View File

@@ -0,0 +1,139 @@
package admin
import (
"errors"
"fmt"
"mime/multipart"
"os"
"path/filepath"
"time"
"quyun/app/models"
"quyun/database/schemas/public/model"
"quyun/pkg/utils"
"quyun/providers/app"
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
)
// @provider
type uploads struct {
app *app.Config
}
func (up *uploads) storagePath() string {
return filepath.Join(up.app.StoragePath, "uploads")
}
type UploadChunk struct {
Chunk int `query:"chunk"`
Md5 string `query:"md5"`
}
type UploadFileInfo struct {
Md5 string `json:"md5"`
Filename string `json:"filename"`
Mime string `json:"mime"`
Chunks int `json:"chunks"`
}
// Upload chunks
// @Router /v1/admin/uploads/:md5/chunks/:idx [post]
// @Bind md5 path
// @Bind idx path
// @Bind file file
func (up *uploads) Chunks(ctx fiber.Ctx, md5, idx string, file *multipart.FileHeader) error {
tmpPath := filepath.Join(up.storagePath(), md5, idx)
// if tmpPath not exists, create it
if _, err := os.Stat(tmpPath); os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Dir(tmpPath), os.ModePerm); err != nil {
log.WithError(err).Errorf("create tmpPath failed %s", tmpPath)
return err
}
}
// save file to tmpPath
if err := ctx.SaveFile(file, tmpPath); err != nil {
log.WithError(err).Errorf("save file to tmpPath failed %s", tmpPath)
return err
}
return nil
}
// Complete uploads
// @Router /v1/admin/uploads/:md5/complete [post]
// @Bind md5 path
// @Bind body body
func (up *uploads) Complete(ctx fiber.Ctx, md5 string, body *UploadFileInfo) error {
// merge chunks
path := filepath.Join(up.storagePath(), md5)
defer os.RemoveAll(path)
targetFile := filepath.Join(up.storagePath(), md5, body.Filename)
// if targetFile not exists, create it
tf, err := os.Create(targetFile)
if err != nil {
return err
}
for i := 0; i < body.Chunks; i++ {
tmpPath := filepath.Join(up.storagePath(), md5, fmt.Sprintf("%d", i))
// open chunk file
chunkFile, err := os.Open(tmpPath)
if err != nil {
tf.Close()
return err
}
// copy chunk file to target file
if _, err := tf.ReadFrom(chunkFile); err != nil {
chunkFile.Close()
tf.Close()
return err
}
chunkFile.Close()
}
tf.Close()
// validate md5
ok, err := utils.CompareFileMd5(targetFile, md5)
if err != nil {
return err
}
if !ok {
return errors.New("md5 not match")
}
// save file to target path
targetPath := filepath.Join(up.storagePath(), md5+filepath.Ext(body.Filename))
if err := os.Rename(targetFile, targetPath); err != nil {
return err
}
fState, err := os.Stat(targetPath)
if err != nil {
return err
}
model := &model.Medias{
CreatedAt: time.Now(),
Name: body.Filename,
MimeType: body.Mime,
Size: fState.Size(), // Updated to use fState.Size()
Path: targetPath,
}
// save to db
if err := models.Medias.Create(ctx.Context(), model); err != nil {
return err
}
log.Infof("File %s uploaded successfully", body.Filename)
return nil
}