go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/chirp/pkg/controller/chirp.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package controller 9 10 import ( 11 "fmt" 12 "net/http" 13 14 "go.charczuk.com/sdk/apputil" 15 "go.charczuk.com/sdk/uuid" 16 "go.charczuk.com/sdk/web" 17 18 "go.charczuk.com/projects/chirp/pkg/config" 19 "go.charczuk.com/projects/chirp/pkg/model" 20 ) 21 22 type Chirp struct { 23 apputil.BaseController 24 Config config.Config 25 Model model.Manager 26 } 27 28 func (c Chirp) Register(app *web.App) { 29 app.Get("/chirp/:id", web.NestMiddleware(c.chirp, web.SessionRequired)) 30 app.Get("/chirp.new", web.NestMiddleware(c.new, web.SessionRequired)) 31 app.Get("/chirp.quote/:id", web.NestMiddleware(c.newQuoted, web.SessionRequired)) 32 app.Get("/chirp.reply/:id", web.NestMiddleware(c.newReply, web.SessionRequired)) 33 34 app.Post("/chirp.new", web.NestMiddleware(c.postNew, web.SessionRequired)) 35 app.Post("/chirp.like", web.NestMiddleware(c.postLike, web.SessionRequired)) 36 app.Post("/chirp.unlike", web.NestMiddleware(c.postUnlike, web.SessionRequired)) 37 app.Post("/chirp.delete", web.NestMiddleware(c.postDelete, web.SessionRequired)) 38 } 39 40 type chirpViewModel struct { 41 Chirp *model.ChirpFull 42 Replies []model.ChirpFull 43 } 44 45 type newChirpViewModel struct { 46 Quoted *model.ChirpFull 47 Reply *model.ChirpFull 48 } 49 50 func (c Chirp) chirp(r web.Context) web.Result { 51 id, err := web.RouteValue[uuid.UUID](r, "id") 52 if err != nil { 53 return r.Views().BadRequest(err) 54 } 55 chirp, found, err := c.Model.Chirp(r, c.GetUserID(r), id) 56 if err != nil { 57 return r.Views().InternalError(err) 58 } 59 if !found { 60 return r.Views().NotFound() 61 } 62 replies, err := c.Model.ChirpReplies(r, c.GetUserID(r), chirp.ID) 63 if err != nil { 64 return r.Views().InternalError(err) 65 } 66 return r.Views().View("view_chirp", chirpViewModel{ 67 Chirp: &chirp, 68 Replies: replies, 69 }) 70 } 71 72 func (c Chirp) new(r web.Context) web.Result { 73 return r.Views().View("chirp_new", newChirpViewModel{}) 74 } 75 76 func (c Chirp) newQuoted(r web.Context) web.Result { 77 id, err := web.RouteValue[uuid.UUID](r, "id") 78 if err != nil { 79 return r.Views().BadRequest(err) 80 } 81 reply, found, err := c.Model.Chirp(r, c.GetUserID(r), id) 82 if err != nil { 83 return r.Views().InternalError(err) 84 } 85 if !found { 86 return r.Views().NotFound() 87 } 88 return r.Views().View("chirp_new", newChirpViewModel{ 89 Quoted: &reply, 90 }) 91 } 92 93 func (c Chirp) newReply(r web.Context) web.Result { 94 id, err := web.RouteValue[uuid.UUID](r, "id") 95 if err != nil { 96 return r.Views().BadRequest(err) 97 } 98 reply, found, err := c.Model.Chirp(r, c.GetUserID(r), id) 99 if err != nil { 100 return r.Views().InternalError(err) 101 } 102 if !found { 103 return r.Views().NotFound() 104 } 105 return r.Views().View("chirp_new", newChirpViewModel{ 106 Reply: &reply, 107 }) 108 } 109 110 func (c Chirp) postNew(r web.Context) web.Result { 111 text, err := web.FormValue[string](r, "text") 112 if err != nil { 113 return r.Views().BadRequest(err) 114 } 115 if len([]rune(text)) > 512 { 116 return r.Views().BadRequest(fmt.Errorf("contents exceed maximum length of 512 unicode code points")) 117 } 118 119 chirp := model.Chirp{ 120 UserID: c.GetUserID(r), 121 Text: text, 122 } 123 124 replyID, _ := web.FormValue[uuid.UUID](r, "replyID") 125 if !replyID.IsZero() { 126 chirp.ReplyID = &replyID 127 } 128 129 quotedID, _ := web.FormValue[uuid.UUID](r, "quotedID") 130 if !quotedID.IsZero() { 131 chirp.QuotedID = "edID 132 } 133 err = c.Model.CreateChirp(r, &chirp) 134 if err != nil { 135 return r.Views().InternalError(err) 136 } 137 err = c.Model.PublishChirp(r, &chirp) 138 if err != nil { 139 return r.Views().InternalError(err) 140 } 141 return web.RedirectWithMethod(http.MethodGet, "/home") 142 } 143 144 func (c Chirp) postDelete(r web.Context) web.Result { 145 id, err := web.FormValue[uuid.UUID](r, "id") 146 if err != nil { 147 return r.Views().BadRequest(err) 148 } 149 150 chirp, found, err := c.Model.Chirp(r, c.GetUserID(r), id) 151 if err != nil { 152 return r.Views().InternalError(err) 153 } 154 if !found { 155 return r.Views().NotFound() 156 } 157 _, err = c.Model.DeleteChirp(r, chirp.Chirp) 158 if err != nil { 159 return r.Views().InternalError(err) 160 } 161 return web.RedirectWithMethod(http.MethodGet, "/home") 162 } 163 164 func (c Chirp) postLike(r web.Context) web.Result { 165 id, err := web.FormValue[uuid.UUID](r, "id") 166 if err != nil { 167 return r.Views().BadRequest(err) 168 } 169 chirp, found, err := c.Model.Chirp(r, c.GetUserID(r), id) 170 if err != nil { 171 return r.Views().InternalError(err) 172 } 173 if !found { 174 return r.Views().NotFound() 175 } 176 if chirp.Status.IsLiked { 177 return r.Views().BadRequest(fmt.Errorf("chirp is liked; cannot continue")) 178 } 179 err = c.Model.LikeChirp(r, c.GetUserID(r), chirp.Chirp) 180 if err != nil { 181 return r.Views().InternalError(err) 182 } 183 return web.RedirectWithMethod(http.MethodGet, "/home") 184 } 185 186 func (c Chirp) postUnlike(r web.Context) web.Result { 187 id, err := web.FormValue[uuid.UUID](r, "id") 188 if err != nil { 189 return r.Views().BadRequest(err) 190 } 191 chirp, found, err := c.Model.Chirp(r, c.GetUserID(r), id) 192 if err != nil { 193 return r.Views().InternalError(err) 194 } 195 if !found { 196 return r.Views().NotFound() 197 } 198 if !chirp.Status.IsLiked { 199 return r.Views().BadRequest(fmt.Errorf("chirp is unliked; cannot continue")) 200 } 201 err = c.Model.UnlikeChirp(r, c.GetUserID(r), chirp.ID) 202 if err != nil { 203 return r.Views().InternalError(err) 204 } 205 return web.RedirectWithMethod(http.MethodGet, "/home") 206 }