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 }