Add file upload on gist creation/edition (#507)
This commit is contained in:
@@ -2,11 +2,15 @@ package gist
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/thomiceli/opengist/internal/config"
|
||||
"github.com/thomiceli/opengist/internal/db"
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
"github.com/thomiceli/opengist/internal/i18n"
|
||||
"github.com/thomiceli/opengist/internal/validator"
|
||||
"github.com/thomiceli/opengist/internal/web/context"
|
||||
@@ -44,10 +48,16 @@ func ProcessCreate(ctx *context.Context) error {
|
||||
|
||||
dto.Files = make([]db.FileDTO, 0)
|
||||
fileCounter := 0
|
||||
for i := 0; i < len(ctx.Request().PostForm["content"]); i++ {
|
||||
name := ctx.Request().PostForm["name"][i]
|
||||
content := ctx.Request().PostForm["content"][i]
|
||||
|
||||
names := ctx.Request().PostForm["name"]
|
||||
contents := ctx.Request().PostForm["content"]
|
||||
|
||||
// Process files from text editors
|
||||
for i, content := range contents {
|
||||
if content == "" {
|
||||
continue
|
||||
}
|
||||
name := names[i]
|
||||
if name == "" {
|
||||
fileCounter += 1
|
||||
name = "gistfile" + strconv.Itoa(fileCounter) + ".txt"
|
||||
@@ -59,10 +69,57 @@ func ProcessCreate(ctx *context.Context) error {
|
||||
}
|
||||
|
||||
dto.Files = append(dto.Files, db.FileDTO{
|
||||
Filename: strings.Trim(name, " "),
|
||||
Filename: strings.TrimSpace(name),
|
||||
Content: escapedValue,
|
||||
})
|
||||
}
|
||||
|
||||
// Process uploaded files from UUID arrays
|
||||
fileUUIDs := ctx.Request().PostForm["uploadedfile_uuid"]
|
||||
fileFilenames := ctx.Request().PostForm["uploadedfile_filename"]
|
||||
if len(fileUUIDs) == len(fileFilenames) {
|
||||
for i, fileUUID := range fileUUIDs {
|
||||
filePath := filepath.Join(filepath.Join(config.GetHomeDir(), "uploads"), fileUUID)
|
||||
|
||||
if _, err := os.Stat(filePath); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
dto.Files = append(dto.Files, db.FileDTO{
|
||||
Filename: fileFilenames[i],
|
||||
SourcePath: filePath,
|
||||
Content: "", // Empty since we're using SourcePath
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Process binary file operations (edit mode)
|
||||
binaryOldNames := ctx.Request().PostForm["binary_old_name"]
|
||||
binaryNewNames := ctx.Request().PostForm["binary_new_name"]
|
||||
if len(binaryOldNames) == len(binaryNewNames) {
|
||||
for i, oldName := range binaryOldNames {
|
||||
newName := binaryNewNames[i]
|
||||
|
||||
if newName == "" { // deletion
|
||||
continue
|
||||
}
|
||||
|
||||
if !isCreate {
|
||||
gistOld := ctx.GetData("gist").(*db.Gist)
|
||||
|
||||
fileContent, _, err := git.GetFileContent(gistOld.User.Username, gistOld.Uuid, "HEAD", oldName, false)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
dto.Files = append(dto.Files, db.FileDTO{
|
||||
Filename: newName,
|
||||
Content: fileContent,
|
||||
Binary: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.SetData("dto", dto)
|
||||
|
||||
err = ctx.Validate(dto)
|
||||
@@ -101,24 +158,13 @@ func ProcessCreate(ctx *context.Context) error {
|
||||
}
|
||||
|
||||
if gist.Title == "" {
|
||||
if ctx.Request().PostForm["name"][0] == "" {
|
||||
if dto.Files[0].Filename == "" {
|
||||
gist.Title = "gist:" + gist.Uuid
|
||||
} else {
|
||||
gist.Title = ctx.Request().PostForm["name"][0]
|
||||
gist.Title = dto.Files[0].Filename
|
||||
}
|
||||
}
|
||||
|
||||
if len(dto.Files) > 0 {
|
||||
split := strings.Split(dto.Files[0].Content, "\n")
|
||||
if len(split) > 10 {
|
||||
gist.Preview = strings.Join(split[:10], "\n")
|
||||
} else {
|
||||
gist.Preview = dto.Files[0].Content
|
||||
}
|
||||
|
||||
gist.PreviewFilename = dto.Files[0].Filename
|
||||
}
|
||||
|
||||
if err = gist.InitRepository(); err != nil {
|
||||
return ctx.ErrorRes(500, "Error creating the repository", err)
|
||||
}
|
||||
@@ -139,6 +185,9 @@ func ProcessCreate(ctx *context.Context) error {
|
||||
|
||||
gist.AddInIndex()
|
||||
gist.UpdateLanguages()
|
||||
if err = gist.UpdatePreviewAndCount(true); err != nil {
|
||||
return ctx.ErrorRes(500, "Error updating preview and count", err)
|
||||
}
|
||||
|
||||
return ctx.RedirectTo("/" + user.Username + "/" + gist.Identifier())
|
||||
}
|
||||
|
||||
77
internal/web/handlers/gist/upload.go
Normal file
77
internal/web/handlers/gist/upload.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package gist
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/thomiceli/opengist/internal/config"
|
||||
"github.com/thomiceli/opengist/internal/web/context"
|
||||
)
|
||||
|
||||
func Upload(ctx *context.Context) error {
|
||||
err := ctx.Request().ParseMultipartForm(32 << 20) // 32 MB max
|
||||
if err != nil {
|
||||
return ctx.ErrorRes(400, ctx.Tr("error.bad-request"), err)
|
||||
}
|
||||
|
||||
fileHeader, err := ctx.FormFile("file")
|
||||
if err != nil {
|
||||
return ctx.ErrorRes(400, ctx.Tr("error.no-file-uploaded"), err)
|
||||
}
|
||||
|
||||
file, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
return ctx.ErrorRes(400, ctx.Tr("error.cannot-open-file"), err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fileUUID, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return ctx.ErrorRes(500, "Error generating UUID", err)
|
||||
}
|
||||
|
||||
uploadsDir := filepath.Join(config.GetHomeDir(), "uploads")
|
||||
if err := os.MkdirAll(uploadsDir, 0755); err != nil {
|
||||
return ctx.ErrorRes(500, "Error creating uploads directory", err)
|
||||
}
|
||||
|
||||
filename := fileUUID.String()
|
||||
filePath := filepath.Join(uploadsDir, filename)
|
||||
|
||||
destFile, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return ctx.ErrorRes(500, "Error creating file", err)
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
if _, err := io.Copy(destFile, file); err != nil {
|
||||
return ctx.ErrorRes(500, "Error saving file", err)
|
||||
}
|
||||
|
||||
return ctx.JSON(200, map[string]string{
|
||||
"uuid": filename,
|
||||
"filename": fileHeader.Filename,
|
||||
})
|
||||
}
|
||||
|
||||
func DeleteUpload(ctx *context.Context) error {
|
||||
uuid := ctx.Param("uuid")
|
||||
if uuid == "" {
|
||||
return ctx.ErrorRes(400, ctx.Tr("error.bad-request"), nil)
|
||||
}
|
||||
|
||||
uploadsDir := filepath.Join(config.GetHomeDir(), "uploads")
|
||||
filePath := filepath.Join(uploadsDir, uuid)
|
||||
|
||||
if _, err := os.Stat(filePath); err == nil {
|
||||
if err := os.Remove(filePath); err != nil {
|
||||
return ctx.ErrorRes(500, "Error deleting file", err)
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.JSON(200, map[string]string{
|
||||
"status": "deleted",
|
||||
})
|
||||
}
|
||||
@@ -29,6 +29,8 @@ func (s *Server) registerRoutes() {
|
||||
r.GET("/", gist.Create, logged)
|
||||
r.POST("/", gist.ProcessCreate, logged)
|
||||
r.POST("/preview", gist.Preview, logged)
|
||||
r.POST("/upload", gist.Upload, logged)
|
||||
r.DELETE("/upload/:uuid", gist.DeleteUpload, logged)
|
||||
|
||||
r.GET("/healthcheck", health.Healthcheck)
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestGists(t *testing.T) {
|
||||
Content: []string{"", "yeah\ncool", "yeah\ncool gist actually"},
|
||||
Topics: "",
|
||||
}
|
||||
err = s.Request("POST", "/", gist2, 400)
|
||||
err = s.Request("POST", "/", gist2, 302)
|
||||
require.NoError(t, err)
|
||||
|
||||
gist3 := db.GistDTO{
|
||||
@@ -82,7 +82,7 @@ func TestGists(t *testing.T) {
|
||||
err = s.Request("POST", "/", gist3, 302)
|
||||
require.NoError(t, err)
|
||||
|
||||
gist3db, err := db.GetGistByID("2")
|
||||
gist3db, err := db.GetGistByID("3")
|
||||
require.NoError(t, err)
|
||||
|
||||
gist3files, err := git.GetFilesOfRepository(gist3db.User.Username, gist3db.Uuid, "HEAD")
|
||||
|
||||
Reference in New Issue
Block a user