package controllers import ( "context" "log" "math" "net/http" "path/filepath" "strconv" "strings" "github.com/dchest/captcha" "github.com/gin-gonic/gin" Db "micrach/db" Repositories "micrach/repositories" Utils "micrach/utils" ) func GetThreads(c *gin.Context) { pageString := c.DefaultQuery("page", "1") page, err := strconv.Atoi(pageString) if err != nil { c.HTML(http.StatusNotFound, "404.html", nil) return } if page <= 0 { c.HTML(http.StatusNotFound, "404.html", nil) return } limit := 10 offset := limit * (page - 1) threads, err := Repositories.Posts.Get(limit, offset) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } count, err := Repositories.Posts.GetCount() if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } pagesCount := int(math.Ceil(float64(count) / 10)) if page > pagesCount && count != 0 { c.HTML(http.StatusNotFound, "404.html", nil) return } captchaID := captcha.New() htmlData := Repositories.GetThreadsHtmlData{ Threads: threads, PagesCount: pagesCount, Page: page, FormData: Repositories.HtmlFormData{ CaptchaID: captchaID, }, } c.HTML(http.StatusOK, "index.html", htmlData) } func GetThread(c *gin.Context) { threadIDString := c.Param("threadID") threadID, err := strconv.Atoi(threadIDString) if err != nil { c.HTML(http.StatusNotFound, "404.html", nil) return } thread, err := Repositories.Posts.GetThreadByPostID(threadID) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } if thread == nil { c.HTML(http.StatusNotFound, "404.html", nil) return } firstPost := thread[0] captchaID := captcha.New() htmlData := Repositories.GetThreadHtmlData{ Thread: thread, FormData: Repositories.HtmlFormData{ FirstPostID: firstPost.ID, CaptchaID: captchaID, }, } c.HTML(http.StatusOK, "thread.html", htmlData) } func CreateThread(c *gin.Context) { form, err := c.MultipartForm() if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } captchaID := form.Value["captchaId"][0] captchaString := form.Value["captcha"][0] isCaptchaValid := captcha.VerifyString(captchaID, captchaString) if !isCaptchaValid { errorHtmlData := Repositories.BadRequestHtmlData{ Message: Repositories.InvalidCaptchaErrorMessage, } c.HTML(http.StatusInternalServerError, "400.html", errorHtmlData) return } // TODO: dat shit crashes if no fields in request text := form.Value["text"][0] title := form.Value["title"][0] isPostValid := Utils.ValidatePost(title, text) if !isPostValid { errorHtmlData := Repositories.BadRequestHtmlData{ Message: Repositories.InvalidTitleOrTextErrorMessage, } c.HTML(http.StatusInternalServerError, "400.html", errorHtmlData) return } filesInRequest := form.File["files"] isFilesSizesNotToBig := Utils.CheckFilesSize(filesInRequest) if !isFilesSizesNotToBig { errorHtmlData := Repositories.BadRequestHtmlData{ Message: Repositories.InvalidFileSizeMessage, } c.HTML(http.StatusInternalServerError, "400.html", errorHtmlData) return } conn, err := Db.Pool.Acquire(context.TODO()) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } defer conn.Release() tx, err := conn.Begin(context.TODO()) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } defer tx.Rollback(context.TODO()) post := Repositories.Post{ IsParent: true, Title: title, Text: text, IsSage: false, } threadID, err := Repositories.Posts.CreateInTx(tx, post) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } err = Utils.CreateThreadFolder(threadID) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } for _, fileInRequest := range filesInRequest { file := Repositories.File{ PostID: threadID, Name: fileInRequest.Filename, // image/jpeg -> jpeg Ext: strings.Split(fileInRequest.Header["Content-Type"][0], "/")[1], Size: int(fileInRequest.Size), } fileID, err := Repositories.Files.CreateInTx(tx, file) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } path := filepath.Join( Utils.UPLOADS_DIR_PATH, strconv.Itoa(threadID), "o", strconv.Itoa(fileID)+"."+file.Ext, ) err = c.SaveUploadedFile(fileInRequest, path) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } // creating thumbnail thumbImg, err := Utils.MakeImageThumbnail(path, file.Ext, threadID, fileID) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } // saving thumbnail err = Utils.SaveImageThumbnail(thumbImg, threadID, fileID, file.Ext) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } } tx.Commit(context.TODO()) c.Redirect(http.StatusFound, "/"+strconv.Itoa(threadID)) } func UpdateThread(c *gin.Context) { threadIDString := c.Param("threadID") threadID, err := strconv.Atoi(threadIDString) if err != nil { c.HTML(http.StatusNotFound, "500.html", nil) return } form, err := c.MultipartForm() if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } captchaID := form.Value["captchaId"][0] captchaString := form.Value["captcha"][0] isCaptchaValid := captcha.VerifyString(captchaID, captchaString) if !isCaptchaValid { errorHtmlData := Repositories.BadRequestHtmlData{ Message: Repositories.InvalidCaptchaErrorMessage, } c.HTML(http.StatusInternalServerError, "400.html", errorHtmlData) return } // TODO: dat shit crashes if no fields in request text := form.Value["text"][0] isPostValid := Utils.ValidatePost("", text) if !isPostValid { errorHtmlData := Repositories.BadRequestHtmlData{ Message: Repositories.InvalidTitleOrTextErrorMessage, } c.HTML(http.StatusInternalServerError, "400.html", errorHtmlData) return } filesInRequest := form.File["files"] isFilesSizesNotToBig := Utils.CheckFilesSize(filesInRequest) if !isFilesSizesNotToBig { errorHtmlData := Repositories.BadRequestHtmlData{ Message: Repositories.InvalidFileSizeMessage, } c.HTML(http.StatusInternalServerError, "400.html", errorHtmlData) return } isSageField := form.Value["sage"] var isSageString string if len(isSageField) != 0 { isSageString = isSageField[0] } isSage := isSageString == "on" conn, err := Db.Pool.Acquire(context.TODO()) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } defer conn.Release() tx, err := conn.Begin(context.TODO()) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } defer tx.Rollback(context.TODO()) post := Repositories.Post{ IsParent: false, ParentID: threadID, Title: "", Text: text, IsSage: isSage, } postID, err := Repositories.Posts.CreateInTx(tx, post) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } for _, fileInRequest := range filesInRequest { file := Repositories.File{ PostID: postID, Name: fileInRequest.Filename, // image/jpeg -> jpeg Ext: strings.Split(fileInRequest.Header["Content-Type"][0], "/")[1], Size: int(fileInRequest.Size), } fileID, err := Repositories.Files.CreateInTx(tx, file) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } path := filepath.Join( Utils.UPLOADS_DIR_PATH, strconv.Itoa(threadID), "o", strconv.Itoa(fileID)+"."+file.Ext, ) err = c.SaveUploadedFile(fileInRequest, path) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } // creating thumbnail thumbImg, err := Utils.MakeImageThumbnail(path, file.Ext, threadID, fileID) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } // saving thumbnail err = Utils.SaveImageThumbnail(thumbImg, threadID, fileID, file.Ext) if err != nil { log.Println("error:", err) c.HTML(http.StatusInternalServerError, "500.html", nil) return } } tx.Commit(context.TODO()) c.Redirect(http.StatusFound, "/"+strconv.Itoa(threadID)) }