|
|
@@ -1,37 +1,49 @@
|
|
|
import { isValidObjectId } from '@growi/core/src/utils/objectid-utils';
|
|
|
-import {
|
|
|
+import monggoose, {
|
|
|
Types, Document, Model, Schema,
|
|
|
} from 'mongoose';
|
|
|
|
|
|
-import { IBookmarkFolder, BookmarkFolderItems } from '~/interfaces/bookmark-info';
|
|
|
|
|
|
+import { IBookmarkFolder, BookmarkFolderItems } from '~/interfaces/bookmark-info';
|
|
|
+import { IPageHasId } from '~/interfaces/page';
|
|
|
|
|
|
import loggerFactory from '../../utils/logger';
|
|
|
import { getOrCreateModel } from '../util/mongoose-utils';
|
|
|
|
|
|
import { InvalidParentBookmarkFolderError } from './errors';
|
|
|
|
|
|
+
|
|
|
const logger = loggerFactory('growi:models:bookmark-folder');
|
|
|
+const Bookmark = monggoose.model('Bookmark');
|
|
|
+
|
|
|
|
|
|
export interface BookmarkFolderDocument extends Document {
|
|
|
_id: Types.ObjectId
|
|
|
name: string
|
|
|
owner: Types.ObjectId
|
|
|
- parent?: [this]
|
|
|
+ parent?: this[]
|
|
|
+ bookmarks?: Types.ObjectId[]
|
|
|
}
|
|
|
|
|
|
export interface BookmarkFolderModel extends Model<BookmarkFolderDocument>{
|
|
|
- createByParameters(params: IBookmarkFolder): BookmarkFolderDocument
|
|
|
- findFolderAndChildren(user: Types.ObjectId | string, parentId?: Types.ObjectId | string): BookmarkFolderItems[]
|
|
|
- findChildFolderById(parentBookmarkFolder: Types.ObjectId | string): Promise<BookmarkFolderDocument[]>
|
|
|
- deleteFolderAndChildren(bookmarkFolderId: Types.ObjectId | string): {deletedCount: number}
|
|
|
- updateBookmarkFolder(bookmarkFolderId: string, name: string, parent: string): BookmarkFolderDocument | null
|
|
|
+ createByParameters(params: IBookmarkFolder): Promise<BookmarkFolderDocument>
|
|
|
+ findFolderAndChildren(user: Types.ObjectId | string, parentId?: Types.ObjectId | string): Promise<BookmarkFolderItems[]>
|
|
|
+ deleteFolderAndChildren(bookmarkFolderId: Types.ObjectId | string): Promise<{deletedCount: number}>
|
|
|
+ updateBookmarkFolder(bookmarkFolderId: string, name: string, parent: string): Promise<BookmarkFolderDocument>
|
|
|
+ insertOrUpdateBookmarkedPage(pageId: IPageHasId, userId: Types.ObjectId | string, folderId: string): Promise<BookmarkFolderDocument>
|
|
|
}
|
|
|
|
|
|
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: [{
|
|
|
+ type: Schema.Types.ObjectId, ref: 'Bookmark', required: false,
|
|
|
+ }],
|
|
|
+ required: false,
|
|
|
+ default: [],
|
|
|
+ },
|
|
|
}, {
|
|
|
toObject: { virtuals: true },
|
|
|
});
|
|
|
@@ -44,10 +56,10 @@ bookmarkFolderSchema.virtual('children', {
|
|
|
|
|
|
bookmarkFolderSchema.statics.createByParameters = async function(params: IBookmarkFolder): Promise<BookmarkFolderDocument> {
|
|
|
const { name, owner, parent } = params;
|
|
|
- let bookmarkFolder;
|
|
|
+ let bookmarkFolder: BookmarkFolderDocument;
|
|
|
|
|
|
if (parent == null) {
|
|
|
- bookmarkFolder = await this.create({ name, owner }) as unknown as BookmarkFolderDocument;
|
|
|
+ bookmarkFolder = await this.create({ name, owner });
|
|
|
}
|
|
|
else {
|
|
|
// Check if parent folder id is valid and parent folder exists
|
|
|
@@ -60,7 +72,7 @@ bookmarkFolderSchema.statics.createByParameters = async function(params: IBookma
|
|
|
if (parentFolder == null) {
|
|
|
throw new InvalidParentBookmarkFolderError('Parent folder not found');
|
|
|
}
|
|
|
- bookmarkFolder = await this.create({ name, owner, parent: parentFolder._id }) as unknown as BookmarkFolderDocument;
|
|
|
+ bookmarkFolder = await this.create({ name, owner, parent: parentFolder._id });
|
|
|
}
|
|
|
|
|
|
return bookmarkFolder;
|
|
|
@@ -71,23 +83,45 @@ bookmarkFolderSchema.statics.findFolderAndChildren = async function(
|
|
|
parentId?: Types.ObjectId | string,
|
|
|
): Promise<BookmarkFolderItems[]> {
|
|
|
|
|
|
- const parentFolder = await this.findById(parentId) as unknown as BookmarkFolderDocument;
|
|
|
- const bookmarkFolders = await this.find({ owner: userId, parent: parentFolder })
|
|
|
- .populate({ path: 'children' }).exec() as unknown as BookmarkFolderItems[];
|
|
|
+ let parentFolder: BookmarkFolderDocument | null;
|
|
|
+ let query = {};
|
|
|
+ // Load child bookmark folders
|
|
|
+ if (parentId != null) {
|
|
|
+ parentFolder = await this.findById(parentId);
|
|
|
+ if (parentFolder != null) {
|
|
|
+ query = { owner: userId, parent: parentFolder };
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ throw new InvalidParentBookmarkFolderError('Parent folder not found');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Load initial / root bookmark folders
|
|
|
+ else {
|
|
|
+ query = { owner: userId, parent: null };
|
|
|
+ }
|
|
|
+ const bookmarkFolders: BookmarkFolderItems[] = await this.find(query)
|
|
|
+ .populate({ path: 'children' })
|
|
|
+ .populate({
|
|
|
+ path: 'bookmarks',
|
|
|
+ model: 'Bookmark',
|
|
|
+ populate: {
|
|
|
+ path: 'page',
|
|
|
+ model: 'Page',
|
|
|
+ },
|
|
|
+ });
|
|
|
return bookmarkFolders;
|
|
|
};
|
|
|
|
|
|
-bookmarkFolderSchema.statics.findChildFolderById = async function(parentFolderId: Types.ObjectId | string): Promise<BookmarkFolderDocument[]> {
|
|
|
- const parentFolder = await this.findById(parentFolderId) as unknown as BookmarkFolderDocument;
|
|
|
- const childFolders = await this.find({ parent: parentFolder });
|
|
|
- return childFolders;
|
|
|
-};
|
|
|
-
|
|
|
-bookmarkFolderSchema.statics.deleteFolderAndChildren = async function(boookmarkFolderId: Types.ObjectId | string): Promise<{deletedCount: number}> {
|
|
|
+bookmarkFolderSchema.statics.deleteFolderAndChildren = async function(bookmarkFolderId: Types.ObjectId | string): Promise<{deletedCount: number}> {
|
|
|
+ const bookmarkFolder = await this.findById(bookmarkFolderId);
|
|
|
// Delete parent and all children folder
|
|
|
- const bookmarkFolder = await this.findByIdAndDelete(boookmarkFolderId);
|
|
|
let deletedCount = 0;
|
|
|
if (bookmarkFolder != null) {
|
|
|
+ // Delete Bookmarks
|
|
|
+ const bookmarks = bookmarkFolder?.bookmarks;
|
|
|
+ if (bookmarks && bookmarks.length > 0) {
|
|
|
+ await Bookmark.deleteMany({ _id: { $in: bookmarks } });
|
|
|
+ }
|
|
|
// Delete all child recursively and update deleted count
|
|
|
const childFolders = await this.find({ parent: bookmarkFolder });
|
|
|
await Promise.all(childFolders.map(async(child) => {
|
|
|
@@ -96,21 +130,38 @@ bookmarkFolderSchema.statics.deleteFolderAndChildren = async function(boookmarkF
|
|
|
}));
|
|
|
const deletedChild = await this.deleteMany({ parent: bookmarkFolder });
|
|
|
deletedCount += deletedChild.deletedCount + 1;
|
|
|
+ bookmarkFolder.delete();
|
|
|
}
|
|
|
return { deletedCount };
|
|
|
};
|
|
|
|
|
|
-bookmarkFolderSchema.statics.updateBookmarkFolder = async function(bookmarkFolderId: string, name: string, parent: string):
|
|
|
- Promise<BookmarkFolderDocument | null> {
|
|
|
-
|
|
|
- const parentFolder = await this.findById(parent);
|
|
|
+bookmarkFolderSchema.statics.updateBookmarkFolder = async function(bookmarkFolderId: string, name: string, parentId: string):
|
|
|
+ Promise<BookmarkFolderDocument> {
|
|
|
+ const parentFolder = await this.findById(parentId);
|
|
|
const updateFields = {
|
|
|
name, parent: parentFolder?._id || null,
|
|
|
};
|
|
|
const bookmarkFolder = await this.findByIdAndUpdate(bookmarkFolderId, { $set: updateFields }, { new: true });
|
|
|
+ if (bookmarkFolder == null) {
|
|
|
+ throw new Error('Update bookmark folder failed');
|
|
|
+ }
|
|
|
return bookmarkFolder;
|
|
|
|
|
|
};
|
|
|
|
|
|
+bookmarkFolderSchema.statics.insertOrUpdateBookmarkedPage = async function(pageId: IPageHasId, userId: Types.ObjectId | string, folderId: string):
|
|
|
+Promise<BookmarkFolderDocument> {
|
|
|
+
|
|
|
+ // Create bookmark or update existing
|
|
|
+ const bookmarkedPage = await Bookmark.findOneAndUpdate({ page: pageId, user: userId }, { page: pageId, user: userId }, { new: true, upsert: true });
|
|
|
+
|
|
|
+ // Remove existing bookmark in bookmark folder
|
|
|
+ await this.updateMany({}, { $pull: { bookmarks: bookmarkedPage._id } });
|
|
|
+
|
|
|
+ // Insert bookmark into bookmark folder
|
|
|
+ const bookmarkFolder = await this.findByIdAndUpdate(folderId, { $addToSet: { bookmarks: bookmarkedPage } }, { new: true, upsert: true });
|
|
|
+ return bookmarkFolder;
|
|
|
+};
|
|
|
+
|
|
|
|
|
|
export default getOrCreateModel<BookmarkFolderDocument, BookmarkFolderModel>('BookmarkFolder', bookmarkFolderSchema);
|