@@ -174,6 +174,160 @@ const routerFactory = (crowi: Crowi): Router => {
174174 } ,
175175 ) ;
176176
177+ /**
178+ * @swagger
179+ *
180+ * /page-listing/info:
181+ * get:
182+ * tags: [PageListing]
183+ * security:
184+ * - bearer: []
185+ * - accessTokenInQuery: []
186+ * summary: /page-listing/info
187+ * description: Get summary information of pages
188+ * parameters:
189+ * - name: pageIds
190+ * in: query
191+ * description: Array of page IDs to retrieve information for (One of pageIds or path is required)
192+ * schema:
193+ * type: array
194+ * items:
195+ * type: string
196+ * - name: path
197+ * in: query
198+ * description: Path of the page to retrieve information for (One of pageIds or path is required)
199+ * schema:
200+ * type: string
201+ * - name: attachBookmarkCount
202+ * in: query
203+ * schema:
204+ * type: boolean
205+ * - name: attachShortBody
206+ * in: query
207+ * schema:
208+ * type: boolean
209+ * responses:
210+ * 200:
211+ * description: Get the information of a page
212+ * content:
213+ * application/json:
214+ * schema:
215+ * type: object
216+ * additionalProperties:
217+ * $ref: '#/components/schemas/PageInfoAll'
218+ */
219+ router . get (
220+ '/info' ,
221+ accessTokenParser ( [ SCOPE . READ . FEATURES . PAGE ] , { acceptLegacy : true } ) ,
222+ validator . pageIdsOrPathRequired ,
223+ validator . infoParams ,
224+ apiV3FormValidator ,
225+ async ( req : AuthorizedRequest , res : ApiV3Response ) => {
226+ const {
227+ pageIds,
228+ path,
229+ attachBookmarkCount : attachBookmarkCountParam ,
230+ attachShortBody : attachShortBodyParam ,
231+ } = req . query ;
232+
233+ const attachBookmarkCount : boolean = attachBookmarkCountParam === 'true' ;
234+ const attachShortBody : boolean = attachShortBodyParam === 'true' ;
235+
236+ const Page = mongoose . model < HydratedDocument < PageDocument > , PageModel > (
237+ 'Page' ,
238+ ) ;
239+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
240+ const Bookmark = mongoose . model < any , any > ( 'Bookmark' ) ;
241+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
242+ const pageService = crowi . pageService ;
243+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
244+ const pageGrantService : IPageGrantService = crowi . pageGrantService ! ;
245+
246+ try {
247+ const pages =
248+ pageIds != null
249+ ? await Page . findByIdsAndViewer (
250+ pageIds as string [ ] ,
251+ req . user ,
252+ null ,
253+ true ,
254+ )
255+ : await Page . findByPathAndViewer (
256+ path as string ,
257+ req . user ,
258+ null ,
259+ false ,
260+ true ,
261+ ) ;
262+
263+ const foundIds = pages . map ( ( page ) => page . _id ) ;
264+
265+ let shortBodiesMap : Record < string , string | null > | undefined ;
266+ if ( attachShortBody ) {
267+ shortBodiesMap = await pageService . shortBodiesMapByPageIds (
268+ foundIds ,
269+ req . user ,
270+ ) ;
271+ }
272+
273+ let bookmarkCountMap : Record < string , number > | undefined ;
274+ if ( attachBookmarkCount ) {
275+ bookmarkCountMap = ( await Bookmark . getPageIdToCountMap (
276+ foundIds ,
277+ ) ) as Record < string , number > ;
278+ }
279+
280+ const idToPageInfoMap : Record < string , IPageInfo | IPageInfoForListing > =
281+ { } ;
282+
283+ const isGuestUser = req . user == null ;
284+
285+ const userRelatedGroups = await pageGrantService . getUserRelatedGroups (
286+ req . user ,
287+ ) ;
288+
289+ for ( const page of pages ) {
290+ const basicPageInfo = {
291+ ...pageService . constructBasicPageInfo ( page , isGuestUser ) ,
292+ bookmarkCount :
293+ bookmarkCountMap != null
294+ ? ( bookmarkCountMap [ page . _id . toString ( ) ] ?? 0 )
295+ : 0 ,
296+ } ;
297+
298+ // TODO: use pageService.getCreatorIdForCanDelete to get creatorId (https://redmine.weseek.co.jp/issues/140574)
299+ const canDeleteCompletely = pageService . canDeleteCompletely (
300+ page ,
301+ page . creator == null ? null : getIdForRef ( page . creator ) ,
302+ req . user ,
303+ false ,
304+ userRelatedGroups ,
305+ ) ; // use normal delete config
306+
307+ const pageInfo = ! isIPageInfoForEntity ( basicPageInfo )
308+ ? basicPageInfo
309+ : ( {
310+ ...basicPageInfo ,
311+ isAbleToDeleteCompletely : canDeleteCompletely ,
312+ revisionShortBody :
313+ shortBodiesMap != null
314+ ? ( shortBodiesMap [ page . _id . toString ( ) ] ?? undefined )
315+ : undefined ,
316+ } satisfies IPageInfoForListing ) ;
317+
318+ idToPageInfoMap [ page . _id . toString ( ) ] = pageInfo ;
319+ }
320+
321+ return res . apiv3 ( idToPageInfoMap ) ;
322+ } catch ( err ) {
323+ logger . error ( 'Error occurred while fetching page informations.' , err ) ;
324+ return res . apiv3Err (
325+ new ErrorV3 ( 'Error occurred while fetching page informations.' ) ,
326+ ) ;
327+ }
328+ } ,
329+ ) ;
330+
177331 /**
178332 * @swagger
179333 *
0 commit comments