Skip to content

Commit

Permalink
Add ZkBadgeAppConfig (sismo-core#154)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: leo Sayous <[email protected]>
  • Loading branch information
gabin54 and leosayous21 authored Jul 10, 2023
1 parent f009c9d commit f12e8f4
Show file tree
Hide file tree
Showing 79 changed files with 23,242 additions and 329 deletions.
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ POSTGRES_DATABASE=""

# The URL of the Sismo API Hub
NEXT_PUBLIC_HUB_API_URL="https://hub.sismo.io"

# Defender ZK Badge relayer
SH_RELAY_DEFENDER_API_KEYS={"mumbai": { "key": "", "secret": ""}}

# Zk Badge contract addresses
NEXT_PUBLIC_ZK_BADGE_ADDRESSES={ "mumbai": "", "sepolia": ""}
14 changes: 12 additions & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
{
"tabWidth": 2,
"printWidth": 100
}
"printWidth": 100,

"overrides": [
{
"files": "*.sol",
"options": {
"tabWidth": 2,
"printWidth": 100
}
}
]
}
5 changes: 4 additions & 1 deletion jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@

// Used for __tests__/testing-library.js
// Learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect'
import '@testing-library/jest-dom/extend-expect'
const { TextEncoder } = require('text-encoding');

global.TextEncoder = TextEncoder;
21 changes: 8 additions & 13 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,14 @@ const nextConfig = {
sassOptions: {
additionalData: `@use "styles/color" as color; @use "styles/mixin" as mixin;`,
includePaths: [path.join(__dirname, 'src')],
},
compiler: {
styledComponents: true
}
// redirects: async () => {
// return [
// {
// source: "/the-merge-contributors",
// destination: "/space/the-merge-contributors",
// permanent: true
// },
// ]
// }
},
compiler: {
styledComponents: true
},
webpack: config => {
config.resolve.fallback = { fs: false, net: false, tls: false };
return config;
},
}

module.exports = nextConfig
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@
},
"dependencies": {
"@google-cloud/local-auth": "^2.1.1",
"@rainbow-me/rainbowkit": "^1.0.5",
"@sismo-core/sismo-connect-react": "^0.0.16",
"@sismo-core/sismo-connect-server": "^0.0.16",
"@types/luxon": "^3.3.0",
"@types/node": "18.16.1",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.1",
"aws-sdk": "^2.1411.0",
"axios": "^1.4.0",
"bufferutil": "^4.0.7",
"classnames": "^2.3.2",
"defender-autotask-utils": "^1.44.0",
"defender-relay-client": "^1.44.0",
"eslint": "8.39.0",
"eslint-config-next": "13.3.1",
"ethers": "5.6.2",
"google-auth-library": "^8.7.0",
"googleapis": "^118.0.0",
"luxon": "^3.3.0",
Expand All @@ -40,9 +45,12 @@
"server-only": "^0.0.1",
"sharp": "^0.32.1",
"styled-components": "^6.0.0-beta.15",
"text-encoding": "^0.7.0",
"typeorm": "^0.3.17",
"typescript": "5.0.4",
"utf-8-validate": "^6.0.3"
"utf-8-validate": "^6.0.3",
"viem": "^1.2.12",
"wagmi": "^1.3.7"
},
"devDependencies": {
"@testing-library/jest-dom": "5.16.4",
Expand Down
1 change: 0 additions & 1 deletion space-configs/main/sismo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export default {
"Future of France is an invitation-only event during EthCC week in Paris, organized by French-based crypto startups. The number of tickets is limited. Exclusive for members of Sismo Community Level 3.",
tags: ["Event", "Ticket"],
image: "sismo_appstore_fof_tickets.png",

createdAt: new Date("2023-07-03T18:00"),
},
sismoConnectRequest: {
Expand Down
25 changes: 18 additions & 7 deletions space-configs/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Network } from "@/src/libs/contracts/networks";
import { AuthRequest, ClaimRequest } from "@sismo-core/sismo-connect-react";

export type SpaceConfig = {
Expand Down Expand Up @@ -53,12 +54,11 @@ type AppCommonConfig = {
};
};

export type ExternalAppTemplateConfig = {
link: string;
};
export type ExternalAppConfig = AppCommonConfig & {
type: "external";
templateConfig: ExternalAppTemplateConfig;
templateConfig: {
link: string;
};
};

export type UserSelection = FirstComeFirstServed | Lottery;
Expand Down Expand Up @@ -86,14 +86,25 @@ export type ZkDropAppConfig = AppCommonConfig & {
};
};

