Skip to content

Commit 35e10db

Browse files
committed
implement comments
1 parent 0640694 commit 35e10db

30 files changed

+365
-95
lines changed

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ local-up:
99
local-down:
1010
@docker compose -f compose.local.yml down
1111

12-
.PHONY: local-run
13-
local-run:
12+
.PHONY: local-serve
13+
local-serve:
1414
@go run main.go serve
1515

1616
.PHONY: lint

internal/app/app.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ func (a *App) Close() {
8787
if a.HttpServer != nil {
8888
a.HttpServer.Close()
8989
}
90-
if a.Container.DB != nil {
91-
a.Container.DB.Close()
90+
if a.Container.Database != nil {
91+
a.Container.Database.Close()
9292
}
9393
if a.Container.Logger != nil {
9494
a.Container.Logger.Close()

internal/container/container.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/neatplex/nightell-core/internal/logger"
88
"github.com/neatplex/nightell-core/internal/mailer"
99
"github.com/neatplex/nightell-core/internal/s3"
10+
"github.com/neatplex/nightell-core/internal/services/comment"
1011
"github.com/neatplex/nightell-core/internal/services/file"
1112
"github.com/neatplex/nightell-core/internal/services/followship"
1213
"github.com/neatplex/nightell-core/internal/services/like"
@@ -21,13 +22,14 @@ type Container struct {
2122
Config *config.Config
2223
Logger *logger.Logger
2324
S3 *s3.S3
24-
DB *database.Database
25+
Database *database.Database
2526
Mailer *mailer.Mailer
2627
GC *gc.Gc
2728
UserService *user.Service
2829
TokenService *token.Service
2930
RemoveService *remove.Service
3031
PostService *post.Service
32+
CommentService *comment.Service
3133
FileService *file.Service
3234
LikeService *like.Service
3335
FollowshipService *followship.Service
@@ -46,13 +48,14 @@ func New(
4648
Config: config,
4749
Logger: logger,
4850
S3: s3,
49-
DB: db,
51+
Database: db,
5052
Mailer: mailer,
5153
GC: gc,
5254
UserService: user.New(db, mailer),
5355
TokenService: token.New(db),
5456
RemoveService: remove.New(db),
5557
PostService: post.New(db),
58+
CommentService: comment.New(db),
5659
FileService: file.New(db, s3),
5760
LikeService: like.New(db),
5861
FollowshipService: followship.New(db),

internal/database/database.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func (d *Database) migrate() error {
8080
&models.User{},
8181
&models.Token{},
8282
&models.Post{},
83+
&models.Comment{},
8384
&models.File{},
8485
&models.Like{},
8586
&models.Followship{},
@@ -94,7 +95,7 @@ func (d *Database) migrate() error {
9495

9596
func (d *Database) Close() {
9697
if db, err := d.handler.DB(); err != nil {
97-
d.l.Error("database: cannot get DB from GORM to close", zap.Error(err))
98+
d.l.Error("database: cannot get Database from GORM to close", zap.Error(err))
9899
} else {
99100
if err = db.Close(); err != nil {
100101
d.l.Error("database: cannot close database", zap.Error(err))

internal/gc/gc.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ func (g *Gc) cleanup() {
3838
for _, file := range files {
3939
var post *models.Post
4040
r = g.database.Handler().
41-
Where("audio_id = ?", file.ID).
42-
Or("image_id = ?", file.ID).
41+
Where("audio_id = ?", file.Id).
42+
Or("image_id = ?", file.Id).
4343
First(&post)
4444
if r.Error != nil && !errors.Is(r.Error, gorm.ErrRecordNotFound) {
4545
g.l.Error("gc: cannot fetch post", zap.Error(errors.WithStack(r.Error)))
4646
return
4747
}
48-
if post == nil || post.ID == 0 {
48+
if post == nil || post.Id == 0 {
4949
if err := g.s3.Delete(file.Path); err != nil {
5050
g.l.Error("gc: cannot delete s3 file", zap.Error(errors.WithStack(err)))
5151
return
@@ -54,7 +54,7 @@ func (g *Gc) cleanup() {
5454
if r.Error != nil {
5555
g.l.Error("gc: cannot delete db file", zap.Error(errors.WithStack(r.Error)))
5656
} else {
57-
g.l.Info("gc: cleaned", zap.Uint64("id", file.ID), zap.String("path", file.Path))
57+
g.l.Info("gc: cleaned", zap.Uint64("id", file.Id), zap.String("path", file.Path))
5858
}
5959
}
6060
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package v1
2+
3+
import (
4+
"github.com/cockroachdb/errors"
5+
"github.com/labstack/echo/v4"
6+
"github.com/neatplex/nightell-core/internal/container"
7+
"github.com/neatplex/nightell-core/internal/models"
8+
"github.com/neatplex/nightell-core/internal/utils"
9+
"net/http"
10+
)
11+
12+
func CommentsIndex(ctr *container.Container) echo.HandlerFunc {
13+
return func(ctx echo.Context) error {
14+
user := ctx.Get("user").(*models.User)
15+
16+
comments, err := ctr.CommentService.IndexByUser(
17+
user.Id,
18+
utils.StringToID(ctx.QueryParams().Get("lastId"), ^uint64(0)),
19+
utils.StringToInt(ctx.QueryParams().Get("count"), 100, 10),
20+
)
21+
if err != nil {
22+
return errors.WithStack(err)
23+
}
24+
25+
return ctx.JSON(http.StatusCreated, map[string]interface{}{
26+
"comments": comments,
27+
})
28+
}
29+
}
30+
31+
func CommentsIndexByPost(ctr *container.Container) echo.HandlerFunc {
32+
return func(ctx echo.Context) error {
33+
post, err := ctr.PostService.FindBy("id", utils.StringToID(ctx.Param("postId"), 0))
34+
if err != nil {
35+
return errors.WithStack(err)
36+
}
37+
if post == nil {
38+
return ctx.NoContent(http.StatusNotFound)
39+
}
40+
41+
comments, err := ctr.CommentService.IndexByPost(
42+
post.Id,
43+
utils.StringToID(ctx.QueryParams().Get("lastId"), ^uint64(0)),
44+
utils.StringToInt(ctx.QueryParams().Get("count"), 100, 10),
45+
)
46+
if err != nil {
47+
return errors.WithStack(err)
48+
}
49+
50+
return ctx.JSON(http.StatusCreated, map[string]interface{}{
51+
"comments": comments,
52+
})
53+
}
54+
}
55+
56+
type commentsStoreRequest struct {
57+
Text string `json:"text" validate:"max=255"`
58+
PostId uint64 `json:"post_id" validate:"required"`
59+
}
60+
61+
func CommentsStore(ctr *container.Container) echo.HandlerFunc {
62+
return func(ctx echo.Context) error {
63+
user := ctx.Get("user").(*models.User)
64+
65+
var r commentsStoreRequest
66+
if err := ctx.Bind(&r); err != nil {
67+
return ctx.JSON(http.StatusBadRequest, map[string]string{
68+
"message": "Cannot parse the request body.",
69+
})
70+
}
71+
if err := ctx.Validate(r); err != nil {
72+
return ctx.JSON(http.StatusUnprocessableEntity, map[string]string{
73+
"message": err.Error(),
74+
})
75+
}
76+
77+
post, err := ctr.PostService.FindById(r.PostId)
78+
if err != nil {
79+
return errors.WithStack(err)
80+
}
81+
if post == nil {
82+
return ctx.JSON(http.StatusNotFound, map[string]string{
83+
"message": "Post not found.",
84+
})
85+
}
86+
87+
id, err := ctr.CommentService.Create(&models.Comment{
88+
PostId: post.Id,
89+
UserId: user.Id,
90+
Text: r.Text,
91+
})
92+
if err != nil {
93+
return errors.WithStack(err)
94+
}
95+
96+
comment, err := ctr.CommentService.FindById(id)
97+
if err != nil {
98+
return errors.WithStack(err)
99+
}
100+
101+
return ctx.JSON(http.StatusCreated, map[string]interface{}{
102+
"comment": comment,
103+
})
104+
}
105+
}
106+
107+
func CommentsDelete(ctr *container.Container) echo.HandlerFunc {
108+
return func(ctx echo.Context) error {
109+
user := ctx.Get("user").(*models.User)
110+
111+
comment, err := ctr.CommentService.FindById(utils.StringToID(ctx.Param("commentId"), 0))
112+
if err != nil {
113+
return errors.WithStack(err)
114+
}
115+
if comment == nil {
116+
return ctx.NoContent(http.StatusNotFound)
117+
}
118+
119+
if comment.UserId != user.Id && comment.Post.UserId != user.Id {
120+
return ctx.JSON(http.StatusForbidden, map[string]string{
121+
"message": "You do not have permission to perform this action.",
122+
})
123+
}
124+
125+
ctr.CommentService.Delete(comment)
126+
127+
return ctx.NoContent(http.StatusNoContent)
128+
}
129+
}

internal/http/server/handlers/v1/feed.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func Feed(ctr *container.Container) echo.HandlerFunc {
1414
user := ctx.Get("user").(*models.User)
1515

1616
posts, err := ctr.PostService.Feed(
17-
user.ID,
17+
user.Id,
1818
utils.StringToID(ctx.QueryParams().Get("lastId"), ^uint64(0)),
1919
utils.StringToInt(ctx.QueryParams().Get("count"), 100, 10),
2020
)

internal/http/server/handlers/v1/files.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func FilesStore(ctr *container.Container) echo.HandlerFunc {
3737
path := ctr.FileService.Path(extension)
3838

3939
err = ctr.FileService.Create(&models.File{
40-
UserID: user.ID,
40+
UserId: user.Id,
4141
Extension: extension,
4242
Path: path,
4343
})

internal/http/server/handlers/v1/likes.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ func LikesDelete(ctr *container.Container) echo.HandlerFunc {
6363
})
6464
}
6565

66-
if like.UserID != user.ID {
66+
if like.UserId != user.Id {
6767
return ctx.JSON(http.StatusForbidden, map[string]string{
6868
"message": "You do not have permission to perform this action.",
6969
})
7070
}
7171

72-
if err = ctr.LikeService.Delete(like.ID); err != nil {
72+
if err = ctr.LikeService.Delete(like.Id); err != nil {
7373
return errors.WithStack(err)
7474
}
7575

internal/http/server/handlers/v1/posts.go

+16-15
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ func PostsIndex(ctr *container.Container) echo.HandlerFunc {
2020
}
2121

2222
posts, err := ctr.PostService.Index(
23-
user.ID,
23+
user.Id,
2424
utils.StringToID(ctx.QueryParams().Get("lastId"), ^uint64(0)),
2525
utils.StringToInt(ctx.QueryParams().Get("count"), 100, 10),
2626
)
2727
if err != nil {
2828
return errors.WithStack(err)
2929
}
30+
3031
return ctx.JSON(http.StatusCreated, map[string]interface{}{
3132
"posts": posts,
3233
})
@@ -65,7 +66,7 @@ func PostsStore(ctr *container.Container) echo.HandlerFunc {
6566
"message": "Audio file not found.",
6667
})
6768
}
68-
if s, _ := ctr.PostService.FindBy("audio_id", audio.ID); s != nil {
69+
if s, _ := ctr.PostService.FindBy("audio_id", audio.Id); s != nil {
6970
return ctx.JSON(http.StatusUnprocessableEntity, map[string]string{
7071
"message": "The selected file is already in use.",
7172
})
@@ -91,12 +92,12 @@ func PostsStore(ctr *container.Container) echo.HandlerFunc {
9192
"message": "Image file not found.",
9293
})
9394
}
94-
if s, _ := ctr.PostService.FindBy("image_id", image.ID); s != nil {
95+
if s, _ := ctr.PostService.FindBy("image_id", image.Id); s != nil {
9596
return ctx.JSON(http.StatusUnprocessableEntity, map[string]string{
9697
"message": "The selected file is already in use.",
9798
})
9899
}
99-
if s, _ := ctr.UserService.FindBy("image_id", image.ID); s != nil {
100+
if s, _ := ctr.UserService.FindBy("image_id", image.Id); s != nil {
100101
return ctx.JSON(http.StatusUnprocessableEntity, map[string]string{
101102
"message": "The selected file is already in use.",
102103
})
@@ -110,15 +111,15 @@ func PostsStore(ctr *container.Container) echo.HandlerFunc {
110111
"message": "The selected file is not an image.",
111112
})
112113
}
113-
imageId = &image.ID
114+
imageId = &image.Id
114115
}
115116

116117
id, err := ctr.PostService.Create(&models.Post{
117-
UserID: user.ID,
118+
UserId: user.Id,
118119
Title: r.Title,
119120
Description: r.Description,
120-
AudioID: audio.ID,
121-
ImageID: imageId,
121+
AudioId: audio.Id,
122+
ImageId: imageId,
122123
LikesCount: 0,
123124
CommentsCount: 0,
124125
})
@@ -137,11 +138,6 @@ func PostsStore(ctr *container.Container) echo.HandlerFunc {
137138
}
138139
}
139140

140-
type postsUpdateCaptionRequest struct {
141-
Title string `json:"title" validate:"required,min=1,max=50"`
142-
Description string `json:"description" validate:"max=300"`
143-
}
144-
145141
func PostsShow(ctr *container.Container) echo.HandlerFunc {
146142
return func(ctx echo.Context) error {
147143
post, err := ctr.PostService.FindById(utils.StringToID(ctx.Param("postId"), 0))
@@ -157,6 +153,11 @@ func PostsShow(ctr *container.Container) echo.HandlerFunc {
157153
}
158154
}
159155

156+
type postsUpdateCaptionRequest struct {
157+
Title string `json:"title" validate:"required,min=1,max=50"`
158+
Description string `json:"description" validate:"max=300"`
159+
}
160+
160161
func PostsUpdate(ctr *container.Container) echo.HandlerFunc {
161162
return func(ctx echo.Context) error {
162163
user := ctx.Get("user").(*models.User)
@@ -169,7 +170,7 @@ func PostsUpdate(ctr *container.Container) echo.HandlerFunc {
169170
return ctx.NoContent(http.StatusNotFound)
170171
}
171172

172-
if post.UserID != user.ID {
173+
if post.UserId != user.Id {
173174
return ctx.JSON(http.StatusForbidden, map[string]string{
174175
"message": "You do not have permission to perform this action.",
175176
})
@@ -207,7 +208,7 @@ func PostsDelete(ctr *container.Container) echo.HandlerFunc {
207208
return ctx.NoContent(http.StatusNotFound)
208209
}
209210

210-
if post.UserID != user.ID {
211+
if post.UserId != user.Id {
211212
return ctx.JSON(http.StatusForbidden, map[string]string{
212213
"message": "You do not have permission to perform this action.",
213214
})

0 commit comments

Comments
 (0)