diff options
| author | Elizabeth Hunt <elizabeth@simponic.xyz> | 2024-08-17 18:29:33 -0400 |
|---|---|---|
| committer | simponic <simponic@hatecomputers.club> | 2024-08-17 18:29:33 -0400 |
| commit | b1775c4408bb00803eba321aa66ab92d6ba45580 (patch) | |
| tree | 90179edff8951b06abb91495ce21c8b1841d2d82 /api/kennel | |
| parent | 0b8883c236a06a14e5e6958ed47f89729b0e41aa (diff) | |
| download | hatecomputers.club-b1775c4408bb00803eba321aa66ab92d6ba45580.tar.gz hatecomputers.club-b1775c4408bb00803eba321aa66ab92d6ba45580.zip | |
kennel (#13)
Reviewed-on: https://git.hatecomputers.club/hatecomputers/hatecomputers.club/pulls/13
Co-authored-by: Elizabeth Hunt <elizabeth@simponic.xyz>
Co-committed-by: Elizabeth Hunt <elizabeth@simponic.xyz>
Diffstat (limited to 'api/kennel')
| -rw-r--r-- | api/kennel/kennel.go | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/api/kennel/kennel.go b/api/kennel/kennel.go new file mode 100644 index 0000000..a68388d --- /dev/null +++ b/api/kennel/kennel.go @@ -0,0 +1,238 @@ +package kennel + +import ( + "encoding/json" + "log" + "net/http" + "strings" + + "git.hatecomputers.club/hatecomputers/hatecomputers.club/adapters/files" + "git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" + "git.hatecomputers.club/hatecomputers/hatecomputers.club/database" + "git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" +) + +const MaxCatSize = 1024 * 100 // 60KB +const CatsPath = "cats/" +const CatsPrefix = "/uploads/cats/" +const DefaultCatSpritesheet = "/static/img/cat_spritesheets/default.gif" +const MaxUserCats = 15 + +func ListUserCatsContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { + return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { + userID := context.User.ID + + cats, err := database.GetUserKennelCats(context.DBConn, userID) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + + (*context.TemplateData)["Cats"] = cats + return success(context, req, resp) + } +} + +func CreateCatContinuation(fileAdapter files.FilesAdapter, maxUserCats int, maxCatSize int, catsPath string, catsPrefix string, defaultCatSpritesheet string) func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { + return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { + return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { + formErrors := types.BannerMessages{ + Messages: []string{}, + } + + numCats, err := database.CountUserKennelCats(context.DBConn, context.User.ID) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + if numCats >= maxUserCats { + formErrors.Messages = append(formErrors.Messages, "max cats reached for user") + } + + err = req.ParseMultipartForm(int64(maxCatSize)) + if err != nil { + formErrors.Messages = append(formErrors.Messages, "cat spritesheet too large") + } + + catID := utils.RandomId() + spritesheetPath := catsPrefix + catID + + if len(formErrors.Messages) == 0 { + file, _, err := req.FormFile("spritesheet") + if file != nil && err != nil { + formErrors.Messages = append(formErrors.Messages, "error uploading spritesheet") + } else if file != nil { + defer file.Close() + reader := http.MaxBytesReader(resp, file, int64(maxCatSize)) + defer reader.Close() + + _, err = fileAdapter.CreateFile(catsPath+catID, reader) + if err != nil { + log.Println(err) + formErrors.Messages = append(formErrors.Messages, "error saving spritesheet (is it too big?)") + } + } else if file == nil && err != nil { + spritesheetPath = defaultCatSpritesheet + } + } + + link := req.FormValue("link") + description := req.FormValue("description") + name := req.FormValue("name") + + cat := &database.KennelCat{ + ID: catID, + UserID: context.User.ID, + Name: name, + Link: link, + Description: description, + Spritesheet: spritesheetPath, + } + formErrors.Messages = append(formErrors.Messages, validateCat(cat)...) + if len(formErrors.Messages) == 0 { + _, err := database.SaveKennelCat(context.DBConn, cat) + if err != nil { + log.Println(err) + formErrors.Messages = append(formErrors.Messages, "failed to save cat") + } + } + + if len(formErrors.Messages) > 0 { + (*context.TemplateData)["Error"] = formErrors + (*context.TemplateData)["CatForm"] = cat + resp.WriteHeader(http.StatusBadRequest) + + return failure(context, req, resp) + } + + formSuccess := types.BannerMessages{ + Messages: []string{"cat added."}, + } + (*context.TemplateData)["Success"] = formSuccess + return success(context, req, resp) + } + } +} + +func RemoveCatContinuation(fileAdapter files.FilesAdapter, catsPath string) func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { + return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { + return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { + catID := req.FormValue("id") + + cat, err := database.GetKennelCat(context.DBConn, catID) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + if cat == nil || cat.UserID != context.User.ID { + resp.WriteHeader(http.StatusUnauthorized) + return failure(context, req, resp) + } + + err = database.DeleteKennelCat(context.DBConn, catID) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + + err = fileAdapter.DeleteFile(catsPath + catID) + if err != nil && fileAdapter.FileExists(catsPath+catID) { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + + return success(context, req, resp) + } + } +} + +func RingContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { + return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { + order := req.URL.Query().Get("order") + + if order == "random" { + kennelCat, err := database.GetRandomKennelCat(context.DBConn) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + http.Redirect(resp, req, kennelCat.Link, http.StatusFound) + return success(context, req, resp) + } + + id := req.URL.Query().Get("id") + if id == "" { + resp.WriteHeader(http.StatusBadRequest) + return failure(context, req, resp) + } + if order != "random" && order != "next" && order != "prev" { + kennelCat, err := database.GetKennelCat(context.DBConn, id) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusNotFound) + return failure(context, req, resp) + } + http.Redirect(resp, req, kennelCat.Link, http.StatusFound) + return success(context, req, resp) + } + + nextCat, err := database.GetNextKennelCat(context.DBConn, id, order == "next") + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + + http.Redirect(resp, req, nextCat.Link, http.StatusFound) + return success(context, req, resp) + } +} + +func GetKennelContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { + return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { + cats, err := database.GetKennel(context.DBConn) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + json, err := json.Marshal(cats) + if err != nil { + log.Println(err) + resp.WriteHeader(http.StatusInternalServerError) + return failure(context, req, resp) + } + + resp.Header().Set("Content-Type", "application/json") + resp.Write(json) + return success(context, req, resp) + } +} + +func validateCat(cat *database.KennelCat) []string { + errors := []string{} + + if cat.Name == "" { + errors = append(errors, "name is required") + } + if cat.Link == "" { + errors = append(errors, "link is required") + } + if !strings.HasPrefix(cat.Link, "http://") && !strings.HasPrefix(cat.Link, "https://") { + errors = append(errors, "link must be a valid URL") + } + if cat.Description == "" { + errors = append(errors, "description is required") + } + if len(cat.Description) > 100 { + errors = append(errors, "description must be less than 100 characters") + } + + return errors +} |
