Skip to content

Commit

Permalink
Adding Basic File Uploader (#14)
Browse files Browse the repository at this point in the history
implements part of #13
  • Loading branch information
matheusgomes28 authored Feb 28, 2024
1 parent 4e09929 commit 3065664
Show file tree
Hide file tree
Showing 12 changed files with 340 additions and 161 deletions.
155 changes: 6 additions & 149 deletions admin-app/app.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package admin_app

import (
"encoding/json"
"net/http"
"strconv"

"github.com/gin-gonic/gin"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/rs/zerolog/log"
)

type PostBinding struct {
Expand All @@ -32,150 +27,6 @@ type DeletePostRequest struct {
Id int `json:"id"`
}

func getPostHandler(database database.Database) func(*gin.Context) {
return func(c *gin.Context) {
// localhost:8080/post/{id}
var post_binding PostBinding
if err := c.ShouldBindUri(&post_binding); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not get post id",
"msg": err.Error(),
})
return
}

post_id, err := strconv.Atoi(post_binding.Id)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid post id type",
"msg": err.Error(),
})
return
}

post, err := database.GetPost(post_id)
if err != nil {
log.Warn().Msgf("could not get post from DB: %v", err)
c.JSON(http.StatusNotFound, gin.H{
"error": "post id not found",
"msg": err.Error(),
})
return
}

c.JSON(http.StatusOK, gin.H{
"id": post.Id,
"title": post.Title,
"excerpt": post.Excerpt,
"content": post.Content,
})
}
}

func postPostHandler(database database.Database) func(*gin.Context) {
return func(c *gin.Context) {
var add_post_request AddPostRequest
decoder := json.NewDecoder(c.Request.Body)
err := decoder.Decode(&add_post_request)

if err != nil {
log.Warn().Msgf("could not get post from DB: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid request body",
"msg": err.Error(),
})
return
}

id, err := database.AddPost(
add_post_request.Title,
add_post_request.Excerpt,
add_post_request.Content,
)
if err != nil {
log.Error().Msgf("failed to add post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not add post",
"msg": err.Error(),
})
return
}

c.JSON(http.StatusOK, gin.H{
"id": id,
})
}
}

func putPostHandler(database database.Database) func(*gin.Context) {
return func(c *gin.Context) {
var change_post_request ChangePostRequest
decoder := json.NewDecoder(c.Request.Body)
decoder.DisallowUnknownFields()

err := decoder.Decode(&change_post_request)
if err != nil {
log.Warn().Msgf("could not get post from DB: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid request body",
"msg": err.Error(),
})
return
}

err = database.ChangePost(
change_post_request.Id,
change_post_request.Title,
change_post_request.Excerpt,
change_post_request.Content,
)
if err != nil {
log.Error().Msgf("failed to change post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not change post",
"msg": err.Error(),
})
return
}

c.JSON(http.StatusOK, gin.H{
"id": change_post_request.Id,
})
}
}

func deletePostHandler(database database.Database) func(*gin.Context) {
return func(c *gin.Context) {
var delete_post_request DeletePostRequest
decoder := json.NewDecoder(c.Request.Body)
decoder.DisallowUnknownFields()

err := decoder.Decode(&delete_post_request)
if err != nil {
log.Warn().Msgf("could not delete post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid request body",
"msg": err.Error(),
})
return
}

err = database.DeletePost(delete_post_request.Id)
if err != nil {
log.Error().Msgf("failed to delete post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not delete post",
"msg": err.Error(),
})
return
}

c.JSON(http.StatusOK, gin.H{
"id": delete_post_request.Id,
})
}
}

func SetupRoutes(app_settings common.AppSettings, database database.Database) *gin.Engine {

r := gin.Default()
Expand All @@ -185,5 +36,11 @@ func SetupRoutes(app_settings common.AppSettings, database database.Database) *g
r.POST("/posts", postPostHandler(database))
r.PUT("/posts", putPostHandler(database))
r.DELETE("/posts", deletePostHandler(database))

// CRUD images
// r.GET("/images/:id", getImageHandler(&database))
r.POST("/images", postImageHandler(app_settings, database))
// r.DELETE("/images", deleteImageHandler(&database))

return r
}
101 changes: 101 additions & 0 deletions admin-app/image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package admin_app

import (
"fmt"
"net/http"
"os"
"path/filepath"
"slices"

"github.com/fossoreslp/go-uuid-v4"
"github.com/gin-gonic/gin"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/rs/zerolog/log"
)

type AddImageRequest struct {
Alt string `json:"alt"`
}

// TODO : need these endpoints
// r.GET("/images/:id", getImageHandler(&database))
// r.POST("/images", postImageHandler(&database))
// r.DELETE("/images", deleteImageHandler(&database))
// func getImageHandler(database *database.Database) func(*gin.Context) {
// return func(c *gin.Context) {
// // Get the image from database
// }
// }

func postImageHandler(app_settings common.AppSettings, database database.Database) func(*gin.Context) {
return func(c *gin.Context) {
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 10*1000000)
form, err := c.MultipartForm()
if err != nil {
log.Error().Msgf("could not create multipart form: %v", err)
return
}

alt_text_array := form.Value["alt"]
alt_text := "unknown"
if len(alt_text_array) > 0 {
alt_text = alt_text_array[0]
}

// Begin saving the file to the filesystem
file_array := form.File["file"]
if len(file_array) == 0 {
log.Error().Msgf("could not get the file array: %v", err)
return
}
file := file_array[0]
if file == nil {
log.Error().Msgf("could not upload file: %v", err)
return
}
allowed_types := []string{"image/jpeg", "image/png", "image/gif"}
if file_content_type := file.Header.Get("content-type"); !slices.Contains(allowed_types, file_content_type) {
log.Error().Msgf("file type not supported")
return
}

uuid, err := uuid.New()
if err != nil {
log.Error().Msgf("could not create the UUID: %v", err)
return
}

allowed_extensions := []string{"jpeg", "jpg", "png"}
ext := filepath.Ext(file.Filename)
// check ext is supported
if ext == "" && slices.Contains(allowed_extensions, ext) {
log.Error().Msgf("file extension is not supported %v", err)
return
}

filename := fmt.Sprintf("%s.%s", uuid.String(), ext)
image_path := filepath.Join(app_settings.ImageDirectory, filename)
err = c.SaveUploadedFile(file, image_path)
if err != nil {
log.Error().Msgf("could not save file: %v", err)
return
}
// End saving to filesystem

// Save metadata into the DB
err = database.AddImage(uuid.String(), file.Filename, alt_text)
if err != nil {
log.Error().Msgf("could not add image metadata to db: %v", err)
err := os.Remove(image_path)
if err != nil {
log.Error().Msgf("could not remove image: %v", err)
}
return
}

c.JSON(http.StatusOK, gin.H{
"id": uuid.String(),
})
}
}
Loading

0 comments on commit 3065664

Please sign in to comment.