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 = &quotedID
   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  }