diff options
Diffstat (limited to 'repository')
-rw-r--r-- | repository/node.go | 58 | ||||
-rw-r--r-- | repository/post.go | 70 | ||||
-rw-r--r-- | repository/topic.go | 101 | ||||
-rw-r--r-- | repository/user.go | 98 |
4 files changed, 249 insertions, 78 deletions
diff --git a/repository/node.go b/repository/node.go deleted file mode 100644 index 27282af..0000000 --- a/repository/node.go +++ /dev/null @@ -1,58 +0,0 @@ -package repository - -import ( - "context" - - "github.com/uptrace/bun" - "gitrepo.ru/neonxp/gorum/models" -) - -type Node struct { - db *bun.DB -} - -func NewNode(db *bun.DB) *Node { - return &Node{ - db: db, - } -} - -func (t *Node) Create( - ctx context.Context, - ntype models.NodeType, - text string, - authorID int, - parentID int, -) (int, error) { - post := &models.Node{ - Type: ntype, - Text: text, - AuthorID: authorID, - ParentID: parentID, - } - _, err := t.db.NewInsert().Model(post).Returning("id").Exec(ctx) - - return post.ID, err -} - -func (t *Node) Get(ctx context.Context, topicID int) (*models.Node, error) { - node := new(models.Node) - - return node, t.db.NewSelect(). - Model(node). - Where(`n.id = ?`, topicID). - Relation("Author"). - Relation("Parent"). - Scan(ctx) -} - -func (t *Node) List(ctx context.Context, topicID int) ([]*models.Node, error) { - posts := make([]*models.Node, 0) - - return posts, t.db.NewSelect(). - Model(&posts). - Where(`parent_id = ?`, topicID). - Relation("Author"). - Relation("Children"). - Scan(ctx) -} diff --git a/repository/post.go b/repository/post.go new file mode 100644 index 0000000..1b0fef6 --- /dev/null +++ b/repository/post.go @@ -0,0 +1,70 @@ +package repository + +import ( + "encoding/json" + "fmt" + "strconv" + "time" + + "gitrepo.ru/neonxp/gorum/models" + "go.etcd.io/bbolt" +) + +type Post struct { + db *bbolt.DB +} + +func NewPost(db *bbolt.DB) *Post { + return &Post{ + db: db, + } +} + +func (t *Post) CreatePost( + text string, + authorID string, + topicID uint64, +) (uint64, error) { + post := &models.Post{ + Text: text, + AuthorID: authorID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + return post.ID, t.db.Update(func(tx *bbolt.Tx) error { + bucket, err := tx.CreateBucketIfNotExists([]byte(fmt.Sprintf("posts_%d", topicID))) + if err != nil { + return err + } + id, err := bucket.NextSequence() + if err != nil { + return err + } + post.ID = id + pb, err := json.Marshal(post) + if err != nil { + return err + } + + return bucket.Put([]byte(strconv.Itoa(int(id))), pb) + }) +} + +func (t *Post) List(topicID uint64) ([]*models.Post, error) { + posts := make([]*models.Post, 0) + + return posts, t.db.View(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte(fmt.Sprintf("posts_%d", topicID))).ForEach(func(k, v []byte) error { + post := new(models.Post) + + if err := json.Unmarshal(v, post); err != nil { + return err + } + + posts = append(posts, post) + + return nil + }) + }) +} diff --git a/repository/topic.go b/repository/topic.go new file mode 100644 index 0000000..4c34643 --- /dev/null +++ b/repository/topic.go @@ -0,0 +1,101 @@ +package repository + +import ( + "encoding/json" + "fmt" + "strconv" + "time" + + "gitrepo.ru/neonxp/gorum/models" + "go.etcd.io/bbolt" +) + +type Topic struct { + db *bbolt.DB +} + +func NewTopic(db *bbolt.DB) *Topic { + return &Topic{ + db: db, + } +} + +func (t *Topic) Init() error { + return t.db.Update(func(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte("topics")) + return err + }) +} + +func (t *Topic) Create(title, text, authorID string, parentID uint64) (*models.Topic, error) { + topic := &models.Topic{ + Topic: title, + Text: text, + AuthorID: authorID, + ParentID: parentID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + return topic, t.db.Update(func(tx *bbolt.Tx) error { + bucket, err := tx.CreateBucketIfNotExists([]byte("topics")) + if err != nil { + return err + } + id, err := bucket.NextSequence() + if err != nil { + return err + } + topic.ID = id + tb, err := json.Marshal(topic) + if err != nil { + return err + } + + if _, err := tx.CreateBucketIfNotExists([]byte(fmt.Sprintf("posts_%d", topic.ID))); err != nil { + return err + } + + return bucket.Put([]byte(strconv.Itoa(int(topic.ID))), tb) + }) +} + +func (t *Topic) List(parentID uint64) ([]*models.Topic, error) { + topics := make([]*models.Topic, 0) + + return topics, t.db.View(func(tx *bbolt.Tx) error { + bucket := tx.Bucket([]byte("topics")) + if bucket == nil { + return models.ErrDBNotInitialized + } + + return bucket.ForEach(func(k, v []byte) error { + t := new(models.Topic) + if err := json.Unmarshal(v, t); err != nil { + return err + } + if t.ParentID == parentID { + topics = append(topics, t) + } + + return nil + }) + }) +} + +func (t *Topic) Get(topicID uint64) (*models.Topic, error) { + topic := new(models.Topic) + + return topic, t.db.View(func(tx *bbolt.Tx) error { + bucket := tx.Bucket([]byte("topics")) + if bucket == nil { + return models.ErrDBNotInitialized + } + tb := bucket.Get([]byte(strconv.Itoa(int(topicID)))) + if tb == nil { + return models.ErrTopicNotFound + } + + return json.Unmarshal(tb, topic) + }) +} diff --git a/repository/user.go b/repository/user.go index 5c3cce6..b01eaee 100644 --- a/repository/user.go +++ b/repository/user.go @@ -1,31 +1,44 @@ package repository import ( - "context" + "encoding/json" "fmt" - "github.com/uptrace/bun" + normalizer "github.com/dimuska139/go-email-normalizer/v2" "gitrepo.ru/neonxp/gorum/models" + "go.etcd.io/bbolt" "golang.org/x/crypto/bcrypt" ) type User struct { - db *bun.DB + db *bbolt.DB } -func NewUser(db *bun.DB) *User { +func NewUser(db *bbolt.DB) *User { return &User{ db: db, } } -func (u *User) Create(ctx context.Context, email, password, username string, role models.UserRole) (int, error) { +func (t *User) Init() error { + return t.db.Update(func(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte("users")) + return err + }) +} +func (u *User) Create(email, password, username string, role models.UserRole) error { + + if len(password) < 8 { + return models.ErrInvalidPassword + } hpassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { - return 0, models.ErrInvalidPassword + return models.ErrInvalidPassword } + email = normalizer.NewNormalizer().Normalize(email) + user := &models.User{ Email: email, Password: string(hpassword), @@ -33,29 +46,74 @@ func (u *User) Create(ctx context.Context, email, password, username string, rol Role: role, } - if _, err := u.db.NewInsert().Model(user).Returning("id").Exec(ctx); err != nil { - return 0, models.ErrUserAlreadyExists - } + u.db.Update(func(tx *bbolt.Tx) error { + bucket, err := tx.CreateBucketIfNotExists([]byte("users")) + if err != nil { + return err + } + ub := bucket.Get([]byte(email)) + if ub != nil { + return models.ErrUserAlreadyExists + } + + ub, err = json.Marshal(user) + if err != nil { + return err + } + + return bucket.Put([]byte(email), ub) + }) - return user.ID, nil + return nil } -func (u *User) Login(ctx context.Context, email, password string) (*models.User, error) { +func (u *User) Login(email, password string) (*models.User, error) { user := new(models.User) + email = normalizer.NewNormalizer().Normalize(email) - if err := u.db.NewSelect().Model(user).Where("email = ?", email).Scan(ctx); err != nil { - return nil, fmt.Errorf("user not found: %w", models.ErrInvalidUserOrPassword) - } + return user, u.db.View(func(tx *bbolt.Tx) error { + ub := tx.Bucket([]byte("users")).Get([]byte(email)) + if ub == nil { + return models.ErrInvalidUserOrPassword + } + if err := json.Unmarshal(ub, user); err != nil { + return err + } - if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { - return nil, fmt.Errorf("invalid password: %w", models.ErrInvalidUserOrPassword) - } + if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { + return fmt.Errorf("invalid password: %w", models.ErrInvalidUserOrPassword) + } + + return nil + }) +} + +func (u *User) Get(email string) (*models.User, error) { + user := new(models.User) + email = normalizer.NewNormalizer().Normalize(email) + + return user, u.db.View(func(tx *bbolt.Tx) error { + ub := tx.Bucket([]byte("users")).Get([]byte(email)) + if ub == nil { + return models.ErrInvalidUserOrPassword + } - return user, nil + return json.Unmarshal(ub, user) + }) } -func (u *User) List(ctx context.Context) ([]*models.User, error) { +func (u *User) List() ([]*models.User, error) { ret := make([]*models.User, 0) - return ret, u.db.NewSelect().Model(&ret).Scan(ctx) + return ret, u.db.View(func(tx *bbolt.Tx) error { + bucket := tx.Bucket([]byte("users")) + return bucket.ForEach(func(k, v []byte) error { + u := new(models.User) + if err := json.Unmarshal(v, u); err != nil { + return err + } + ret = append(ret, u) + return nil + }) + }) } |