Skip to content

Commit

Permalink
Merge pull request #4975 from Giveth/new_release_vouched_superfluid
Browse files Browse the repository at this point in the history
New release: Vouched projects &  and superfluid Base improvements
  • Loading branch information
kkatusic authored Jan 27, 2025
2 parents 0c16398 + f667925 commit b3dea9b
Show file tree
Hide file tree
Showing 31 changed files with 839 additions and 107 deletions.
1 change: 1 addition & 0 deletions lang/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@
"label.email_verified": "Correu electrònic verificat",
"label.email_verify": "Verifica el correu electrònic",
"label.email_already_verified": "El teu correu electrònic ha estat verificat. Ara pots desar la informació del teu perfil.",
"label.email_cooldown": "No has rebut el correu electrònic? Revisa la carpeta de correu brossa o <button>Torna a enviar el codi de verificació!</button> en <time>02:59</time>",
"label.email_used": "Aquesta adreça de correu electrònic s'utilitzarà per enviar-te comunicacions importants.",
"label.email_used_another": "Aquest correu electrònic ja ha estat verificat en un altre perfil!",
"label.email_sent_to": "Codi de verificació enviat a {email}",
Expand Down
1 change: 1 addition & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@
"label.email_verified": "Email Verified",
"label.email_verify": "Verify Email",
"label.email_already_verified": "Your email has been verified. You can now save your profile information.",
"label.email_cooldown": "Didn't get the email? Check your spam folder or <button>Resend Verification Code!</button> in <time>02:59</time>",
"label.email_used": "This email address will be used to send you important communications.",
"label.email_used_another": "This email that has already been verified on another profile!",
"label.email_sent_to": "Verification code sent to {email}",
Expand Down
1 change: 1 addition & 0 deletions lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@
"label.email_verified": "Correo electrónico verificado",
"label.email_verify": "Verificar correo electrónico",
"label.email_already_verified": "Tu correo electrónico ha sido verificado. Ahora puedes guardar la información de tu perfil.",
"label.email_cooldown": "¿No recibiste el correo electrónico? Revisa tu carpeta de spam o <button>¡Reenviar código de verificación!</button> en <time>02:59</time>",
"label.email_used": "Esta dirección de correo electrónico se utilizará para enviarte comunicaciones importantes.",
"label.email_used_another": "¡Este correo electrónico ya ha sido verificado en otro perfil!",
"label.email_sent_to": "Código de verificación enviado a {email}",
Expand Down
263 changes: 263 additions & 0 deletions pages/api/generate-sitemap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
import fs from 'fs';
import path from 'path';
import { NextApiRequest, NextApiResponse } from 'next';
import { User } from '@sentry/types';
import config from '@/configuration';
import { initializeApollo } from '@/apollo/apolloClient';
import { OPTIONS_HOME_PROJECTS } from '@/apollo/gql/gqlOptions';
import { FETCH_ALL_PROJECTS } from '@/apollo/gql/gqlProjects';
import { EProjectsSortBy } from '@/apollo/types/gqlEnums';
import { getMainCategorySlug } from '@/helpers/projects';
import { escapeXml } from '@/helpers/xml';
import { IProject, IQFRound } from '@/apollo/types/types';
import { FETCH_QF_ROUNDS_QUERY } from '@/apollo/gql/gqlQF';
import { FETCH_ALL_USERS_BASIC_DATA } from '@/apollo/gql/gqlUser';
import { addressToUserView } from '@/lib/routeCreators';
import { shortenAddress } from '@/lib/helpers';

const URL = config.FRONTEND_LINK;

function generateProjectsSiteMap(projects: IProject[]) {
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
${projects
.map(
({
slug,
title = '',
descriptionSummary = '',
}: {
slug: string;
title?: string;
descriptionSummary?: string;
}) => {
return `
<url>
<loc>${`${URL}/project/${slug}`}</loc>
<title>${escapeXml(title)}</title>
<description>${escapeXml(descriptionSummary)}</description>
</url>
`;
},
)
.join('')}
</urlset>`;
}

function generateQFRoundsSiteMap(rounds: IQFRound[]) {
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
${rounds
.map(
({
slug,
name = '',
description = '',
}: {
slug: string;
name?: string;
description?: string;
}) => {
// Default to empty strings if any field is null
const safeSlug = slug || '';
const safeName = name || '';
const safeDescription = description || '';
return `
<url>
<loc>${`${URL}/qf-archive/${safeSlug}`}</loc>
<title>${escapeXml(safeName)}</title>
<description>${escapeXml(safeDescription)}</description>
</url>
`;
},
)
.join('')}
</urlset>`;
}

