Browse Source

Add route and modify bookmark folder schema

https://youtrack.weseek.co.jp/issue/GW-7910
- Add bookmarks field to BookmarkFolderDocument
- Add bookmarks to schema definition
- Update insertOrUpdateBookmarkedPage statics method
- Get schema from Bookmark model
- Update bookmarks type in BookmarkFolderItems
- Create route to insert bookmark to folder
- Implement insert bookmark route to BookmarkMenuItem
Mudana-Grune 3 năm trước cách đây
mục cha
commit
2c070da073

+ 15 - 1
packages/app/src/components/Bookmarks/BookmarkFolderMenu.tsx

@@ -9,6 +9,7 @@ import { toastError, toastSuccess } from '~/client/util/apiNotification';
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { BookmarkFolderItems } from '~/interfaces/bookmark-info';
 import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
+import { useSWRxCurrentPage } from '~/stores/page';
 
 import FolderIcon from '../Icons/FolderIcon';
 
@@ -28,6 +29,7 @@ const BookmarkFolderMenu = (props: Props): JSX.Element => {
   const [isCreateAction, setIsCreateAction] = useState(false);
   const { mutate: mutateChildBookmarkData } = useSWRxBookamrkFolderAndChild(null);
   const [selectedItem, setSelectedItem] = useState<string | null>(null);
+  const { data: currentPage } = useSWRxCurrentPage();
 
   const onClickNewBookmarkFolder = useCallback(() => {
     setIsCreateAction(true);
@@ -47,9 +49,21 @@ const BookmarkFolderMenu = (props: Props): JSX.Element => {
 
   }, [mutateChildBookmarkData, t]);
 
+  const addBookmarkToFolder = useCallback(async(folderId: string) => {
+    try {
+      await apiv3Post('/bookmark-folder/add-boookmark-to-folder', { page: currentPage, folderId });
+      toastSuccess('Bookmark added to bookmark folder successfully');
+    }
+    catch (err) {
+      toastError(err);
+    }
+
+  }, [currentPage]);
+
   const onMenuItemClickHandler = useCallback((itemId: string) => {
     setSelectedItem(itemId);
-  }, []);
+    addBookmarkToFolder(itemId);
+  }, [addBookmarkToFolder]);
 
   return (
     <UncontrolledDropdown className={`grw-bookmark-folder-dropdown ${styles['grw-bookmark-folder-dropdown']}`}>

+ 1 - 1
packages/app/src/interfaces/bookmark-info.ts

@@ -29,5 +29,5 @@ export interface BookmarkFolderItems {
   name: string
   parent: string
   children: this[]
-  bookmarks: BookmarkedPage[]
+  bookmarks: [Ref<BookmarkedPage>]
 }

+ 10 - 6
packages/app/src/server/models/bookmark-folder.ts

@@ -1,11 +1,10 @@
 import { isValidObjectId } from '@growi/core/src/utils/objectid-utils';
 import {
-  Types, Document, Model, Schema,
+  Types, Document, Model, Schema, model,
 } from 'mongoose';
 
-import { IBookmarkFolder, BookmarkFolderItems } from '~/interfaces/bookmark-info';
+import { IBookmarkFolder, BookmarkFolderItems, MyBookmarkList } from '~/interfaces/bookmark-info';
 import { IPageHasId } from '~/interfaces/page';
-import { IUserHasId } from '~/interfaces/user';
 
 import loggerFactory from '../../utils/logger';
 import { getOrCreateModel } from '../util/mongoose-utils';
@@ -16,11 +15,14 @@ import { InvalidParentBookmarkFolderError } from './errors';
 const logger = loggerFactory('growi:models:bookmark-folder');
 const Bookmark = require('./bookmark');
 
+const BookmarkSchema = model('Bookmark').schema;
+
 export interface BookmarkFolderDocument extends Document {
   _id: Types.ObjectId
   name: string
   owner: Types.ObjectId
   parent?: [this]
+  bookmarks: MyBookmarkList
 }
 
 export interface BookmarkFolderModel extends Model<BookmarkFolderDocument>{
@@ -29,12 +31,14 @@ export interface BookmarkFolderModel extends Model<BookmarkFolderDocument>{
   findChildFolderById(parentBookmarkFolder: Types.ObjectId | string): Promise<BookmarkFolderDocument[]>
   deleteFolderAndChildren(bookmarkFolderId: Types.ObjectId | string): {deletedCount: number}
   updateBookmarkFolder(bookmarkFolderId: string, name: string, parent: string): BookmarkFolderDocument | null
+  insertOrUpdateBookmarkedPage(page: IPageHasId, userId: Types.ObjectId | string, folderId: string)
 }
 
 const bookmarkFolderSchema = new Schema<BookmarkFolderDocument, BookmarkFolderModel>({
   name: { type: String },
   owner: { type: Schema.Types.ObjectId, ref: 'User', index: true },
   parent: { type: Schema.Types.ObjectId, ref: 'BookmarkFolder', required: false },
+  bookmarks: { type: [BookmarkSchema], default: [], required: false },
 }, {
   toObject: { virtuals: true },
 });
@@ -115,10 +119,10 @@ bookmarkFolderSchema.statics.updateBookmarkFolder = async function(bookmarkFolde
 
 };
 
-bookmarkFolderSchema.statics.insertOrUpdateBookmarkedPage = async function(page: IPageHasId, user: IUserHasId, bookmarkFolderId: string):
+bookmarkFolderSchema.statics.insertOrUpdateBookmarkedPage = async function(page: IPageHasId, userId: Types.ObjectId | string, folderId: string):
 Promise<BookmarkFolderDocument> {
-  const bookmarkedPage = await Bookmark.findOneAndUpdate({ page, user }, { new: true, upsert: true });
-  const bookmarkFolder = await this.findByIdAndUpdate(bookmarkFolderId, { $set: { bookmarks: bookmarkedPage } }, { new: true, upsert: true });
+  const bookmarkedPage = await Bookmark.findOneAndUpdate({ page: page._id, user: userId }, { new: true, upsert: true });
+  const bookmarkFolder = await this.findByIdAndUpdate(folderId, { $addToSet: { bookmarks: bookmarkedPage } }, { new: true, upsert: true });
   return bookmarkFolder;
 };
 

+ 15 - 0
packages/app/src/server/routes/apiv3/bookmark-folder.ts

@@ -88,5 +88,20 @@ module.exports = (crowi) => {
       return res.apiv3Err(err, 500);
     }
   });
+
+  router.post('/add-boookmark-to-folder', accessTokenParser, loginRequiredStrictly, validator.bookmarkFolder, apiV3FormValidator, async(req, res) => {
+    const userId = req.user?._id;
+    const { page, folderId } = req.body;
+
+    try {
+      const bookmarkFolder = await BookmarkFolder.insertOrUpdateBookmarkedPage(page, userId, folderId);
+      logger.debug('bookmark added to folder created', bookmarkFolder);
+      return res.apiv3({ bookmarkFolder });
+    }
+    catch (err) {
+      return res.apiv3Err(err, 500);
+    }
+  });
+
   return router;
 };