diff --git a/src/Entities/EntityFilters/AccountFilterInfo.ts b/src/Entities/EntityFilters/AccountFilterInfo.ts index 419fb6fc..6d39e69f 100755 --- a/src/Entities/EntityFilters/AccountFilterInfo.ts +++ b/src/Entities/EntityFilters/AccountFilterInfo.ts @@ -130,6 +130,11 @@ export class AccountFilterInfo extends CriteriaFilter { } }; + // Add any parameters to the response + public addResponseFields(pRequest: Request) { + return; + }; + // Passed (what should be) an AccountEntity, test if the filters // think it's passable. // Return 'true' of this account fits the search criteria. diff --git a/src/Entities/EntityFilters/AccountScopeFilter.ts b/src/Entities/EntityFilters/AccountScopeFilter.ts index ecc44277..432e1ef8 100755 --- a/src/Entities/EntityFilters/AccountScopeFilter.ts +++ b/src/Entities/EntityFilters/AccountScopeFilter.ts @@ -60,6 +60,11 @@ export class AccountScopeFilter extends CriteriaFilter { }; }; + // Add any parameters to the response + public addResponseFields(pRequest: Request) { + return; + }; + // Return if we've found admin enabling parameters public AsAdmin(): boolean { return this._asAdmin; diff --git a/src/Entities/EntityFilters/CriteriaFilter.ts b/src/Entities/EntityFilters/CriteriaFilter.ts index c835ff32..49adb7bb 100755 --- a/src/Entities/EntityFilters/CriteriaFilter.ts +++ b/src/Entities/EntityFilters/CriteriaFilter.ts @@ -20,6 +20,9 @@ export abstract class CriteriaFilter { // Take a request and extract filter parameters abstract parametersFromRequest(pRequest: Request): void; + // Adds additional fields to the response + abstract addResponseFields(pRequest: Request): void; + // Test a thing and return 'true' if it should be included in the set abstract criteriaTest(pThingy: any): boolean; diff --git a/src/Entities/EntityFilters/GenericFilter.ts b/src/Entities/EntityFilters/GenericFilter.ts index 43f1e33b..92e83c14 100755 --- a/src/Entities/EntityFilters/GenericFilter.ts +++ b/src/Entities/EntityFilters/GenericFilter.ts @@ -34,6 +34,11 @@ export class GenericFilter extends CriteriaFilter { return; }; + // Add any parameters to the response + public addResponseFields(pRequest: Request) { + return; + }; + // Test a thing and return 'true' if it should be included in the set public criteriaTest(pThingy: any): boolean { return true; diff --git a/src/Entities/EntityFilters/PaginationInfo.ts b/src/Entities/EntityFilters/PaginationInfo.ts index 2a45948e..ee1c053b 100755 --- a/src/Entities/EntityFilters/PaginationInfo.ts +++ b/src/Entities/EntityFilters/PaginationInfo.ts @@ -23,6 +23,8 @@ import { Logger } from '@Tools/Logging'; export class PaginationInfo extends CriteriaFilter { public PageNum: number = 1; public PerPage: number = 20; + public TotalPages: number = 1; + public TotalEntries: number = 20; // results from as filter operation private _currentPage: number = 1; @@ -35,6 +37,8 @@ export class PaginationInfo extends CriteriaFilter { super(); this.PageNum = Clamp(pPageNum, 1, 1000); this.PerPage = Clamp(pPerPage, 1, 1000); + this.TotalPages = this.PageNum; + this.TotalEntries = 0; } public parametersFromRequest(pRequest: Request) : void { @@ -44,6 +48,8 @@ export class PaginationInfo extends CriteriaFilter { if (pRequest.query.per_page) { this.PerPage = Clamp(Number(pRequest.query.per_page), 1, 1000); }; + this.TotalPages = this.PageNum; + this.TotalEntries = 0; // Logger.debug(`PaginstationInfo: pageNum=${this.PageNum}, perPage=${this.PerPage}`); } @@ -52,9 +58,18 @@ export class PaginationInfo extends CriteriaFilter { // "total_pages": num, // "per_page": num, // "total_entries": num + public addResponseFields(pRequest: Request): void { + if (pRequest.vRestResp) { + pRequest.vRestResp.addAdditionalField('current_page', this.PageNum); + pRequest.vRestResp.addAdditionalField('per_page', this.PerPage); + pRequest.vRestResp.addAdditionalField('total_pages', this.TotalPages); + pRequest.vRestResp.addAdditionalField('total_entries', this.TotalEntries); + }; + }; public criteriaTest(pThingy: any): boolean { if (! this._doingQuery) { + this.TotalEntries++; if (++this._currentItem > this.PerPage) { this._currentItem = 1; ++this._currentPage; diff --git a/src/Entities/EntityFilters/RequestScopeFilter.ts b/src/Entities/EntityFilters/RequestScopeFilter.ts index 2260c6be..e3c6bdd2 100755 --- a/src/Entities/EntityFilters/RequestScopeFilter.ts +++ b/src/Entities/EntityFilters/RequestScopeFilter.ts @@ -72,6 +72,11 @@ export class RequestScopeFilter extends CriteriaFilter { }; }; + // Add any parameters to the response + public addResponseFields(pRequest: Request) { + return; + }; + // Return if we've found admin enabling parameters public AsAdmin(): boolean { return this._asAdmin; diff --git a/src/Entities/Sessions.ts b/src/Entities/Sessions.ts index f16605fa..b3cf8e91 100755 --- a/src/Entities/Sessions.ts +++ b/src/Entities/Sessions.ts @@ -17,7 +17,7 @@ import { Config } from '@Base/config'; import { SessionEntity } from '@Entities/SessionEntity'; -import { PaginationInfo } from '@Entities/EntityFilters/PaginationInfo'; +import { CriteriaFilter } from '@Entities/EntityFilters/CriteriaFilter'; import { VKeyedCollection } from '@Tools/vTypes'; import { GenUUID, genRandomString, IsNullOrEmpty } from '@Tools/Misc'; @@ -87,10 +87,10 @@ export const Sessions = { clearCounts(pSession: SessionEntity): void { pSession.countReference = 0; }, - *enumerate(pPager?: PaginationInfo): Generator { + *enumerate(pFilter?: CriteriaFilter): Generator { for (const sess of _currentSessions.values()) { - if (pPager) { - if (pPager.criteriaTest(sess)) { + if (pFilter) { + if (pFilter.criteriaTest(sess)) { yield sess; }; } diff --git a/src/routes/api/v1/accounts.ts b/src/routes/api/v1/accounts.ts index dabfc86d..8a55e57d 100755 --- a/src/routes/api/v1/accounts.ts +++ b/src/routes/api/v1/accounts.ts @@ -47,6 +47,7 @@ const procGetAccounts: RequestHandler = async (req: Request, resp: Response, nex req.vRestResp.Data = { accounts: accts }; + pager.addResponseFields(req); } else { req.vRestResp.respondFailure('No account specified'); diff --git a/src/routes/api/v1/users/connections.ts b/src/routes/api/v1/users/connections.ts index 25095e31..8ba27640 100755 --- a/src/routes/api/v1/users/connections.ts +++ b/src/routes/api/v1/users/connections.ts @@ -43,26 +43,30 @@ const procGetUsersConnections: RequestHandler = async (req: Request, resp: Respo Logger.debug(`procGetUsersConnections: user=${req.vAuthAccount.username}, connections=${JSON.stringify(connections)}`); const connectionInfo: any[] = []; for (const connectionUsername of connections) { - const aAccount = await Accounts.getAccountWithUsername(connectionUsername); - if (aAccount) { - connectionInfo.push( { - 'username': connectionUsername, - 'connection': SArray.has(req.vAuthAccount.friends, connectionUsername) ? 'is_friend' : 'is_connection', - 'images': await buildImageInfo(aAccount), - 'location': await buildLocationInfo(aAccount) - }); - } - else { - Logger.error(`procGetUsersConnections: connection name with no account. acct=${req.vAuthAccount.id}, name=${connectionUsername}`); - connectionInfo.push( { - 'username': connectionUsername, - 'connection': 'unknown' - }); + if (pager.criteriaTest(connectionUsername)) { + const aAccount = await Accounts.getAccountWithUsername(connectionUsername); + if (aAccount) { + connectionInfo.push( { + 'username': connectionUsername, + 'connection': SArray.has(req.vAuthAccount.friends, connectionUsername) ? 'is_friend' : 'is_connection', + 'images': await buildImageInfo(aAccount), + 'location': await buildLocationInfo(aAccount) + }); + } + else { + Logger.error(`procGetUsersConnections: connection name with no account. acct=${req.vAuthAccount.id}, name=${connectionUsername}`); + connectionInfo.push( { + 'username': connectionUsername, + 'connection': 'unknown' + }); + }; }; }; req.vRestResp.Data = { 'users': connectionInfo }; + // Add the 'current_page' and 'total_pages' to the response + pager.addResponseFields(req); } else { req.vRestResp.respondFailure('unauthorized'); diff --git a/src/routes/explore.ts b/src/routes/explore.ts index 13d6b413..2f275892 100755 --- a/src/routes/explore.ts +++ b/src/routes/explore.ts @@ -68,6 +68,8 @@ const procGetExplore: RequestHandler = async (req: Request, resp: Response, next }; req.vRestResp.Data = allPlaces; + pager.addResponseFields(req); + next(); };