diff --git a/apps/scoutgame/__e2e__/UserPage/buyNft.spec.ts b/apps/scoutgame/__e2e__/UserPage/buyNft.spec.ts
index 1d9d4aeb64..b115a729c6 100644
--- a/apps/scoutgame/__e2e__/UserPage/buyNft.spec.ts
+++ b/apps/scoutgame/__e2e__/UserPage/buyNft.spec.ts
@@ -1,10 +1,6 @@
-import { prisma } from '@charmverse/core/prisma-client';
import { getBuilderContractAddress } from '@packages/scoutgame/builderNfts/constants';
import { currentSeason } from '@packages/scoutgame/dates';
import { mockBuilder, mockBuilderNft } from '@packages/scoutgame/testing/database';
-import { delay } from '@root/lib/utils/async';
-import { custom, http } from 'viem';
-import { optimism } from 'viem/chains';
import { expect, test } from '../test';
@@ -37,7 +33,10 @@ test.describe('Buy Nft', () => {
});
await userPage.mockNftAPIs({
- builder,
+ builder: {
+ id: builder.id,
+ path: builder.path!
+ },
isSuccess: true
});
@@ -45,8 +44,8 @@ test.describe('Buy Nft', () => {
await page.goto(`/home`);
await page.waitForURL('**/home');
- await page.goto(`/u/${builder.username}`);
- await page.waitForURL(`**/u/${builder.username}`);
+ await page.goto(`/u/${builder.path}`);
+ await page.waitForURL(`**/u/${builder.path}`);
// Card CTA button
const scoutButton = page.locator('data-test=scout-button').first();
diff --git a/apps/scoutgame/__e2e__/po/UserPage.po.ts b/apps/scoutgame/__e2e__/po/UserPage.po.ts
index 59772ce09d..94af1afe16 100644
--- a/apps/scoutgame/__e2e__/po/UserPage.po.ts
+++ b/apps/scoutgame/__e2e__/po/UserPage.po.ts
@@ -7,13 +7,7 @@ export class UserPage extends GeneralPageLayout {
super(page);
}
- async mockNftAPIs({
- builder,
- isSuccess
- }: {
- builder: { id: string; username?: string | null; path?: string | null };
- isSuccess: boolean;
- }) {
+ async mockNftAPIs({ builder, isSuccess }: { builder: { id: string; path: string }; isSuccess: boolean }) {
// Used for debugging all routes. Keep caution as the next page.route() function will not run anymore.
// await page.route('**', (route) => {
// console.log('Intercepted URL:', route.request().url());
@@ -139,7 +133,7 @@ export class UserPage extends GeneralPageLayout {
});
// Mocking server action to handle the pending transaction and mint the NFT without calling decent
- await this.page.route(`**/u/${builder.username}`, async (route) => {
+ await this.page.route(`**/u/${builder.path}`, async (route) => {
const method = route.request().method();
const body = route.request().postDataJSON()?.[0];
diff --git a/apps/scoutgame/app/(general)/claim/page.tsx b/apps/scoutgame/app/(general)/claim/page.tsx
index 04983e590e..69348f3e83 100644
--- a/apps/scoutgame/app/(general)/claim/page.tsx
+++ b/apps/scoutgame/app/(general)/claim/page.tsx
@@ -25,7 +25,7 @@ export default async function Claim({ searchParams }: { searchParams: { tab: str
return (
diff --git a/apps/scoutgame/app/(general)/profile/page.tsx b/apps/scoutgame/app/(general)/profile/page.tsx
index 051864173a..a70c3ff6df 100644
--- a/apps/scoutgame/app/(general)/profile/page.tsx
+++ b/apps/scoutgame/app/(general)/profile/page.tsx
@@ -44,7 +44,7 @@ export default async function Profile({
{
- const user = await getUserByPath(params.username);
+export async function generateMetadata({ params }: Props, parent: ResolvingMetadata): Promise {
+ const user = await getUserByPath(params.path);
if (!user) {
return {};
@@ -24,19 +24,19 @@ export async function generateMetadata({ params, searchParams }: Props, parent:
const previousOg = previousMetadata.openGraph || ({} as ResolvedOpenGraph);
return {
- title: `${user.username} user profile`,
+ title: `${user.displayName} user profile`,
openGraph: {
images: user.nftImageUrl || user.avatar || previousOg.images || '',
- title: `${user.username} user profile`
+ title: `${user.displayName} user profile`
},
twitter: {
- title: `${user.username} user profile`
+ title: `${user.displayName} user profile`
}
};
}
export default async function Profile({ params, searchParams }: Props) {
- const user = await getUserByPath(params.username);
+ const user = await getUserByPath(params.path);
const tab = searchParams.tab || (user?.builderStatus === 'approved' ? 'builder' : 'scout');
if (!user || typeof tab !== 'string') {
diff --git a/apps/scoutgame/app/api/builders/search/route.ts b/apps/scoutgame/app/api/builders/search/route.ts
index 52a7801aeb..9eb2cc7b14 100644
--- a/apps/scoutgame/app/api/builders/search/route.ts
+++ b/apps/scoutgame/app/api/builders/search/route.ts
@@ -4,18 +4,18 @@ import { searchBuilders } from 'lib/builders/searchBuilders';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
- const username = searchParams.get('username');
- if (typeof username !== 'string') {
- return new Response('username is required', { status: 400 });
+ const search = searchParams.get('search');
+ if (typeof search !== 'string') {
+ return new Response('path is required', { status: 400 });
}
try {
const result = await searchBuilders({
- username
+ search
});
return Response.json(result);
} catch (error) {
- log.error('Error requesting user from farcaster', { error, username });
+ log.error('Error requesting user from farcaster', { error, search });
return new Response(`Unknown error: ${(error as Error).message}`, { status: 500 });
}
}
diff --git a/apps/scoutgame/app/api/session/refresh/route.ts b/apps/scoutgame/app/api/session/refresh/route.ts
index 8f66ebc842..5f7fb3e835 100644
--- a/apps/scoutgame/app/api/session/refresh/route.ts
+++ b/apps/scoutgame/app/api/session/refresh/route.ts
@@ -20,7 +20,7 @@ export async function GET(req: NextRequest) {
select: {
bio: true,
displayName: true,
- username: true,
+ path: true,
farcasterId: true
}
});
@@ -35,13 +35,12 @@ export async function GET(req: NextRequest) {
});
if (profile) {
const bio = profile.profile.bio.text;
- const displayName = profile.display_name || profile.username;
- const username = profile.username;
+ const displayName = profile.display_name;
const hasProfileChanged =
// Re-enable this once Neynar fixes their caching mechanism
// scout.avatar !== profile.body.avatarUrl ||
- scout.bio !== bio || scout.displayName !== displayName || scout.username !== username;
+ scout.bio !== bio || scout.displayName !== displayName;
if (hasProfileChanged) {
await prisma.scout.update({
@@ -52,8 +51,7 @@ export async function GET(req: NextRequest) {
// Re-enable this once Neynar fixes their caching mechanism
// avatar: profile.pfp_url,
bio,
- displayName,
- username
+ displayName
}
});
log.info('Updated Farcaster profile', { userId, profile });
diff --git a/apps/scoutgame/components/[username]/FarcasterMetadata.tsx b/apps/scoutgame/components/[path]/FarcasterMetadata.tsx
similarity index 95%
rename from apps/scoutgame/components/[username]/FarcasterMetadata.tsx
rename to apps/scoutgame/components/[path]/FarcasterMetadata.tsx
index 424771cdc3..2799c0a0cb 100644
--- a/apps/scoutgame/components/[username]/FarcasterMetadata.tsx
+++ b/apps/scoutgame/components/[path]/FarcasterMetadata.tsx
@@ -18,7 +18,7 @@ export function FarcasterMetadata({
{/* Button 1 */}
-
+
>
);
}
diff --git a/apps/scoutgame/components/[username]/PublicProfilePage.tsx b/apps/scoutgame/components/[path]/PublicProfilePage.tsx
similarity index 97%
rename from apps/scoutgame/components/[username]/PublicProfilePage.tsx
rename to apps/scoutgame/components/[path]/PublicProfilePage.tsx
index eabc51e813..58f8f6bcf2 100644
--- a/apps/scoutgame/components/[username]/PublicProfilePage.tsx
+++ b/apps/scoutgame/components/[path]/PublicProfilePage.tsx
@@ -34,7 +34,7 @@ export function PublicProfilePage({ user, tab }: { user: UserProfile; tab: strin
{tab === 'builder' ? (
diff --git a/apps/scoutgame/components/[username]/PublicProfileTabsMenu.tsx b/apps/scoutgame/components/[path]/PublicProfileTabsMenu.tsx
similarity index 82%
rename from apps/scoutgame/components/[username]/PublicProfileTabsMenu.tsx
rename to apps/scoutgame/components/[path]/PublicProfileTabsMenu.tsx
index e3450595f8..485eac5378 100644
--- a/apps/scoutgame/components/[username]/PublicProfileTabsMenu.tsx
+++ b/apps/scoutgame/components/[path]/PublicProfileTabsMenu.tsx
@@ -7,20 +7,20 @@ import { TabsMenu } from 'components/common/Tabs/TabsMenu';
export function PublicProfileTabsMenu({
tab,
- username,
+ path,
isApprovedBuilder
}: {
tab: string;
- username: string;
+ path: string;
isApprovedBuilder?: boolean;
}) {
const router = useRouter();
useEffect(() => {
if (!isApprovedBuilder && tab === 'builder') {
- router.push(`/u/${username}/?tab=scout`);
+ router.push(`/u/${path}/?tab=scout`);
}
- }, [isApprovedBuilder, tab, username]);
+ }, [isApprovedBuilder, tab, path]);
return (
{totalUnclaimedPoints === 0 ? null : (
diff --git a/apps/scoutgame/components/claim/components/BuilderRewardsScreen/BuilderRewardsTable.tsx b/apps/scoutgame/components/claim/components/BuilderRewardsScreen/BuilderRewardsTable.tsx
index 3b474c1bd8..4dd53e4a6f 100644
--- a/apps/scoutgame/components/claim/components/BuilderRewardsScreen/BuilderRewardsTable.tsx
+++ b/apps/scoutgame/components/claim/components/BuilderRewardsScreen/BuilderRewardsTable.tsx
@@ -13,11 +13,11 @@ function BuilderRewardsTableRow({ reward }: { reward: BuilderReward }) {
return (
-
+
-
+
- {reward.username}
+ {reward.displayName}
@@ -64,7 +64,7 @@ export function BuilderRewardsTable({
}}
>
{builderRewards.map((reward) => (
-
+
))}
diff --git a/apps/scoutgame/components/claim/components/PointsClaimScreen/PointsClaimScreen.tsx b/apps/scoutgame/components/claim/components/PointsClaimScreen/PointsClaimScreen.tsx
index f43ac532a1..cb2699a526 100644
--- a/apps/scoutgame/components/claim/components/PointsClaimScreen/PointsClaimScreen.tsx
+++ b/apps/scoutgame/components/claim/components/PointsClaimScreen/PointsClaimScreen.tsx
@@ -40,11 +40,11 @@ function PointsClaimSuccessModal({
export function PointsClaimScreen({
totalUnclaimedPoints,
- username,
+ displayName,
bonusPartners
}: {
totalUnclaimedPoints: number;
- username: string;
+ displayName: string;
bonusPartners: string[];
}) {
const { executeAsync, isExecuting, result } = useAction(claimPointsAction);
@@ -98,7 +98,7 @@ export function PointsClaimScreen({
>
- {username} will receive
+ {displayName} will receive
@@ -123,7 +123,7 @@ export function PointsClaimScreen({
) : (
<>
- Hey {username},
+ Hey {displayName},
You have no rewards to claim.
diff --git a/apps/scoutgame/components/common/Card/BuilderCard/BuilderCard.tsx b/apps/scoutgame/components/common/Card/BuilderCard/BuilderCard.tsx
index f3b231b60e..91342887b0 100644
--- a/apps/scoutgame/components/common/Card/BuilderCard/BuilderCard.tsx
+++ b/apps/scoutgame/components/common/Card/BuilderCard/BuilderCard.tsx
@@ -9,7 +9,7 @@ import { ScoutButton } from '../../ScoutButton/ScoutButton';
import { BuilderCardNftDisplay } from './BuilderCardNftDisplay';
import { BuilderCardStats } from './BuilderCardStats';
-type RequiredBuilderInfoFields = 'username' | 'builderStatus' | 'id' | 'path';
+type RequiredBuilderInfoFields = 'displayName' | 'builderStatus' | 'id' | 'path';
export function BuilderCard({
builder,
@@ -36,7 +36,7 @@ export function BuilderCard({
>
theme.breakpoints.down('sm'), { noSsr: true });
- let gemHeight = size === 'x-small' ? 12 : size === 'small' ? 13.5 : size === 'medium' ? 14.5 : 16;
- if (isMobile) {
- gemHeight *= 0.75;
- }
+ const gemHeight = size === 'x-small' || size === 'small' ? 12.5 : size === 'medium' ? 14.5 : 16;
return (
<>
}>
@@ -28,7 +25,7 @@ export function BuilderCardActivity({
flexDirection='row'
gap={{
xs: 0.75,
- md: 1.25
+ md: size === 'medium' || size === 'large' ? 1.25 : 0.75
}}
width='100%'
height={gemHeight}
diff --git a/apps/scoutgame/components/common/Card/BuilderCard/BuilderCardNftDisplay.tsx b/apps/scoutgame/components/common/Card/BuilderCard/BuilderCardNftDisplay.tsx
index 763d498f77..2913e3c832 100644
--- a/apps/scoutgame/components/common/Card/BuilderCard/BuilderCardNftDisplay.tsx
+++ b/apps/scoutgame/components/common/Card/BuilderCard/BuilderCardNftDisplay.tsx
@@ -24,12 +24,12 @@ const nftDisplaySize = {
export function BuilderCardNftDisplay({
nftImageUrl,
children,
- username,
+ path,
showHotIcon = false,
size = 'medium',
hideDetails = false
}: {
- username: string | null;
+ path: string;
nftImageUrl?: string | null;
showHotIcon?: boolean;
children?: React.ReactNode;
@@ -43,7 +43,7 @@ export function BuilderCardNftDisplay({
- @{username}
+ {displayName}
{typeof builderPoints === 'number' && (
@@ -50,7 +51,7 @@ export function BuilderCardStats({
sx={{
fontSize: {
xs: '12px',
- md: '14px'
+ md: mdFontSize
}
}}
component='span'
@@ -69,7 +70,7 @@ export function BuilderCardStats({
sx={{
fontSize: {
xs: '12px',
- md: '14px'
+ md: mdFontSize
}
}}
component='span'
@@ -87,7 +88,7 @@ export function BuilderCardStats({
sx={{
fontSize: {
xs: '12px',
- md: '14px'
+ md: mdFontSize
}
}}
component='span'
@@ -107,7 +108,7 @@ export function BuilderCardStats({
color: 'text.secondary',
fontSize: {
xs: '7.5px',
- md: '10px'
+ md: size === 'medium' || size === 'large' ? '10px' : '8px'
}
}}
>
diff --git a/apps/scoutgame/components/common/Card/ScoutCard.tsx b/apps/scoutgame/components/common/Card/ScoutCard.tsx
index 19d3787a68..9d235bb4e3 100644
--- a/apps/scoutgame/components/common/Card/ScoutCard.tsx
+++ b/apps/scoutgame/components/common/Card/ScoutCard.tsx
@@ -51,17 +51,6 @@ export function ScoutCard({ scout }: { scout: ScoutInfo }) {
>
{scout.displayName}
-
- {scout.username}
-
-
{scout.nfts}
diff --git a/apps/scoutgame/components/common/Gallery/BuildersGallery.tsx b/apps/scoutgame/components/common/Gallery/BuildersGallery.tsx
index fb3ecf706e..10857f67c5 100644
--- a/apps/scoutgame/components/common/Gallery/BuildersGallery.tsx
+++ b/apps/scoutgame/components/common/Gallery/BuildersGallery.tsx
@@ -23,7 +23,7 @@ export function BuildersGallery({
columns={{ xs: 2, sm: 3, md: builders.length < columns ? builders.length : columns }}
>
{builders.map((builder) => (
-
+
{builder.nftsSoldToScout !== undefined && builder.nftsSoldToScout > 0 && (
diff --git a/apps/scoutgame/components/common/Gallery/ScoutsGallery.tsx b/apps/scoutgame/components/common/Gallery/ScoutsGallery.tsx
index ba9527ce6f..5cf2b4e935 100644
--- a/apps/scoutgame/components/common/Gallery/ScoutsGallery.tsx
+++ b/apps/scoutgame/components/common/Gallery/ScoutsGallery.tsx
@@ -9,8 +9,8 @@ export function ScoutsGallery({ scouts }: { scouts: ScoutInfo[] }) {
{scouts.map((scout) => (
-
-
+
+
diff --git a/apps/scoutgame/components/common/Header/Header.tsx b/apps/scoutgame/components/common/Header/Header.tsx
index 9d8934387f..f7fad912c7 100644
--- a/apps/scoutgame/components/common/Header/Header.tsx
+++ b/apps/scoutgame/components/common/Header/Header.tsx
@@ -16,8 +16,6 @@ import { Hidden } from 'components/common/Hidden';
import { SiteNavigation } from 'components/common/SiteNavigation';
import { useUser } from 'components/layout/UserProvider';
-import { InstallAppMenuItem } from './components/InstallAppMenuItem';
-
export function Header() {
const router = useRouter();
const { user, refreshUser } = useUser();
@@ -109,7 +107,7 @@ export function Header() {
alt='Scout Game points icon'
priority={true}
/>
-
+
) : null}
- {displayName || 'N/A'}
- {username || 'N/A'}
-
-
+ {displayName}
+
+
+
+ {githubLogin ? (
+
- {githubLogin ? (
-
-
-
- ) : null}
-
+ ) : null}
)}
- setAuthPopup(false)} path={`/u/${builder.username}`} />
+ setAuthPopup(false)} path={`/u/${builder.path}`} />
);
diff --git a/apps/scoutgame/components/home/components/HomePageTable/components/ActivityTable.tsx b/apps/scoutgame/components/home/components/HomePageTable/components/ActivityTable.tsx
index 8eebac25f4..19c31091aa 100644
--- a/apps/scoutgame/components/home/components/HomePageTable/components/ActivityTable.tsx
+++ b/apps/scoutgame/components/home/components/HomePageTable/components/ActivityTable.tsx
@@ -55,8 +55,8 @@ export function BuilderActivityAction({ activity }: { activity: BuilderActivity
}
}}
>
-
- {activity.scout}
+
+ {activity.scout.displayName}
)}
@@ -125,14 +125,14 @@ export function ActivityTable({ activities }: { activities: BuilderActivity[] })
-
- {activity.username}
+
+ {activity.displayName}
-
- {row.username}
+
+ {row.displayName}
diff --git a/apps/scoutgame/components/home/components/HomePageTable/components/TopBuildersTable.tsx b/apps/scoutgame/components/home/components/HomePageTable/components/TopBuildersTable.tsx
index d556fc81eb..ed00d320b8 100644
--- a/apps/scoutgame/components/home/components/HomePageTable/components/TopBuildersTable.tsx
+++ b/apps/scoutgame/components/home/components/HomePageTable/components/TopBuildersTable.tsx
@@ -45,7 +45,7 @@ export function TopBuildersTable({ builders }: { builders: TopBuilderInfo[] }) {
{builders.map((builder, index) => (
-
- {builder.username}
+
+ {builder.displayName}
diff --git a/apps/scoutgame/components/home/components/HomePageTable/components/TopScoutsTable.tsx b/apps/scoutgame/components/home/components/HomePageTable/components/TopScoutsTable.tsx
index 4f507125c4..2e157a1d38 100644
--- a/apps/scoutgame/components/home/components/HomePageTable/components/TopScoutsTable.tsx
+++ b/apps/scoutgame/components/home/components/HomePageTable/components/TopScoutsTable.tsx
@@ -44,7 +44,7 @@ export function TopScoutsTable({ scouts }: { scouts: TopScout[] }) {
{scouts.map((scout, index) => (
-
- {scout.username}
+
+ {scout.displayName}
diff --git a/apps/scoutgame/components/profile/components/BuilderProfile/BuilderActivitiesList.tsx b/apps/scoutgame/components/profile/components/BuilderProfile/BuilderActivitiesList.tsx
index 21d2db6dc1..cec0021ef2 100644
--- a/apps/scoutgame/components/profile/components/BuilderProfile/BuilderActivitiesList.tsx
+++ b/apps/scoutgame/components/profile/components/BuilderProfile/BuilderActivitiesList.tsx
@@ -34,7 +34,7 @@ export function BuilderActivityDetail({ activity }: { activity: BuilderActivity
return (
{activity.type === 'nft_purchase' ? (
- {activity.scout}
+ {activity.scout.displayName}
) : activity.type === 'github_event' ? (
{activity.repo}
) : null}
diff --git a/apps/scoutgame/components/profile/components/BuilderProfile/BuilderProfile.tsx b/apps/scoutgame/components/profile/components/BuilderProfile/BuilderProfile.tsx
index 8745e49787..fe24a6db8d 100644
--- a/apps/scoutgame/components/profile/components/BuilderProfile/BuilderProfile.tsx
+++ b/apps/scoutgame/components/profile/components/BuilderProfile/BuilderProfile.tsx
@@ -97,7 +97,7 @@ export async function BuilderProfile({ builder }: { builder: BuilderUserInfo })
) : null}
-
+
diff --git a/apps/scoutgame/components/scout/components/SearchBuildersInput.tsx b/apps/scoutgame/components/scout/components/SearchBuildersInput.tsx
index 86386cf862..1a965d077c 100644
--- a/apps/scoutgame/components/scout/components/SearchBuildersInput.tsx
+++ b/apps/scoutgame/components/scout/components/SearchBuildersInput.tsx
@@ -56,7 +56,7 @@ export function SearchBuildersInput() {
}
return (
-
+
-
- {option.username}
+
+ {option.displayName}
@@ -79,7 +79,7 @@ export function SearchBuildersInput() {
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
options={searchResults ?? []}
- getOptionLabel={(option) => option.username}
+ getOptionLabel={(option) => option.displayName}
onInputChange={(event, value) => setSearchTerm(value)}
renderInput={(params) => (
(username ? '/api/builders/search' : null, {
- username
+export function useSearchBuilders(search: string) {
+ return useGETImmutable(search ? '/api/builders/search' : null, {
+ search
});
}
diff --git a/apps/scoutgame/hooks/api/session.ts b/apps/scoutgame/hooks/api/session.ts
index 79443c1b7a..adad79dd90 100644
--- a/apps/scoutgame/hooks/api/session.ts
+++ b/apps/scoutgame/hooks/api/session.ts
@@ -18,7 +18,13 @@ export function useGetUserTrigger() {
}
export function useGetClaimablePoints() {
- return useGETImmutable<{ points: number }>('/api/session/claimable-points');
+ return useGETImmutable<{ points: number }>(
+ '/api/session/claimable-points',
+ {},
+ {
+ refreshInterval: 30000
+ }
+ );
}
export function useGetPendingNftTransactions<
diff --git a/apps/scoutgame/lib/blockchain/findOrCreateWalletUser.ts b/apps/scoutgame/lib/blockchain/findOrCreateWalletUser.ts
index 02fad68b33..2ea0fa784f 100644
--- a/apps/scoutgame/lib/blockchain/findOrCreateWalletUser.ts
+++ b/apps/scoutgame/lib/blockchain/findOrCreateWalletUser.ts
@@ -25,6 +25,6 @@ export async function findOrCreateWalletUser({
avatar: ensDetails?.avatar || undefined,
walletAddress: wallet,
displayName: ens || shortenHex(wallet),
- username: shortenHex(wallet)
+ path: shortenHex(wallet)
});
}
diff --git a/apps/scoutgame/lib/builders/__tests__/getTopBuilders.spec.ts b/apps/scoutgame/lib/builders/__tests__/getTopBuilders.spec.ts
index 69614dffb1..0551a06254 100644
--- a/apps/scoutgame/lib/builders/__tests__/getTopBuilders.spec.ts
+++ b/apps/scoutgame/lib/builders/__tests__/getTopBuilders.spec.ts
@@ -43,7 +43,7 @@ describe('getTopBuilders', () => {
expect(result).toHaveLength(1);
const topBuilder = result[0] as TopBuilderInfo;
expect(topBuilder.id).toBe(builder.id);
- expect(topBuilder.username).toBe(builder.username);
+ expect(topBuilder.path).toBe(builder.path);
expect(topBuilder.seasonPoints).toBe(100);
expect(topBuilder.allTimePoints).toBe(500);
expect(topBuilder.scoutedBy).toBe(2); // Should count unique scouts, not total sales
diff --git a/apps/scoutgame/lib/builders/getBuilderActivities.ts b/apps/scoutgame/lib/builders/getBuilderActivities.ts
index d06298871c..fb43f86405 100644
--- a/apps/scoutgame/lib/builders/getBuilderActivities.ts
+++ b/apps/scoutgame/lib/builders/getBuilderActivities.ts
@@ -9,7 +9,10 @@ export type BuilderActivityType = 'nft_purchase' | 'merged_pull_request';
type NftPurchaseActivity = {
type: 'nft_purchase';
- scout: string;
+ scout: {
+ path: string;
+ displayName: string;
+ };
};
type MergedPullRequestActivity = {
@@ -59,8 +62,8 @@ export async function getBuilderActivities({
select: {
scout: {
select: {
- username: true,
- path: true
+ path: true,
+ displayName: true
}
},
tokensPurchased: true
@@ -91,10 +94,14 @@ export async function getBuilderActivities({
if (event.type === 'nft_purchase' && event.nftPurchaseEvent) {
return {
...event.builder,
+ path: event.builder.path!,
id: event.id,
createdAt: event.createdAt,
type: 'nft_purchase' as const,
- scout: event.nftPurchaseEvent.scout.username || ''
+ scout: {
+ path: event.nftPurchaseEvent.scout.path!,
+ displayName: event.nftPurchaseEvent.scout.displayName
+ }
};
} else if (
(event.type === 'merged_pull_request' || event.type === 'daily_commit') &&
@@ -103,6 +110,7 @@ export async function getBuilderActivities({
) {
return {
...event.builder,
+ path: event.builder.path!,
id: event.id,
createdAt: event.createdAt,
type: 'github_event' as const,
diff --git a/apps/scoutgame/lib/builders/getBuilderRewards.ts b/apps/scoutgame/lib/builders/getBuilderRewards.ts
index c6932ac88b..aefd6e8287 100644
--- a/apps/scoutgame/lib/builders/getBuilderRewards.ts
+++ b/apps/scoutgame/lib/builders/getBuilderRewards.ts
@@ -3,7 +3,8 @@ import { currentSeason } from '@packages/scoutgame/dates';
import { isTruthy } from '@root/lib/utils/types';
export type BuilderReward = {
- username: string;
+ path: string | null;
+ displayName: string;
avatar: string | null;
points: number;
rank: number | null;
@@ -44,7 +45,8 @@ export async function getSeasonBuilderRewards({ userId }: { userId: string }): P
builder: {
select: {
id: true,
- username: true,
+ path: true,
+ displayName: true,
avatar: true
}
}
@@ -71,7 +73,8 @@ export async function getSeasonBuilderRewards({ userId }: { userId: string }): P
if (cardsHeld) {
if (!builderRewardsRecord[builderId]) {
builderRewardsRecord[builderId] = {
- username: builder.username || '',
+ path: builder.path,
+ displayName: builder.displayName,
avatar: builder.avatar,
cardsHeld,
points: 0,
@@ -131,7 +134,8 @@ export async function getWeeklyBuilderRewards({
builder: {
select: {
id: true,
- username: true,
+ path: true,
+ displayName: true,
avatar: true,
userWeeklyStats: {
where: {
@@ -167,10 +171,11 @@ export async function getWeeklyBuilderRewards({
}
return {
rank,
- username: builder.username || '',
+ path: builder.path,
avatar: builder.avatar,
points: receipt.value,
- cardsHeld
+ cardsHeld,
+ displayName: builder.displayName
};
})
.filter(isTruthy)
diff --git a/apps/scoutgame/lib/builders/getBuilderScouts.ts b/apps/scoutgame/lib/builders/getBuilderScouts.ts
index 1dd494d456..251bf717cd 100644
--- a/apps/scoutgame/lib/builders/getBuilderScouts.ts
+++ b/apps/scoutgame/lib/builders/getBuilderScouts.ts
@@ -15,10 +15,7 @@ export async function getBuilderScouts(builderId: string) {
},
select: {
scout: {
- select: {
- displayName: true,
- ...BasicUserInfoSelect
- }
+ select: BasicUserInfoSelect
},
tokensPurchased: true
}
@@ -32,6 +29,7 @@ export async function getBuilderScouts(builderId: string) {
if (!existingScout) {
scoutsRecord[event.scout.id] = {
...event.scout,
+ path: event.scout.path!,
nfts: 0
};
}
diff --git a/apps/scoutgame/lib/builders/getLeaderboard.ts b/apps/scoutgame/lib/builders/getLeaderboard.ts
index 0ba0654639..5eb97bc3c2 100644
--- a/apps/scoutgame/lib/builders/getLeaderboard.ts
+++ b/apps/scoutgame/lib/builders/getLeaderboard.ts
@@ -5,8 +5,8 @@ import { getCurrentWeek, currentSeason } from '@packages/scoutgame/dates';
export type LeaderBoardRow = {
id: string;
avatar: string | null;
- username: string | null;
- path: string | null;
+ displayName: string;
+ path: string;
builderStatus: BuilderStatus;
progress: number;
gemsCollected: number;
@@ -37,8 +37,8 @@ export async function getLeaderboard({ limit = 10 }: { limit: number }): Promise
select: {
id: true,
avatar: true,
- username: true,
path: true,
+ displayName: true,
builderStatus: true,
builderNfts: {
select: {
@@ -61,8 +61,8 @@ export async function getLeaderboard({ limit = 10 }: { limit: number }): Promise
return {
id: weeklyTopBuilder.user.id,
avatar: weeklyTopBuilder.user.avatar,
- username: weeklyTopBuilder.user.username,
- path: weeklyTopBuilder.user.path,
+ displayName: weeklyTopBuilder.user.displayName,
+ path: weeklyTopBuilder.user.path!,
builderStatus: weeklyTopBuilder.user.builderStatus!,
gemsCollected: weeklyTopBuilder.gemsCollected,
progress,
diff --git a/apps/scoutgame/lib/builders/getSortedBuilders.ts b/apps/scoutgame/lib/builders/getSortedBuilders.ts
index 0fd54e9729..18188692d6 100644
--- a/apps/scoutgame/lib/builders/getSortedBuilders.ts
+++ b/apps/scoutgame/lib/builders/getSortedBuilders.ts
@@ -44,8 +44,8 @@ export async function getSortedBuilders({
cursor: cursor ? { id: cursor.userId } : undefined,
select: {
id: true,
- username: true,
path: true,
+ displayName: true,
builderStatus: true,
createdAt: true,
builderNfts: {
@@ -92,8 +92,8 @@ export async function getSortedBuilders({
return scouts.map((scout) => ({
id: scout.id,
nftImageUrl: scout.builderNfts[0]?.imageUrl,
- username: scout.username,
- path: scout.path,
+ path: scout.path!,
+ displayName: scout.displayName,
builderPoints: scout.userAllTimeStats[0]?.pointsEarnedAsBuilder ?? 0,
price: scout.builderNfts?.[0]?.currentPrice ?? 0,
scoutedBy: scout.builderNfts?.[0]?.nftSoldEvents?.length ?? 0,
@@ -142,8 +142,8 @@ export async function getSortedBuilders({
user: {
select: {
id: true,
- username: true,
path: true,
+ displayName: true,
builderStatus: true,
builderNfts: {
where: {
@@ -184,8 +184,8 @@ export async function getSortedBuilders({
id: stat.user.id,
rank: stat.rank ?? -1,
nftImageUrl: stat.user.builderNfts[0]?.imageUrl,
- username: stat.user.username,
- path: stat.user.path,
+ path: stat.user.path!,
+ displayName: stat.user.displayName,
builderPoints: stat.user.userAllTimeStats[0]?.pointsEarnedAsBuilder ?? 0,
price: stat.user.builderNfts?.[0]?.currentPrice ?? 0,
scoutedBy: stat.user.builderNfts?.[0]?.nftSoldEvents?.length ?? 0,
@@ -235,8 +235,8 @@ export async function getSortedBuilders({
user: {
select: {
id: true,
- username: true,
path: true,
+ displayName: true,
builderStatus: true,
userAllTimeStats: {
select: {
@@ -274,8 +274,8 @@ export async function getSortedBuilders({
id: stat.user.id,
rank: stat.rank ?? -1,
nftImageUrl: stat.user.builderNfts[0]?.imageUrl,
- username: stat.user.username,
- path: stat.user.path,
+ path: stat.user.path!,
+ displayName: stat.user.displayName,
builderPoints: stat.user.userAllTimeStats[0]?.pointsEarnedAsBuilder ?? 0,
price: stat.user.builderNfts?.[0]?.currentPrice ?? 0,
nftsSold: stat.user.userSeasonStats[0]?.nftsSold ?? 0,
diff --git a/apps/scoutgame/lib/builders/getTodaysHotBuilders.ts b/apps/scoutgame/lib/builders/getTodaysHotBuilders.ts
index d5aeedcb4b..2b605ff7b5 100644
--- a/apps/scoutgame/lib/builders/getTodaysHotBuilders.ts
+++ b/apps/scoutgame/lib/builders/getTodaysHotBuilders.ts
@@ -26,7 +26,7 @@ export async function getTodaysHotBuilders(): Promise {
const builders = await prisma.scout.findMany({
where: {
builderStatus: 'approved',
- username: {
+ path: {
in: preselectedBuilderUsernames
}
},
@@ -70,8 +70,8 @@ export async function getTodaysHotBuilders(): Promise {
.map((builder) => {
return {
id: builder.id,
- username: builder.username || '',
- path: builder.path,
+ path: builder.path!,
+ displayName: builder.displayName,
builderPoints: builder.userSeasonStats[0]?.pointsEarnedAsBuilder || 0,
price: builder.builderNfts[0]?.currentPrice ?? 0,
nftImageUrl: builder.builderNfts[0]?.imageUrl,
@@ -158,8 +158,8 @@ export async function getTodaysHotBuilders(): Promise {
const user = builder.user;
return {
id: user.id,
- username: user.username || '',
- path: user.path,
+ path: user.path!,
+ displayName: user.displayName,
builderPoints: user.userSeasonStats[0]?.pointsEarnedAsBuilder || 0,
price: user.builderNfts[0]?.currentPrice ?? 0,
nftImageUrl: user.builderNfts[0]?.imageUrl,
diff --git a/apps/scoutgame/lib/builders/getTopBuilders.ts b/apps/scoutgame/lib/builders/getTopBuilders.ts
index aaea4cc924..76b0685d6e 100644
--- a/apps/scoutgame/lib/builders/getTopBuilders.ts
+++ b/apps/scoutgame/lib/builders/getTopBuilders.ts
@@ -6,8 +6,8 @@ import { isTruthy } from '@root/lib/utils/types';
export type TopBuilderInfo = {
id: string;
- username: string | null;
- path: string | null;
+ displayName: string;
+ path: string;
avatar: string | null;
seasonPoints: number;
builderStatus: BuilderStatus;
@@ -38,8 +38,8 @@ export async function getTopBuilders({
select: {
id: true,
builderStatus: true,
- username: true,
path: true,
+ displayName: true,
avatar: true,
userAllTimeStats: {
select: {
@@ -69,7 +69,7 @@ export async function getTopBuilders({
return topBuilders
.map((builder) => {
const { user, pointsEarnedAsBuilder } = builder;
- const { id, username, path, avatar } = user;
+ const { id, path, displayName, avatar } = user;
const nft = user.builderNfts[0];
if (!nft) {
return null;
@@ -77,8 +77,8 @@ export async function getTopBuilders({
return {
id,
- username,
- path,
+ path: path!,
+ displayName,
avatar,
nftImageUrl: nft.imageUrl,
seasonPoints: pointsEarnedAsBuilder,
diff --git a/apps/scoutgame/lib/builders/searchBuilders.ts b/apps/scoutgame/lib/builders/searchBuilders.ts
index a3f63c30be..e01f398154 100644
--- a/apps/scoutgame/lib/builders/searchBuilders.ts
+++ b/apps/scoutgame/lib/builders/searchBuilders.ts
@@ -3,7 +3,8 @@ import { currentSeason } from '@packages/scoutgame/dates';
export type BuilderSearchResult = {
id: string;
- username: string;
+ path: string;
+ displayName: string;
avatar: string | null;
seasonPoints: number;
allTimePoints: number;
@@ -12,31 +13,42 @@ export type BuilderSearchResult = {
};
export async function searchBuilders({
- username,
+ search,
limit = 10
}: {
- username: string;
+ search: string;
limit?: number;
}): Promise {
const builders = await prisma.scout.findMany({
where: {
- username: {
- contains: username,
- mode: 'insensitive'
- }
+ OR: [
+ {
+ path: {
+ contains: search,
+ mode: 'insensitive'
+ }
+ },
+ {
+ displayName: {
+ contains: search,
+ mode: 'insensitive'
+ }
+ }
+ ]
},
take: limit,
orderBy: {
// Sort by similarity to the query
_relevance: {
- fields: ['username'],
- search: username,
+ fields: ['path', 'displayName'],
+ search,
sort: 'desc'
}
},
select: {
id: true,
- username: true,
+ path: true,
+ displayName: true,
avatar: true,
userSeasonStats: {
where: {
@@ -67,7 +79,8 @@ export async function searchBuilders({
return builders.map((builder) => ({
id: builder.id,
- username: builder.username || '',
+ path: builder.path!,
+ displayName: builder.displayName!,
avatar: builder.avatar,
seasonPoints: builder.userSeasonStats?.[0]?.pointsEarnedAsBuilder ?? 0,
allTimePoints: builder.userAllTimeStats?.[0]?.pointsEarnedAsBuilder ?? 0,
diff --git a/apps/scoutgame/lib/farcaster/findOrCreateFarcasterUser.ts b/apps/scoutgame/lib/farcaster/findOrCreateFarcasterUser.ts
index b980edbef4..9b1fac6679 100644
--- a/apps/scoutgame/lib/farcaster/findOrCreateFarcasterUser.ts
+++ b/apps/scoutgame/lib/farcaster/findOrCreateFarcasterUser.ts
@@ -23,8 +23,8 @@ export async function findOrCreateFarcasterUser({
avatar: profile.pfp_url,
bio: profile.profile.bio.text,
walletAddress: profile.verifications[0],
- displayName: profile.display_name || profile.username,
- username: profile.username,
+ displayName: profile.display_name,
+ path: profile.username,
tierOverride
});
}
diff --git a/apps/scoutgame/lib/scouts/getScoutedBuilders.ts b/apps/scoutgame/lib/scouts/getScoutedBuilders.ts
index 165c290aad..198c2be1d3 100644
--- a/apps/scoutgame/lib/scouts/getScoutedBuilders.ts
+++ b/apps/scoutgame/lib/scouts/getScoutedBuilders.ts
@@ -76,8 +76,8 @@ export async function getScoutedBuilders({ scoutId }: { scoutId: string }): Prom
return {
id: builder.id,
nftImageUrl: builder.builderNfts[0]?.imageUrl,
- username: builder.username || '',
- path: builder.path,
+ path: builder.path!,
+ displayName: builder.displayName,
builderStatus: builder.builderStatus!,
builderPoints: builder.userSeasonStats[0]?.pointsEarnedAsBuilder ?? 0,
nftsSold: builder.userSeasonStats[0]?.nftsSold ?? 0,
diff --git a/apps/scoutgame/lib/scouts/getTopScouts.ts b/apps/scoutgame/lib/scouts/getTopScouts.ts
index 0a5261a86c..f0777554fd 100644
--- a/apps/scoutgame/lib/scouts/getTopScouts.ts
+++ b/apps/scoutgame/lib/scouts/getTopScouts.ts
@@ -3,7 +3,8 @@ import { currentSeason } from '@packages/scoutgame/dates';
export type TopScout = {
id: string;
- username: string;
+ path: string;
+ displayName: string;
avatar: string | null;
buildersScouted: number;
nftsHeld: number;
@@ -25,7 +26,8 @@ export async function getTopScouts({ limit }: { limit: number }): Promise {
},
select: {
id: true,
- username: true,
path: true,
displayName: true,
avatar: true,
diff --git a/apps/scoutgame/lib/session/getUserFromSession.ts b/apps/scoutgame/lib/session/getUserFromSession.ts
index 3e56b08b03..d1debf3cf7 100644
--- a/apps/scoutgame/lib/session/getUserFromSession.ts
+++ b/apps/scoutgame/lib/session/getUserFromSession.ts
@@ -6,7 +6,6 @@ import { cacheGetUser, getUser } from './getUser';
export type SessionUser = Pick<
Scout,
| 'id'
- | 'username'
| 'path'
| 'displayName'
| 'avatar'
diff --git a/apps/scoutgame/lib/users/findOrCreateUser.ts b/apps/scoutgame/lib/users/findOrCreateUser.ts
index 49ecd86a5f..ae1c7cc30f 100644
--- a/apps/scoutgame/lib/users/findOrCreateUser.ts
+++ b/apps/scoutgame/lib/users/findOrCreateUser.ts
@@ -34,7 +34,7 @@ export async function findOrCreateUser({
avatar?: string;
bio?: string;
displayName: string;
- username: string;
+ path: string;
tierOverride?: ConnectWaitlistTier;
}): Promise {
if (!farcasterId && !walletAddress) {
@@ -130,7 +130,8 @@ export async function findOrCreateUser({
trackUserAction('sign_up', {
userId: newScout.id,
- username: userProps.username,
+ path: userProps.path!,
+ displayName: userProps.displayName,
fid: farcasterId
});
diff --git a/apps/scoutgame/lib/users/getUserByPath.ts b/apps/scoutgame/lib/users/getUserByPath.ts
index c11163ceac..e05996e3b3 100644
--- a/apps/scoutgame/lib/users/getUserByPath.ts
+++ b/apps/scoutgame/lib/users/getUserByPath.ts
@@ -5,7 +5,7 @@ import { cache } from 'react';
import type { BasicUserInfo } from './interfaces';
import { BasicUserInfoSelect } from './queries';
-export async function getUserByUsernamePath(username: string): Promise<
+async function _getUserByPath(path: string): Promise<
| (BasicUserInfo & {
nftImageUrl?: string;
congratsImageUrl?: string | null;
@@ -16,7 +16,7 @@ export async function getUserByUsernamePath(username: string): Promise<
> {
const user = await prisma.scout.findFirst({
where: {
- username
+ path
},
select: { ...BasicUserInfoSelect, displayName: true, builderNfts: true }
});
@@ -27,10 +27,11 @@ export async function getUserByUsernamePath(username: string): Promise<
return {
...user,
+ path: user.path!,
nftImageUrl: user?.builderNfts[0]?.imageUrl,
congratsImageUrl: user?.builderNfts[0]?.congratsImageUrl,
githubLogin: user?.githubUser[0]?.login
};
}
-export const getUserByPath = cache(getUserByUsernamePath);
+export const getUserByPath = cache(_getUserByPath);
diff --git a/apps/scoutgame/lib/users/interfaces.ts b/apps/scoutgame/lib/users/interfaces.ts
index 22f9180c5a..57a818ac5c 100644
--- a/apps/scoutgame/lib/users/interfaces.ts
+++ b/apps/scoutgame/lib/users/interfaces.ts
@@ -2,8 +2,8 @@ import type { BuilderStatus } from '@charmverse/core/prisma';
export type MinimalUserInfo = {
id: string;
- username: string | null;
- path: string | null;
+ displayName: string;
+ path: string;
avatar?: string | null;
};
diff --git a/apps/scoutgame/lib/users/queries.ts b/apps/scoutgame/lib/users/queries.ts
index 17845aa8c8..b720262339 100644
--- a/apps/scoutgame/lib/users/queries.ts
+++ b/apps/scoutgame/lib/users/queries.ts
@@ -2,8 +2,8 @@ import type { Prisma } from '@charmverse/core/prisma-client';
export const BasicUserInfoSelect = {
id: true,
- username: true,
path: true,
+ displayName: true,
avatar: true,
bio: true,
githubUser: {
@@ -16,7 +16,7 @@ export const BasicUserInfoSelect = {
export const MinimalScoutInfoSelect = {
id: true,
- username: true,
+ path: true,
avatar: true,
displayName: true
} satisfies Prisma.ScoutSelect;
diff --git a/apps/scoutgame/middleware.ts b/apps/scoutgame/middleware.ts
index afaa1f431e..0b66d4e386 100644
--- a/apps/scoutgame/middleware.ts
+++ b/apps/scoutgame/middleware.ts
@@ -2,7 +2,7 @@ import { getSession } from '@connect-shared/lib/session/getSession';
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
-const privateLinks = ['/profile', '/notifications', '/welcome'];
+const privateLinks = ['/profile', '/notifications', '/welcome', '/claim'];
export async function middleware(request: NextRequest) {
const session = await getSession();
const isLoggedIn = !!session.scoutId;
diff --git a/apps/scoutgame/scripts/onboardScouts.ts b/apps/scoutgame/scripts/onboardScouts.ts
index ba78ffbef1..9efae54097 100644
--- a/apps/scoutgame/scripts/onboardScouts.ts
+++ b/apps/scoutgame/scripts/onboardScouts.ts
@@ -20,7 +20,7 @@ async function onboardScouts({ fids, tierOverride }: { fids: number[]; tierOverr
const fid = fidsRequiringAccount[i];
console.log(`Creating user ${i + 1} / ${totalFidsToProcess}`);
const user = await findOrCreateFarcasterUser({ fid, tierOverride: 'mythic' });
- console.log(`Created user ${user.id}. View: https://scoutgame.xyz/u/${user.username}`);
+ console.log(`Created user ${user.id}. View: https://scoutgame.xyz/u/${user.path}`);
}
}
diff --git a/apps/scoutgameadmin/app/api/partners/celo/route.ts b/apps/scoutgameadmin/app/api/partners/celo/route.ts
index 2b71e244d3..3747cd10e3 100644
--- a/apps/scoutgameadmin/app/api/partners/celo/route.ts
+++ b/apps/scoutgameadmin/app/api/partners/celo/route.ts
@@ -25,7 +25,7 @@ export async function GET() {
builder: {
select: {
email: true,
- username: true
+ displayName: true
}
},
githubEvent: {
@@ -43,7 +43,7 @@ export async function GET() {
}
});
const rows = events.map((event) => ({
- 'Farcaster Name': event.builder.username,
+ 'Farcaster Name': event.builder.displayName,
Email: event.builder.email,
Repo: `${event.githubEvent!.repo.owner}/${event.githubEvent!.repo.name}`,
Date: event.createdAt.toDateString(),
diff --git a/apps/scoutgameadmin/app/api/partners/moxie/route.ts b/apps/scoutgameadmin/app/api/partners/moxie/route.ts
index 5a5aeef056..8e45a540e7 100644
--- a/apps/scoutgameadmin/app/api/partners/moxie/route.ts
+++ b/apps/scoutgameadmin/app/api/partners/moxie/route.ts
@@ -10,11 +10,11 @@ export const dynamic = 'force-dynamic';
type MoxieBonusRow = {
'Builder FID': number;
- 'Builder username': string;
+ 'Builder path': string;
'Builder event': string;
'Scout FID': number;
'Scout email': string;
- 'Scout username': string;
+ 'Scout path': string;
};
export async function GET() {
@@ -27,7 +27,7 @@ export async function GET() {
},
select: {
farcasterId: true,
- username: true,
+ path: true,
events: {
where: {
type: {
@@ -46,7 +46,7 @@ export async function GET() {
scout: {
select: {
farcasterId: true,
- username: true
+ path: true
}
}
}
@@ -82,9 +82,9 @@ export async function GET() {
rows.push({
'Scout FID': scoutFid!,
'Scout email': scout.email || '',
- 'Scout username': scout.username,
+ 'Scout path': scout.path!,
'Builder FID': builder.farcasterId,
- 'Builder username': builder.username,
+ 'Builder path': builder.path!,
'Builder event':
(builder.events[0]!.type === 'merged_pull_request' ? `PR on ` : `Commit on `) +
builder.events[0]!.createdAt.toDateString()
diff --git a/apps/scoutgameadmin/app/api/users/export/route.ts b/apps/scoutgameadmin/app/api/users/export/route.ts
index 816e87abd5..c9b4ffcbcd 100644
--- a/apps/scoutgameadmin/app/api/users/export/route.ts
+++ b/apps/scoutgameadmin/app/api/users/export/route.ts
@@ -8,7 +8,7 @@ export const dynamic = 'force-dynamic';
type ScoutWithGithubUser = {
id: string;
- username: string;
+ path: string;
createdAt: string;
email?: string;
tokenId?: number;
@@ -29,7 +29,7 @@ export async function GET() {
const users = await prisma.scout.findMany({
select: {
id: true,
- username: true,
+ path: true,
sendMarketing: true,
createdAt: true,
avatar: true,
@@ -50,7 +50,7 @@ export async function GET() {
});
const rows: ScoutWithGithubUser[] = users.map((user) => ({
id: user.id,
- username: user.username,
+ path: user.path!,
createdAt: user.createdAt.toDateString(),
email: user.email || undefined,
optedInToMarketing: user.sendMarketing ? 'Yes' : '',
diff --git a/apps/scoutgameadmin/lib/users/getUser.ts b/apps/scoutgameadmin/lib/users/getUser.ts
index 8a0f741c01..1a5764ea45 100644
--- a/apps/scoutgameadmin/lib/users/getUser.ts
+++ b/apps/scoutgameadmin/lib/users/getUser.ts
@@ -42,7 +42,7 @@ export async function getUser({ searchString }: { searchString: string }): Promi
}
const user = await prisma.scout.findUnique({
where: {
- username: searchString
+ path: searchString
},
include: {
githubUser: true
diff --git a/apps/scoutgamecron/src/scripts/createBuilder.ts b/apps/scoutgamecron/src/scripts/createBuilder.ts
index 80c65cf2ed..95f5ede499 100644
--- a/apps/scoutgamecron/src/scripts/createBuilder.ts
+++ b/apps/scoutgamecron/src/scripts/createBuilder.ts
@@ -38,12 +38,12 @@ async function createBuilder({ fid, githubLogin }: { fid: number; githubLogin: s
// }
const builder = await prisma.scout.upsert({
where: {
- username
+ path: username
},
update: {},
create: {
displayName,
- username,
+ path: username,
avatar: avatarUrl,
bio,
builderStatus: 'applied',
@@ -63,7 +63,7 @@ async function createBuilder({ fid, githubLogin }: { fid: number; githubLogin: s
});
console.log('Created a builder record', builder);
await approveBuilder({ builderId: builder.id, season: currentSeason });
- console.log('Builder NFT created. View profile here:', 'https://scoutgame.xyz/u/' + builder.username);
+ console.log('Builder NFT created. View profile here:', 'https://scoutgame.xyz/u/' + builder.path);
process.exit(0);
}
diff --git a/apps/scoutgamecron/src/scripts/createBuilders.ts b/apps/scoutgamecron/src/scripts/createBuilders.ts
index aaf74d2fff..6b1ce57247 100644
--- a/apps/scoutgamecron/src/scripts/createBuilders.ts
+++ b/apps/scoutgamecron/src/scripts/createBuilders.ts
@@ -35,21 +35,21 @@ async function createBuilders() {
continue;
}
const displayName = profile.display_name;
- const username = profile.username;
+ const path = profile.username;
const avatarUrl = profile.pfp_url;
const bio = profile.profile.bio.text;
- if (!username) {
+ if (!path) {
log.info(`No username found for ${login} with fid ${fid}`);
continue;
}
const builder = await prisma.scout.upsert({
where: {
- username
+ path
},
update: {},
create: {
displayName,
- username,
+ path,
avatar: avatarUrl,
bio,
builderStatus: 'applied',
diff --git a/apps/scoutgamecron/src/scripts/createScouts.ts b/apps/scoutgamecron/src/scripts/createScouts.ts
index 5885d1059e..38279f2457 100644
--- a/apps/scoutgamecron/src/scripts/createScouts.ts
+++ b/apps/scoutgamecron/src/scripts/createScouts.ts
@@ -17,12 +17,12 @@ async function createScouts(farcasterUsernames: string[]) {
const scout = await prisma.scout.upsert({
where: {
- username: farcasterUsername
+ path: farcasterUsername
},
update: {},
create: {
displayName,
- username: farcasterUsername,
+ path: farcasterUsername,
avatar: avatarUrl,
bio,
farcasterId: fid,
diff --git a/apps/scoutgamecron/src/scripts/deleteBuilderAndRedistributePoints.ts b/apps/scoutgamecron/src/scripts/deleteBuilderAndRedistributePoints.ts
index af64e4e9ff..aa01911e33 100644
--- a/apps/scoutgamecron/src/scripts/deleteBuilderAndRedistributePoints.ts
+++ b/apps/scoutgamecron/src/scripts/deleteBuilderAndRedistributePoints.ts
@@ -2,15 +2,15 @@ import { prisma } from '@charmverse/core/prisma-client';
import { currentSeason } from '@packages/scoutgame/dates';
import { sendPoints } from '@packages/scoutgame/points/sendPoints';
-async function deleteBuilderAndRedistributePoints({ builderUsername }: { builderUsername: string }) {
+async function deleteBuilderAndRedistributePoints({ builderPath }: { builderPath: string }) {
const builder = await prisma.scout.findUnique({
where: {
- username: builderUsername
+ path: builderPath
}
});
if (!builder) {
- throw new Error(`Builder with username ${builderUsername} not found`);
+ throw new Error(`Builder with path ${builderPath} not found`);
}
const nftPurchaseEvents = await prisma.nFTPurchaseEvent.findMany({
@@ -18,7 +18,7 @@ async function deleteBuilderAndRedistributePoints({ builderUsername }: { builder
builderNFT: {
season: currentSeason,
builder: {
- username: builderUsername
+ path: builderPath
}
}
},
@@ -46,7 +46,7 @@ async function deleteBuilderAndRedistributePoints({ builderUsername }: { builder
async (tx) => {
await prisma.scout.delete({
where: {
- username: builderUsername
+ path: builderPath
}
});
await prisma.nFTPurchaseEvent.deleteMany({
@@ -88,5 +88,5 @@ async function deleteBuilderAndRedistributePoints({ builderUsername }: { builder
}
deleteBuilderAndRedistributePoints({
- builderUsername: ''
+ builderPath: 'path'
});
diff --git a/apps/scoutgamecron/src/scripts/fixArtwork.ts b/apps/scoutgamecron/src/scripts/fixArtwork.ts
index ef64a01428..d0c0533c79 100644
--- a/apps/scoutgamecron/src/scripts/fixArtwork.ts
+++ b/apps/scoutgamecron/src/scripts/fixArtwork.ts
@@ -3,7 +3,7 @@ import { prisma } from '@charmverse/core/prisma-client';
import { uploadMetadata } from '@packages/scoutgame/builderNfts/artwork/uploadMetadata';
import { builderContractReadonlyApiClient } from '@packages/scoutgame/builderNfts/clients/builderContractReadClient';
import { getBuilderContractAddress } from '@packages/scoutgame/builderNfts/constants';
-import { uploadArtwork, uploadArtworkCongrats } from '@packages/scoutgame/builderNfts/artwork/uploadArtwork';
+import { uploadArtwork } from '@packages/scoutgame/builderNfts/artwork/uploadArtwork';
import { currentSeason } from '@packages/scoutgame/dates';
async function refreshArtworks() {
@@ -15,7 +15,8 @@ async function refreshArtworks() {
builder: {
select: {
avatar: true,
- username: true
+ path: true,
+ displayName: true
}
}
},
@@ -53,7 +54,7 @@ async function refreshArtworks() {
avatar,
season: currentSeason,
tokenId: BigInt(tokenId),
- username: nft.builder.username
+ displayName: nft.builder.displayName
});
await prisma.builderNft.update({
@@ -68,7 +69,7 @@ async function refreshArtworks() {
const metadataPath = await uploadMetadata({
season: currentSeason,
tokenId: BigInt(tokenId),
- username: nft.builder.username,
+ path: nft.builder.path!,
attributes: []
});
diff --git a/apps/scoutgamecron/src/scripts/issuePoints.ts b/apps/scoutgamecron/src/scripts/issuePoints.ts
index b295c00f37..5ab89c89c6 100644
--- a/apps/scoutgamecron/src/scripts/issuePoints.ts
+++ b/apps/scoutgamecron/src/scripts/issuePoints.ts
@@ -48,7 +48,7 @@ async function issuePoints({ points }: { points: number }) {
tx
});
- await refreshPointStatsFromHistory({ userIdOrUsername: scout.id, tx });
+ await refreshPointStatsFromHistory({ userIdOrPath: scout.id, tx });
},
{ timeout: 15000 }
);
diff --git a/apps/scoutgamecron/src/scripts/refreshPointsFromTransactionHistory.ts b/apps/scoutgamecron/src/scripts/refreshPointsFromTransactionHistory.ts
index 9c3da84fcf..43ac90321a 100644
--- a/apps/scoutgamecron/src/scripts/refreshPointsFromTransactionHistory.ts
+++ b/apps/scoutgamecron/src/scripts/refreshPointsFromTransactionHistory.ts
@@ -5,7 +5,7 @@ import { prettyPrint } from '@packages/utils/strings';
async function refreshPointsFromTransactionHistory() {
const scouts = await prisma.scout.findMany({
- select: { id: true, username: true },
+ select: { id: true, path: true },
orderBy: {
id: 'asc'
},
@@ -19,11 +19,11 @@ async function refreshPointsFromTransactionHistory() {
for (let i = 0; i < scouts.length; i++) {
const scout = scouts[i];
try {
- log.info(`Fixing points for ${scout.username} ${i + 1} / ${scouts.length}`);
- const stats = await refreshPointStatsFromHistory({ userIdOrUsername: scout.id });
- log.info(`Successfully fixed points for ${scout.username}. New balance: ${stats.balance}`);
+ log.info(`Fixing points for ${scout.path} ${i + 1} / ${scouts.length}`);
+ const stats = await refreshPointStatsFromHistory({ userIdOrPath: scout.id });
+ log.info(`Successfully fixed points for ${scout.path}. New balance: ${stats.balance}`);
} catch (error) {
- log.error(`Failed to fix points for ${scout.username}: ${prettyPrint(error)}`);
+ log.error(`Failed to fix points for ${scout.path}: ${prettyPrint(error)}`);
}
}
}
diff --git a/apps/scoutgamecron/src/scripts/seeder/generateBuilder.ts b/apps/scoutgamecron/src/scripts/seeder/generateBuilder.ts
index 50b1b19b55..226dc58078 100644
--- a/apps/scoutgamecron/src/scripts/seeder/generateBuilder.ts
+++ b/apps/scoutgamecron/src/scripts/seeder/generateBuilder.ts
@@ -1,6 +1,6 @@
import fs from 'fs/promises';
import { fileURLToPath } from 'url';
-import path from 'path';
+import {dirname, join} from 'path';
import type { Prisma } from '@charmverse/core/prisma-client';
import { prisma } from '@charmverse/core/prisma-client';
import { faker } from '@faker-js/faker';
@@ -12,7 +12,7 @@ export async function generateBuilder({ index }: { index: number }) {
const firstName = faker.person.firstName();
const lastName = faker.person.lastName();
const displayName = `${firstName} ${lastName}`;
- const username = faker.internet
+ const path = faker.internet
.userName({
firstName,
lastName
@@ -28,7 +28,7 @@ export async function generateBuilder({ index }: { index: number }) {
const githubUser = {
id: faker.number.int({ min: 10000000, max: 25000000 }),
- login: username,
+ login: path,
email,
displayName
};
@@ -41,13 +41,13 @@ export async function generateBuilder({ index }: { index: number }) {
const imageUrl = faker.datatype.boolean() ? avatar : faker.image.url();
const nftImageBuffer = await generateNftImage({
avatar: imageUrl,
- username
+ displayName
});
// images will be hosted by the
const __filename = fileURLToPath(import.meta.url);
- const __dirname = path.dirname(__filename);
- const scoutgamePublicFolder = path.join(
+ const __dirname = dirname(__filename);
+ const scoutgamePublicFolder = join(
__dirname,
'..',
'..',
@@ -93,7 +93,7 @@ export async function generateBuilder({ index }: { index: number }) {
}
const builder = await prisma.scout.create({
data: {
- username,
+ path,
displayName,
email,
avatar,
diff --git a/apps/scoutgamecron/src/scripts/seeder/generateNftPurchaseEvents.ts b/apps/scoutgamecron/src/scripts/seeder/generateNftPurchaseEvents.ts
index 6147e95988..24dcf480db 100644
--- a/apps/scoutgamecron/src/scripts/seeder/generateNftPurchaseEvents.ts
+++ b/apps/scoutgamecron/src/scripts/seeder/generateNftPurchaseEvents.ts
@@ -1,10 +1,11 @@
import { prisma } from '@charmverse/core/prisma-client';
import { faker } from '@faker-js/faker';
-import { currentSeason, getWeekFromDate } from '@packages/scoutgame/dates';
-import { BuilderInfo } from './generateSeedData';
+import { builderTokenDecimals } from '@packages/scoutgame/builderNfts/constants';
+import { recordNftMintWithoutRefresh } from '@packages/scoutgame/builderNfts/recordNftMint';
+import { getWeekFromDate } from '@packages/scoutgame/dates';
import { DateTime } from 'luxon';
+import { BuilderInfo } from './generateSeedData';
import { randomTimeOfDay } from './generator';
-import { builderTokenDecimals } from '@packages/scoutgame/builderNfts/constants';
export async function generateNftPurchaseEvents(scoutId: string, assignedBuilders: BuilderInfo[], date: DateTime) {
const week = getWeekFromDate(date.toJSDate());
@@ -25,47 +26,20 @@ export async function generateNftPurchaseEvents(scoutId: string, assignedBuilder
id: builder.builderNftId
},
data: {
- currentPrice: Math.ceil(nftPrice + nftPrice * 0.1)
+ currentPrice: Math.ceil(nftPrice + nftPrice * 0.1),
}
- }),
- await tx.nFTPurchaseEvent.create({
- data: {
- id: faker.string.uuid(),
- scoutId,
- tokensPurchased: nftsPurchased,
- txHash: faker.finance.ethereumAddress(),
- // Converting points to fiat equivalent in order to reduce the number of points earned
- pointsValue,
- paidInPoints: false,
- builderNftId,
- activities: {
- create: {
- recipientType: 'builder',
- type: 'nft_purchase',
- userId: builder.id,
- createdAt
- }
- },
- builderEvent: {
- create: {
- id: faker.string.uuid(),
- builderId: builder.id,
- season: currentSeason,
- week,
- type: 'nft_purchase',
- createdAt,
- pointsReceipts: {
- create: {
- id: faker.string.uuid(),
- recipientId: builder.id,
- value: pointsValue * 0.1,
- createdAt
- }
- }
- }
- }
- }
- });
+ })
+
+ await recordNftMintWithoutRefresh({
+ builderNftId,
+ amount: nftsPurchased,
+ paidWithPoints: false,
+ pointsValue,
+ scoutId,
+ mintTxHash: faker.finance.ethereumAddress(),
+ recipientAddress: faker.finance.ethereumAddress(),
+ createdAt
+ });
});
}
}
diff --git a/apps/scoutgamecron/src/scripts/seeder/generateScout.ts b/apps/scoutgamecron/src/scripts/seeder/generateScout.ts
index e14a3e96a0..56134a66a9 100644
--- a/apps/scoutgamecron/src/scripts/seeder/generateScout.ts
+++ b/apps/scoutgamecron/src/scripts/seeder/generateScout.ts
@@ -5,7 +5,7 @@ export async function generateScout({ index }: { index: number }) {
const firstName = faker.person.firstName();
const lastName = faker.person.lastName();
const displayName = `${firstName} ${lastName}`;
- const username = faker.internet
+ const path = faker.internet
.userName({
firstName,
lastName
@@ -20,7 +20,7 @@ export async function generateScout({ index }: { index: number }) {
const scout = await prisma.scout.create({
data: {
- username,
+ path,
displayName,
email,
avatar,
diff --git a/apps/scoutgamecron/src/scripts/seeder/generateSeedData.ts b/apps/scoutgamecron/src/scripts/seeder/generateSeedData.ts
index 4c7d88bd68..fcf33ce0bf 100644
--- a/apps/scoutgamecron/src/scripts/seeder/generateSeedData.ts
+++ b/apps/scoutgamecron/src/scripts/seeder/generateSeedData.ts
@@ -123,8 +123,6 @@ export async function generateSeedData() {
totalGithubEvents += dailyGithubEvents;
}
- await updateBuildersRank({ week });
-
for (const scout of scouts) {
// Do not purchase your own nft
const dailyNftsPurchased = await generateNftPurchaseEvents(
@@ -136,9 +134,10 @@ export async function generateSeedData() {
}
await updateBuilderCardActivity(date.minus({ days: 1 }));
-
+
// Check if we are at the end of the week
if (date.weekday === 7) {
+ await updateBuildersRank({ week });
const topWeeklyBuilders = await getBuildersLeaderboard({ quantity: 100, week });
for (const { builder, gemsCollected, rank } of topWeeklyBuilders) {
try {
@@ -173,6 +172,8 @@ export async function generateSeedData() {
}
}
+ await updateBuildersRank({ week: getWeekFromDate(endDate.toJSDate()) });
+
log.info('generated seed data', {
totalUsers,
totalBuilders,
diff --git a/apps/scoutgamecron/src/scripts/seeder/seedWithRealCharmverseGithubData.ts b/apps/scoutgamecron/src/scripts/seeder/seedWithRealCharmverseGithubData.ts
index a46525bc3d..19d38d8346 100644
--- a/apps/scoutgamecron/src/scripts/seeder/seedWithRealCharmverseGithubData.ts
+++ b/apps/scoutgamecron/src/scripts/seeder/seedWithRealCharmverseGithubData.ts
@@ -82,7 +82,7 @@ export async function seedWithRealCharmverseGithubData() {
builder: {
create: {
displayName: builder,
- username: builder + Math.random().toString().replace('.', '').slice(0, 6),
+ path: builder + Math.random().toString().replace('.', '').slice(0, 6),
builderStatus: 'approved',
avatar
}
@@ -98,7 +98,7 @@ export async function seedWithRealCharmverseGithubData() {
builder: {
create: {
displayName: builder,
- username: builder,
+ path: builder,
builderStatus: 'approved',
avatar: avatar
}
diff --git a/apps/scoutgamecron/src/tasks/processGemsPayout/sendGemsPayoutEmails/sendGemsPayoutEmails.ts b/apps/scoutgamecron/src/tasks/processGemsPayout/sendGemsPayoutEmails/sendGemsPayoutEmails.ts
index 714e14c5f0..203092ce08 100644
--- a/apps/scoutgamecron/src/tasks/processGemsPayout/sendGemsPayoutEmails/sendGemsPayoutEmails.ts
+++ b/apps/scoutgamecron/src/tasks/processGemsPayout/sendGemsPayoutEmails/sendGemsPayoutEmails.ts
@@ -15,7 +15,6 @@ export async function sendGemsPayoutEmails({ week }: { week: string }) {
},
select: {
id: true,
- username: true,
displayName: true,
email: true
}
diff --git a/apps/scoutgamecron/src/tasks/updateMixpanelProfilesTask.ts b/apps/scoutgamecron/src/tasks/updateMixpanelProfilesTask.ts
index f5b11d62df..d283771bfe 100644
--- a/apps/scoutgamecron/src/tasks/updateMixpanelProfilesTask.ts
+++ b/apps/scoutgamecron/src/tasks/updateMixpanelProfilesTask.ts
@@ -8,7 +8,7 @@ function getMixpanelUserProfile(user: Scout): MixPanelUserProfile {
return {
$name: user.displayName,
$email: user.email,
- username: user.username,
+ path: user.path!,
onboarded: !!user.onboardedAt,
'Agreed To TOS': !!user.agreedToTermsAt,
'Enable Marketing': user.sendMarketing,
diff --git a/package-lock.json b/package-lock.json
index 5d6ce6998a..958beb3191 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -122103,4 +122103,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 43f7080da0..33039c3c57 100644
--- a/package.json
+++ b/package.json
@@ -468,4 +468,4 @@
"msw": {
"workerDirectory": "public"
}
-}
+}
\ No newline at end of file
diff --git a/packages/mixpanel/src/interfaces.ts b/packages/mixpanel/src/interfaces.ts
index 87a43b3e44..b4482ed7b8 100644
--- a/packages/mixpanel/src/interfaces.ts
+++ b/packages/mixpanel/src/interfaces.ts
@@ -9,7 +9,8 @@ export interface BaseEventWithoutGroup {
}
export type UserSignupEvent = BaseEventWithoutGroup & {
- username: string;
+ displayName: string;
+ path: string;
fid?: number;
};
diff --git a/packages/mixpanel/src/updateUserProfile.ts b/packages/mixpanel/src/updateUserProfile.ts
index 1854e90ac5..0bbc5e6721 100644
--- a/packages/mixpanel/src/updateUserProfile.ts
+++ b/packages/mixpanel/src/updateUserProfile.ts
@@ -6,7 +6,7 @@ import { getApiKey } from './mixpanel';
export type MixPanelUserProfile = {
$name: string;
$email: string | null;
- username: string;
+ path: string;
onboarded: boolean;
'Agreed To TOS': boolean;
'Enable Marketing': boolean;
diff --git a/packages/scoutgame/src/__tests__/getBuildersLeaderboard.spec.ts b/packages/scoutgame/src/__tests__/getBuildersLeaderboard.spec.ts
index a7c7945541..a577439c41 100644
--- a/packages/scoutgame/src/__tests__/getBuildersLeaderboard.spec.ts
+++ b/packages/scoutgame/src/__tests__/getBuildersLeaderboard.spec.ts
@@ -100,14 +100,14 @@ describe('getBuildersLeaderboard', () => {
it('should sort builders by username when gems collected and events are the same', async () => {
const testWeek = v4();
const builders = await Promise.all([
- mockBuilder({ username: `charlie-${v4()}` }),
- mockBuilder({ username: `alice-${v4()}` }),
- mockBuilder({ username: `bob-${v4()}` }),
- mockBuilder({ username: `david-${v4()}` }),
- mockBuilder({ username: `eve-${v4()}` })
+ mockBuilder({ path: `charlie-${v4()}` }),
+ mockBuilder({ path: `alice-${v4()}` }),
+ mockBuilder({ path: `bob-${v4()}` }),
+ mockBuilder({ path: `david-${v4()}` }),
+ mockBuilder({ path: `eve-${v4()}` })
]);
- const sortedBuilders = builders.sort((a, b) => a.username.localeCompare(b.username));
+ const sortedBuilders = builders.sort((a, b) => a.displayName.localeCompare(b.displayName));
// Create weekly stats with 0 gems collected for all builders
await Promise.all(
@@ -129,7 +129,7 @@ describe('getBuildersLeaderboard', () => {
// Check if builders are sorted by username in ascending order
sortedBuilders.forEach((builder, index) => {
- expect(topBuilders[index].builder.username).toBe(builder.username);
+ expect(topBuilders[index].builder.displayName).toBe(builder.displayName);
});
// Verify that all builders have 0 gems collected
@@ -146,11 +146,12 @@ describe('getBuildersLeaderboard', () => {
it('should only include builders with approved status', async () => {
const testWeek = v4();
const builders = await Promise.all([
- mockBuilder({ username: `charlie-${v4()}`, builderStatus: 'approved' }),
- mockBuilder({ username: `alice-${v4()}`, builderStatus: 'applied' }),
- mockBuilder({ username: `bob-${v4()}`, builderStatus: 'rejected' }),
- mockBuilder({ username: `david-${v4()}`, builderStatus: 'approved' }),
- mockBuilder({ username: `eve-${v4()}`, builderStatus: 'approved' })
+ mockBuilder({ builderStatus: 'approved', displayName: 'Charlie' }),
+ mockBuilder({ builderStatus: 'approved', displayName: 'David' }),
+ mockBuilder({ builderStatus: 'approved', displayName: 'Eve' }),
+ mockBuilder({ builderStatus: 'applied', displayName: 'Alice' }),
+ mockBuilder({ builderStatus: 'banned', displayName: 'Foo' }),
+ mockBuilder({ builderStatus: 'rejected', displayName: 'Bob' })
]);
// Create weekly stats with 0 gems collected for all builders
diff --git a/packages/scoutgame/src/builderNfts/artwork/generateNftImage.tsx b/packages/scoutgame/src/builderNfts/artwork/generateNftImage.tsx
index b7dd37cc32..d595898dc2 100644
--- a/packages/scoutgame/src/builderNfts/artwork/generateNftImage.tsx
+++ b/packages/scoutgame/src/builderNfts/artwork/generateNftImage.tsx
@@ -82,13 +82,81 @@ function calculateFontSize(text: string, maxWidth: number, initialFontSize: numb
return minFontSize;
}
+export async function updateNftImage({
+ displayName,
+ currentNftImage
+}: {
+ currentNftImage: string;
+ displayName: string;
+}): Promise {
+ const cutoutWidth = 300;
+ const cutoutHeight = 400;
+
+ const baseImage = new ImageResponse(
+ (
+
+
+
+
+ ),
+ {
+ width: cutoutWidth,
+ height: cutoutHeight
+ }
+ );
+
+ const baseImageBuffer = await baseImage.arrayBuffer();
+ const imageBuffer = sharp(Buffer.from(baseImageBuffer)).png().toBuffer();
+
+ return imageBuffer;
+}
+
export async function generateNftImage({
avatar,
- username,
+ displayName,
imageHostingBaseUrl
}: {
avatar: string | null;
- username: string;
+ displayName: string;
imageHostingBaseUrl?: string; // when running inside of next.js, we need to use the server url
}): Promise {
const { overlaysBase64, noPfpAvatarBase64, font } = await getAssets(imageHostingBaseUrl);
@@ -145,13 +213,13 @@ export async function generateNftImage({
style={{
color: 'white',
textAlign: 'center',
- fontSize: `${calculateFontSize(username, 280, 24)}px`,
+ fontSize: `${calculateFontSize(displayName, 280, 24)}px`,
whiteSpace: 'nowrap',
maxWidth: `${280}px`,
fontFamily: 'K2D'
}}
>
- {username}
+ {displayName}
diff --git a/packages/scoutgame/src/builderNfts/artwork/uploadArtwork.ts b/packages/scoutgame/src/builderNfts/artwork/uploadArtwork.ts
index 42e17bd2dc..6544714978 100644
--- a/packages/scoutgame/src/builderNfts/artwork/uploadArtwork.ts
+++ b/packages/scoutgame/src/builderNfts/artwork/uploadArtwork.ts
@@ -2,7 +2,7 @@ import { S3Client } from '@aws-sdk/client-s3';
import type { PutObjectCommandInput, S3ClientConfig } from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';
-import { generateNftImage, generateNftCongrats } from './generateNftImage';
+import { generateNftImage, generateNftCongrats, updateNftImage } from './generateNftImage';
import { getNftCongratsFilePath, getNftFilePath, imageDomain } from './utils';
function getS3ClientConfig() {
@@ -26,19 +26,26 @@ export async function uploadArtwork({
avatar,
tokenId,
season,
- username
+ displayName,
+ currentNftImage
}: {
imageHostingBaseUrl?: string;
- username: string;
+ displayName: string;
season: string;
avatar: string | null;
tokenId: bigint | number;
+ currentNftImage?: string;
}) {
- const imageBuffer = await generateNftImage({
- avatar,
- username,
- imageHostingBaseUrl
- });
+ const imageBuffer = currentNftImage
+ ? await updateNftImage({
+ displayName,
+ currentNftImage
+ })
+ : await generateNftImage({
+ avatar,
+ displayName,
+ imageHostingBaseUrl
+ });
const imagePath = getNftFilePath({ season, tokenId: Number(tokenId), type: 'artwork.png' });
diff --git a/packages/scoutgame/src/builderNfts/artwork/uploadMetadata.ts b/packages/scoutgame/src/builderNfts/artwork/uploadMetadata.ts
index 109e1c165a..4f9aca4c9c 100644
--- a/packages/scoutgame/src/builderNfts/artwork/uploadMetadata.ts
+++ b/packages/scoutgame/src/builderNfts/artwork/uploadMetadata.ts
@@ -100,7 +100,7 @@ const client = new S3Client(getS3ClientConfig());
* Uploads OpenSea metadata to S3.
*
* @param {Object} params - Parameters for creating the OpenSea metadata.
- * @param {string} params.username - The username of the NFT owner.
+ * @param {string} params.path - The path of the NFT owner.
* @param {string} params.season - The season of the NFT.
* @param {string | null} params.avatar - The avatar image URL for the NFT.
* @param {bigint | number} params.tokenId - The unique token ID of the NFT.
@@ -111,12 +111,12 @@ const client = new S3Client(getS3ClientConfig());
* @returns {Promise} - The URL of the uploaded metadata JSON.
*/
export async function uploadMetadata({
- username,
+ path,
season,
tokenId,
attributes
}: {
- username: string;
+ path: string;
season: string;
tokenId: bigint | number;
attributes?: { trait_type: string; value: string | number }[];
@@ -128,7 +128,7 @@ export async function uploadMetadata({
const metadata: OpenSeaMetadata = {
name: `ScoutGame Builders NFT #${tokenId}`,
description: '',
- external_url: `${process.env.DOMAIN}/u/${username}`,
+ external_url: `${process.env.DOMAIN}/u/${path}`,
image: `${imageDomain}/${getNftFilePath({ season, tokenId: Number(tokenId), type: 'artwork.png' })}`,
attributes: attributes || []
};
diff --git a/packages/scoutgame/src/builderNfts/createBuilderNft.ts b/packages/scoutgame/src/builderNfts/createBuilderNft.ts
index e7ccac9449..e6ae12e2fa 100644
--- a/packages/scoutgame/src/builderNfts/createBuilderNft.ts
+++ b/packages/scoutgame/src/builderNfts/createBuilderNft.ts
@@ -12,10 +12,12 @@ export async function createBuilderNft({
avatar,
tokenId,
builderId,
- username
+ displayName,
+ path
}: {
imageHostingBaseUrl?: string;
- username: string;
+ displayName: string;
+ path: string;
avatar: string | null;
tokenId: bigint;
builderId: string;
@@ -26,7 +28,7 @@ export async function createBuilderNft({
const fileUrl = await uploadArtwork({
imageHostingBaseUrl,
- username,
+ displayName,
season: currentSeason,
avatar,
tokenId
@@ -42,7 +44,7 @@ export async function createBuilderNft({
await uploadMetadata({
season: currentSeason,
tokenId,
- username
+ path
});
const builderNft = await prisma.builderNft.create({
diff --git a/packages/scoutgame/src/builderNfts/recordNftMint.ts b/packages/scoutgame/src/builderNfts/recordNftMint.ts
index b6f38ea901..0b7f3c834f 100644
--- a/packages/scoutgame/src/builderNfts/recordNftMint.ts
+++ b/packages/scoutgame/src/builderNfts/recordNftMint.ts
@@ -9,23 +9,8 @@ import { getCurrentWeek } from '@packages/scoutgame/dates';
import type { MintNFTParams } from './mintNFT';
-export async function recordNftMint(params: MintNFTParams & { mintTxHash: string }) {
- const { amount, builderNftId, paidWithPoints, pointsValue, recipientAddress, scoutId, mintTxHash } = params;
-
- if (!mintTxHash.trim().startsWith('0x')) {
- throw new InvalidInputError(`Mint transaction hash is required`);
- }
-
- const existingTx = await prisma.nFTPurchaseEvent.findFirst({
- where: {
- txHash: mintTxHash
- }
- });
-
- if (existingTx) {
- log.warn(`Tried to record duplicate tx ${mintTxHash}`, { params, existingTx });
- return;
- }
+export async function recordNftMintWithoutRefresh(params: MintNFTParams & { createdAt?: Date; mintTxHash: string }) {
+ const { createdAt, amount, builderNftId, paidWithPoints, pointsValue, scoutId, mintTxHash } = params;
const builderNft = await prisma.builderNft.findFirstOrThrow({
where: {
@@ -44,17 +29,19 @@ export async function recordNftMint(params: MintNFTParams & { mintTxHash: string
});
// The builder receives 20% of the points value, regardless of whether the purchase was paid with points or not
- const pointsReceipts: { value: number; recipientId?: string; senderId?: string }[] = [
+ const pointsReceipts: { value: number; recipientId?: string; senderId?: string; createdAt?: Date }[] = [
{
value: Math.floor(pointsValue * 0.2),
- recipientId: builderNft.builderId
+ recipientId: builderNft.builderId,
+ createdAt
}
];
if (paidWithPoints) {
pointsReceipts.push({
value: pointsValue,
- senderId: scoutId
+ senderId: scoutId,
+ createdAt
});
}
@@ -81,6 +68,7 @@ export async function recordNftMint(params: MintNFTParams & { mintTxHash: string
nftPurchaseEvent: {
create: {
pointsValue,
+ createdAt,
tokensPurchased: amount,
paidInPoints: paidWithPoints,
txHash: mintTxHash?.toLowerCase(),
@@ -90,7 +78,8 @@ export async function recordNftMint(params: MintNFTParams & { mintTxHash: string
create: {
recipientType: 'builder',
type: 'nft_purchase',
- userId: builderNft.builderId
+ userId: builderNft.builderId,
+ createdAt
}
}
}
@@ -164,6 +153,33 @@ export async function recordNftMint(params: MintNFTParams & { mintTxHash: string
return builderEvent.nftPurchaseEvent;
});
+
+ return {
+ builderNft,
+ mintTxHash,
+ nftPurchaseEvent: nftPurchaseEvent as NFTPurchaseEvent
+ };
+}
+
+export async function recordNftMint(params: MintNFTParams & { mintTxHash: string }) {
+ const { amount, builderNftId, paidWithPoints, recipientAddress, scoutId, mintTxHash } = params;
+
+ if (!mintTxHash.trim().startsWith('0x')) {
+ throw new InvalidInputError(`Mint transaction hash is required`);
+ }
+
+ const existingTx = await prisma.nFTPurchaseEvent.findFirst({
+ where: {
+ txHash: mintTxHash
+ }
+ });
+
+ if (existingTx) {
+ log.warn(`Tried to record duplicate tx ${mintTxHash}`, { params, existingTx });
+ return;
+ }
+
+ const { builderNft, nftPurchaseEvent } = await recordNftMintWithoutRefresh(params);
log.info('Minted NFT', { builderNftId, recipientAddress, tokenId: builderNft.tokenId, amount, userId: scoutId });
trackUserAction('nft_purchase', {
userId: builderNft.builderId,
diff --git a/packages/scoutgame/src/builderNfts/registerBuilderNFT.ts b/packages/scoutgame/src/builderNfts/registerBuilderNFT.ts
index 22b9a72c14..27ffd2f31f 100644
--- a/packages/scoutgame/src/builderNfts/registerBuilderNFT.ts
+++ b/packages/scoutgame/src/builderNfts/registerBuilderNFT.ts
@@ -44,7 +44,8 @@ export async function registerBuilderNFT({
select: {
githubUser: true,
avatar: true,
- username: true,
+ path: true,
+ displayName: true,
builderStatus: true
}
});
@@ -70,7 +71,8 @@ export async function registerBuilderNFT({
tokenId: existingTokenId,
builderId,
avatar: builder.avatar,
- username: builder.username || ''
+ path: builder.path!,
+ displayName: builder.displayName
});
const nftWithRefreshedPrice = await refreshBuilderNftPrice({ builderId, season });
diff --git a/packages/scoutgame/src/builderNfts/syncUserNFTsFromOnchainData.ts b/packages/scoutgame/src/builderNfts/syncUserNFTsFromOnchainData.ts
index d38f507f46..77bc88953d 100644
--- a/packages/scoutgame/src/builderNfts/syncUserNFTsFromOnchainData.ts
+++ b/packages/scoutgame/src/builderNfts/syncUserNFTsFromOnchainData.ts
@@ -9,24 +9,24 @@ import { getTokenPurchasePrice } from './getTokenPurchasePrice';
import { handlePendingTransaction } from './handlePendingTransaction';
export async function syncUserNFTsFromOnchainData({
- username,
+ path,
scoutId,
fromBlock
}: {
- username?: string;
+ path?: string;
scoutId?: string;
fromBlock?: number;
}): Promise {
- if (!username && !scoutId) {
- throw new Error('Either username or scoutId must be provided');
- } else if (username && scoutId) {
- throw new Error('Only one of username or scoutId can be provided');
+ if (!path && !scoutId) {
+ throw new Error('Either path or scoutId must be provided');
+ } else if (path && scoutId) {
+ throw new Error('Only one of path or scoutId can be provided');
}
const scout = await prisma.scout.findFirstOrThrow({
where: {
id: scoutId,
- username
+ path
}
});
diff --git a/packages/scoutgame/src/getBuildersLeaderboard.ts b/packages/scoutgame/src/getBuildersLeaderboard.ts
index b58f7f94ea..003598af43 100644
--- a/packages/scoutgame/src/getBuildersLeaderboard.ts
+++ b/packages/scoutgame/src/getBuildersLeaderboard.ts
@@ -3,7 +3,8 @@ import { prisma } from '@charmverse/core/prisma-client';
export type LeaderboardBuilder = {
builder: {
id: string;
- username: string;
+ path: string;
+ displayName: string;
};
gemsCollected: number;
rank: number;
@@ -30,7 +31,8 @@ export async function getBuildersLeaderboard({
user: {
select: {
id: true,
- username: true,
+ path: true,
+ displayName: true,
events: {
where: {
type: 'merged_pull_request'
@@ -57,7 +59,7 @@ export async function getBuildersLeaderboard({
const userAEvent = a.user.events[0]?.createdAt.getTime() ?? 0;
const userBEvent = b.user.events[0]?.createdAt.getTime() ?? 0;
if (userBEvent === userAEvent) {
- return a.user.username.localeCompare(b.user.username);
+ return a.user.displayName.localeCompare(b.user.displayName);
}
return userAEvent - userBEvent;
@@ -67,11 +69,12 @@ export async function getBuildersLeaderboard({
.map((userWeeklyStat, index) => ({
builder: {
id: userWeeklyStat.user.id,
- username: userWeeklyStat.user.username
+ path: userWeeklyStat.user.path,
+ displayName: userWeeklyStat.user.displayName
},
gemsCollected: userWeeklyStat.gemsCollected,
rank: index + 1
- }));
+ })) as LeaderboardBuilder[];
if (quantity) {
return topBuilders.slice(0, quantity);
diff --git a/packages/scoutgame/src/points/__tests__/getPointStatsFromHistory.spec.ts b/packages/scoutgame/src/points/__tests__/getPointStatsFromHistory.spec.ts
index 7f479fdda2..e7ef85d76c 100644
--- a/packages/scoutgame/src/points/__tests__/getPointStatsFromHistory.spec.ts
+++ b/packages/scoutgame/src/points/__tests__/getPointStatsFromHistory.spec.ts
@@ -1,5 +1,5 @@
import { InvalidInputError } from '@charmverse/core/errors';
-import type { PointsReceipt, Prisma, Scout } from '@charmverse/core/prisma-client';
+import type { PointsReceipt, Scout } from '@charmverse/core/prisma-client';
import { prisma } from '@charmverse/core/prisma-client';
import { jest } from '@jest/globals';
import { v4 as uuid } from 'uuid';
@@ -12,11 +12,11 @@ describe('getPointStatsFromHistory', () => {
let user: Scout;
beforeAll(async () => {
- user = await mockScout({ username: uuid() });
+ user = await mockScout({ path: `user-${uuid()}` });
});
it('should return point stats when valid UUID is provided', async () => {
- const stats = await getPointStatsFromHistory({ userIdOrUsername: user.id });
+ const stats = await getPointStatsFromHistory({ userIdOrPath: user.id });
expect(stats).toMatchObject({
userId: user.id,
pointsSpent: expect.any(Number),
@@ -31,7 +31,7 @@ describe('getPointStatsFromHistory', () => {
// @TODO: Redo the find by username logic
it('should return point stats when valid username is provided', async () => {
- const stats = await getPointStatsFromHistory({ userIdOrUsername: user.id });
+ const stats = await getPointStatsFromHistory({ userIdOrPath: user.path! });
expect(stats).toMatchObject({
userId: user.id,
pointsSpent: expect.any(Number),
@@ -83,7 +83,7 @@ describe('getPointStatsFromHistory', () => {
jest.spyOn(prisma.pointsReceipt, 'findMany').mockResolvedValueOnce(allPointsReceivedRecords as PointsReceipt[]);
- const pointStats = await getPointStatsFromHistory({ userIdOrUsername: user.id });
+ const pointStats = await getPointStatsFromHistory({ userIdOrPath: user.id });
// Sanity check that the points add up
expect(pointStats.claimedPoints + pointStats.unclaimedPoints).toEqual(
@@ -103,12 +103,12 @@ describe('getPointStatsFromHistory', () => {
});
it('should throw InvalidInputError when userIdOrUsername is empty', async () => {
- await expect(getPointStatsFromHistory({ userIdOrUsername: '' })).rejects.toThrow(InvalidInputError);
+ await expect(getPointStatsFromHistory({ userIdOrPath: '' })).rejects.toThrow(InvalidInputError);
});
it('should throw an error when userIdOrUsername is invalid UUID and does not exist as a username', async () => {
const nonExistentUserId = uuid();
- await expect(getPointStatsFromHistory({ userIdOrUsername: nonExistentUserId })).rejects.toThrow();
+ await expect(getPointStatsFromHistory({ userIdOrPath: nonExistentUserId })).rejects.toThrow();
});
it('should throw an assertion error if point records for individual categories do not match the full list of point records', async () => {
@@ -134,6 +134,6 @@ describe('getPointStatsFromHistory', () => {
jest.spyOn(prisma.pointsReceipt, 'findMany').mockResolvedValueOnce(bonusPointsReceivedRecords as PointsReceipt[]); // Mismatch points
jest.spyOn(prisma.pointsReceipt, 'findMany').mockResolvedValueOnce(allPointsReceivedRecords as PointsReceipt[]); // Mismatch points
- await expect(getPointStatsFromHistory({ userIdOrUsername: user.id })).rejects.toThrow();
+ await expect(getPointStatsFromHistory({ userIdOrPath: user.id })).rejects.toThrow();
});
});
diff --git a/packages/scoutgame/src/points/getPointStatsFromHistory.ts b/packages/scoutgame/src/points/getPointStatsFromHistory.ts
index db79070260..420b83ef68 100644
--- a/packages/scoutgame/src/points/getPointStatsFromHistory.ts
+++ b/packages/scoutgame/src/points/getPointStatsFromHistory.ts
@@ -22,19 +22,19 @@ const include: Prisma.PointsReceiptInclude = {
};
export async function getPointStatsFromHistory({
- userIdOrUsername,
+ userIdOrPath,
tx = prisma
}: {
- userIdOrUsername: string;
+ userIdOrPath: string;
tx?: Prisma.TransactionClient;
}): Promise {
- if (!userIdOrUsername) {
- throw new InvalidInputError('userIdOrUsername is required');
+ if (!userIdOrPath) {
+ throw new InvalidInputError('userIdOrPath is required');
}
const userId = await tx.scout
.findUniqueOrThrow({
- where: { id: userIdOrUsername },
+ where: isUuid(userIdOrPath) ? { id: userIdOrPath } : { path: userIdOrPath },
select: {
id: true
}
diff --git a/packages/scoutgame/src/points/refreshPointStatsFromHistory.ts b/packages/scoutgame/src/points/refreshPointStatsFromHistory.ts
index 7cdf3187fd..05b3c31662 100644
--- a/packages/scoutgame/src/points/refreshPointStatsFromHistory.ts
+++ b/packages/scoutgame/src/points/refreshPointStatsFromHistory.ts
@@ -7,16 +7,16 @@ import { getPointStatsFromHistory, type PointStats } from './getPointStatsFromHi
import { setPointsEarnedStats } from './updatePointsEarned';
export async function refreshPointStatsFromHistory({
- userIdOrUsername,
+ userIdOrPath,
season = currentSeason,
tx
}: {
- userIdOrUsername: string;
+ userIdOrPath: string;
season?: string;
tx?: Prisma.TransactionClient;
}): Promise {
async function txHandler(_tx: Prisma.TransactionClient) {
- const stats = await getPointStatsFromHistory({ userIdOrUsername, tx: _tx });
+ const stats = await getPointStatsFromHistory({ userIdOrPath, tx: _tx });
await setPointsEarnedStats({
season,
diff --git a/packages/scoutgame/src/scripts/generateActivities.ts b/packages/scoutgame/src/scripts/generateActivities.ts
deleted file mode 100644
index 1a22e289e6..0000000000
--- a/packages/scoutgame/src/scripts/generateActivities.ts
+++ /dev/null
@@ -1,452 +0,0 @@
-import { log } from '@charmverse/core/log';
-import { GithubEventType } from '@charmverse/core/prisma';
-import { PointsDirection, prisma } from '@charmverse/core/prisma-client';
-
-import type { BuilderEvent } from '@charmverse/core/prisma';
-import { getBuilderContractAddress, builderNftChain } from '../builderNfts/constants';
-import type { ActivityToRecord } from '../recordGameActivity';
-import { recordGameActivity } from '../recordGameActivity';
-import { refreshUserStats } from '../refreshUserStats';
-import {
- mockBuilderStrike,
- mockPointReceipt,
- mockGemPayoutEvent,
- mockNFTPurchaseEvent,
- mockScout,
- mockGithubUser
-} from '../testing/database';
-import { randomLargeInt, mockSeason } from '../testing/generators';
-import { getCurrentWeek, currentSeason } from '../dates';
-
-type RepoAddress = {
- repoOwner?: string;
- repoName?: string;
-};
-
-type MockEventParams = {
- userId: string;
- amount?: number;
-};
-
-async function createMockEvents({ userId, amount = 5 }: MockEventParams) {
- const scout = await prisma.scout.findFirstOrThrow({
- where: {
- id: userId
- },
- include: {
- githubUser: true
- }
- });
- const week = new Date().getUTCDate();
-
- for (let i = 0; i < amount; i++) {
- // Frequent NFT Purchase events (occur in every loop)
- await mockNFTPurchaseEvent({
- builderId: userId,
- scoutId: userId,
- points: Math.floor(Math.random() * 100) + 1 // Random points between 1 and 100
- });
-
- // Rare Builder Strike events (10% chance of occurrence)
- if (Math.random() < 0.1) {
- await mockBuilderStrike({
- builderId: userId,
- pullRequestNumber: i + 1,
- repoOwner: 'test_owner',
- repoName: 'test_repo'
- });
- }
-
- // Point Receipt events
- await mockPointReceipt({
- builderId: userId,
- amount: Math.floor(Math.random() * 50) + 1, // Random points between 1 and 50
- senderId: scout.id,
- recipientId: undefined
- });
-
- // Gems Payout events
- await mockGemPayoutEvent({
- builderId: userId,
- week: `W-${week}-${i}`,
- amount: Math.floor(Math.random() * 10) + 1 // Random points between 1 and 10
- });
- }
-}
-
-async function ensureGithubRepoExists({
- repoOwner = `acme-${randomLargeInt()}`,
- repoName = `acme-repo-${randomLargeInt()}`,
- id
-}: Partial & { id?: number }) {
- const repo = await prisma.githubRepo.findFirst({
- where: {
- owner: repoOwner,
- name: repoName
- }
- });
-
- if (repo) {
- return repo;
- }
-
- return prisma.githubRepo.create({
- data: {
- id: id ?? randomLargeInt(),
- owner: repoOwner,
- name: repoName,
- defaultBranch: 'main'
- }
- });
-}
-
-async function ensureGithubUserExists(
- { login, builderId }: { login?: string; builderId?: string } = { login: `github:${randomLargeInt()}` }
-) {
- const githubUser = await prisma.githubUser.findFirst({ where: { login } });
-
- if (githubUser) {
- return githubUser;
- }
-
- const id = randomLargeInt();
-
- const name = `github_user:${id}`;
- return prisma.githubUser.create({
- data: {
- login: name,
- builderId,
- displayName: name,
- id
- }
- });
-}
-
-async function ensureMergedGithubPullRequestExists({
- repoOwner,
- repoName,
- pullRequestNumber = randomLargeInt(),
- githubUserId,
- builderId
-}: {
- pullRequestNumber?: number;
- githubUserId: number;
- builderId?: string;
- id?: number;
-} & RepoAddress): Promise {
- builderId = builderId ?? (await mockScout().then((scout) => scout.id));
-
- const builderGithubUser = await mockGithubUser({ builderId });
-
- // Ensure the repository exists
- const repo = await ensureGithubRepoExists({ repoOwner, repoName });
-
- const pullRequest = await prisma.githubEvent.findFirst({
- where: {
- repoId: repo.id,
- pullRequestNumber,
- githubUser: {
- id: builderGithubUser.id
- },
- type: 'merged_pull_request'
- },
- select: {
- builderEvent: true,
- repoId: true
- }
- });
-
- if (pullRequest?.builderEvent) {
- return pullRequest.builderEvent as BuilderEvent;
- }
-
- const githubEvent = await prisma.githubEvent
- .findFirstOrThrow({
- where: {
- repoId: repo.id,
- pullRequestNumber,
- createdBy: githubUserId,
- type: GithubEventType.merged_pull_request
- }
- })
- .catch((err) => {
- return prisma.githubEvent.create({
- data: {
- repoId: repo.id,
- pullRequestNumber,
- title: `Mock Pull Request ${pullRequestNumber}`,
- type: 'merged_pull_request',
- createdBy: builderGithubUser.id,
- url: ``
- }
- });
- });
-
- const builderEvent = await prisma.builderEvent.create({
- data: {
- builderId: builderId as string,
- season: mockSeason,
- type: 'merged_pull_request',
- githubEventId: githubEvent.id,
- week: getCurrentWeek()
- }
- });
-
- return builderEvent;
-}
-
-function getRandomDateWithinLast30Days() {
- const now = new Date();
- const pastDate = new Date(now);
- pastDate.setDate(now.getDate() - 30);
- return new Date(pastDate.getTime() + Math.random() * (now.getTime() - pastDate.getTime()));
-}
-
-export async function generateActivities({ userId }: { userId: string }) {
- const mints = await prisma.nFTPurchaseEvent.findMany({
- where: {
- scoutId: userId
- }
- });
-
- const builderStrikeEvents = await prisma.builderStrike.findMany({
- where: {
- builderId: userId
- }
- });
-
- const pointRecepts = await prisma.pointsReceipt.findMany({
- where: {
- OR: [
- {
- senderId: userId
- },
- {
- recipientId: userId
- }
- ]
- }
- });
-
- const gemPayouts = await prisma.gemsPayoutEvent.findMany({
- where: {
- builderId: userId
- }
- });
-
- const builderTokenEvents = await prisma.builderNft.findFirst({
- where: {
- chainId: builderNftChain.id,
- contractAddress: getBuilderContractAddress(),
- builderId: userId
- },
- include: {
- nftSoldEvents: {
- select: {
- scoutId: true
- }
- }
- }
- });
-
- const events: ActivityToRecord[] = [
- ...mints.map((event) => ({
- activity: {
- userId: event.scoutId,
- amount: event.tokensPurchased,
- pointsDirection: PointsDirection.in,
- createdAt: getRandomDateWithinLast30Days()
- },
- sourceEvent: {
- nftPurchaseEventId: event.id
- }
- })),
- ...builderStrikeEvents.map((event) => ({
- activity: {
- userId: event.builderId,
- amount: 0,
- pointsDirection: PointsDirection.in,
- createdAt: getRandomDateWithinLast30Days()
- },
- sourceEvent: {
- builderStrikeId: event.id
- }
- })),
- ...pointRecepts.flatMap((event) => {
- const _events: ActivityToRecord[] = [];
-
- if (event.senderId) {
- _events.push({
- activity: {
- userId: event.senderId,
- amount: event.value,
- pointsDirection: PointsDirection.out,
- createdAt: getRandomDateWithinLast30Days()
- },
- sourceEvent: {
- pointsReceiptId: event.id
- }
- });
- }
-
- if (event.recipientId) {
- _events.push({
- activity: {
- userId: event.recipientId,
- amount: event.value,
- pointsDirection: PointsDirection.in,
- createdAt: getRandomDateWithinLast30Days()
- },
- sourceEvent: {
- pointsReceiptId: event.id
- }
- });
- }
-
- return _events;
- }),
- ...gemPayouts.flatMap((event) => {
- const _events: ActivityToRecord[] = [];
- if (event.points) {
- _events.push({
- activity: {
- userId: event.builderId,
- amount: event.points,
- pointsDirection: PointsDirection.in,
- createdAt: getRandomDateWithinLast30Days()
- },
- sourceEvent: {
- gemsPayoutEventId: event.id
- }
- });
- }
-
- if (event.points) {
- _events.push({
- activity: {
- userId: event.builderId,
- amount: event.points,
- pointsDirection: PointsDirection.in,
- createdAt: getRandomDateWithinLast30Days()
- },
- sourceEvent: {
- gemsPayoutEventId: event.id
- }
- });
- }
-
- return _events;
- }),
- ...(builderTokenEvents?.nftSoldEvents.map((event) => ({
- activity: {
- userId: event.scoutId,
- amount: 0,
- pointsDirection: PointsDirection.in,
- createdAt: getRandomDateWithinLast30Days()
- },
- sourceEvent: {
- builderStrikeId: event.scoutId
- }
- })) || [])
- ];
-
- // Ensure no NFTs are sold until the BuilderToken is issued
- const builderTokenIssuedAt = builderTokenEvents ? getRandomDateWithinLast30Days() : null;
- if (builderTokenIssuedAt) {
- builderTokenEvents!.createdAt = builderTokenIssuedAt;
- events.push({
- activity: {
- userId: builderTokenEvents!.builderId,
- amount: 0,
- pointsDirection: PointsDirection.in,
- createdAt: builderTokenIssuedAt
- },
- sourceEvent: {
- builderStrikeId: builderTokenEvents!.id
- }
- });
- }
-
- // Sort events by createdAt
- events.sort((a, b) => a.activity.createdAt!.getTime() - b.activity.createdAt!.getTime());
-
- // Record activities
- for (const event of events) {
- await recordGameActivity(event).catch((error) => log.error(`Error recording activity`, { error }));
- }
-
- const stats = await prisma.userWeeklyStats.upsert({
- where: {
- userId_week: {
- userId,
- week: getCurrentWeek()
- }
- },
- create: {
- userId,
- season: currentSeason,
- week: getCurrentWeek(),
- gemsCollected: 30
- },
- update: {
- gemsCollected: 30
- }
- });
-}
-
-const githubLogin = 'motechFR';
-
-async function script() {
- const githubAccount = await ensureGithubUserExists({
- login: githubLogin
- });
-
- let user = await prisma.scout.findFirst({
- where: {
- githubUser: {
- some: {
- login: githubLogin
- }
- }
- }
- });
-
- if (!user) {
- user = await prisma.scout.create({
- data: {
- displayName: githubAccount.login as string,
- username: githubAccount.login as string,
- builderStatus: 'approved',
- githubUser: {
- connect: {
- id: githubAccount.id
- }
- }
- }
- });
- }
-
- const userId = user.id;
-
- const current = await prisma.scoutGameActivity.count({
- where: {
- userId
- }
- });
-
- await createMockEvents({ userId, amount: 7 });
-
- await generateActivities({ userId });
-
- const newCount = await prisma.scoutGameActivity.count({
- where: {
- userId
- }
- });
-
- await refreshUserStats({ userId });
-
- log.info(`Created ${newCount - current}`);
-}
-
-script();
diff --git a/packages/scoutgame/src/scripts/importScouts.ts b/packages/scoutgame/src/scripts/importScouts.ts
index 3b040f7e47..85b72c3c58 100644
--- a/packages/scoutgame/src/scripts/importScouts.ts
+++ b/packages/scoutgame/src/scripts/importScouts.ts
@@ -1,4 +1,5 @@
import { prisma } from '@charmverse/core/prisma-client';
+import { log } from '@charmverse/core/log';
import { getFarcasterUserByIds } from '@packages/farcaster/getFarcasterUserById';
@@ -15,7 +16,7 @@ async function query() {
}
});
const newUsers = FIDS.filter((fid) => !w.some((scout) => scout.farcasterId === fid));
- console.log('retrieved', newUsers);
+ log.info(`retrieved ${newUsers.length} new users`);
const users = await getFarcasterUserByIds(newUsers);
for (const user of users) {
const scout = await prisma.scout.findFirst({
@@ -24,20 +25,24 @@ async function query() {
}
});
if (scout) {
- console.log('scout already exists', scout.username);
+ log.info(`scout already exists`, {
+ path: scout.path,
+ fid: user.fid,
+ displayName: user.display_name
+ });
continue;
}
const newScout = await prisma.scout.create({
data: {
farcasterId: user.fid,
- username: user.username,
+ path: user.username,
displayName: user.display_name || user.username,
avatar: user.pfp_url,
bio: user.profile.bio.text,
currentBalance: startingBalance
}
});
- console.log('created scout', newScout.username);
+ log.info(`created scout ${newScout.path}`);
}
}
diff --git a/packages/scoutgame/src/scripts/query.ts b/packages/scoutgame/src/scripts/query.ts
index 6aace143cb..3a04137350 100644
--- a/packages/scoutgame/src/scripts/query.ts
+++ b/packages/scoutgame/src/scripts/query.ts
@@ -25,7 +25,7 @@ async function query() {
const nft = nfts[i];
console.log('Processing NFT', nft.tokenId, `--- ${i + 1} / ${nfts.length}`);
await uploadArtwork({
- username: nft.builder.username,
+ displayName: nft.builder.displayName,
season: currentSeason,
avatar: nft.builder.avatar as string,
tokenId: nft.tokenId
@@ -34,7 +34,7 @@ async function query() {
await uploadMetadata({
season: currentSeason,
tokenId: nft.tokenId,
- username: nft.builder.username
+ path: nft.builder.path!
});
}
}
diff --git a/packages/scoutgame/src/scripts/uploadNFTArtwork.ts b/packages/scoutgame/src/scripts/uploadNFTArtwork.ts
index 375ddb7167..7958026671 100644
--- a/packages/scoutgame/src/scripts/uploadNFTArtwork.ts
+++ b/packages/scoutgame/src/scripts/uploadNFTArtwork.ts
@@ -1,51 +1,61 @@
import { prisma } from '@charmverse/core/prisma-client';
import { uploadArtwork, uploadArtworkCongrats } from '../builderNfts/artwork/uploadArtwork';
+import { currentSeason } from '../dates';
+import { log } from '@charmverse/core/log';
async function uploadNFTArtwork() {
- const scouts = await prisma.scout.findMany({
+ const builders = await prisma.scout.findMany({
where: {
- builderStatus: 'approved'
+ username: 'safwan',
+ builderStatus: {
+ in: ['approved', 'banned']
+ }
},
select: {
avatar: true,
- username: true,
- builderNfts: true
+ displayName: true,
+ builderNfts: {
+ where: {
+ season: currentSeason
+ }
+ }
}
});
- // const w = await prisma.builderNft.deleteMany({});
- const mappedWithimage = await Promise.all(
- scouts.map(async (scout) => {
+
+ for (const builder of builders) {
+ const builderNft = builder.builderNfts[0];
+ try {
const imageUrl = await uploadArtwork({
- username: scout.username,
- season: scout.builderNfts[0].season,
- avatar: scout.avatar,
- tokenId: scout.builderNfts[0].tokenId
+ displayName: 'safwan 🎩🚨',
+ season: currentSeason,
+ avatar: builder.avatar,
+ tokenId: builderNft.tokenId,
});
const congratsImageUrl = await uploadArtworkCongrats({
- season: scout.builderNfts[0].season,
- tokenId: scout.builderNfts[0].tokenId,
+ season: currentSeason,
+ tokenId: builderNft.tokenId,
userImage: imageUrl
});
- return {
- nft: scout.builderNfts[0],
- scout,
- imageUrl,
- congratsImageUrl
- };
- })
- );
- for (const image of mappedWithimage) {
- await prisma.builderNft.update({
- where: {
- id: image.nft!.id
- },
- data: {
- imageUrl: image.imageUrl,
- congratsImageUrl: image.congratsImageUrl
- }
- });
+ await prisma.builderNft.update({
+ where: {
+ id: builderNft.id
+ },
+ data: {
+ imageUrl,
+ congratsImageUrl
+ }
+ });
+ log.info(`Updated ${builderNft.tokenId}`, {
+ tokenId: builderNft.tokenId
+ });
+ } catch (error) {
+ log.error(`Error updating ${builderNft.tokenId}`, {
+ error,
+ tokenId: builderNft.tokenId
+ });
+ }
}
}
diff --git a/packages/scoutgame/src/testing/database.ts b/packages/scoutgame/src/testing/database.ts
index 67056f29ec..ea91010316 100644
--- a/packages/scoutgame/src/testing/database.ts
+++ b/packages/scoutgame/src/testing/database.ts
@@ -14,10 +14,10 @@ type RepoAddress = {
export async function mockBuilder({
id,
createdAt,
+ displayName = 'Test User',
builderStatus = 'approved',
githubUserId = randomLargeInt(),
onboardedAt,
- username = uuid(),
path = uuid(),
agreedToTermsAt = new Date(),
nftSeason = mockSeason,
@@ -27,9 +27,8 @@ export async function mockBuilder({
const result = await prisma.scout.create({
data: {
createdAt,
- username,
path,
- displayName: 'Test User',
+ displayName,
builderStatus,
onboardedAt,
agreedToTermsAt,
@@ -37,7 +36,7 @@ export async function mockBuilder({
githubUser: {
create: {
id: githubUserId,
- login: username!
+ login: path!
}
}
},
@@ -56,7 +55,7 @@ export async function mockBuilder({
export type MockBuilder = Awaited>;
export async function mockScout({
- username = `user-${uuid()}`,
+ path = `user-${uuid()}`,
displayName = 'Test Scout',
agreedToTermsAt = new Date(),
onboardedAt = new Date(),
@@ -64,7 +63,7 @@ export async function mockScout({
season,
email
}: {
- username?: string;
+ path?: string;
agreedToTermsAt?: Date | null;
onboardedAt?: Date | null;
displayName?: string;
@@ -74,7 +73,7 @@ export async function mockScout({
} = {}) {
const scout = await prisma.scout.create({
data: {
- username,
+ path,
agreedToTermsAt,
onboardedAt,
displayName,
diff --git a/scripts/migrations/2024_10_17_fixScoutScores.ts b/scripts/migrations/2024_10_17_fixScoutScores.ts
index 7f14223b5c..d996249c5e 100644
--- a/scripts/migrations/2024_10_17_fixScoutScores.ts
+++ b/scripts/migrations/2024_10_17_fixScoutScores.ts
@@ -55,7 +55,7 @@ async function query() {
select: {
id: true,
farcasterId: true,
- username: true,
+ path: true,
currentBalance: true,
nftPurchaseEvents: true
}
@@ -84,14 +84,14 @@ async function query() {
// console.log(event.builder.username, event.pointsReceipts[0].value, event.builder.nftPurchaseEvents.length);
// }
// await refreshPointStatsFromHistory({ userIdOrUsername: event.builder.id });
- const stats = await getPointStatsFromHistory({ userIdOrUsername: event.builder.id });
+ const stats = await getPointStatsFromHistory({ userIdOrPath: event.builder.id });
const currentbalance = event.builder.currentBalance;
const newBalance = stats.balance + event.pointsReceipts[0].value;
if (newBalance === currentbalance) {
- unchanged.push(event.builder.username);
+ unchanged.push(event.builder.path!);
}
if (friendIds.includes(event.builder.id)) {
- _friends.push(event.builder.username);
+ _friends.push(event.builder.path!);
}
if (currentbalance === newBalance) {
// good to go
@@ -103,12 +103,12 @@ async function query() {
userId: event.builder.id,
builderEventId: event.id
});
- fixable.push(event.builder.username);
+ fixable.push(event.builder.path!);
} else if (newBalance < 0) {
// good to go
// console.log('Good to go:', event);
console.log('Negative balance:', {
- username: event.builder.username,
+ path: event.builder.path!,
allpointsReceived: stats.unclaimedPoints + stats.claimedPoints,
// unclaimedPoints: stats.unclaimedPoints,
...stats,
@@ -123,11 +123,11 @@ async function query() {
builderEventId: event.id
});
// break;
- needsFix.push(event.builder.username);
+ needsFix.push(event.builder.path!);
} else {
console.log('Good to go:', event);
console.log('Will fix but check update:', {
- username: event.builder.username,
+ path: event.builder.path!,
allpointsReceived: stats.unclaimedPoints + stats.claimedPoints,
// unclaimedPoints: stats.unclaimedPoints,
...stats,
@@ -163,7 +163,7 @@ async function query() {
userId: event.builder.id,
builderEventId: event.id
});
- fixableButCHeck.push(event.builder.username);
+ fixableButCHeck.push(event.builder.path!);
}
}
console.log({
@@ -232,7 +232,7 @@ async function fixEvents({
}
})
]);
- const stats = await getPointStatsFromHistory({ userIdOrUsername: userId });
+ const stats = await getPointStatsFromHistory({ userIdOrPath: userId });
const scout = await prisma.scout.update({
where: {
id: userId
diff --git a/scripts/migrations/2024_10_29_migrateScoutPaths.ts b/scripts/migrations/2024_10_29_migrateScoutPaths.ts
new file mode 100644
index 0000000000..47d7d2e4b2
--- /dev/null
+++ b/scripts/migrations/2024_10_29_migrateScoutPaths.ts
@@ -0,0 +1,25 @@
+import { log } from '@charmverse/core/log';
+import { prisma } from '@charmverse/core/prisma-client';
+
+async function migrateScoutPaths() {
+ const scouts = await prisma.scout.findMany({
+ where: {
+ path: null
+ },
+ select: {
+ id: true,
+ username: true
+ }
+ });
+ for (const scout of scouts) {
+ await prisma.scout.update({
+ where: { id: scout.id },
+ data: {
+ path: scout.username
+ }
+ });
+ log.info(`Updated path for ${scout.username}`);
+ }
+}
+
+migrateScoutPaths();
\ No newline at end of file