nim/internal/handlers/post.go

182 lines
4.7 KiB
Go

package handlers
import (
"crypto/sha256"
"encoding/base64"
"log"
"mime"
"path"
"strconv"
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"nim.jasinco.work/app/internal"
"nim.jasinco.work/app/nimdb"
)
var supported_filetype = []string{"image/png", "image/jpeg", "image/webp", "image/gif", "image/heif", "video/H264", "video/H265", "video/mp4"}
func find_supported(mimetype string) bool {
for _, supported := range supported_filetype {
if strings.Compare(supported, mimetype) == 0 {
return true
}
}
return false
}
func Fetch_post(c *fiber.Ctx) error {
cursor := c.Query("cursor")
ctx := c.Context()
var rec []nimdb.GetPostRow
var err error
if len(cursor) == 0 {
rec, err = internal.NIMDB.GetPost(ctx, internal.FETCH_LENGTH)
if err != nil {
log.Println(err)
return fiber.ErrInternalServerError
}
} else if cursor_num, err := strconv.Atoi(cursor); err == nil {
rec_cur, err := internal.NIMDB.GetPostWithCursor(ctx, nimdb.GetPostWithCursorParams{ID: int32(cursor_num), Limit: internal.FETCH_LENGTH})
if err != nil {
log.Println(err)
return c.Status(500).SendString("Failed to Query DB")
}
rec = make([]nimdb.GetPostRow, len(rec_cur))
for id, val := range rec_cur {
rec[id] = nimdb.GetPostRow(val)
}
} else {
return c.Status(fiber.StatusBadRequest).SendString("Can't parse cursor")
}
if len(rec) == 0 {
return c.SendStatus(fiber.StatusNoContent)
}
return c.JSON(rec)
}
func Delete_post(c *fiber.Ctx) error {
post := c.Query("post")
hash := c.Query("hash")
ctx := c.Context()
post_id, err := strconv.Atoi(post)
post_id_i32 := int32(post_id)
if err != nil {
return c.Status(500).SendString("Failed to Parse Int")
}
tx, err := internal.POOL.Begin(ctx)
if err != nil {
return c.Status(500).SendString("Failed to Start Transaction")
}
defer tx.Rollback(ctx)
qtx := internal.NIMDB.WithTx(tx)
if err = qtx.DeletePost(ctx, nimdb.DeletePostParams{ID: post_id_i32, Hash: hash}); err != nil {
return err
}
if err = qtx.InvalidateMedia(ctx, pgtype.Int4{Int32: post_id_i32}); err != nil {
return err
}
if tx.Commit(ctx) != nil {
return c.Status(500).SendString("Failed to Commit")
}
if internal.IGAPI_ACTIVATE {
internal.IGAPI_CHAN <- internal.PR{ACT_TYPE: 1, ID: post_id_i32}
}
return c.SendStatus(200)
}
func Insert_Post(c *fiber.Ctx) error {
ctx := c.Context()
tx, err := internal.POOL.Begin(ctx)
if err != nil {
return c.Status(500).SendString("Failed to Start Transaction")
}
defer tx.Rollback(ctx)
qtx := internal.NIMDB.WithTx(tx)
if form, err := c.MultipartForm(); err == nil {
content := form.Value["content"]
signing := form.Value["signing"]
files := form.File["enclosure"]
if len(content) == 0 || len(content[0]) == 0 {
return fiber.ErrBadRequest
}
post_hash := sha256.New()
post_hash.Write([]byte(content[0]))
signing_pgt := new(pgtype.Text)
signing_pgt.Valid = false
if len(signing) > 0 && len(signing[0]) > 0 {
post_hash.Write([]byte(signing[0]))
signing_pgt.Valid = true
signing_pgt.String = signing[0]
}
now, err := time.Now().MarshalBinary()
if err != nil {
c.SendString("Failed to get time")
return c.SendStatus(500)
}
credential, err := qtx.InsertPost(ctx,
nimdb.InsertPostParams{
Content: content[0],
Signing: *signing_pgt,
Hash: base64.StdEncoding.EncodeToString(post_hash.Sum(now)),
},
)
if err != nil {
log.Println(err.Error())
return c.Status(500).SendString("Failed to insert post")
}
for _, file := range files {
filemime, _, err := mime.ParseMediaType(file.Header.Get("Content-Type"))
if err != nil {
return c.Status(fiber.ErrBadRequest.Code).SendString("Failed to parse content type")
}
if !find_supported(filemime) {
return c.Status(fiber.ErrBadRequest.Code).SendString("Unsupported Type")
}
filetype := strings.Split(filemime, "/")[0]
mid, err := uuid.NewRandom()
if err != nil {
c.SendString("Faild to generate UUIDv4")
return c.SendStatus(500)
}
fxnamepath := filetype + "/" + mid.String()
if err = c.SaveFile(file, path.Join("./static", fxnamepath)); err != nil {
log.Println("Can't save to ./static", err.Error())
return fiber.ErrInternalServerError
}
if err := qtx.InsertPostImage(ctx, nimdb.InsertPostImageParams{
Url: fxnamepath,
PostID: pgtype.Int4{Int32: credential.ID, Valid: true},
}); err != nil {
log.Println(err.Error())
return c.Status(500).SendString("Failed to insert image")
}
}
if err = tx.Commit(ctx); err != nil {
log.Println(err.Error())
c.SendString("Failed to send Commit")
return c.SendStatus(500)
}
return c.JSON(credential)
}
return fiber.ErrBadRequest
}