// Function to generate the XML sitemap for users
function generateUsersSiteMap(users: User[]) {
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
${users
.filter(({ walletAddress }) => walletAddress !== null)
.map(({ name = '', walletAddress = '' }) => {
const userUrl =
addressToUserView(walletAddress.toLowerCase()) || '';
const safeName = escapeXml(
name ||
shortenAddress(walletAddress.toLowerCase()) ||
'\u200C',
);
return `
<url>
<loc>${`${URL}${userUrl}`}</loc>
<title>${safeName}</title>
</url>
`;
})
.join('')}
</urlset>`;
}

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const authHeader = req.headers['authorization'];

// Only allow GET requests
if (req.method !== 'GET') {
return res.status(405).end();
}

if (authHeader !== `Bearer ${process.env.SITEMAP_CRON_SECRET}`) {
return res.status(405).end();
}

try {
/* PROJECT SITEMAP */

// Get first project data
const projectData = await getProjects(0);

const projects: IProject[] = projectData.allProjects?.projects || [];

if (projectData.allProjects.totalCount > 50) {
for (let i = 50; i < projectData.allProjects.totalCount; i += 50) {
const fetchNewProjectData = await getProjects(i);
projects.push(...fetchNewProjectData.allProjects?.projects);
}
}

// Generate XML content
const sitemapContent = generateProjectsSiteMap(projects);

// Define the file path
const filePath = path.join(
process.cwd(),
'public',
'sitemap',
'projects-sitemap.xml',
);

// Write the XML content to the file
await fs.promises.writeFile(filePath, sitemapContent, 'utf-8');

/* QF ARCHIVED ROUNDS SITEMAP */

// Get first project data
const roundsData = await getArchivedRounds();

// // Generate XML content
const sitemapRoundsContent = generateQFRoundsSiteMap(roundsData);

// Define the file path
const filePathQFRounds = path.join(
process.cwd(),
'public',
'sitemap',
'qf-sitemap.xml',
);

// // Write the XML content to the file
await fs.promises.writeFile(
filePathQFRounds,
sitemapRoundsContent,
'utf-8',
);

/* USER SITEMAP */

// Fetch user data
const users = await getUsers(0);
const userTotalCount = users.totalCount;
const userEntries = [...users.users];

// Fetch remaining users if necessary
if (userTotalCount > 50) {
for (let i = 50; i < userTotalCount; i += 50) {
const nextBatch = await getUsers(i);
userEntries.push(...nextBatch.users);
}
}

// Generate XML content for users
const sitemapUsersContent = generateUsersSiteMap(userEntries);

// Define the file path for users sitemap
const filePathUsers = path.join(
process.cwd(),
'public',
'sitemap',
'users-sitemap.xml',
);

// Write the XML content to the file
await fs.promises.writeFile(
filePathUsers,
sitemapUsersContent,
'utf-8',
);

// Respond with success
res.status(200).json({
message: 'Sitemap generated and saved successfully',
});
} catch (error) {
console.error('Error generating or saving sitemap:', error);
res.status(500).json({ error: 'Failed to generate sitemap' });
}
}

// Fetch project data from GraphQL
async function getProjects(skip: number) {
const apolloClient = initializeApollo();
const slug = 'all';
const { variables, notifyOnNetworkStatusChange } = OPTIONS_HOME_PROJECTS;

const { data } = await apolloClient.query({
query: FETCH_ALL_PROJECTS,
variables: {
...variables,
limit: 50,
skip: skip,
sortingBy: EProjectsSortBy.INSTANT_BOOSTING,
mainCategory: getMainCategorySlug({ slug }),
notifyOnNetworkStatusChange,
},
fetchPolicy: 'no-cache',
});

return data;
}

// Fetch qf archived rounds data from GraphQL
async function getArchivedRounds() {
const apolloClient = initializeApollo();

const { data } = await apolloClient.query({
query: FETCH_QF_ROUNDS_QUERY,
});

return data.qfRounds || [];
}

// Fetch user data from GraphQL
async function getUsers(skip: number) {
const apolloClient = initializeApollo();

const { data } = await apolloClient.query({
query: FETCH_ALL_USERS_BASIC_DATA, // Query for user data
variables: {
limit: 50,
skip: skip,
},
fetchPolicy: 'no-cache',
});

return data.allUsersBasicData || { users: [], totalCount: 0 };
}
10 changes: 2 additions & 8 deletions pages/qf-archive/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { GeneralMetatags } from '@/components/Metatag';
import { ArchivedQFRoundsView } from '@/components/views/archivedQFRounds/ArchivedQFRounds.view';
import { ArchivedQFRoundsProvider } from '@/components/views/archivedQFRounds/archivedQfRounds.context';
import { archivedQFRoundsMetaTags } from '@/content/metatags';

const ArchivedQFPageRoute = () => {
return (
<>
<GeneralMetatags
info={{
title: 'Giveth | Archived QF Rounds',
desc: 'Explore past quadratic funding rounds on Giveth! Check out the projects who participated, matching funds, donations and more info on this page.',
image: 'https://giveth.io/images/banners/qf-banner.svg',
url: `https://giveth.io/qf-archive`,
}}
/>
<GeneralMetatags info={archivedQFRoundsMetaTags} />
<ArchivedQFRoundsProvider>
<ArchivedQFRoundsView />
</ArchivedQFRoundsProvider>
Expand Down
Loading

0 comments on commit b3dea9b

Please sign in to comment.