export type ZkBadgeChainName = Network.Gnosis | Network.Mumbai | Network.Sepolia;
export type ZkBadgeAppConfig = AppCommonConfig & {
type: "zkbadge";
type: "zkBadge";
templateConfig: {
step1CtaText?: string;
step2CtaText: string;
appDescription?: string;
chainId: number;
collectionId: string;
tokenId: string;
badgeMetadata: {
name: string;
description: string;
image: string;
};
chains: [
{
name: ZkBadgeChainName;
relayerEnabled?: boolean;
}
];
};
};

Expand Down
10 changes: 6 additions & 4 deletions src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getApps, getSpaces } from "../../libs/spaces/spaces";
import { SpaceType, ZkAppType } from "../../libs/spaces";

import { SpaceType, ZkAppType } from "../../services/spaces-service";
import HomeMain from "@/src/components/HomeMain";
import env from "@/src/environments";
import ServiceFactory from "@/src/services/service-factory/service-factory";

export type SpaceImportedImage = {
config: SpaceType;
Expand Down Expand Up @@ -38,9 +39,10 @@ export async function generateMetadata() {
}

export default async function HomePage() {
const spaces: SpaceType[] = await getSpaces();
const apps: ZkAppType[] = await getApps({ sortedBy: "createdAt" });
const spacesService = ServiceFactory.getSpacesService();

const spaces: SpaceType[] = await spacesService.getSpaces();
const apps: ZkAppType[] = await spacesService.getApps({ sortedBy: "createdAt" });

return <>{spaces && <HomeMain spaces={spaces} apps={apps}/>}</>;
}
15 changes: 11 additions & 4 deletions src/app/[...app]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import 'server-only';
import env from "@/src/environments";
import { ClaimRequest } from "@sismo-core/sismo-connect-server";
import { notFound } from "next/navigation";
import { ZkAppType, getApps, getSpaces } from "@/src/libs/spaces";
import { ZkAppType } from "@/src/services/spaces-service";
import { GroupProvider, GroupSnapshotMetadata } from "@/src/libs/group-provider";
import AppMain from "@/src/components/AppMain";
import ServiceFactory from '@/src/services/service-factory/service-factory';

// This function runs at build time on the server it generates the static paths for each page
export async function generateStaticParams() {
const spaces = await getSpaces();
const spacesService = ServiceFactory.getSpacesService();

const spaces = await spacesService.getSpaces();
type ZkAppTypeWithSpaceSlug = ZkAppType & {
spaceSlug: string;
};
Expand Down Expand Up @@ -37,11 +40,13 @@ export async function generateStaticParams() {

// This function runs at build time on the server it generates the HTML metadata for each page
export async function generateMetadata({ params }: { params: { app: [string, string] } }) {
const spacesService = ServiceFactory.getSpacesService();

let app: ZkAppType;
let appImage;
try {
const { app: slug } = params;
const apps = await getApps({ where: { spaceSlug: slug[0], appSlug: slug[1] } });
const apps = await spacesService.getApps({ where: { spaceSlug: slug[0], appSlug: slug[1] } });
if (apps.length !== 1) return notFound();
app = apps[0];

Expand Down Expand Up @@ -78,9 +83,11 @@ export async function generateMetadata({ params }: { params: { app: [string, str

// This function runs at build time on the server it generates the HTML for each page
export default async function AppPage({ params }: { params: { app: [string, string] } }) {
const spacesService = ServiceFactory.getSpacesService();

const { app: slug } = params;

const apps = await getApps({ where: { spaceSlug: slug[0], appSlug: slug[1] } });
const apps = await spacesService.getApps({ where: { spaceSlug: slug[0], appSlug: slug[1] } });
if (apps.length !== 1) return notFound();
const app = apps[0];

Expand Down
24 changes: 19 additions & 5 deletions src/app/[space]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import getImgSrcFromConfig, { ImportedNextImage } from "@/src/utils/getImgSrcFromConfig";
import { notFound } from "next/navigation";
import SpacesMain from "@/src/components/SpacesMain";
import { SpaceType, ZkAppType, getSpace, getSpaces } from "@/src/libs/spaces";
import { SpaceType, ZkAppType } from "@/src/services/spaces-service";
import ServiceFactory from "@/src/services/service-factory/service-factory";

// This function runs at build time on the server it generates the static paths for each page
export async function generateStaticParams() {
const spaces = await getSpaces();
const spacesService = ServiceFactory.getSpacesService();

const spaces = await spacesService.getSpaces();
return spaces?.map((space: SpaceType) => {
return {
space: space.slug,
Expand All @@ -15,11 +18,17 @@ export async function generateStaticParams() {

// This function runs at build time on the server it generates the HTML metadata for each page
export async function generateMetadata({ params }: { params: { space: string } }) {
const spacesService = ServiceFactory.getSpacesService();

let space: SpaceType;
let imageMetadata: string;
try {
const { space: slug } = params;
space = await getSpace({ slug: slug });
const spaces = await spacesService.getSpaces({ where: { spaceSlug: slug } });
if (!spaces || spaces.length !== 1) {
notFound();
}
space = spaces[0];
let pfpImage;
if (typeof space?.profileImage === "string") {
pfpImage = await getImgSrcFromConfig({
Expand Down Expand Up @@ -68,11 +77,16 @@ export type ImportedImage = {

// This function runs at build time on the server it generates the HTML for each page
export default async function SpacePage({ params }: { params: { space: string } }) {
const spacesService = ServiceFactory.getSpacesService();

let space: SpaceType;
try {
const { space: slug } = params;
const _space = await getSpace({ slug: slug });
space = _space;
const _spaces = await spacesService.getSpaces({ where: { spaceSlug: slug } });
if (!_spaces || _spaces?.length !== 1) {
notFound();
}
space = _spaces[0];
} catch (e) {
notFound();
}
Expand Down
67 changes: 67 additions & 0 deletions src/app/api/zk-badge/image/[tokenId]/route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* @jest-environment node
*/
import ServiceFactory from "@/src/services/service-factory/service-factory";
import { GET } from "../../image/[tokenId]/route";
import { spaceMock1, spaceMock2 } from "@/src/services/spaces-service/tests/spaces-mock";
import fs from 'fs';
import path from 'path';


describe('GET /api/zk-badge/image/[tokenId]', () => {

beforeEach(() => {
let spacesService = ServiceFactory.getSpacesService();
const configs = [
spaceMock1,
spaceMock2
]
spacesService.updateConfigs(configs);
})

afterEach(() => {
let configs = ServiceFactory.getSpaceConfigs();
let spacesService = ServiceFactory.getSpacesService();
spacesService.updateConfigs(configs);
jest.clearAllMocks();
})

it('should return an error response if no badge is found', async () => {
const params = { tokenId: "1234" };
const response = await GET(null, { params });
const data = await response.json();
expect(data).toEqual({ error: 'No badge found for tokenId: 1234' });
});

it('should return an error response if no badge image is found', async () => {
const params = { tokenId: "40000001" };
const response = await GET(null, { params });
const data = await response.json();
expect(data).toEqual({ error: 'No badge image found for tokenId: 40000001' });
});

it('should return an image response if a badge is found', async () => {
jest.spyOn(fs, 'readFileSync');

const params = { tokenId: "40000001" };
const dummyImageBuffer = Buffer.from([0, 1, 2, 3, 4, 5]);
const imagePath = path.join(process.cwd(), '/space-config/space/images/image.png');

(fs.readFileSync as jest.Mock).mockImplementation((path) => {
if (path === imagePath) {
return dummyImageBuffer;
}
});

const response = await GET(null, { params });

const reader = response.body.getReader();
const result = await reader.read();

const data = Buffer.from(result.value);

expect(Buffer.compare(data, dummyImageBuffer)).toEqual(0);
expect(response.status).toEqual(200);
expect(response.headers.get('Content-Type')).toEqual('image/jpeg');
});
});
Loading

0 comments on commit f12e8f4

Please sign in to comment.