From bc6b0d41ed20975ebd011fe864a688cbdb1f701a Mon Sep 17 00:00:00 2001 From: codermuss Date: Sun, 28 Jul 2024 18:44:26 +0300 Subject: [PATCH] add create post --- Makefile | 5 +- api/post.go | 96 ++++++++++++++++++++++++++++++ api/server.go | 1 + db/migration/000001_initial.up.sql | 7 +-- db/query/posts.sql | 11 ++-- db/query/user_posts.sql | 4 +- db/sqlc/models.go | 17 +++--- db/sqlc/posts.sql.go | 47 ++++++--------- db/sqlc/posts_test.go | 22 ++----- db/sqlc/user_posts.sql.go | 37 ++++++------ locales/assets/en.json | 3 + locales/localekeys.g.go | 1 + util/random.go | 4 ++ 13 files changed, 168 insertions(+), 87 deletions(-) diff --git a/Makefile b/Makefile index 9890b3e..e656361 100644 --- a/Makefile +++ b/Makefile @@ -30,4 +30,7 @@ server: mock: mockgen -package mockdb -destination db/mock/store.go github.com/mustafayilmazdev/musarchive/db/sqlc Store -.PHONY: postgres migrateup1 migrateup migratedown migratedown1 new_migration test sqlc server +locale: + musale --json=locales/assets/en.json --output=locales/localekeys.go -p=localization + +.PHONY: postgres migrateup1 migrateup migratedown migratedown1 new_migration test sqlc server mock locale diff --git a/api/post.go b/api/post.go index ce2c3b1..fd94199 100644 --- a/api/post.go +++ b/api/post.go @@ -6,12 +6,108 @@ import ( "strconv" "github.com/gin-gonic/gin" + "github.com/jackc/pgx/v5/pgtype" db "github.com/mustafayilmazdev/musarchive/db/sqlc" localization "github.com/mustafayilmazdev/musarchive/locales" "github.com/mustafayilmazdev/musarchive/token" "github.com/mustafayilmazdev/musarchive/util" ) +type createPostRequest struct { + Title string `json:"title" binding:"required"` + Content string `json:"content" binding:"required"` + CoverImage pgtype.Text `json:"cover_image"` + Categories *[]int `json:"categories"` + Tags *[]int `json:"tags"` +} + +func (server *Server) CreatePost(ctx *gin.Context) { + locale := ctx.Query(util.Locale) + var req createPostRequest + if err := ctx.ShouldBindJSON(&req); err != nil { + BuildResponse(ctx, BaseResponse{ + Code: http.StatusBadRequest, + Message: ResponseMessage{ + Type: ERROR, + Content: err.Error(), + }, + }) + return + } + authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) + arg := db.InsertPostParams{ + UserID: pgtype.Int4{ + Valid: true, + Int32: int32(authPayload.UserID), + }, + Title: req.Title, + Content: req.Content, + CoverImage: req.CoverImage, + } + + post, err := server.store.InsertPost(ctx, arg) + if err != nil { + BuildResponse(ctx, BaseResponse{ + Code: http.StatusInternalServerError, + Message: ResponseMessage{ + Type: ERROR, + Content: err.Error(), + }, + }) + return + } + + if req.Categories != nil { + for _, categoryID := range *req.Categories { + postCategoryArg := db.InsertPostCategoryParams{ + PostID: post.ID, + CategoryID: int32(categoryID), + } + _, err = server.store.InsertPostCategory(ctx, postCategoryArg) + if err != nil { + BuildResponse(ctx, BaseResponse{ + Code: http.StatusInternalServerError, + Message: ResponseMessage{ + Type: ERROR, + Content: err.Error(), + }, + }) + return + } + } + } + + if req.Tags != nil { + for _, v := range *req.Tags { + postTag := db.InsertPostTagParams{ + PostID: post.ID, + TagID: int32(v), + } + _, err = server.store.InsertPostTag(ctx, postTag) + + if err != nil { + BuildResponse(ctx, BaseResponse{ + Code: http.StatusInternalServerError, + Message: ResponseMessage{ + Type: ERROR, + Content: err.Error(), + }, + }) + return + } + } + } + + BuildResponse(ctx, BaseResponse{ + Code: http.StatusOK, + Data: post, + Message: ResponseMessage{ + Type: SUCCESS, + Content: server.lm.Translate(locale, localization.Post_InsertSuccess), + }, + }) +} + func (server *Server) GetPosts(ctx *gin.Context) { localeValue := ctx.Query(util.Locale) pageStr := ctx.Query(util.Page) diff --git a/api/server.go b/api/server.go index 9129967..3e542d4 100644 --- a/api/server.go +++ b/api/server.go @@ -51,6 +51,7 @@ func (server *Server) setupRouter() { { authRoutes.GET("/posts", server.GetPosts) authRoutes.GET("/followed_posts", server.GetFollowedPosts) + authRoutes.POST("/create_post", server.CreatePost) } // Serve the bundled static files diff --git a/db/migration/000001_initial.up.sql b/db/migration/000001_initial.up.sql index 2bd8c77..ebac2f1 100644 --- a/db/migration/000001_initial.up.sql +++ b/db/migration/000001_initial.up.sql @@ -27,12 +27,11 @@ CREATE TABLE "posts" ( "id" INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "user_id" int, "title" varchar(255) NOT NULL, - "summary" text NOT NULL, "content" text NOT NULL, "cover_image" varchar(255), - "created_at" timestamptz DEFAULT (now()), - "updated_at" timestamptz DEFAULT (now()), - "likes" int DEFAULT 0 + "created_at" timestamptz NOT NULL DEFAULT (now()), + "updated_at" timestamptz NOT NULL DEFAULT (now()), + "likes" int NOT NULL DEFAULT 0 ); CREATE TABLE "tags" ( diff --git a/db/query/posts.sql b/db/query/posts.sql index 9d250bb..a52814e 100644 --- a/db/query/posts.sql +++ b/db/query/posts.sql @@ -1,15 +1,15 @@ -- name: InsertPost :one -INSERT INTO posts (user_id, title, summary, content, cover_image, created_at, updated_at, likes) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8) +INSERT INTO posts (user_id, title, content, cover_image, created_at, updated_at, likes) +VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *; -- name: GetPost :one -SELECT id, user_id, title, summary, content, cover_image, created_at, updated_at, likes +SELECT id, user_id, title, content, cover_image, created_at, updated_at, likes FROM posts WHERE id = $1; -- name: GetPosts :many -SELECT id, user_id, title, summary, content, cover_image, created_at, updated_at, likes +SELECT id, user_id, title, content, cover_image, created_at, updated_at, likes FROM posts ORDER BY id LIMIT $1 OFFSET $2; @@ -17,7 +17,6 @@ ORDER BY id LIMIT $1 OFFSET $2; UPDATE posts SET title = COALESCE(sqlc.narg(title),title), - summary = COALESCE(sqlc.narg(summary),summary), content = COALESCE(sqlc.narg(content),content), cover_image = COALESCE(sqlc.narg(cover_image),cover_image), likes = COALESCE(sqlc.narg(likes),likes) @@ -25,7 +24,7 @@ UPDATE posts RETURNING *; -- name: GetFollowedPosts :many -SELECT p.id, p.user_id, p.title, p.summary, p.content, p.cover_image, p.created_at, p.updated_at, p.likes +SELECT p.id, p.user_id, p.title, p.content, p.cover_image, p.created_at, p.updated_at, p.likes FROM posts p JOIN user_followers f ON p.user_id = f.user_id WHERE f.follower_id = $1 diff --git a/db/query/user_posts.sql b/db/query/user_posts.sql index 5ddb8d4..26296fa 100644 --- a/db/query/user_posts.sql +++ b/db/query/user_posts.sql @@ -8,13 +8,13 @@ DELETE FROM user_posts WHERE user_id = $1 AND post_id = $2; -- name: GetUserPosts :many -SELECT b.id, b.title, b.summary, b.content, b.cover_image, b.created_at, b.updated_at, b.likes +SELECT b.id, b.title, b.content, b.cover_image, b.created_at, b.updated_at, b.likes FROM posts b JOIN user_posts up ON up.post_id = b.id WHERE up.user_id = $1; -- name: GetUserPost :one -SELECT b.id, b.title, b.summary, b.content, b.cover_image, b.created_at, b.updated_at, b.likes +SELECT b.id, b.title, b.content, b.cover_image, b.created_at, b.updated_at, b.likes FROM posts b JOIN user_posts up ON up.post_id = b.id WHERE up.user_id = $1 AND b.id = $2; \ No newline at end of file diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 5952f63..fb0dd33 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -38,15 +38,14 @@ type Onboarding struct { } type Post struct { - ID int32 `json:"id"` - UserID pgtype.Int4 `json:"user_id"` - Title string `json:"title"` - Summary string `json:"summary"` - Content string `json:"content"` - CoverImage pgtype.Text `json:"cover_image"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Likes pgtype.Int4 `json:"likes"` + ID int32 `json:"id"` + UserID pgtype.Int4 `json:"user_id"` + Title string `json:"title"` + Content string `json:"content"` + CoverImage pgtype.Text `json:"cover_image"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Likes int32 `json:"likes"` } type PostCategory struct { diff --git a/db/sqlc/posts.sql.go b/db/sqlc/posts.sql.go index a62ac47..7fb79d7 100644 --- a/db/sqlc/posts.sql.go +++ b/db/sqlc/posts.sql.go @@ -7,6 +7,7 @@ package db import ( "context" + "time" "github.com/jackc/pgx/v5/pgtype" ) @@ -22,7 +23,7 @@ func (q *Queries) DeletePost(ctx context.Context, id int32) error { } const getFollowedPosts = `-- name: GetFollowedPosts :many -SELECT p.id, p.user_id, p.title, p.summary, p.content, p.cover_image, p.created_at, p.updated_at, p.likes +SELECT p.id, p.user_id, p.title, p.content, p.cover_image, p.created_at, p.updated_at, p.likes FROM posts p JOIN user_followers f ON p.user_id = f.user_id WHERE f.follower_id = $1 @@ -48,7 +49,6 @@ func (q *Queries) GetFollowedPosts(ctx context.Context, arg GetFollowedPostsPara &i.ID, &i.UserID, &i.Title, - &i.Summary, &i.Content, &i.CoverImage, &i.CreatedAt, @@ -66,7 +66,7 @@ func (q *Queries) GetFollowedPosts(ctx context.Context, arg GetFollowedPostsPara } const getPost = `-- name: GetPost :one -SELECT id, user_id, title, summary, content, cover_image, created_at, updated_at, likes +SELECT id, user_id, title, content, cover_image, created_at, updated_at, likes FROM posts WHERE id = $1 ` @@ -78,7 +78,6 @@ func (q *Queries) GetPost(ctx context.Context, id int32) (Post, error) { &i.ID, &i.UserID, &i.Title, - &i.Summary, &i.Content, &i.CoverImage, &i.CreatedAt, @@ -89,7 +88,7 @@ func (q *Queries) GetPost(ctx context.Context, id int32) (Post, error) { } const getPosts = `-- name: GetPosts :many -SELECT id, user_id, title, summary, content, cover_image, created_at, updated_at, likes +SELECT id, user_id, title, content, cover_image, created_at, updated_at, likes FROM posts ORDER BY id LIMIT $1 OFFSET $2 ` @@ -112,7 +111,6 @@ func (q *Queries) GetPosts(ctx context.Context, arg GetPostsParams) ([]Post, err &i.ID, &i.UserID, &i.Title, - &i.Summary, &i.Content, &i.CoverImage, &i.CreatedAt, @@ -130,27 +128,25 @@ func (q *Queries) GetPosts(ctx context.Context, arg GetPostsParams) ([]Post, err } const insertPost = `-- name: InsertPost :one -INSERT INTO posts (user_id, title, summary, content, cover_image, created_at, updated_at, likes) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8) -RETURNING id, user_id, title, summary, content, cover_image, created_at, updated_at, likes +INSERT INTO posts (user_id, title, content, cover_image, created_at, updated_at, likes) +VALUES ($1, $2, $3, $4, $5, $6, $7) +RETURNING id, user_id, title, content, cover_image, created_at, updated_at, likes ` type InsertPostParams struct { - UserID pgtype.Int4 `json:"user_id"` - Title string `json:"title"` - Summary string `json:"summary"` - Content string `json:"content"` - CoverImage pgtype.Text `json:"cover_image"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Likes pgtype.Int4 `json:"likes"` + UserID pgtype.Int4 `json:"user_id"` + Title string `json:"title"` + Content string `json:"content"` + CoverImage pgtype.Text `json:"cover_image"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Likes int32 `json:"likes"` } func (q *Queries) InsertPost(ctx context.Context, arg InsertPostParams) (Post, error) { row := q.db.QueryRow(ctx, insertPost, arg.UserID, arg.Title, - arg.Summary, arg.Content, arg.CoverImage, arg.CreatedAt, @@ -162,7 +158,6 @@ func (q *Queries) InsertPost(ctx context.Context, arg InsertPostParams) (Post, e &i.ID, &i.UserID, &i.Title, - &i.Summary, &i.Content, &i.CoverImage, &i.CreatedAt, @@ -176,17 +171,15 @@ const updatePost = `-- name: UpdatePost :one UPDATE posts SET title = COALESCE($1,title), - summary = COALESCE($2,summary), - content = COALESCE($3,content), - cover_image = COALESCE($4,cover_image), - likes = COALESCE($5,likes) - WHERE id = $6 -RETURNING id, user_id, title, summary, content, cover_image, created_at, updated_at, likes + content = COALESCE($2,content), + cover_image = COALESCE($3,cover_image), + likes = COALESCE($4,likes) + WHERE id = $5 +RETURNING id, user_id, title, content, cover_image, created_at, updated_at, likes ` type UpdatePostParams struct { Title pgtype.Text `json:"title"` - Summary pgtype.Text `json:"summary"` Content pgtype.Text `json:"content"` CoverImage pgtype.Text `json:"cover_image"` Likes pgtype.Int4 `json:"likes"` @@ -196,7 +189,6 @@ type UpdatePostParams struct { func (q *Queries) UpdatePost(ctx context.Context, arg UpdatePostParams) (Post, error) { row := q.db.QueryRow(ctx, updatePost, arg.Title, - arg.Summary, arg.Content, arg.CoverImage, arg.Likes, @@ -207,7 +199,6 @@ func (q *Queries) UpdatePost(ctx context.Context, arg UpdatePostParams) (Post, e &i.ID, &i.UserID, &i.Title, - &i.Summary, &i.Content, &i.CoverImage, &i.CreatedAt, diff --git a/db/sqlc/posts_test.go b/db/sqlc/posts_test.go index cadc9db..beab392 100644 --- a/db/sqlc/posts_test.go +++ b/db/sqlc/posts_test.go @@ -18,12 +18,14 @@ func createRandomPost(t *testing.T) Post { Int32: user.ID, }, Title: util.RandomTitle(), - Summary: util.RandomString(15), Content: util.RandomDescription(), CoverImage: pgtype.Text{ Valid: true, String: util.RandomImage(), }, + CreatedAt: util.DateFixedLocal(), + UpdatedAt: util.DateFixedLocal(), + Likes: util.RandomLike(), } post, err := testStore.InsertPost(context.Background(), arg) require.NoError(t, err) @@ -31,11 +33,11 @@ func createRandomPost(t *testing.T) Post { require.Equal(t, arg.UserID, post.UserID) require.Equal(t, arg.Title, post.Title) - require.Equal(t, arg.Summary, post.Summary) require.Equal(t, arg.Content, post.Content) require.Equal(t, arg.Likes, post.Likes) require.Equal(t, arg.CreatedAt, post.CreatedAt) require.Equal(t, arg.UpdatedAt, post.UpdatedAt) + require.Equal(t, arg.Likes, post.Likes) return post } @@ -52,7 +54,6 @@ func TestGetBlog(t *testing.T) { require.Equal(t, randomBlog.UserID, post.UserID) require.Equal(t, randomBlog.Title, post.Title) - require.Equal(t, randomBlog.Summary, post.Summary) require.Equal(t, randomBlog.Content, post.Content) require.Equal(t, randomBlog.Likes, post.Likes) require.Equal(t, randomBlog.CreatedAt, post.CreatedAt) @@ -74,7 +75,6 @@ func TestUpdatePostTitle(t *testing.T) { require.NotEmpty(t, post) require.Equal(t, randomBlog.UserID, post.UserID) require.NotEqual(t, randomBlog.Title, post.Title) - require.Equal(t, randomBlog.Summary, post.Summary) require.Equal(t, randomBlog.Content, post.Content) require.Equal(t, randomBlog.Likes, post.Likes) require.Equal(t, randomBlog.CreatedAt, post.CreatedAt) @@ -85,17 +85,12 @@ func TestUpdatePostSummary(t *testing.T) { randomBlog := createRandomPost(t) updatePost := UpdatePostParams{ ID: randomBlog.ID, - Summary: pgtype.Text{ - Valid: true, - String: util.RandomString(10), - }, } post, err := testStore.UpdatePost(context.Background(), updatePost) require.NoError(t, err) require.NotEmpty(t, post) require.Equal(t, randomBlog.UserID, post.UserID) require.Equal(t, randomBlog.Title, post.Title) - require.NotEqual(t, randomBlog.Summary, post.Summary) require.Equal(t, randomBlog.Content, post.Content) require.Equal(t, randomBlog.Likes, post.Likes) require.Equal(t, randomBlog.CreatedAt, post.CreatedAt) @@ -120,7 +115,6 @@ func TestUpdatePostContent(t *testing.T) { require.Equal(t, randomBlog.UserID, post.UserID) require.Equal(t, randomBlog.Title, post.Title) - require.Equal(t, randomBlog.Summary, post.Summary) require.Equal(t, randomBlog.Likes, post.Likes) require.Equal(t, randomBlog.CreatedAt, post.CreatedAt) require.Equal(t, randomBlog.UpdatedAt, post.UpdatedAt) @@ -158,10 +152,6 @@ func TestUpdatePostAll(t *testing.T) { Valid: true, String: util.RandomTitle(), }, - Summary: pgtype.Text{ - Valid: true, - String: util.RandomString(10), - }, Content: pgtype.Text{ Valid: true, String: util.RandomDescription(), @@ -182,13 +172,11 @@ func TestUpdatePostAll(t *testing.T) { require.NotEqual(t, randomBlog.CoverImage, post.CoverImage) require.NotEqual(t, randomBlog.Likes, post.Likes) require.NotEqual(t, randomBlog.Title, post.Title) - require.NotEqual(t, randomBlog.Summary, post.Summary) require.NotEqual(t, randomBlog.Content, post.Content) require.Equal(t, updatePost.Title.String, post.Title) - require.Equal(t, updatePost.Summary.String, post.Summary) require.Equal(t, updatePost.Content.String, post.Content) - require.Equal(t, updatePost.Likes, post.Likes) + require.Equal(t, updatePost.Likes.Int32, post.Likes) require.Equal(t, updatePost.CoverImage, post.CoverImage) require.Equal(t, randomBlog.UserID, post.UserID) diff --git a/db/sqlc/user_posts.sql.go b/db/sqlc/user_posts.sql.go index eafc932..4e387b6 100644 --- a/db/sqlc/user_posts.sql.go +++ b/db/sqlc/user_posts.sql.go @@ -7,6 +7,7 @@ package db import ( "context" + "time" "github.com/jackc/pgx/v5/pgtype" ) @@ -27,7 +28,7 @@ func (q *Queries) DeleteUserPost(ctx context.Context, arg DeleteUserPostParams) } const getUserPost = `-- name: GetUserPost :one -SELECT b.id, b.title, b.summary, b.content, b.cover_image, b.created_at, b.updated_at, b.likes +SELECT b.id, b.title, b.content, b.cover_image, b.created_at, b.updated_at, b.likes FROM posts b JOIN user_posts up ON up.post_id = b.id WHERE up.user_id = $1 AND b.id = $2 @@ -39,14 +40,13 @@ type GetUserPostParams struct { } type GetUserPostRow struct { - ID int32 `json:"id"` - Title string `json:"title"` - Summary string `json:"summary"` - Content string `json:"content"` - CoverImage pgtype.Text `json:"cover_image"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Likes pgtype.Int4 `json:"likes"` + ID int32 `json:"id"` + Title string `json:"title"` + Content string `json:"content"` + CoverImage pgtype.Text `json:"cover_image"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Likes int32 `json:"likes"` } func (q *Queries) GetUserPost(ctx context.Context, arg GetUserPostParams) (GetUserPostRow, error) { @@ -55,7 +55,6 @@ func (q *Queries) GetUserPost(ctx context.Context, arg GetUserPostParams) (GetUs err := row.Scan( &i.ID, &i.Title, - &i.Summary, &i.Content, &i.CoverImage, &i.CreatedAt, @@ -66,21 +65,20 @@ func (q *Queries) GetUserPost(ctx context.Context, arg GetUserPostParams) (GetUs } const getUserPosts = `-- name: GetUserPosts :many -SELECT b.id, b.title, b.summary, b.content, b.cover_image, b.created_at, b.updated_at, b.likes +SELECT b.id, b.title, b.content, b.cover_image, b.created_at, b.updated_at, b.likes FROM posts b JOIN user_posts up ON up.post_id = b.id WHERE up.user_id = $1 ` type GetUserPostsRow struct { - ID int32 `json:"id"` - Title string `json:"title"` - Summary string `json:"summary"` - Content string `json:"content"` - CoverImage pgtype.Text `json:"cover_image"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Likes pgtype.Int4 `json:"likes"` + ID int32 `json:"id"` + Title string `json:"title"` + Content string `json:"content"` + CoverImage pgtype.Text `json:"cover_image"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Likes int32 `json:"likes"` } func (q *Queries) GetUserPosts(ctx context.Context, userID int32) ([]GetUserPostsRow, error) { @@ -95,7 +93,6 @@ func (q *Queries) GetUserPosts(ctx context.Context, userID int32) ([]GetUserPost if err := rows.Scan( &i.ID, &i.Title, - &i.Summary, &i.Content, &i.CoverImage, &i.CreatedAt, diff --git a/locales/assets/en.json b/locales/assets/en.json index 2a40e88..a98b255 100644 --- a/locales/assets/en.json +++ b/locales/assets/en.json @@ -29,5 +29,8 @@ "UnsupportedAuthorization":"Unsupported authorization type {{.arg0}}", "InvalidAuthorization":"Invalid authorization header format", "HeaderIsNotProvided":"Authorization header is not provided" + }, + "Post":{ + "InsertSuccess":"Post created successfully!" } } \ No newline at end of file diff --git a/locales/localekeys.g.go b/locales/localekeys.g.go index b88e163..775603c 100644 --- a/locales/localekeys.g.go +++ b/locales/localekeys.g.go @@ -18,6 +18,7 @@ const ( Middleware_UnsupportedAuthorization = "Middleware.UnsupportedAuthorization" Pagination_pageError = "Pagination.pageError" Pagination_sizeError = "Pagination.sizeError" + Post_InsertSuccess = "Post.InsertSuccess" Success_Migrate = "Success.Migrate" User_RegisterSuccess = "User.RegisterSuccess" ) diff --git a/util/random.go b/util/random.go index 840b7dc..634e73d 100644 --- a/util/random.go +++ b/util/random.go @@ -84,6 +84,10 @@ func DateFixed() time.Time { return time.Date(2000, time.May, 6, 0, 0, 0, 0, time.UTC) } +func DateFixedLocal() time.Time { + return time.Date(2000, time.May, 6, 0, 0, 0, 0, time.Local) +} + func RandomOwner() string { return RandomString(6) }