mirror of
https://github.com/hexolan/panels.git
synced 2026-03-26 12:40:21 +00:00
init post-service
This commit is contained in:
162
services/post-service/internal/post.go
Normal file
162
services/post-service/internal/post.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"context"
|
||||
"strconv"
|
||||
"encoding/json"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/go-ozzo/ozzo-validation/v4"
|
||||
)
|
||||
|
||||
// Post Models
|
||||
type Post struct {
|
||||
Id PostId `json:"id"`
|
||||
|
||||
PanelId string `json:"panel_id"`
|
||||
AuthorId string `json:"author_id"`
|
||||
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type PostCreate struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func (p *PostCreate) Validate() error {
|
||||
return validation.ValidateStruct(
|
||||
p,
|
||||
validation.Field(&p.Title, validation.Required, validation.Length(3, 512), validation.Match(regexp.MustCompile("^[^_][\\w ]+[^_]$"))),
|
||||
validation.Field(&p.Content, validation.Required, validation.Length(3, 2048)),
|
||||
)
|
||||
}
|
||||
|
||||
type PostUpdate struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
Content *string `json:"content,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PostUpdate) Validate() error {
|
||||
return validation.ValidateStruct(
|
||||
p,
|
||||
validation.Field(&p.Title, validation.NilOrNotEmpty, validation.Length(3, 512), validation.Match(regexp.MustCompile("^[^_][\\w ]+[^_]$"))),
|
||||
validation.Field(&p.Content, validation.NilOrNotEmpty, validation.Length(3, 2048)),
|
||||
)
|
||||
}
|
||||
|
||||
// Service Interface Methods
|
||||
type PostService interface {
|
||||
PostRepository
|
||||
}
|
||||
|
||||
type PostRepository interface {
|
||||
CreatePost(ctx context.Context, panelId string, authorId string, data PostCreate) (*Post, error)
|
||||
GetPost(ctx context.Context, id PostId) (*Post, error)
|
||||
GetPanelPost(ctx context.Context, id PostId, panelId string) (*Post, error)
|
||||
UpdatePost(ctx context.Context, id PostId, data PostUpdate) (*Post, error)
|
||||
DeletePost(ctx context.Context, id PostId) error
|
||||
|
||||
GetFeedPosts(ctx context.Context) ([]*Post, error)
|
||||
GetUserPosts(ctx context.Context, userId string) ([]*Post, error)
|
||||
GetPanelPosts(ctx context.Context, panelId string) ([]*Post, error)
|
||||
}
|
||||
|
||||
type PostDBRepository interface {
|
||||
PostRepository
|
||||
|
||||
DeletePostsByUser(ctx context.Context, userId string) ([]PostId, error)
|
||||
DeletePostsOnPanel(ctx context.Context, panelId string) ([]PostId, error)
|
||||
}
|
||||
|
||||
// Converts IDs between int64 (base 10) internally and string (base 36) externally
|
||||
type PostId struct {
|
||||
Id int64
|
||||
}
|
||||
|
||||
func (pid *PostId) GetId() int64 {
|
||||
if pid == nil {
|
||||
return 0
|
||||
}
|
||||
return pid.Id
|
||||
}
|
||||
|
||||
func (pid *PostId) GetReprId() string {
|
||||
if pid.GetId() == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strconv.FormatInt(pid.GetId(), 36)
|
||||
}
|
||||
|
||||
func (pid *PostId) Scan(value interface{}) error {
|
||||
scnr := sql.NullInt64{}
|
||||
err := scnr.Scan(value)
|
||||
if err != nil {
|
||||
return NewServiceError(InvalidArgumentErrorCode, "failed to scan post id: must be of type int64")
|
||||
} else if scnr.Int64 < 1 {
|
||||
return NewServiceError(InvalidArgumentErrorCode, "invalid post id: value must be greater than 0")
|
||||
}
|
||||
|
||||
pid.Id = scnr.Int64
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pid PostId) Value() (driver.Value, error) {
|
||||
if pid.GetId() == 0 {
|
||||
return nil, NewServiceError(InvalidArgumentErrorCode, "post id not provided (of default value)")
|
||||
}
|
||||
|
||||
return driver.Value(pid.GetId()), nil
|
||||
}
|
||||
|
||||
func (pid PostId) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(pid.GetReprId())
|
||||
}
|
||||
|
||||
func (pid *PostId) UnmarshalJSON(data []byte) error {
|
||||
// Attempt to unmarshal the representative id
|
||||
var repr_id string
|
||||
err := json.Unmarshal(data, &repr_id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reconstruct the ID using the representative ID
|
||||
id, err := getIdFromRepr(repr_id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pid.Id = *id
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewPostId(id int64) (*PostId, error) {
|
||||
if id < 1 {
|
||||
return nil, NewServiceError(InvalidArgumentErrorCode, "invalid post id: value must be greater than 0")
|
||||
}
|
||||
|
||||
return &PostId{Id: id}, nil
|
||||
}
|
||||
|
||||
func NewPostIdFromRepr(reprId string) (*PostId, error) {
|
||||
id, err := getIdFromRepr(reprId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewPostId(*id)
|
||||
}
|
||||
|
||||
func getIdFromRepr(reprId string) (*int64, error) {
|
||||
id, err := strconv.ParseInt(reprId, 36, 64)
|
||||
return &id, err
|
||||
}
|
||||
Reference in New Issue
Block a user