All files / lib/models bookmark.ts

23.73% Statements 14/59
0% Branches 0/20
9.09% Functions 1/11
23.73% Lines 14/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162                                                                16x 16x   16x         16x   16x                                       16x       16x                                                   16x           16x                                       16x                                 16x                     16x                     16x   16x    
import Crowi from 'server/crowi'
import { Types, Document, Model, Schema, model } from 'mongoose'
import Debug from 'debug'
 
export interface BookmarkDocument extends Document {
  _id: Types.ObjectId
  page: Types.ObjectId | any
  user: Types.ObjectId | any
  createdAt: Date
}
export interface BookmarkModel extends Model<BookmarkDocument> {
  populatePage(bookmarks: any[], requestUser?: any): Promise<BookmarkDocument[]>
  findByPageIdAndUserId(pageId: Types.ObjectId, userId: Types.ObjectId): Promise<BookmarkDocument | null>
  findByUserId(
    userId: Types.ObjectId,
    option: any,
  ): Promise<{
    meta: {
      total: any
      limit: any
      offset: any
    }
    data: any
  }>
  countByPageId(pageId: Types.ObjectId): Promise<number>
  findByUser(user: any, option: any): Promise<BookmarkDocument[]>
  add(page: any, user: any): Promise<BookmarkDocument>
  removeBookmarksByPageId(pageId: Types.ObjectId): any
  removeBookmark(page: any, user: any): any
}
 
export default (crowi: Crowi) => {
  const debug = Debug('crowi:models:Bookmark')
  const BookmarkEvent = crowi.event('Bookmark')
 
  const BookmarkSchema = new Schema<BookmarkDocument, BookmarkModel>({
    page: { type: Schema.Types.ObjectId, ref: 'Page', index: true },
    user: { type: Schema.Types.ObjectId, ref: 'User', index: true },
    createdAt: { type: Date, default: Date.now() },
  })
  BookmarkSchema.index({ page: 1, user: 1 }, { unique: true })
 
  BookmarkSchema.statics.populatePage = async function(bookmarks, requestUser) {
    requestUser = requestUser || null
 
    const populatedBookmarks = await Bookmark.populate(bookmarks, {
      path: 'page',
      populate: { path: 'revision', model: 'Revision', populate: { path: 'author', model: 'User' } },
    })
 
    // hmm...
    return populatedBookmarks.filter(bookmark => {
      // requestUser を指定しない場合 public のみを返す
      if (requestUser === null) {
        return bookmark.page.isPublic()
      }
 
      return bookmark.page.isGrantedFor(requestUser)
    })
  }
 
  // Bookmark チェック用
  BookmarkSchema.statics.findByPageIdAndUserId = function(pageId, userId) {
    return Bookmark.findOne({ page: pageId, user: userId }).exec()
  }
 
  BookmarkSchema.statics.findByUserId = async function(userId, option) {
    const limit = option.limit || 50
    const offset = option.offset || 0
 
    const finder = Bookmark.find({ user: userId })
      .sort({ createdAt: -1 })
      .skip(offset)
      .limit(limit)
      .exec()
      .then(bookmarks => Bookmark.populatePage(bookmarks))
 
    const counter = Bookmark.countDocuments({ user: userId }).exec()
 
    const [bookmarks, count] = await Promise.all([finder, counter])
 
    return {
      meta: {
        total: count,
        limit: limit,
        offset: offset,
      },
      data: bookmarks,
    }
  }
 
  // Bookmark count
  BookmarkSchema.statics.countByPageId = async function(pageId) {
    const count = await Bookmark.countDocuments({ page: pageId })
 
    return count
  }
 
  BookmarkSchema.statics.findByUser = async function(user, option) {
    const requestUser = option.requestUser || null
 
    const limit = option.limit || 50
    const offset = option.offset || 0
    const populatePage = option.populatePage || false
 
    const bookmarks = await Bookmark.find({ user: user._id })
      .sort({ createdAt: -1 })
      .skip(offset)
      .limit(limit)
      .exec()
 
    if (!populatePage) {
      return bookmarks
    }
 
    return Bookmark.populatePage(bookmarks, requestUser)
  }
 
  BookmarkSchema.statics.add = async function(page, user) {
    const newBookmark = new (Bookmark as any)({ page, user, createdAt: Date.now() })
 
    try {
      const Bookmark = await newBookmark.save()
      BookmarkEvent.emit('create', page._id)
      return Bookmark
    } catch (err) {
      if (err.code === 11000) {
        // duplicate key (dummy response of new object)
        return newBookmark
      }
      debug('Bookmark.save failed', err)
      throw err
    }
  }
 
  BookmarkSchema.statics.removeBookmarksByPageId = async function(pageId) {
    try {
      const data = await Bookmark.deleteMany({ page: pageId })
      BookmarkEvent.emit('delete', pageId)
      return data
    } catch (err) {
      debug('Bookmark.remove failed (removeBookmarkByPage)', err)
      throw err
    }
  }
 
  BookmarkSchema.statics.removeBookmark = async function(page, user) {
    try {
      const data = await Bookmark.findOneAndRemove({ page, user })
      BookmarkEvent.emit('delete', page)
      return data
    } catch (err) {
      debug('Bookmark.findOneAndRemove failed', err)
      throw err
    }
  }
 
  const Bookmark = model<BookmarkDocument, BookmarkModel>('Bookmark', BookmarkSchema)
 
  return Bookmark
}