@@ -3,14 +3,16 @@ import {
33 ERROR_WHILE_CREATING_REQUEST ,
44 IMPERSONATION_NOT_COMPLETED ,
55 REQUEST_ALREADY_PENDING ,
6- REQUEST_STATE
6+ REQUEST_STATE ,
7+ ERROR_WHILE_FETCHING_REQUEST
78} from "../constants/requests" ;
89import { Timestamp } from "firebase-admin/firestore" ;
9- import { CreateImpersonationRequestModelDto , ImpersonationRequest } from "../types/impersonationRequest" ;
10+ import { Query , CollectionReference } from '@google-cloud/firestore' ;
11+ import { CreateImpersonationRequestModelDto , ImpersonationRequest , PaginatedImpersonationRequests , ImpersonationRequestQuery } from "../types/impersonationRequest" ;
1012import { Forbidden } from "http-errors" ;
1113const logger = require ( "../utils/logger" ) ;
12-
1314const impersonationRequestModel = firestore . collection ( "impersonationRequests" ) ;
15+ const DEFAULT_PAGE_SIZE = 5 ;
1416
1517/**
1618 * Creates a new impersonation request in Firestore.
@@ -55,4 +57,115 @@ export const createImpersonationRequest = async (
5557 logger . error ( ERROR_WHILE_CREATING_REQUEST , { error, requestData : body } ) ;
5658 throw error ;
5759 }
58- } ;
60+ } ;
61+
62+ /**
63+ * Retrieves an impersonation request by its ID.
64+ * @param {string } id - The ID of the impersonation request to retrieve.
65+ * @returns {Promise<ImpersonationRequest|null> } The found impersonation request or null if not found.
66+ * @throws {Error } Logs and rethrows any error encountered during fetch.
67+ */
68+ export const getImpersonationRequestById = async (
69+ id : string
70+ ) : Promise < ImpersonationRequest | null > => {
71+ try {
72+ const requestDoc = await impersonationRequestModel . doc ( id ) . get ( ) ;
73+ if ( ! requestDoc . exists ) {
74+ return null ;
75+ }
76+ const data = requestDoc . data ( ) as ImpersonationRequest ;
77+ return {
78+ id : requestDoc . id ,
79+ ...data ,
80+ } ;
81+ } catch ( error ) {
82+ logger . error ( `${ ERROR_WHILE_FETCHING_REQUEST } for ID: ${ id } ` , error ) ;
83+ throw error ;
84+ }
85+ } ;
86+
87+ /**
88+ * Retrieves a paginated list of impersonation requests based on query filters.
89+ * @param {object } query - The query filters.
90+ * @param {string } [query.createdBy] - Filter by the username of the request creator.
91+ * @param {string } [query.createdFor] - Filter by the username of the user the request is created for.
92+ * @param {string } [query.status] - Filter by request status (e.g., "APPROVED", "PENDING", "REJECTED").
93+ * @param {string } [query.prev] - Document ID to use as the ending point for backward pagination.
94+ * @param {string } [query.next] - Document ID to use as the starting point for forward pagination.
95+ * @param {string } [query.size] - Number of results per page.
96+ * @returns {Promise<PaginatedImpersonationRequests|null> } The paginated impersonation requests or null if none found.
97+ * @throws Logs and rethrows any error encountered during fetch.
98+ */
99+ export const getImpersonationRequests = async (
100+ query
101+ ) : Promise < PaginatedImpersonationRequests | null > => {
102+
103+ let { createdBy, createdFor, status, prev, next, size = DEFAULT_PAGE_SIZE } = query ;
104+
105+ size = size ? Number . parseInt ( size ) : DEFAULT_PAGE_SIZE ;
106+
107+
108+ try {
109+ let requestQuery : Query < ImpersonationRequest > = impersonationRequestModel as CollectionReference < ImpersonationRequest > ;
110+
111+ if ( createdBy ) {
112+ requestQuery = requestQuery . where ( "createdBy" , "==" , createdBy ) ;
113+ }
114+ if ( status ) {
115+ requestQuery = requestQuery . where ( "status" , "==" , status ) ;
116+ }
117+ if ( createdFor ) {
118+ requestQuery = requestQuery . where ( "createdFor" , "==" , createdFor ) ;
119+ }
120+
121+ requestQuery = requestQuery . orderBy ( "createdAt" , "desc" ) ;
122+ let requestQueryDoc = requestQuery ;
123+
124+ if ( prev ) {
125+ requestQueryDoc = requestQueryDoc . limitToLast ( size ) ;
126+ } else {
127+ requestQueryDoc = requestQueryDoc . limit ( size ) ;
128+ }
129+
130+ if ( next ) {
131+ const doc = await impersonationRequestModel . doc ( next ) . get ( ) ;
132+ requestQueryDoc = requestQueryDoc . startAt ( doc ) ;
133+ } else if ( prev ) {
134+ const doc = await impersonationRequestModel . doc ( prev ) . get ( ) ;
135+ requestQueryDoc = requestQueryDoc . endAt ( doc ) ;
136+ }
137+
138+ const snapshot = await requestQueryDoc . get ( ) ;
139+ let nextDoc ;
140+ let prevDoc ;
141+
142+ if ( ! snapshot . empty ) {
143+ const first = snapshot . docs [ 0 ] ;
144+ prevDoc = await requestQuery . endBefore ( first ) . limitToLast ( 1 ) . get ( ) ;
145+ const last = snapshot . docs [ snapshot . docs . length - 1 ] ;
146+ nextDoc = await requestQuery . startAfter ( last ) . limit ( 1 ) . get ( ) ;
147+ }
148+
149+ const allRequests = snapshot . empty
150+ ? [ ]
151+ : snapshot . docs . map ( doc => ( {
152+ id : doc . id ,
153+ ...doc . data ( )
154+ } ) ) ;
155+
156+ if ( allRequests . length === 0 ) {
157+ return null ;
158+ }
159+
160+ const count = allRequests . length ;
161+ return {
162+ allRequests,
163+ prev : prevDoc && ! prevDoc . empty ? prevDoc . docs [ 0 ] . id : null ,
164+ next : nextDoc && ! nextDoc . empty ? nextDoc . docs [ 0 ] . id : null ,
165+ count,
166+ } ;
167+ } catch ( error ) {
168+ logger . error ( ERROR_WHILE_FETCHING_REQUEST , error ) ;
169+ throw error ;
170+ }
171+ }
0 commit comments