diff --git a/package-lock.json b/package-lock.json index 60928184f..def684091 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "giveth-graphql-api", - "version": "1.15.1", + "version": "1.15.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "giveth-graphql-api", - "version": "1.15.1", + "version": "1.15.2", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index c407ea079..8c67ecea5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "giveth-graphql-api", - "version": "1.15.1", + "version": "1.15.2", "description": "Backend GraphQL server for Giveth originally forked from Topia", "main": "./dist/index.js", "dependencies": { diff --git a/src/server/adminJs/adminJs-types.ts b/src/server/adminJs/adminJs-types.ts index b616d6e93..254890507 100644 --- a/src/server/adminJs/adminJs-types.ts +++ b/src/server/adminJs/adminJs-types.ts @@ -28,10 +28,11 @@ export interface AdminJsProjectsQuery { verified?: string; // listed?: string; isImported?: string; - reviewStatus: ReviewStatus; + reviewStatus?: ReviewStatus; } export interface AdminJsDonationsQuery { + id?: string; projectId?: string; contactEmail?: string; referrerWallet?: string; @@ -43,6 +44,7 @@ export interface AdminJsDonationsQuery { currency?: string; transactionNetworkId?: string; isProjectVerified?: string; + qfRoundId?: string; } // headers defined by the verification team for exporting @@ -94,4 +96,6 @@ export const donationHeaders = [ 'createdAt', 'referrerWallet', 'isTokenEligibleForGivback', + 'qfRoundId', + 'qfRoundUserScore', ]; diff --git a/src/server/adminJs/adminJs.ts b/src/server/adminJs/adminJs.ts index 77a5b182c..c47e51fa3 100644 --- a/src/server/adminJs/adminJs.ts +++ b/src/server/adminJs/adminJs.ts @@ -1,4 +1,4 @@ -import adminJs, { AdminJSOptions } from 'adminjs'; +import adminJs, { ActionContext, AdminJSOptions } from 'adminjs'; import { User } from '../../entities/user'; import adminJsExpress from '@adminjs/express'; import config from '../../config'; @@ -72,37 +72,25 @@ export const getAdminJsRouter = async () => { ); }; -// Express Middleware to save query of a search -export const adminJsQueryCache = async (req, res, next) => { - if ( - req.url.startsWith('/admin/api/resources/') && - req.headers.cookie.includes('adminbro') - ) { - const admin = await getCurrentAdminJsSession(req); - if (!admin) return next(); // skip saving queries - - const matches = req.url.match(/\/admin\/api\/resources\/(.+?)(\/|$)/); - if (!matches) return next(); // invalid URL - - const resourceName = matches[1]; - const queryStrings = {}; - - // Extract filter names and values from URL query string parameters - for (const key of Object.keys(req.query)) { - const [_, filter] = key.split('.'); - if (!filter) continue; - - queryStrings[filter] = req.query[key]; - } - // Save query strings to Redis hash with an expiration - await redis.hset( - `adminbro:${admin.id}:${resourceName}`, - queryStrings, - 'ex', - 1800, - ); +// Extract Referrer Header Parameter Filter Params +export const extractAdminJsReferrerUrlParams = (req: ActionContext) => { + const queryStrings = {}; + + const refererUrlHeaderIndex = req?.rawHeaders?.indexOf('Referer'); + if (!refererUrlHeaderIndex || refererUrlHeaderIndex < 0) return {}; + + const refererUrl = new URL(req.rawHeaders[refererUrlHeaderIndex + 1]); + const searchParams = refererUrl.searchParams; + + // Extract filter names and values from URL query string parameters + for (const [key, value] of searchParams.entries()) { + const [_, filter] = key.split('.'); + if (!filter) continue; + + queryStrings[filter] = value; } - next(); + + return queryStrings; }; // Get CurrentSession for external express middlewares diff --git a/src/server/adminJs/tabs/donationTab.ts b/src/server/adminJs/tabs/donationTab.ts index 41c7a8689..e7e5af86c 100644 --- a/src/server/adminJs/tabs/donationTab.ts +++ b/src/server/adminJs/tabs/donationTab.ts @@ -40,6 +40,8 @@ import { addDonationsSheetToSpreadsheet, } from '../../../services/googleSheets'; import { SelectQueryBuilder } from 'typeorm'; +import { ActionContext } from 'adminjs'; +import { extractAdminJsReferrerUrlParams } from '../adminJs'; export const createDonation = async ( request: AdminJsRequestInterface, @@ -183,14 +185,25 @@ export const buildDonationsQuery = ( const query = Donation.createQueryBuilder('donation') .leftJoinAndSelect('donation.user', 'user') .leftJoinAndSelect('donation.project', 'project') + .leftJoinAndSelect('donation.qfRound', 'qfRound') .where('donation.amount > 0') .addOrderBy('donation.createdAt', 'DESC'); + if (queryStrings.id) + query.andWhere('donation.id = :id', { + id: queryStrings.id, + }); + if (queryStrings.projectId) query.andWhere('donation.projectId = :projectId', { projectId: queryStrings.projectId, }); + if (queryStrings.qfRoundId) + query.andWhere('donation.qfRoundId = :qfRoundId', { + qfRoundId: queryStrings.qfRoundId, + }); + if (queryStrings.userId) query.andWhere('donation.userId = :userId', { userId: queryStrings.userId, @@ -250,16 +263,13 @@ export const buildDonationsQuery = ( }; export const exportDonationsWithFiltersToCsv = async ( - _request: AdminJsRequestInterface, + _request: ActionContext, _response, context: AdminJsContextInterface, ) => { try { const { records } = context; - const rawQueryStrings = await redis.get( - `adminbro:${context.currentAdmin.id}:Donation`, - ); - const queryStrings = rawQueryStrings ? JSON.parse(rawQueryStrings) : {}; + const queryStrings = extractAdminJsReferrerUrlParams(_request); const projectsQuery = buildDonationsQuery(queryStrings); const projects = await projectsQuery.getMany(); @@ -316,6 +326,8 @@ const sendDonationsToGoogleSheet = async ( createdAt: donation?.createdAt.toISOString(), referrerWallet: donation?.referrerWallet || '', isTokenEligibleForGivback: Boolean(donation?.isTokenEligibleForGivback), + qfRoundId: donation?.qfRound?.id || '', + qfRoundUserScore: donation?.qfRoundUserScore || '', }; }); @@ -339,6 +351,16 @@ export const donationTab = { new: false, }, }, + qfRoundId: { + type: Number, + isVisible: { + list: false, + filter: true, + show: true, + edit: false, + new: false, + }, + }, nonce: { isVisible: false, }, @@ -448,6 +470,15 @@ export const donationTab = { new: false, }, }, + qfRoundUserScore: { + isVisible: { + list: false, + filter: false, + show: true, + edit: false, + new: false, + }, + }, tokenAddress: { isVisible: false, }, @@ -462,7 +493,7 @@ export const donationTab = { }, toWalletAddress: { isVisible: { - list: true, + list: false, filter: true, show: true, edit: false, diff --git a/src/server/adminJs/tabs/projectsTab.ts b/src/server/adminJs/tabs/projectsTab.ts index 9e40ac138..547731cb5 100644 --- a/src/server/adminJs/tabs/projectsTab.ts +++ b/src/server/adminJs/tabs/projectsTab.ts @@ -5,7 +5,7 @@ import { ReviewStatus, RevokeSteps, } from '../../../entities/project'; -import adminJs from 'adminjs'; +import adminJs, { ActionContext } from 'adminjs'; import { canAccessProjectAction, canAccessQfRoundAction, @@ -62,6 +62,7 @@ import { refreshProjectDonationSummaryView, refreshProjectEstimatedMatchingView, } from '../../../services/projectViewsService'; +import { extractAdminJsReferrerUrlParams } from '../adminJs'; // add queries depending on which filters were selected export const buildProjectsQuery = ( @@ -605,16 +606,13 @@ export const listDelist = async ( }; export const exportProjectsWithFiltersToCsv = async ( - _request: AdminJsRequestInterface, + _request, _response, context: AdminJsContextInterface, ) => { try { const { records } = context; - const rawQueryStrings = await redis.get( - `adminbro:${context.currentAdmin.id}:Project`, - ); - const queryStrings = rawQueryStrings ? JSON.parse(rawQueryStrings) : {}; + const queryStrings = extractAdminJsReferrerUrlParams(_request); const projectsQuery = buildProjectsQuery(queryStrings); const projects = await projectsQuery.getMany(); diff --git a/src/server/bootstrap.ts b/src/server/bootstrap.ts index c9c7f6a14..e3d9bd50a 100644 --- a/src/server/bootstrap.ts +++ b/src/server/bootstrap.ts @@ -22,11 +22,7 @@ import { runCheckPendingProjectListingCronJob } from '../services/cronJobs/syncP import { runCheckProjectVerificationStatus } from '../services/cronJobs/checkProjectVerificationStatus'; import { webhookHandler } from '../services/transak/webhookHandler'; -import { - adminJsQueryCache, - adminJsRootPath, - getAdminJsRouter, -} from './adminJs/adminJs'; +import { adminJsRootPath, getAdminJsRouter } from './adminJs/adminJs'; import { redis } from '../redis'; import { logger } from '../utils/logger'; import { runNotifyMissingDonationsCronJob } from '../services/cronJobs/notifyDonationsWithSegment'; @@ -337,7 +333,6 @@ export async function bootstrap() { ); // AdminJs! - app.use(adminJsQueryCache); app.use(adminJsRootPath, await getAdminJsRouter()); if (!isTestEnv) {