172 lines
4.7 KiB
Go
172 lines
4.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/ArtalkJS/Artalk/internal/artransfer"
|
|
"github.com/ArtalkJS/Artalk/internal/core"
|
|
"github.com/ArtalkJS/Artalk/internal/i18n"
|
|
"github.com/ArtalkJS/Artalk/internal/log"
|
|
"github.com/ArtalkJS/Artalk/internal/utils"
|
|
"github.com/ArtalkJS/Artalk/server/common"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
func AdminTransfer(app *core.App, router fiber.Router) {
|
|
router.Post("/import", adminImport(app))
|
|
router.Post("/import-upload", adminImportUpload(app))
|
|
router.Post("/export", adminExport(app))
|
|
}
|
|
|
|
type ParamsAdminImport struct {
|
|
Payload string `form:"payload"`
|
|
}
|
|
|
|
// @Summary Transfer Import
|
|
// @Description Import data to Artalk
|
|
// @Tags Transfer
|
|
// @Param payload formData string false "the transfer importer payload"
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {object} common.JSONResult
|
|
// @Router /admin/import [post]
|
|
func adminImport(app *core.App) func(c *fiber.Ctx) error {
|
|
return func(c *fiber.Ctx) error {
|
|
var p ParamsAdminImport
|
|
if isOK, resp := common.ParamsDecode(c, &p); !isOK {
|
|
return resp
|
|
}
|
|
|
|
var payloadMapRaw map[string]interface{}
|
|
err := json.Unmarshal([]byte(p.Payload), &payloadMapRaw)
|
|
if err != nil {
|
|
return common.RespError(c, "Payload parsing error", common.Map{
|
|
"error": err,
|
|
})
|
|
}
|
|
|
|
payloadMap := map[string]string{}
|
|
for k, v := range payloadMapRaw {
|
|
payloadMap[k] = utils.ToString(v) // convert all value to string
|
|
}
|
|
|
|
payloadArr := []string{}
|
|
for k, v := range payloadMap {
|
|
payloadArr = append(payloadArr, k+":"+v)
|
|
}
|
|
|
|
if !common.GetIsSuperAdmin(app, c) {
|
|
user := common.GetUserByReq(app, c)
|
|
if sitName, isExist := payloadMap["t_name"]; isExist {
|
|
if !utils.ContainsStr(app.Dao().CookUser(&user).SiteNames, sitName) {
|
|
return common.RespError(c, "Destination site name of prohibited import")
|
|
}
|
|
} else {
|
|
return common.RespError(c, "Please fill in the target site name")
|
|
}
|
|
}
|
|
|
|
// TODO bcz 懒,先整这个缓冲输出,以后改成高级点的
|
|
r := c.Response()
|
|
|
|
r.Header.Add(fiber.HeaderContentType, fiber.MIMETextHTMLCharsetUTF8)
|
|
r.SetStatusCode(fiber.StatusOK)
|
|
|
|
buf := bytes.NewBufferString("")
|
|
r.SetBodyStream(buf, -1)
|
|
r.ImmediateHeaderFlush = true
|
|
|
|
buf.Write([]byte(
|
|
`<style>* { font-family: Menlo, Consolas, Monaco, monospace;word-wrap: break-word;white-space: pre-wrap;font-size: 13px; }</style>
|
|
<script>function scroll() { if (!!document.body) { document.body.scrollTo(0, 999999999999); } }</script>`))
|
|
|
|
artransfer.HttpOutput = func(continueRun bool, text string) {
|
|
buf.Write([]byte(text))
|
|
buf.Write([]byte("<script>scroll();</script>"))
|
|
}
|
|
|
|
params := artransfer.ArrToImportParams(payloadArr)
|
|
params.Assumeyes = true
|
|
artransfer.RunImportArtrans(app.Dao(), params)
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// @Summary Transfer Import Upload
|
|
// @Description Upload a file to prepare to import
|
|
// @Tags Transfer
|
|
// @Param file formData file true "upload file in preparation for import task"
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {object} common.JSONResult
|
|
// @Router /admin/import-upload [post]
|
|
func adminImportUpload(app *core.App) func(c *fiber.Ctx) error {
|
|
return func(c *fiber.Ctx) error {
|
|
// 获取 Form
|
|
file, err := c.FormFile("file")
|
|
if err != nil {
|
|
log.Error(err)
|
|
return common.RespError(c, "File read failed")
|
|
}
|
|
|
|
// 打开文件
|
|
src, err := file.Open()
|
|
if err != nil {
|
|
log.Error(err)
|
|
return common.RespError(c, "File open failed")
|
|
}
|
|
defer src.Close()
|
|
|
|
// 读取文件
|
|
buf, err := io.ReadAll(src)
|
|
if err != nil {
|
|
log.Error(err)
|
|
return common.RespError(c, "File read failed")
|
|
}
|
|
|
|
tmpFile, err := os.CreateTemp("", "artalk-import-file-")
|
|
if err != nil {
|
|
log.Error(err)
|
|
return common.RespError(c, "tmp file creation failed")
|
|
}
|
|
|
|
tmpFile.Write(buf)
|
|
|
|
return common.RespData(c, common.Map{
|
|
"filename": tmpFile.Name(),
|
|
})
|
|
}
|
|
}
|
|
|
|
// @Summary Transfer Export
|
|
// @Description Export data from Artalk
|
|
// @Tags Transfer
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {object} common.JSONResult{data=object{data=string}}
|
|
// @Router /admin/export [post]
|
|
func adminExport(app *core.App) func(c *fiber.Ctx) error {
|
|
return func(c *fiber.Ctx) error {
|
|
var siteNameScope []string
|
|
if !common.GetIsSuperAdmin(app, c) {
|
|
// 仅导出限定范围内的站点
|
|
u := common.GetUserByReq(app, c)
|
|
siteNameScope = app.Dao().CookUser(&u).SiteNames
|
|
}
|
|
|
|
jsonStr, err := artransfer.RunExportArtrans(app.Dao(), &artransfer.ExportParams{
|
|
SiteNameScope: siteNameScope,
|
|
})
|
|
if err != nil {
|
|
common.RespError(c, i18n.T("Export error"), common.Map{
|
|
"err": err,
|
|
})
|
|
}
|
|
|
|
return common.RespData(c, common.Map{
|
|
"data": jsonStr,
|
|
})
|
|
}
|
|
}
|