diff --git a/hasura/metadata/databases/default/tables/public_app.yaml b/hasura/metadata/databases/default/tables/public_app.yaml index c18993682..fc7a9aae6 100644 --- a/hasura/metadata/databases/default/tables/public_app.yaml +++ b/hasura/metadata/databases/default/tables/public_app.yaml @@ -40,8 +40,8 @@ insert_permissions: check: {} columns: - engine - - id - is_staging + - name - team_id - role: user permission: @@ -57,12 +57,6 @@ insert_permissions: - role: _eq: ADMIN columns: - - description_internal - - engine - - is_archived - - is_staging - - name - - status - team_id select_permissions: - role: api_key @@ -93,6 +87,8 @@ select_permissions: - is_archived - is_banned - is_staging + - rating_count + - rating_sum - status - team_id filter: {} @@ -133,13 +129,14 @@ update_permissions: permission: columns: - is_banned + - rating_count + - rating_sum filter: {} check: null comment: "" - role: user permission: columns: - - description_internal - is_archived - status filter: diff --git a/hasura/metadata/databases/default/tables/public_app_metadata.yaml b/hasura/metadata/databases/default/tables/public_app_metadata.yaml index 3c7903c8d..c5296cf4a 100644 --- a/hasura/metadata/databases/default/tables/public_app_metadata.yaml +++ b/hasura/metadata/databases/default/tables/public_app_metadata.yaml @@ -66,14 +66,16 @@ insert_permissions: - app_mode - app_website_url - associated_domains + - can_import_all_contacts - category - contracts - description - hero_image_url - - id - integration_url + - is_allowed_unlimited_notifications - is_developer_allow_listing - logo_img_url + - max_notifications_per_day - name - permit2_tokens - short_name @@ -86,8 +88,6 @@ insert_permissions: - whitelisted_addresses - world_app_button_text - world_app_description - - is_allowed_unlimited_notifications - - max_notifications_per_day comment: "" - role: user permission: @@ -109,30 +109,11 @@ insert_permissions: columns: - app_id - app_mode - - app_website_url - - associated_domains - - can_import_all_contacts - - category - - contracts - - description - hero_image_url - - integration_url - - is_developer_allow_listing - logo_img_url - - name - - permit2_tokens - - short_name - showcase_img_urls - - source_code_url - - support_link - - supported_countries - supported_languages - verification_status - - whitelisted_addresses - - world_app_button_text - - world_app_description - - is_allowed_unlimited_notifications - - max_notifications_per_day select_permissions: - role: api_key permission: @@ -357,6 +338,45 @@ update_permissions: _in: - changes_requested - verified + - role: service + permission: + columns: + - app_mode + - app_website_url + - associated_domains + - can_import_all_contacts + - category + - contracts + - created_at + - description + - hero_image_url + - integration_url + - is_allowed_unlimited_notifications + - is_developer_allow_listing + - is_reviewer_app_store_approved + - is_reviewer_world_app_approved + - is_row_verified + - logo_img_url + - max_notifications_per_day + - name + - permit2_tokens + - review_message + - reviewed_by + - short_name + - showcase_img_urls + - source_code_url + - support_link + - supported_countries + - supported_languages + - updated_at + - verification_status + - verified_at + - whitelisted_addresses + - world_app_button_text + - world_app_description + filter: {} + check: null + comment: "" - role: user permission: columns: diff --git a/hasura/metadata/databases/default/tables/public_localisations.yaml b/hasura/metadata/databases/default/tables/public_localisations.yaml index 9d52ee9dd..15317d903 100644 --- a/hasura/metadata/databases/default/tables/public_localisations.yaml +++ b/hasura/metadata/databases/default/tables/public_localisations.yaml @@ -98,14 +98,22 @@ select_permissions: _eq: X-Hasura-User-Id comment: "" update_permissions: - - role: user + - role: service permission: columns: + - app_metadata_id - description + - locale - name - short_name - world_app_button_text - world_app_description + filter: {} + check: null + comment: "" + - role: user + permission: + columns: [] filter: app_metadata: _and: diff --git a/hasura/migrations/default/1733533994467_compute_ratings/down.sql b/hasura/migrations/default/1733533994467_compute_ratings/down.sql new file mode 100644 index 000000000..909acab9d --- /dev/null +++ b/hasura/migrations/default/1733533994467_compute_ratings/down.sql @@ -0,0 +1,5 @@ +ALTER TABLE app +DROP COLUMN IF EXISTS rating_sum; + +ALTER TABLE app +DROP COLUMN IF EXISTS rating_count; \ No newline at end of file diff --git a/hasura/migrations/default/1733533994467_compute_ratings/up.sql b/hasura/migrations/default/1733533994467_compute_ratings/up.sql new file mode 100644 index 000000000..e8674b340 --- /dev/null +++ b/hasura/migrations/default/1733533994467_compute_ratings/up.sql @@ -0,0 +1,26 @@ +-- Step 1: Add new columns for the total rating sum and total number of ratings +ALTER TABLE app +ADD COLUMN IF NOT EXISTS rating_sum BIGINT DEFAULT 0; + +ALTER TABLE app +ADD COLUMN IF NOT EXISTS rating_count BIGINT DEFAULT 0; + +-- Step 2: Update the new columns with the sum of ratings and count of ratings for each app +UPDATE app +SET + rating_sum = ( + SELECT + COALESCE(SUM(rating), 0) + FROM + app_reviews + WHERE + app_reviews.app_id = app.id + ), + rating_count = ( + SELECT + COUNT(*) + FROM + app_reviews + WHERE + app_reviews.app_id = app.id + ); \ No newline at end of file diff --git a/hasura/migrations/default/1733773864649_alter_table_public_app_alter_column_rating_sum/down.sql b/hasura/migrations/default/1733773864649_alter_table_public_app_alter_column_rating_sum/down.sql new file mode 100644 index 000000000..b1e321fe8 --- /dev/null +++ b/hasura/migrations/default/1733773864649_alter_table_public_app_alter_column_rating_sum/down.sql @@ -0,0 +1,13 @@ +ALTER TABLE "public"."app" +ALTER COLUMN "rating_count" TYPE bigint; + +ALTER TABLE "public"."app" +ALTER COLUMN "rating_sum" TYPE bigint; + +alter table "public"."app" +alter column "rating_sum" +drop not null; + +alter table "public"."app" +alter column "rating_count" +drop not null; \ No newline at end of file diff --git a/hasura/migrations/default/1733773864649_alter_table_public_app_alter_column_rating_sum/up.sql b/hasura/migrations/default/1733773864649_alter_table_public_app_alter_column_rating_sum/up.sql new file mode 100644 index 000000000..0f5497767 --- /dev/null +++ b/hasura/migrations/default/1733773864649_alter_table_public_app_alter_column_rating_sum/up.sql @@ -0,0 +1,15 @@ +ALTER TABLE "public"."app" +ALTER COLUMN "rating_sum" TYPE int4; + +ALTER TABLE "public"."app" +ALTER COLUMN "rating_count" TYPE int4; + +alter table "public"."app" +alter column "rating_sum" +set + not null; + +alter table "public"."app" +alter column "rating_count" +set + not null; \ No newline at end of file diff --git a/web/api/helpers/app-rating/graphql/get-app-rating.graphql b/web/api/helpers/app-rating/graphql/get-app-rating.graphql deleted file mode 100644 index 8b21ff03d..000000000 --- a/web/api/helpers/app-rating/graphql/get-app-rating.graphql +++ /dev/null @@ -1,5 +0,0 @@ -query GetAppRating($app_id: String!) { - app_metadata(where: { app_id: { _eq: $app_id } }) { - app_rating - } -} diff --git a/web/api/helpers/app-rating/index.ts b/web/api/helpers/app-rating/index.ts deleted file mode 100644 index 639b82250..000000000 --- a/web/api/helpers/app-rating/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -"use server"; -import { getAPIServiceGraphqlClient } from "../graphql"; -import { getSdk as getAppRatingSdk } from "./graphql/get-app-rating.generated"; - -// Helper function to get rating with Redis caching -export async function getAppRating(appId: string): Promise { - const redisKey = `app:${appId}:rating`; - const lockKey = `lock:${appId}:rating`; - - const redis = global.RedisClient; - - if (!redis) { - throw new Error("Redis client not found"); - } - - try { - // Try to get from cache first - let rating = await redis.get(redisKey); - - if (rating !== null) { - return parseFloat(rating); - } - - // Try to acquire lock - const acquiredLock = await redis.set(lockKey, "pending", "EX", 30); - - if (!acquiredLock) { - for (let i = 0; i < 3; i++) { - await new Promise((resolve) => setTimeout(resolve, 1000)); - rating = await redis.get(redisKey); - if (rating !== null) { - return parseFloat(rating); - } - } - - console.warn("Lock timeout for app rating calculation", { appId }); - } - - const client = await getAPIServiceGraphqlClient(); - - // Calculate rating from DB - const result = await getAppRatingSdk(client).GetAppRating({ - app_id: appId, - }); - - const calculatedRating = result.app_metadata[0].app_rating ?? 0; - - // Cache for 24 hours - await redis.set(redisKey, calculatedRating.toString(), "EX", 24 * 60 * 60); - - return calculatedRating; // Return as float - } catch (error) { - console.warn("Error getting app rating with cache", { error, appId }); - return 0; // Return 0 if there's an error - } finally { - try { - await redis.del(lockKey); - await redis.quit(); // TODO: Remove this logic - } catch (redisError) { - console.error("Error closing Redis connection", { redisError }); - } - } -} diff --git a/web/api/helpers/app-store.ts b/web/api/helpers/app-store.ts index 66b2b4a8b..d05d5e9fc 100644 --- a/web/api/helpers/app-store.ts +++ b/web/api/helpers/app-store.ts @@ -20,9 +20,12 @@ export const formatAppMetadata = async ( (stat) => stat.app_id === appMetadata.app_id, ); - // const appRating = await getAppRating(appMetadata.app_id); - - const appRating = 0; + const appRating = + appData.app.rating_count > 0 + ? parseFloat( + (appData.app.rating_sum / appData.app.rating_count).toFixed(2), + ) + : 0; const localisedContent = appMetadata.localisations?.[0]; @@ -51,7 +54,7 @@ export const formatAppMetadata = async ( return { ...appMetadataWithoutLocalisations, name: name, - app_rating: appRating, + app_rating: appRating ?? 0, world_app_button_text: localisedContent?.world_app_button_text ?? appMetadata.world_app_button_text, diff --git a/web/api/helpers/app-rating/graphql/get-app-rating.generated.ts b/web/api/v2/app/submit-app-review/graphql/fetch-current-app-review.generated.ts similarity index 63% rename from web/api/helpers/app-rating/graphql/get-app-rating.generated.ts rename to web/api/v2/app/submit-app-review/graphql/fetch-current-app-review.generated.ts index c91b17685..48e5495ce 100644 --- a/web/api/helpers/app-rating/graphql/get-app-rating.generated.ts +++ b/web/api/v2/app/submit-app-review/graphql/fetch-current-app-review.generated.ts @@ -4,22 +4,25 @@ import * as Types from "@/graphql/graphql"; import { GraphQLClient, RequestOptions } from "graphql-request"; import gql from "graphql-tag"; type GraphQLClientRequestHeaders = RequestOptions["requestHeaders"]; -export type GetAppRatingQueryVariables = Types.Exact<{ +export type GetAppReviewQueryVariables = Types.Exact<{ app_id: Types.Scalars["String"]["input"]; + nullifier_hash: Types.Scalars["String"]["input"]; }>; -export type GetAppRatingQuery = { +export type GetAppReviewQuery = { __typename?: "query_root"; - app_metadata: Array<{ - __typename?: "app_metadata"; - app_rating?: number | null; - }>; + app_reviews: Array<{ __typename?: "app_reviews"; rating: number }>; }; -export const GetAppRatingDocument = gql` - query GetAppRating($app_id: String!) { - app_metadata(where: { app_id: { _eq: $app_id } }) { - app_rating +export const GetAppReviewDocument = gql` + query GetAppReview($app_id: String!, $nullifier_hash: String!) { + app_reviews( + where: { + nullifier_hash: { _eq: $nullifier_hash } + app_id: { _eq: $app_id } + } + ) { + rating } } `; @@ -43,17 +46,17 @@ export function getSdk( withWrapper: SdkFunctionWrapper = defaultWrapper, ) { return { - GetAppRating( - variables: GetAppRatingQueryVariables, + GetAppReview( + variables: GetAppReviewQueryVariables, requestHeaders?: GraphQLClientRequestHeaders, - ): Promise { + ): Promise { return withWrapper( (wrappedRequestHeaders) => - client.request(GetAppRatingDocument, variables, { + client.request(GetAppReviewDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders, }), - "GetAppRating", + "GetAppReview", "query", variables, ); diff --git a/web/api/v2/app/submit-app-review/graphql/fetch-current-app-review.graphql b/web/api/v2/app/submit-app-review/graphql/fetch-current-app-review.graphql new file mode 100644 index 000000000..e7e1a751b --- /dev/null +++ b/web/api/v2/app/submit-app-review/graphql/fetch-current-app-review.graphql @@ -0,0 +1,10 @@ +query GetAppReview($app_id: String!, $nullifier_hash: String!) { + app_reviews( + where: { + nullifier_hash: { _eq: $nullifier_hash } + app_id: { _eq: $app_id } + } + ) { + rating + } +} diff --git a/web/api/v2/app/submit-app-review/graphql/update-review-counter.generated.ts b/web/api/v2/app/submit-app-review/graphql/update-review-counter.generated.ts new file mode 100644 index 000000000..b88d8091f --- /dev/null +++ b/web/api/v2/app/submit-app-review/graphql/update-review-counter.generated.ts @@ -0,0 +1,68 @@ +/* eslint-disable import/no-relative-parent-imports -- auto generated file */ +import * as Types from "@/graphql/graphql"; + +import { GraphQLClient, RequestOptions } from "graphql-request"; +import gql from "graphql-tag"; +type GraphQLClientRequestHeaders = RequestOptions["requestHeaders"]; +export type UpdateAppRatingSumMutationMutationVariables = Types.Exact<{ + app_id: Types.Scalars["String"]["input"]; + rating: Types.Scalars["Int"]["input"]; +}>; + +export type UpdateAppRatingSumMutationMutation = { + __typename?: "mutation_root"; + update_app?: { + __typename?: "app_mutation_response"; + affected_rows: number; + } | null; +}; + +export const UpdateAppRatingSumMutationDocument = gql` + mutation UpdateAppRatingSumMutation($app_id: String!, $rating: Int!) { + update_app( + where: { id: { _eq: $app_id } } + _inc: { rating_count: 1, rating_sum: $rating } + ) { + affected_rows + } + } +`; + +export type SdkFunctionWrapper = ( + action: (requestHeaders?: Record) => Promise, + operationName: string, + operationType?: string, + variables?: any, +) => Promise; + +const defaultWrapper: SdkFunctionWrapper = ( + action, + _operationName, + _operationType, + _variables, +) => action(); + +export function getSdk( + client: GraphQLClient, + withWrapper: SdkFunctionWrapper = defaultWrapper, +) { + return { + UpdateAppRatingSumMutation( + variables: UpdateAppRatingSumMutationMutationVariables, + requestHeaders?: GraphQLClientRequestHeaders, + ): Promise { + return withWrapper( + (wrappedRequestHeaders) => + client.request( + UpdateAppRatingSumMutationDocument, + variables, + { ...requestHeaders, ...wrappedRequestHeaders }, + ), + "UpdateAppRatingSumMutation", + "mutation", + variables, + ); + }, + }; +} +export type Sdk = ReturnType; diff --git a/web/api/v2/app/submit-app-review/graphql/update-review-counter.graphql b/web/api/v2/app/submit-app-review/graphql/update-review-counter.graphql new file mode 100644 index 000000000..3c06aa67c --- /dev/null +++ b/web/api/v2/app/submit-app-review/graphql/update-review-counter.graphql @@ -0,0 +1,8 @@ +mutation UpdateAppRatingSumMutation($app_id: String!, $rating: Int!) { + update_app( + where: { id: { _eq: $app_id } } + _inc: { rating_count: 1, rating_sum: $rating } + ) { + affected_rows + } +} diff --git a/web/api/v2/app/submit-app-review/index.ts b/web/api/v2/app/submit-app-review/index.ts index 792aa9558..7ec8bd51f 100644 --- a/web/api/v2/app/submit-app-review/index.ts +++ b/web/api/v2/app/submit-app-review/index.ts @@ -10,6 +10,8 @@ import { AppErrorCodes, VerificationLevel } from "@worldcoin/idkit-core"; import { hashToField } from "@worldcoin/idkit-core/hashing"; import { NextRequest, NextResponse } from "next/server"; import * as yup from "yup"; +import { getSdk as fetchAppReview } from "./graphql/fetch-current-app-review.generated"; +import { getSdk as updateReviewCount } from "./graphql/update-review-counter.generated"; import { getSdk as upsertAppReview } from "./graphql/upsert-app-review.generated"; const schema = yup.object({ @@ -93,6 +95,11 @@ export const POST = async (req: NextRequest) => { const serviceClient = await getAPIServiceGraphqlClient(); + const { app_reviews } = await fetchAppReview(serviceClient).GetAppReview({ + nullifier_hash: parsedParams.nullifier_hash, + app_id: app_id, + }); + // Anchor: Insert App Rating or Update App Rating const { insert_app_reviews_one } = await upsertAppReview( serviceClient, @@ -113,6 +120,22 @@ export const POST = async (req: NextRequest) => { }); } + // Anchor: Update App Review Count + let ratingChange = parsedParams.rating; + if (app_reviews.length) { + ratingChange = parsedParams.rating - app_reviews[0].rating; + } + const { update_app } = await updateReviewCount( + serviceClient, + ).UpdateAppRatingSumMutation({ + app_id: app_id, + rating: ratingChange, + }); + + if (!update_app) { + console.warn("Failed to update app review count"); + } + await captureEvent({ event: "action_verify_success", distinctId: `app_review_${app_id}`, diff --git a/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.generated.ts b/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.generated.ts index af5e13452..35b52cff0 100644 --- a/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.generated.ts +++ b/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.generated.ts @@ -47,6 +47,8 @@ export type GetAppMetadataQuery = { }>; app: { __typename?: "app"; + rating_sum: number; + rating_count: number; team: { __typename?: "team"; name?: string | null }; }; }>; @@ -92,6 +94,8 @@ export const GetAppMetadataDocument = gql` team { name } + rating_sum + rating_count } } } diff --git a/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.graphql b/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.graphql index fa429357b..c130c557e 100644 --- a/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.graphql +++ b/web/api/v2/minikit/app-metadata/[app_id]/graphql/get-app-metadata.graphql @@ -37,6 +37,8 @@ query GetAppMetadata($app_id: String!, $locale: String!) { team { name } + rating_sum + rating_count } } } diff --git a/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.generated.ts b/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.generated.ts index 1da934bd0..08009585d 100644 --- a/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.generated.ts +++ b/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.generated.ts @@ -47,6 +47,8 @@ export type GetAppMetadataQuery = { }>; app: { __typename?: "app"; + rating_sum: number; + rating_count: number; team: { __typename?: "team"; name?: string | null }; }; }>; @@ -92,6 +94,8 @@ export const GetAppMetadataDocument = gql` team { name } + rating_sum + rating_count } } } diff --git a/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.graphql b/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.graphql index 4360ea63e..72713c899 100644 --- a/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.graphql +++ b/web/api/v2/public/app/[app_id]/graphql/get-app-metadata.graphql @@ -37,6 +37,8 @@ query GetAppMetadata($app_id: String!, $locale: String!) { team { name } + rating_sum + rating_count } } } diff --git a/web/api/v2/public/apps/graphql/get-app-rankings.generated.ts b/web/api/v2/public/apps/graphql/get-app-rankings.generated.ts index 5f639bedb..341fd48e5 100644 --- a/web/api/v2/public/apps/graphql/get-app-rankings.generated.ts +++ b/web/api/v2/public/apps/graphql/get-app-rankings.generated.ts @@ -48,6 +48,8 @@ export type GetAppsQuery = { }>; app: { __typename?: "app"; + rating_count: number; + rating_sum: number; team: { __typename?: "team"; name?: string | null }; }; }>; @@ -99,6 +101,8 @@ export const GetAppsDocument = gql` team { name } + rating_count + rating_sum } } } diff --git a/web/api/v2/public/apps/graphql/get-app-rankings.graphql b/web/api/v2/public/apps/graphql/get-app-rankings.graphql index c25872702..9f10ba2c6 100644 --- a/web/api/v2/public/apps/graphql/get-app-rankings.graphql +++ b/web/api/v2/public/apps/graphql/get-app-rankings.graphql @@ -43,6 +43,8 @@ query GetApps($limit: Int!, $offset: Int!, $locale: String!) { team { name } + rating_count + rating_sum } } } diff --git a/web/api/v2/public/apps/graphql/get-highlighted-apps.generated.ts b/web/api/v2/public/apps/graphql/get-highlighted-apps.generated.ts index 7a2cb16cf..b211fec2d 100644 --- a/web/api/v2/public/apps/graphql/get-highlighted-apps.generated.ts +++ b/web/api/v2/public/apps/graphql/get-highlighted-apps.generated.ts @@ -51,6 +51,8 @@ export type GetHighlightsQuery = { }>; app: { __typename?: "app"; + rating_count: number; + rating_sum: number; team: { __typename?: "team"; name?: string | null }; }; }>; @@ -108,6 +110,8 @@ export const GetHighlightsDocument = gql` team { name } + rating_count + rating_sum } } } diff --git a/web/api/v2/public/apps/graphql/get-highlighted-apps.graphql b/web/api/v2/public/apps/graphql/get-highlighted-apps.graphql index c8ef6c298..8fa793a2b 100644 --- a/web/api/v2/public/apps/graphql/get-highlighted-apps.graphql +++ b/web/api/v2/public/apps/graphql/get-highlighted-apps.graphql @@ -50,6 +50,8 @@ query GetHighlights( team { name } + rating_count + rating_sum } } } diff --git a/web/components/Category/index.tsx b/web/components/Category/index.tsx index 03add2cd2..d35ffcb22 100644 --- a/web/components/Category/index.tsx +++ b/web/components/Category/index.tsx @@ -70,7 +70,9 @@ export const CategorySelector = (props: { return ( ({ + getSdk: () => ({ + UpdateAppRatingSumMutation, + }), + })), +); + +jest.mock( + "../../../../api/v2/app/submit-app-review/graphql/fetch-current-app-review.generated.ts", + jest.fn(() => ({ + getSdk: () => ({ + GetAppReview, + }), + })), +); + global.fetch = jest.fn(() => Promise.resolve({ json: jest.fn(() => Promise.resolve({})), @@ -50,6 +70,20 @@ describe("/api/v2/app/submit-app-review", () => { }, }); + UpdateAppRatingSumMutation.mockResolvedValue({ + update_app: { + affected_rows: 1, + }, + }); + + GetAppReview.mockResolvedValue({ + app_reviews: [ + { + rating: 3, + }, + ], + }); + const res = await POST(mockReq); expect(res.status).toBe(200); }); diff --git a/web/tests/api/v2/minikit-app-metadata.test.ts b/web/tests/api/v2/minikit-app-metadata.test.ts index 3240e7c99..7f113c702 100644 --- a/web/tests/api/v2/minikit-app-metadata.test.ts +++ b/web/tests/api/v2/minikit-app-metadata.test.ts @@ -28,10 +28,6 @@ jest.mock( }), ); -jest.mock("@/api/helpers/app-rating", () => ({ - getAppRating: jest.fn().mockResolvedValue(3.4), -})); - // #endregion const createMockRequest = (params: { @@ -87,9 +83,8 @@ const validAppMetadataResponse = [ support_link: "mailto:test@test.com", supported_countries: ["us"], supported_languages: ["en"], - app_rating: 0, associated_domains: ["https://worldcoin.org"], - app: { team: { name: "test" } }, + app: { team: { name: "test" }, rating_sum: 10, rating_count: 3 }, }, ]; @@ -127,7 +122,7 @@ const app_metadata = { supported_countries: ["us"], supported_languages: ["en"], associated_domains: ["https://worldcoin.org"], - app_rating: 0, + app_rating: 3.33, unique_users: 0, impressions: 0, team_name: "test", @@ -184,8 +179,7 @@ describe("/api/v2/minikit/app-metadata/[app_id] [success cases]", () => { associated_domains: ["https://worldcoin.org"], supported_countries: ["us"], supported_languages: ["en"], - app_rating: 0, - app: { team: { name: "test" } }, + app: { team: { name: "test" }, rating_sum: 10, rating_count: 3 }, }, ], }); @@ -223,7 +217,7 @@ describe("/api/v2/minikit/app-metadata/[app_id] [success cases]", () => { support_link: "mailto:test@test.com", supported_countries: ["us"], supported_languages: ["en"], - app_rating: 0, + app_rating: 3.33, unique_users: 0, impressions: 0, team_name: "test", diff --git a/web/tests/api/v2/public/apps/app.test.ts b/web/tests/api/v2/public/apps/app.test.ts index e8653cd55..71754db52 100644 --- a/web/tests/api/v2/public/apps/app.test.ts +++ b/web/tests/api/v2/public/apps/app.test.ts @@ -37,12 +37,13 @@ jest.mock( contracts: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], permit2_tokens: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], supported_languages: ["en", "es"], - app_rating: 0, verification_status: "unverified", app: { team: { name: "Example Team", }, + rating_sum: 10, + rating_count: 3, }, }, ], @@ -51,10 +52,6 @@ jest.mock( }), ); -jest.mock("@/api/helpers/app-rating", () => ({ - getAppRating: jest.fn().mockResolvedValue(3.4), -})); - describe("/api/public/app/[app_id]", () => { test("Returns correct value for valid unverified app", async () => { const request = new NextRequest("https://cdn.test.com/api/public/app/1", { @@ -92,7 +89,7 @@ describe("/api/public/app/[app_id]", () => { support_link: "andy@gmail.com", supported_countries: ["us"], supported_languages: ["en", "es"], - app_rating: 0, + app_rating: 3.33, unique_users: 0, impressions: 0, verification_status: "unverified", @@ -136,12 +133,13 @@ describe("/api/public/app/[app_id]", () => { contracts: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], permit2_tokens: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], supported_languages: ["en", "es"], - app_rating: 0, verification_status: "verified", app: { team: { name: "Example Team", }, + rating_sum: 10, + rating_count: 3, }, }, ], @@ -158,6 +156,7 @@ describe("/api/public/app/[app_id]", () => { app_data: { name: "Example App", app_id: "1", + app_rating: 3.33, short_name: "test", logo_img_url: "https://cdn.test.com/1/logo.png", showcase_img_urls: [ @@ -183,7 +182,6 @@ describe("/api/public/app/[app_id]", () => { support_link: "andy@gmail.com", supported_countries: ["us"], supported_languages: ["en", "es"], - app_rating: 0, unique_users: 0, impressions: 0, verification_status: "verified", @@ -236,11 +234,12 @@ describe("/api/public/app/[app_id]", () => { permit2_tokens: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], supported_countries: ["us"], supported_languages: ["en", "es"], - app_rating: 0, app: { team: { name: "Example Team", }, + rating_sum: 10, + rating_count: 3, }, }, ], @@ -272,7 +271,7 @@ describe("/api/public/app/[app_id]", () => { associated_domains: ["https://worldcoin.org"], contracts: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], permit2_tokens: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], - app_rating: 0, + app_rating: 3.33, unique_users: 0, impressions: 0, whitelisted_addresses: ["0x1234", "0x5678"], diff --git a/web/tests/api/v2/public/apps/apps.test.ts b/web/tests/api/v2/public/apps/apps.test.ts index 86a9da83c..379cff0fe 100644 --- a/web/tests/api/v2/public/apps/apps.test.ts +++ b/web/tests/api/v2/public/apps/apps.test.ts @@ -43,15 +43,8 @@ jest.mock( }), ); -jest.mock("@/api/helpers/app-rating", () => ({ - getAppRating: jest.fn().mockResolvedValue(3.4), -})); - beforeEach(() => { jest.resetAllMocks(); - - const { getAppRating } = require("@/api/helpers/app-rating"); - getAppRating.mockResolvedValue(3.4); }); describe("/api/v2/public/apps", () => { @@ -131,6 +124,8 @@ describe("/api/v2/public/apps", () => { team: { name: "Example Team", }, + rating_sum: 10, + rating_count: 3, }, }, { @@ -158,6 +153,8 @@ describe("/api/v2/public/apps", () => { team: { name: "Example Team", }, + rating_sum: 10, + rating_count: 3, }, }, { @@ -189,6 +186,8 @@ describe("/api/v2/public/apps", () => { team: { name: "Example Team", }, + rating_sum: 10, + rating_count: 3, }, }, ], @@ -232,7 +231,7 @@ describe("/api/v2/public/apps", () => { }, world_app_button_text: "random", world_app_description: "random", - app_rating: 0, + app_rating: 3.33, verification_status: "verified", }, { @@ -263,7 +262,7 @@ describe("/api/v2/public/apps", () => { team_name: "Example Team", world_app_button_text: "random", world_app_description: "random", - app_rating: 0, + app_rating: 3.33, verification_status: "verified", }, { @@ -282,7 +281,7 @@ describe("/api/v2/public/apps", () => { whitelisted_addresses: ["0x1234", "0x5678"], unique_users: 0, impressions: 0, - app_rating: 0, + app_rating: 3.33, app_mode: "mini-app", associated_domains: ["https://worldcoin.org"], contracts: ["0x0c892815f0B058E69987920A23FBb33c834289cf"], @@ -348,6 +347,8 @@ describe("/api/v2/public/apps", () => { team: { name: "Example Team", }, + rating_sum: 10, + rating_count: 3, }, }, ], @@ -387,7 +388,7 @@ describe("/api/v2/public/apps", () => { supported_languages: ["en", "es"], ratings_external_nullifier: "0x00ca597c4f12f9f85a633bb04cfdc877af7c2d91a6c1c7fe45031b495a227a58", - app_rating: 0, + app_rating: 3.33, unique_users: 0, impressions: 0, whitelisted_addresses: ["0x1234", "0x5678"],