diff --git a/enshi/src/Components/ArticleViewer/ArticleViewer.tsx b/enshi/src/Components/ArticleViewer/ArticleViewer.tsx index 6da74db..f8a9c6b 100644 --- a/enshi/src/Components/ArticleViewer/ArticleViewer.tsx +++ b/enshi/src/Components/ArticleViewer/ArticleViewer.tsx @@ -5,6 +5,7 @@ import { useAtomValue } from "jotai"; import { useParams } from "react-router-dom"; import { axiosLocalhost } from "../../api/axios/axios"; import { userAtom } from "../../AtomStore/AtomStore"; +import { MINUTE } from "../../constants/timeInMills"; import AddPostToBlogDialog from "../Dialogs/AddPostToBlogDialog/AddPostToBlogDialog"; import ChangePostButton from "./ChangePostButton/ChangePostButton"; import SkeletonPostLoader from "./SkeletonLoader/SkeletonLoader"; @@ -19,7 +20,7 @@ export default function ArticleViewer(props: TArticleViewer) { let queryParams = useParams(); const user = useAtomValue(userAtom); - const { data, isPending } = useQuery({ + const { data: blogData, isPending } = useQuery({ queryKey: [`post_${queryParams["postId"]}`], queryFn: async () => { const response = await axiosLocalhost.get( @@ -28,7 +29,7 @@ export default function ArticleViewer(props: TArticleViewer) { return response.data; }, - gcTime: 0, + gcTime: 2 * MINUTE, refetchOnMount: true, }); @@ -38,7 +39,7 @@ export default function ArticleViewer(props: TArticleViewer) { - {data.title} + {blogData.title} - - + ); diff --git a/enshi/src/constants/timeInMills.ts b/enshi/src/constants/timeInMills.ts new file mode 100644 index 0000000..9855beb --- /dev/null +++ b/enshi/src/constants/timeInMills.ts @@ -0,0 +1,6 @@ +export const SECOND = 1000; +export const MINUTE = 60 * SECOND; +export const HOUR = 60 * MINUTE; +export const DAY = 24 * HOUR; +export const WEEK = 7 * DAY; +export const MONTH = 30 * DAY; \ No newline at end of file diff --git a/enshi_back/ABAC/GlobalRules/IsOwnerOfTheCommentRule.go b/enshi_back/ABAC/GlobalRules/IsOwnerOfTheCommentRule.go new file mode 100644 index 0000000..caf6e5c --- /dev/null +++ b/enshi_back/ABAC/GlobalRules/IsOwnerOfTheCommentRule.go @@ -0,0 +1,28 @@ +package globalrules + +import ( + "context" + db_repo "enshi/db/go_queries" + "enshi/db_connection" + "enshi/middleware/getters" + + "github.com/gin-gonic/gin" +) + +func IsOwnerOfTheCommentRule(c *gin.Context) (bool, []error) { + commentId, err := getters.GetInt64Param(c, "comment-id") + if err != nil { + return false, []error{err} + } + + contextUserId, err := getters.GetUserIdFromContext(c) + if err != nil { + return false, []error{err} + } + + comment, err := db_repo.New(db_connection.Dbx).GetCommentById(context.Background(), commentId) + if err != nil { + return false, []error{err} + } + return contextUserId == comment.UserID, nil +} diff --git a/enshi_back/db/go_queries/badge_queries.sql.go b/enshi_back/db/go_queries/badge_queries.sql.go index cf94d34..d455fcc 100644 --- a/enshi_back/db/go_queries/badge_queries.sql.go +++ b/enshi_back/db/go_queries/badge_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: badge_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/blogs_queries.sql.go b/enshi_back/db/go_queries/blogs_queries.sql.go index 4118c2e..cc7ab84 100644 --- a/enshi_back/db/go_queries/blogs_queries.sql.go +++ b/enshi_back/db/go_queries/blogs_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: blogs_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/bookmarks_queries.sql.go b/enshi_back/db/go_queries/bookmarks_queries.sql.go index f40cd8e..7c04241 100644 --- a/enshi_back/db/go_queries/bookmarks_queries.sql.go +++ b/enshi_back/db/go_queries/bookmarks_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: bookmarks_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/categories_queries.sql.go b/enshi_back/db/go_queries/categories_queries.sql.go index 5adeff7..132c985 100644 --- a/enshi_back/db/go_queries/categories_queries.sql.go +++ b/enshi_back/db/go_queries/categories_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: categories_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/comments_queries.sql.go b/enshi_back/db/go_queries/comments_queries.sql.go index 5457e28..53aaf42 100644 --- a/enshi_back/db/go_queries/comments_queries.sql.go +++ b/enshi_back/db/go_queries/comments_queries.sql.go @@ -1,14 +1,12 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: comments_queries.sql package db_repo import ( "context" - - "github.com/jackc/pgx/v5/pgtype" ) const createComment = `-- name: CreateComment :one @@ -19,10 +17,10 @@ RETURNING comment_id, post_id, user_id, content, created_at ` type CreateCommentParams struct { - CommentID int64 `json:"comment_id"` - PostID pgtype.Int8 `json:"post_id"` - UserID pgtype.Int8 `json:"user_id"` - Content pgtype.Text `json:"content"` + CommentID int64 `json:"comment_id"` + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` + Content string `json:"content"` } func (q *Queries) CreateComment(ctx context.Context, arg CreateCommentParams) (Comment, error) { @@ -53,6 +51,25 @@ func (q *Queries) DeleteComment(ctx context.Context, commentID int64) error { return err } +const getCommentById = `-- name: GetCommentById :one +SELECT comment_id, post_id, user_id, "content", created_at +FROM public."comments" +WHERE comment_id=$1 +` + +func (q *Queries) GetCommentById(ctx context.Context, commentID int64) (Comment, error) { + row := q.db.QueryRow(ctx, getCommentById, commentID) + var i Comment + err := row.Scan( + &i.CommentID, + &i.PostID, + &i.UserID, + &i.Content, + &i.CreatedAt, + ) + return i, err +} + const getCommentByUserId = `-- name: GetCommentByUserId :one SELECT comment_id, post_id, user_id, "content", created_at FROM public."comments" @@ -60,8 +77,8 @@ where public."comments".user_id = $1 and public."comments".post_id = $2 ` type GetCommentByUserIdParams struct { - UserID pgtype.Int8 `json:"user_id"` - PostID pgtype.Int8 `json:"post_id"` + UserID int64 `json:"user_id"` + PostID int64 `json:"post_id"` } func (q *Queries) GetCommentByUserId(ctx context.Context, arg GetCommentByUserIdParams) (Comment, error) { @@ -86,12 +103,12 @@ LIMIT 10 offset ($2 * 10) ` type GetCommentsForPostAscParams struct { - PostID pgtype.Int8 `json:"post_id"` - Column2 interface{} `json:"column_2"` + PostID int64 `json:"post_id"` + Offset interface{} `json:"offset"` } func (q *Queries) GetCommentsForPostAsc(ctx context.Context, arg GetCommentsForPostAscParams) ([]Comment, error) { - rows, err := q.db.Query(ctx, getCommentsForPostAsc, arg.PostID, arg.Column2) + rows, err := q.db.Query(ctx, getCommentsForPostAsc, arg.PostID, arg.Offset) if err != nil { return nil, err } @@ -125,7 +142,7 @@ LIMIT 10 offset ($2 * 10) ` type GetCommentsForPostDescParams struct { - PostID pgtype.Int8 `json:"post_id"` + PostID int64 `json:"post_id"` Column2 interface{} `json:"column_2"` } @@ -163,8 +180,8 @@ RETURNING comment_id, post_id, user_id, content, created_at ` type UpdateCommentByCommentIdParams struct { - CommentID int64 `json:"comment_id"` - Content pgtype.Text `json:"content"` + CommentID int64 `json:"comment_id"` + Content string `json:"content"` } func (q *Queries) UpdateCommentByCommentId(ctx context.Context, arg UpdateCommentByCommentIdParams) (Comment, error) { diff --git a/enshi_back/db/go_queries/db.go b/enshi_back/db/go_queries/db.go index 11d3385..a1ebdbb 100644 --- a/enshi_back/db/go_queries/db.go +++ b/enshi_back/db/go_queries/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 package db_repo diff --git a/enshi_back/db/go_queries/favorites_queries.sql.go b/enshi_back/db/go_queries/favorites_queries.sql.go index 440bfc8..baeac54 100644 --- a/enshi_back/db/go_queries/favorites_queries.sql.go +++ b/enshi_back/db/go_queries/favorites_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: favorites_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/likes_queries.sql.go b/enshi_back/db/go_queries/likes_queries.sql.go index b996985..dd1686f 100644 --- a/enshi_back/db/go_queries/likes_queries.sql.go +++ b/enshi_back/db/go_queries/likes_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: likes_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/models.go b/enshi_back/db/go_queries/models.go index aead1e0..4a81740 100644 --- a/enshi_back/db/go_queries/models.go +++ b/enshi_back/db/go_queries/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 package db_repo @@ -38,9 +38,9 @@ type Category struct { type Comment struct { CommentID int64 `json:"comment_id"` - PostID pgtype.Int8 `json:"post_id"` - UserID pgtype.Int8 `json:"user_id"` - Content pgtype.Text `json:"content"` + PostID int64 `json:"post_id"` + UserID int64 `json:"user_id"` + Content string `json:"content"` CreatedAt pgtype.Timestamp `json:"created_at"` } diff --git a/enshi_back/db/go_queries/multi_queries.sql.go b/enshi_back/db/go_queries/multi_queries.sql.go index 0b76c11..22f2698 100644 --- a/enshi_back/db/go_queries/multi_queries.sql.go +++ b/enshi_back/db/go_queries/multi_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: multi_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/post_tags_queries.sql.go b/enshi_back/db/go_queries/post_tags_queries.sql.go index b14fb8a..c76653f 100644 --- a/enshi_back/db/go_queries/post_tags_queries.sql.go +++ b/enshi_back/db/go_queries/post_tags_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: post_tags_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/post_votes_queries.sql.go b/enshi_back/db/go_queries/post_votes_queries.sql.go index 4c6809c..a4fba0e 100644 --- a/enshi_back/db/go_queries/post_votes_queries.sql.go +++ b/enshi_back/db/go_queries/post_votes_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: post_votes_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/posts_queries.sql.go b/enshi_back/db/go_queries/posts_queries.sql.go index 16b3220..1c93ddf 100644 --- a/enshi_back/db/go_queries/posts_queries.sql.go +++ b/enshi_back/db/go_queries/posts_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: posts_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/profiles_queries.sql.go b/enshi_back/db/go_queries/profiles_queries.sql.go index 70889c2..f2222e3 100644 --- a/enshi_back/db/go_queries/profiles_queries.sql.go +++ b/enshi_back/db/go_queries/profiles_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: profiles_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/tags_queries.sql.go b/enshi_back/db/go_queries/tags_queries.sql.go index a54d7cb..d9ca2e7 100644 --- a/enshi_back/db/go_queries/tags_queries.sql.go +++ b/enshi_back/db/go_queries/tags_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: tags_queries.sql package db_repo diff --git a/enshi_back/db/go_queries/users_queries.sql.go b/enshi_back/db/go_queries/users_queries.sql.go index 58df2d2..8149a60 100644 --- a/enshi_back/db/go_queries/users_queries.sql.go +++ b/enshi_back/db/go_queries/users_queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.28.0 +// sqlc v1.29.0 // source: users_queries.sql package db_repo diff --git a/enshi_back/db/migrations/01_migration.up.sql b/enshi_back/db/migrations/01_migration.up.sql index 6ffcddb..34c90aa 100644 --- a/enshi_back/db/migrations/01_migration.up.sql +++ b/enshi_back/db/migrations/01_migration.up.sql @@ -57,9 +57,9 @@ CREATE TABLE IF NOT EXISTS "public"."bookmarks" ( -- Create "comments" table CREATE TABLE IF NOT EXISTS "public"."comments" ( "comment_id" bigint NOT NULL, - "post_id" bigint NULL, - "user_id" bigint NULL, - "content" text NULL, + "post_id" bigint NOT NULL, + "user_id" bigint NOT NULL, + "content" text NOT NULL, "created_at" timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY ("comment_id"), CONSTRAINT "comments_post_id_fkey" FOREIGN KEY ("post_id") REFERENCES "public"."posts" ("post_id") ON UPDATE NO ACTION ON DELETE CASCADE, diff --git a/enshi_back/db/queries/comments_queries.sql b/enshi_back/db/queries/comments_queries.sql index cb6ba13..a50a032 100644 --- a/enshi_back/db/queries/comments_queries.sql +++ b/enshi_back/db/queries/comments_queries.sql @@ -20,7 +20,7 @@ SELECT comment_id, post_id, user_id, "content", created_at FROM public."comments" where public."comments".post_id = $1 order by created_at ASC -LIMIT 10 offset ($2 * 10); +LIMIT 10 offset (sqlc.arg('offset') * 10); -- name: UpdateCommentByCommentId :one UPDATE public."comments" @@ -31,4 +31,9 @@ RETURNING *; -- name: GetCommentByUserId :one SELECT comment_id, post_id, user_id, "content", created_at FROM public."comments" -where public."comments".user_id = $1 and public."comments".post_id = $2; \ No newline at end of file +where public."comments".user_id = $1 and public."comments".post_id = $2; + +-- name: GetCommentById :one +SELECT comment_id, post_id, user_id, "content", created_at +FROM public."comments" +WHERE comment_id=$1; \ No newline at end of file diff --git a/enshi_back/main.go b/enshi_back/main.go index 553c55a..735ad99 100644 --- a/enshi_back/main.go +++ b/enshi_back/main.go @@ -13,7 +13,6 @@ import ( "os" "github.com/gin-gonic/gin" - "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) var ( @@ -38,7 +37,7 @@ func main() { defer cleanup(context.Background()) router := gin.Default() - router.Use(otelgin.Middleware(serviceName)) + // router.Use(otelgin.Middleware(serviceName)) f, err := os.OpenFile("gin.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) if err != nil { diff --git a/enshi_back/routes/commentRoutes/createComment.go b/enshi_back/routes/commentRoutes/createComment.go new file mode 100644 index 0000000..e043edd --- /dev/null +++ b/enshi_back/routes/commentRoutes/createComment.go @@ -0,0 +1,63 @@ +package routes + +import ( + "context" + "encoding/binary" + rest_api_stuff "enshi/REST_API_stuff" + db_repo "enshi/db/go_queries" + "enshi/db_connection" + "enshi/middleware/getters" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +func CreateComment(c *gin.Context) { + var CommentParams db_repo.CreateCommentParams + if err := c.BindJSON(&CommentParams); err != nil { + rest_api_stuff.BadRequestAnswer(c, err) + return + } + + userId, err := getters.GetUserIdFromContext(c) + if err != nil { + rest_api_stuff.BadRequestAnswer(c, err) + return + } + + if commentId, err := uuid.NewV7(); err != nil { + rest_api_stuff.InternalErrorAnswer(c, err) + return + } else { + CommentParams.CommentID = -int64(binary.BigEndian.Uint64(commentId[8:])) + } + + CommentParams.UserID = userId + + postId, err := getters.GetInt64Param(c, "post-id") + if err != nil { + rest_api_stuff.BadRequestAnswer(c, err) + return + } + CommentParams.PostID = postId + + transaction, err := db_connection.Dbx.Begin(context.Background()) + if err != nil { + rest_api_stuff.InternalErrorAnswer(c, err) + return + } + defer transaction.Rollback(context.Background()) + + _, err = db_repo.New(transaction).CreateComment( + context.Background(), + CommentParams, + ) + + if err != nil { + rest_api_stuff.InternalErrorAnswer(c, err) + return + } + + transaction.Commit(context.Background()) + rest_api_stuff.OkAnswer(c, "comment has been created") +} diff --git a/enshi_back/routes/commentRoutes/getCommentsForPost.go b/enshi_back/routes/commentRoutes/getCommentsForPost.go new file mode 100644 index 0000000..65356f9 --- /dev/null +++ b/enshi_back/routes/commentRoutes/getCommentsForPost.go @@ -0,0 +1,42 @@ +package routes + +import ( + "context" + rest_api_stuff "enshi/REST_API_stuff" + db_repo "enshi/db/go_queries" + "enshi/db_connection" + "enshi/middleware/getters" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" +) + +func GetCommentsForPost(c *gin.Context) { + var params db_repo.GetCommentsForPostAscParams + + postId, err := getters.GetInt64Param(c, "post-id") + if err != nil { + rest_api_stuff.BadRequestAnswer(c, err) + return + } + + offset, err := strconv.Atoi(c.DefaultQuery("offset", "10")) + if err != nil { + params.Offset = int32(0) + } + + params.Offset = int32(offset) + params.PostID = postId + + comments, err := db_repo.New(db_connection.Dbx).GetCommentsForPostAsc( + context.Background(), + params, + ) + if err != nil { + rest_api_stuff.InternalErrorAnswer(c, err) + return + } + + c.JSON(http.StatusOK, comments) +} diff --git a/enshi_back/routes/middlewareSetup.go b/enshi_back/routes/middlewareSetup.go index 64d0f2e..4f589e7 100644 --- a/enshi_back/routes/middlewareSetup.go +++ b/enshi_back/routes/middlewareSetup.go @@ -15,6 +15,7 @@ const ( POST_VOTE_MIDDLEWARE = "POST_VOTE_MIDDLEWARE" POST_VOTES_MIDDLEWARE = "POST_VOTES_MIDDLEWARE" USER_MIDDLEWARE = "USER_MIDDLEWARE" + COMMENT_MIDDLEWARE = "COMMENT_MIDDLEWARE" ) var MiddlewareProvider = middleware.MiddlewareProvider{ @@ -172,6 +173,26 @@ var policiesToRegister = map[string]middleware.RulesToCheck{ MustBeCompleted: rules.ALL_RULES_MUST_BE_COMPLETED, }, }, + + COMMENT_MIDDLEWARE: { + middleware.GET: { + Rules: make([]rules.RuleFunction, 0), + MustBeCompleted: rules.ALL_RULES_MUST_BE_COMPLETED, + }, + middleware.POST: { + Rules: []rules.RuleFunction{ + globalrules.AuthorizedRule, + }, + MustBeCompleted: rules.ALL_RULES_MUST_BE_COMPLETED, + }, + middleware.DELETE: { + Rules: []rules.RuleFunction{ + globalrules.AuthorizedRule, + globalrules.IsOwnerOfTheCommentRule, + }, + MustBeCompleted: rules.ALL_RULES_MUST_BE_COMPLETED, + }, + }, } func InitMiddlewareProvider() { diff --git a/enshi_back/routes/routesSetup.go b/enshi_back/routes/routesSetup.go index f7d73f2..66f2ea9 100644 --- a/enshi_back/routes/routesSetup.go +++ b/enshi_back/routes/routesSetup.go @@ -7,6 +7,7 @@ import ( "enshi/routes/authRoutes" "enshi/routes/blogRoutes" bookmarksroutes "enshi/routes/bookmarksRoutes" + routes "enshi/routes/commentRoutes" "enshi/routes/postsRoutes" "enshi/routes/userProfileRoutes" userroutes "enshi/routes/userRoutes" @@ -280,6 +281,19 @@ func SetupRotes(g *gin.Engine) error { authRoutes.Logout, ) + commentGroup := g.Group("/comments/") + commentGroup.Use(MiddlewareProvider.GetMiddleware(COMMENT_MIDDLEWARE)) + + commentGroup.GET( + ":post-id", + routes.GetCommentsForPost, + ) + + commentGroup.POST( + ":post-id", + routes.CreateComment, + ) + temporal := g.Group("/") temporal.Use(middleware.AuthMiddleware())