From 0bd63b53c50bb45b2eb87d534449124ecedbc27b Mon Sep 17 00:00:00 2001 From: nefrace Date: Tue, 13 Dec 2022 17:07:32 +0300 Subject: [PATCH] Folders handlers --- server/handlersAuth.go | 18 ++++-- server/handlersBookmark.go | 61 ++++++++++++++++++++ server/handlersFolder.go | 115 +++++++++++++++++++++++++++++++++++++ server/server.go | 14 +++++ storage/mongostorage.go | 46 +++++++++++++++ storage/types.go | 17 +++--- 6 files changed, 260 insertions(+), 11 deletions(-) create mode 100644 server/handlersFolder.go diff --git a/server/handlersAuth.go b/server/handlersAuth.go index b88e490..b88bc55 100644 --- a/server/handlersAuth.go +++ b/server/handlersAuth.go @@ -31,11 +31,21 @@ func (s Server) handleRegister(c Context) error { log.Println("Can not generate hash from password: ", err) return ApiError{Status: http.StatusInternalServerError, Err: "cannot register"} } + userId := primitive.NewObjectID() + folderId := primitive.NewObjectID() + newFolder := storage.Folder{ + Id: folderId, + UserID: userId, + Name: "root", + Created: time.Now(), + } + s.Db.CreateFolder(&newFolder) newUser := storage.User{ - Id: primitive.NewObjectID(), - Username: form.Username, - Password: password, - IsAdmin: true, + Id: userId, + Username: form.Username, + Password: password, + IsAdmin: true, + RootFolderId: folderId, } if _, err = s.Db.CreateUser(&newUser); err != nil { log.Println("Can not create user: ", err) diff --git a/server/handlersBookmark.go b/server/handlersBookmark.go index f2dc97b..e660005 100644 --- a/server/handlersBookmark.go +++ b/server/handlersBookmark.go @@ -1,6 +1,7 @@ package server import ( + "context" "log" "strconv" "time" @@ -25,6 +26,11 @@ func (s Server) handleNewBookmark(c Context) error { } ctx := c.R.Context() user := ctx.Value(CtxValue("user")).(*storage.User) + log.Println(form) + if form.FolderID.IsZero() { + log.Println(user) + form.FolderID = user.RootFolderId + } bookmark := storage.Bookmark{ Id: primitive.NewObjectID(), Name: form.Name, @@ -41,6 +47,46 @@ func (s Server) handleNewBookmark(c Context) error { return c.WriteJSON(201, &bookmark) } +func (s Server) handleDeleteBookmark(c Context) error { + user := c.R.Context().Value(CtxValue("user")).(*storage.User) + idStr := c.GetVar("id") + id, err := primitive.ObjectIDFromHex(idStr) + if err != nil { + return ApiError{Err: "wrong id", Status: 400} + } + store := storage.NewStore[storage.Bookmark](&s.Db, "bookmarks") + bookmark, err := store.GetOne(context.TODO(), &bson.D{ + {Key: "_id", Value: id}, + {Key: "userid", Value: user.Id}, + }) + if err != nil { + return ApiError{Err: "not found", Status: 404} + } + err = store.DeleteByID(context.TODO(), bookmark.Id) + if err != nil { + return ApiError{Err: err.Error(), Status: 500} + } + return c.WriteJSON(200, "removed") +} + +func (s Server) handleUpdateBookmark(c Context) error { + user := c.R.Context().Value(CtxValue("user")).(*storage.User) + var form storage.Bookmark + err := DecodeJSON(c.R.Body, &form) + if err != nil { + return ApiError{Err: "wrong body", Status: 400} + } + if form.UserID != user.Id { + return ApiError{Err: "wrong body", Status: 403} + } + store := storage.NewStore[storage.Bookmark](&s.Db, "bookmarks") + err = store.ReplaceByID(context.TODO(), form.Id, &form) + if err != nil { + return ApiError{Err: "couldn't update bookmark: " + err.Error(), Status: 500} + } + return c.WriteJSON(200, "updated") +} + func (s Server) handleGetBookmarks(c Context) error { ctx := c.R.Context() user := ctx.Value(CtxValue("user")).(*storage.User) // Getting currently logged in user @@ -56,6 +102,21 @@ func (s Server) handleGetBookmarks(c Context) error { return c.WriteJSON(200, bookmarks) } +func (s Server) handleGetLastBookmarks(c Context) error { + ctx := c.R.Context() + user := ctx.Value(CtxValue("user")).(*storage.User) + countVar := c.GetVar("count") + count, err := strconv.Atoi(countVar) + if err != nil { + count = 1 + } + bookmarks, err := s.Db.GetLastBookmarks(count, &bson.D{{Key: "userid", Value: user.Id}}) + if err != nil { + return ApiError{Err: "can't get bookmarks: " + err.Error(), Status: 400} + } + return c.WriteJSON(200, bookmarks) +} + func (s Server) handleGetRandomBookmarks(c Context) error { ctx := c.R.Context() user := ctx.Value(CtxValue("user")).(*storage.User) diff --git a/server/handlersFolder.go b/server/handlersFolder.go new file mode 100644 index 0000000..4c82a68 --- /dev/null +++ b/server/handlersFolder.go @@ -0,0 +1,115 @@ +package server + +import ( + "context" + "time" + + "git.nefrace.ru/nefrace/nashboard/storage" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type newFolderForm struct { + Name string + ParentID primitive.ObjectID +} + +func (s Server) handleNewFolder(c Context) error { + var form newFolderForm + err := DecodeJSON(c.R.Body, &form) + if err != nil { + return ApiError{Err: "can't decode json to folder: " + err.Error(), Status: 400} + } + ctx := c.R.Context() + user := ctx.Value(CtxValue("user")).(*storage.User) + if form.ParentID.IsZero() { + rootFolder, _ := s.Db.GetFolder(&bson.D{{Key: "name", Value: "root"}}) + form.ParentID = rootFolder.Id + } + folder := storage.Folder{ + Id: primitive.NewObjectID(), + Name: form.Name, + UserID: user.Id, + ParentID: form.ParentID, + // Tags: form.Tags, + Created: time.Now(), + } + _, err = s.Db.CreateFolder(&folder) + if err != nil { + return ApiError{Err: "can't safe folder: " + err.Error(), Status: 500} + } + return c.WriteJSON(201, &folder) +} + +type folderResult struct { + Folder *storage.Folder + ChildFolders []*storage.Folder + ChildBookmarks []*storage.Bookmark +} + +func (s Server) handleGetFolder(c Context) error { + user := c.R.Context().Value(CtxValue("user")).(*storage.User) // Getting currently logged in user + userFilter := bson.E{Key: "userid", Value: user.Id} + idStr := c.GetVar("id") + query := c.R.URL.Query() + filter := storage.QueryFilter(&query) + filter = append(filter, userFilter) + if idStr != "" { + id, err := primitive.ObjectIDFromHex(idStr) + if err != nil { + return ApiError{Err: "wrong id", Status: 400} + } + filter = bson.D{{Key: "_id", Value: id}, userFilter} + } + folder, err := s.Db.GetFolder(&filter) + if err != nil { + return ApiError{Err: "not found", Status: 404} + } + folders, _ := s.Db.GetChildrenFolders(folder.Id) + bookmarks, _ := s.Db.GetChildrenBookmarks(folder.Id) + return c.WriteJSON(200, &folderResult{ + Folder: folder, + ChildFolders: folders, + ChildBookmarks: bookmarks, + }) +} + +func (s Server) handleUpdateFolder(c Context) error { + user := c.R.Context().Value(CtxValue("user")).(*storage.User) + var form storage.Folder + err := DecodeJSON(c.R.Body, &form) + if err != nil { + return ApiError{Err: "wrong body", Status: 400} + } + if form.UserID != user.Id { + return ApiError{Err: "wrong body", Status: 403} + } + store := storage.NewStore[storage.Folder](&s.Db, "folders") + err = store.ReplaceByID(context.TODO(), form.Id, &form) + if err != nil { + return ApiError{Err: "couldn't update folder: " + err.Error(), Status: 500} + } + return c.WriteJSON(200, "updated") +} + +func (s Server) handleDeleteFolder(c Context) error { + user := c.R.Context().Value(CtxValue("user")).(*storage.User) + idStr := c.GetVar("id") + id, err := primitive.ObjectIDFromHex(idStr) + if err != nil { + return ApiError{Err: "wrong id", Status: 400} + } + store := storage.NewStore[storage.Folder](&s.Db, "folders") + folder, err := store.GetOne(context.TODO(), &bson.D{ + {Key: "_id", Value: id}, + {Key: "userid", Value: user.Id}, + }) + if err != nil { + return ApiError{Err: "not found", Status: 404} + } + err = store.DeleteByID(context.TODO(), folder.Id) + if err != nil { + return ApiError{Err: err.Error(), Status: 500} + } + return c.WriteJSON(200, "removed") +} diff --git a/server/server.go b/server/server.go index b572b90..092e4d9 100644 --- a/server/server.go +++ b/server/server.go @@ -38,12 +38,26 @@ func (s Server) InitHandlers() { // userRouter.Use(s.AuthorizedOnly) userRouter.Path("/me").HandlerFunc(MakeHTTPHandler(s.handleGetMe)) userRouter.Path("/all").HandlerFunc(MakeHTTPHandler(s.handleAllUsers)) + bookmarkRouter := apiRouter.PathPrefix("/bookmark").Subrouter() bookmarkRouter.Use(s.AuthorizedOnly) bookmarkRouter.Path("").Methods("GET").HandlerFunc(MakeHTTPHandler(s.handleGetBookmarks)) bookmarkRouter.Path("").Methods("POST").HandlerFunc(MakeHTTPHandler(s.handleNewBookmark)) + bookmarkRouter.Path("").Methods("PUT").HandlerFunc(MakeHTTPHandler(s.handleUpdateBookmark)) + bookmarkRouter.Path("{id}").Methods("DELETE").HandlerFunc(MakeHTTPHandler(s.handleDeleteBookmark)) + bookmarkRouter.Path("/last").HandlerFunc(MakeHTTPHandler(s.handleGetLastBookmarks)) + bookmarkRouter.Path("/last/{count}").HandlerFunc(MakeHTTPHandler(s.handleGetLastBookmarks)) bookmarkRouter.Path("/random").HandlerFunc(MakeHTTPHandler(s.handleGetRandomBookmarks)) bookmarkRouter.Path("/random/{count}").HandlerFunc(MakeHTTPHandler(s.handleGetRandomBookmarks)) + folderRouter := apiRouter.PathPrefix("/f").Subrouter() + folderRouter.Use(s.AuthorizedOnly) + folderRouter.Path("").Methods("GET").HandlerFunc(MakeHTTPHandler(s.handleGetFolder)) + folderRouter.Path("").Methods("POST").HandlerFunc(MakeHTTPHandler(s.handleNewFolder)) + folderRouter.Path("").Methods("PUT").HandlerFunc(MakeHTTPHandler(s.handleUpdateFolder)) + folderRouter.Path("{id}").Methods("GET").HandlerFunc(MakeHTTPHandler(s.handleGetFolder)) + folderRouter.Path("{id}").Methods("DELETE").HandlerFunc(MakeHTTPHandler(s.handleDeleteFolder)) + folderRouter.Path("/{name}").HandlerFunc(MakeHTTPHandler(s.handleGetFolder)) + r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/"))) } diff --git a/storage/mongostorage.go b/storage/mongostorage.go index f3655da..41bfa39 100644 --- a/storage/mongostorage.go +++ b/storage/mongostorage.go @@ -9,6 +9,7 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" ) type MongodbStorage struct { @@ -116,6 +117,21 @@ func (m MongodbStorage) GetRandomBookmarks(count int, filter *bson.D) ([]*Bookma return bookmarks, err } +func (m MongodbStorage) GetLastBookmarks(count int, filter *bson.D) ([]*Bookmark, error) { + passedFilter := getFilter(filter) + ctx := context.TODO() + store := NewStore[Bookmark](&m, "bookmarks") + bookmarks := []*Bookmark{} + opts := options.Find().SetSort(bson.D{{Key: "created", Value: -1}}).SetLimit(int64(count)) + cur, err := store.Coll.Find(ctx, passedFilter, opts) + if err != nil { + log.Println("Cant find last bookmakrs: ", err) + return bookmarks, err + } + cur.All(ctx, &bookmarks) + return bookmarks, err +} + func (m MongodbStorage) GetUserBookmarks(user *User, filter *bson.D) ([]*Bookmark, error) { passedFilter := getFilter(filter) f := bson.D{{Key: "userid", Value: user.Id}} @@ -125,6 +141,36 @@ func (m MongodbStorage) GetUserBookmarks(user *User, filter *bson.D) ([]*Bookmar return store.GetMany(ctx, &f) } +func (m MongodbStorage) CreateFolder(folder *Folder) (primitive.ObjectID, error) { + store := NewStore[Folder](&m, "folders") + return store.InsertOne(context.TODO(), folder) +} + +func (m MongodbStorage) GetFolderByID(id primitive.ObjectID) (*Folder, error) { + store := NewStore[Folder](&m, "folders") + return store.GetById(context.TODO(), id) +} + +func (m MongodbStorage) GetFolder(filter *bson.D) (*Folder, error) { + store := NewStore[Folder](&m, "folders") + return store.GetOne(context.TODO(), filter) +} + +func (m MongodbStorage) GetFolders(filter *bson.D) ([]*Folder, error) { + store := NewStore[Folder](&m, "folders") + return store.GetMany(context.TODO(), filter) +} + +func (m MongodbStorage) GetChildrenFolders(id primitive.ObjectID) ([]*Folder, error) { + store := NewStore[Folder](&m, "folders") + return store.GetMany(context.TODO(), &bson.D{{Key: "parentid", Value: id}}) +} + +func (m MongodbStorage) GetChildrenBookmarks(id primitive.ObjectID) ([]*Bookmark, error) { + store := NewStore[Bookmark](&m, "bookmarks") + return store.GetMany(context.TODO(), &bson.D{{Key: "folderid", Value: id}}) +} + func (m MongodbStorage) Collection(col string) *mongo.Collection { return m.Db.Database("nash").Collection(col) } diff --git a/storage/types.go b/storage/types.go index 8f8f971..d0f5a52 100644 --- a/storage/types.go +++ b/storage/types.go @@ -9,11 +9,12 @@ import ( ) type User struct { - Id primitive.ObjectID `bson:"_id" json:"id,omitempty"` - Username string - Password []byte `json:"-"` - IsAdmin bool - LastLogin time.Time + Id primitive.ObjectID `bson:"_id" json:"id,omitempty"` + Username string + Password []byte `json:"-"` + IsAdmin bool + LastLogin time.Time + RootFolderId primitive.ObjectID } type Session struct { @@ -36,7 +37,9 @@ type Folder struct { Id primitive.ObjectID `bson:"_id" json:"id,omitempty"` Name string ParentID primitive.ObjectID + UserID primitive.ObjectID Icon []byte + Created time.Time } type Bookmark struct { @@ -46,8 +49,8 @@ type Bookmark struct { UserID primitive.ObjectID FolderID primitive.ObjectID Tags []string - // Icon []byte - Created time.Time + Icon []byte + Created time.Time } type Note struct {