server/admin/api/file.go

282 lines
6.5 KiB
Go
Raw Normal View History

package api
2016-01-20 21:44:34 +00:00
import (
2019-07-21 19:54:48 +00:00
"encoding/hex"
"fmt"
2022-05-16 09:38:46 +00:00
"log"
"net/http"
"path/filepath"
2022-05-16 09:38:46 +00:00
"strconv"
2019-07-21 19:54:48 +00:00
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/libfic"
2022-05-16 09:38:46 +00:00
"github.com/gin-gonic/gin"
)
2022-05-16 09:38:46 +00:00
func declareFilesGlobalRoutes(router *gin.RouterGroup) {
router.DELETE("/files/", clearFiles)
2022-05-16 09:38:46 +00:00
// Remote
router.GET("/remote/themes/:thid/exercices/:exid/files", sync.ApiGetRemoteExerciceFiles)
}
2022-05-16 09:38:46 +00:00
func declareFilesRoutes(router *gin.RouterGroup) {
router.GET("/files", listFiles)
router.POST("/files", createExerciceFile)
2019-07-21 19:54:48 +00:00
2022-05-16 09:38:46 +00:00
apiFilesRoutes := router.Group("/files/:fileid")
apiFilesRoutes.Use(FileHandler)
apiFilesRoutes.GET("", showFile)
apiFilesRoutes.PUT("", updateFile)
apiFilesRoutes.DELETE("", deleteFile)
2019-07-21 19:54:48 +00:00
2022-05-16 09:38:46 +00:00
apiFileDepsRoutes := apiFilesRoutes.Group("/dependancies/:depid")
apiFileDepsRoutes.Use(FileDepHandler)
apiFileDepsRoutes.DELETE("", deleteFileDep)
2019-07-21 19:54:48 +00:00
// Check
2022-05-16 09:38:46 +00:00
apiFilesRoutes.POST("/check", checkFile)
2024-03-17 14:03:30 +00:00
apiFilesRoutes.POST("/gunzip", gunzipFile)
2022-05-16 09:38:46 +00:00
}
func FileHandler(c *gin.Context) {
fileid, err := strconv.ParseInt(string(c.Params.ByName("fileid")), 10, 64)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Invalid file identifier"})
return
}
2019-07-21 19:54:48 +00:00
2022-05-16 09:38:46 +00:00
var file *fic.EFile
if exercice, exists := c.Get("exercice"); exists {
file, err = exercice.(*fic.Exercice).GetFile(fileid)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "File not found"})
return
}
} else {
file, err = fic.GetFile(fileid)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "File not found"})
return
}
}
c.Set("file", file)
c.Next()
}
func FileDepHandler(c *gin.Context) {
depid, err := strconv.ParseInt(string(c.Params.ByName("depid")), 10, 64)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Invalid dependency identifier"})
return
}
c.Set("file-depid", depid)
c.Next()
}
type APIFile struct {
2021-11-22 14:35:07 +00:00
*fic.EFile
Depends []fic.Flag `json:"depends,omitempty"`
}
2021-11-22 14:35:07 +00:00
func genFileList(in []*fic.EFile, e error) (out []APIFile, err error) {
if e != nil {
return nil, e
}
for _, f := range in {
g := APIFile{EFile: f}
var deps []fic.Flag
deps, err = f.GetDepends()
if err != nil {
return
}
for _, d := range deps {
2021-11-22 14:35:07 +00:00
if k, ok := d.(*fic.FlagKey); ok {
k, err = fic.GetFlagKey(k.Id)
if err != nil {
return
}
g.Depends = append(g.Depends, k)
2021-11-22 14:35:07 +00:00
} else if m, ok := d.(*fic.MCQ); ok {
2020-01-20 16:28:37 +00:00
m, err = fic.GetMCQ(m.Id)
if err != nil {
return
}
g.Depends = append(g.Depends, m)
} else {
2020-04-15 05:39:38 +00:00
err = fmt.Errorf("Unknown type %T to handle file dependancy", k)
return
}
}
out = append(out, g)
}
return
}
2022-05-16 09:38:46 +00:00
func listFiles(c *gin.Context) {
var files []APIFile
var err error
2022-05-16 09:38:46 +00:00
if exercice, exists := c.Get("exercice"); exists {
files, err = genFileList(exercice.(*fic.Exercice).GetFiles())
} else {
files, err = genFileList(fic.GetFiles())
}
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, files)
2019-07-21 19:54:48 +00:00
}
2022-05-16 09:38:46 +00:00
func clearFiles(c *gin.Context) {
_, err := fic.ClearFiles()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, true)
}
2022-05-16 09:38:46 +00:00
func showFile(c *gin.Context) {
c.JSON(http.StatusOK, c.MustGet("file").(*fic.EFile))
}
2019-07-21 19:54:48 +00:00
type uploadedFile struct {
URI string
Digest string
}
2022-05-16 09:38:46 +00:00
func createExerciceFile(c *gin.Context) {
exercice, exists := c.Get("exercice")
if !exists {
c.AbortWithStatusJSON(http.StatusMethodNotAllowed, gin.H{"errmsg": "File can only be added inside an exercice."})
return
}
paramsFiles, err := sync.GetExerciceFilesParams(sync.GlobalImporter, exercice.(*fic.Exercice))
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
2019-07-21 19:54:48 +00:00
var uf uploadedFile
err = c.ShouldBindJSON(&uf)
2022-05-16 09:38:46 +00:00
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
2019-07-21 19:54:48 +00:00
}
2022-05-16 09:38:46 +00:00
ret, err := sync.ImportFile(sync.GlobalImporter, uf.URI,
2019-07-21 19:54:48 +00:00
func(filePath string, origin string) (interface{}, error) {
if digest, err := hex.DecodeString(uf.Digest); err != nil {
return nil, err
} else {
published := true
disclaimer := ""
if f, exists := paramsFiles[filepath.Base(filePath)]; exists {
published = !f.Hidden
if disclaimer, err = sync.ProcessMarkdown(sync.GlobalImporter, f.Disclaimer, exercice.(*fic.Exercice).Path); err != nil {
return nil, fmt.Errorf("error during markdown formating of disclaimer: %w", err)
}
}
return exercice.(*fic.Exercice).ImportFile(filePath, origin, digest, nil, disclaimer, published)
2019-07-21 19:54:48 +00:00
}
})
2022-05-16 09:38:46 +00:00
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, ret)
2019-07-21 19:54:48 +00:00
}
2022-05-16 09:38:46 +00:00
func updateFile(c *gin.Context) {
file := c.MustGet("file").(*fic.EFile)
var uf fic.EFile
2022-05-16 09:38:46 +00:00
err := c.ShouldBindJSON(&uf)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
uf.Id = file.Id
if _, err := uf.Update(); err != nil {
2022-05-16 09:38:46 +00:00
log.Println("Unable to updateFile:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to update file."})
return
}
2022-05-16 09:38:46 +00:00
c.JSON(http.StatusOK, uf)
}
2022-05-16 09:38:46 +00:00
func deleteFile(c *gin.Context) {
file := c.MustGet("file").(*fic.EFile)
_, err := file.Delete()
if err != nil {
log.Println("Unable to updateFile:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to update file."})
return
}
c.JSON(http.StatusOK, true)
2016-01-20 21:44:34 +00:00
}
2018-08-19 20:19:49 +00:00
2022-05-16 09:38:46 +00:00
func deleteFileDep(c *gin.Context) {
file := c.MustGet("file").(*fic.EFile)
depid := c.MustGet("file-depid").(int64)
err := file.DeleteDepend(&fic.FlagKey{Id: int(depid)})
if err != nil {
log.Println("Unable to deleteFileDep:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to delete file dependency."})
return
}
c.JSON(http.StatusOK, true)
}
2022-05-16 09:38:46 +00:00
func checkFile(c *gin.Context) {
file := c.MustGet("file").(*fic.EFile)
err := file.CheckFileOnDisk()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, true)
2018-08-19 20:19:49 +00:00
}
2024-03-17 14:03:30 +00:00
func gunzipFile(c *gin.Context) {
file := c.MustGet("file").(*fic.EFile)
err := file.GunzipFileOnDisk()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, true)
}