From 3166349dfbd7bb03a72f0511d09052119148effb Mon Sep 17 00:00:00 2001 From: pluja Date: Thu, 3 Jul 2025 11:17:39 +0000 Subject: [PATCH] Release 202507031117 --- web/prisma/triggers/01_karma_tx.sql | 4 +- web/src/pages/sitemaps/search.xml.ts | 292 +++++++++++++-------------- 2 files changed, 147 insertions(+), 149 deletions(-) diff --git a/web/prisma/triggers/01_karma_tx.sql b/web/prisma/triggers/01_karma_tx.sql index c2256f7..600dcdf 100644 --- a/web/prisma/triggers/01_karma_tx.sql +++ b/web/prisma/triggers/01_karma_tx.sql @@ -275,7 +275,7 @@ CREATE OR REPLACE FUNCTION handle_suggestion_status_change() RETURNS TRIGGER AS $$ DECLARE service_name TEXT; - service_visibility "ServiceVisibility"; + service_visibility "serviceVisibility"; is_user_admin_or_moderator BOOLEAN; BEGIN -- Award karma for first approval @@ -283,7 +283,7 @@ BEGIN -- and ensure it wasn't already APPROVED. IF OLD.status IS DISTINCT FROM 'APPROVED' AND NEW.status = 'APPROVED' THEN -- Fetch service details for the description - SELECT name, visibility INTO service_name, service_visibility FROM "Service" WHERE id = NEW."serviceId"; + SELECT name, serviceVisibility INTO service_name, service_visibility FROM "Service" WHERE id = NEW."serviceId"; -- Only award karma if the service is public IF service_visibility = 'PUBLIC' THEN diff --git a/web/src/pages/sitemaps/search.xml.ts b/web/src/pages/sitemaps/search.xml.ts index 7acd90b..3107a90 100644 --- a/web/src/pages/sitemaps/search.xml.ts +++ b/web/src/pages/sitemaps/search.xml.ts @@ -7,186 +7,184 @@ import { makeSearchFiltersOptions } from '../../lib/searchFiltersOptions' import type { APIRoute } from 'astro' export const GET: APIRoute = async ({ site }) => { - if (!site) { - return new Response('Site URL not configured', { status: 500 }) - } + if (!site) return new Response('Site URL not configured', { status: 500 }) - const searchUrls = await generateSEOSitemapUrls(site.href) + try { + const searchUrls = await generateSEOSitemapUrls(site.href) - const result = ` + const result = ` ${searchUrls.map((url) => `${he.encode(url)}`).join('\n')} `.trim() - return new Response(result, { - headers: { - 'Content-Type': 'application/xml', - }, - }) + return new Response(result, { + headers: { + 'Content-Type': 'application/xml', + }, + }) + } catch (error) { + console.error('Failed to generate SEO sitemap URLs:', error) + return new Response('Failed to generate SEO sitemap URLs', { status: 500 }) + } } async function generateSEOSitemapUrls(siteUrl: string) { - try { - const [categories, attributes] = await Promise.all([ - prisma.category.findMany({ - select: { - name: true, - namePluralLong: true, - slug: true, - icon: true, - _count: { - select: { - services: { - where: { + const [categories, attributes] = await Promise.all([ + prisma.category.findMany({ + select: { + name: true, + namePluralLong: true, + slug: true, + icon: true, + _count: { + select: { + services: { + where: { + serviceVisibility: { in: ['PUBLIC', 'ARCHIVED'] }, + }, + }, + }, + }, + }, + }), + prisma.attribute.findMany({ + select: { + id: true, + slug: true, + title: true, + category: true, + type: true, + _count: { + select: { + services: { + where: { + service: { serviceVisibility: { in: ['PUBLIC', 'ARCHIVED'] }, }, }, }, }, }, - }), - prisma.attribute.findMany({ - select: { - id: true, - slug: true, - title: true, - category: true, - type: true, - _count: { - select: { - services: { - where: { - service: { - serviceVisibility: { in: ['PUBLIC', 'ARCHIVED'] }, - }, - }, - }, - }, - }, - }, - orderBy: [{ category: 'asc' }, { type: 'asc' }, { title: 'asc' }], - }), - ]) + }, + orderBy: [{ category: 'asc' }, { type: 'asc' }, { title: 'asc' }], + }), + ]) - const filtersOptions = makeSearchFiltersOptions({ - filters: null, - categories, - attributes, - }) + const filtersOptions = makeSearchFiltersOptions({ + filters: null, + categories, + attributes, + }) - const byCategory = filtersOptions.categories.map( - (category) => + const byCategory = filtersOptions.categories.map( + (category) => + new URLSearchParams({ + categories: category.slug, + }) + ) + + const byVerificationStatus = filtersOptions.verification.map( + (status) => + new URLSearchParams({ + verification: status.slug, + }) + ) + + const byKycLevel = filtersOptions.kycLevels.map( + (level) => + new URLSearchParams({ + 'max-kyc': level.id, + }) + ) + + const byCurrency = filtersOptions.currencies.map( + (currency) => + new URLSearchParams({ + currencies: currency.slug, + }) + ) + + const withOneAttribute = filtersOptions.attributesByCategory + .flatMap(({ attributes }) => attributes) + .map( + (attribute) => new URLSearchParams({ - categories: category.slug, + [`attr-${attribute.id.toString()}`]: 'yes', + }) + ) + const withoutOneAttribute = filtersOptions.attributesByCategory + .flatMap(({ attributes }) => attributes) + .map( + (attribute) => + new URLSearchParams({ + [`attr-${attribute.id.toString()}`]: 'no', }) ) - const byVerificationStatus = filtersOptions.verification.map( - (status) => - new URLSearchParams({ - verification: status.slug, - }) - ) - - const byKycLevel = filtersOptions.kycLevels.map( - (level) => - new URLSearchParams({ - 'max-kyc': level.id, - }) - ) - - const byCurrency = filtersOptions.currencies.map( + const byCategoryAndCurrency = filtersOptions.categories.flatMap((category) => + filtersOptions.currencies.map( (currency) => new URLSearchParams({ + categories: category.slug, currencies: currency.slug, }) ) + ) - const withOneAttribute = filtersOptions.attributesByCategory + const byCategoryAndAttributes = filtersOptions.categories.flatMap((category) => + filtersOptions.attributesByCategory .flatMap(({ attributes }) => attributes) - .map( - (attribute) => - new URLSearchParams({ - [`attr-${attribute.id.toString()}`]: 'yes', - }) - ) - const withoutOneAttribute = filtersOptions.attributesByCategory + .flatMap((attribute) => [ + new URLSearchParams({ + categories: category.slug, + [`attr-${attribute.id.toString()}`]: 'yes', + }), + new URLSearchParams({ + categories: category.slug, + [`attr-${attribute.id.toString()}`]: 'no', + }), + ]) + ) + + const relevantCurrencies = [ + 'xmr', + 'btc', + ] as const satisfies (typeof filtersOptions.currencies)[number]['slug'][] + + const byCategoryAndAttributesAndRelevantCurrency = filtersOptions.categories.flatMap((category) => + filtersOptions.attributesByCategory .flatMap(({ attributes }) => attributes) - .map( - (attribute) => - new URLSearchParams({ - [`attr-${attribute.id.toString()}`]: 'no', - }) - ) - - const byCategoryAndCurrency = filtersOptions.categories.flatMap((category) => - filtersOptions.currencies.map( - (currency) => - new URLSearchParams({ - categories: category.slug, - currencies: currency.slug, - }) - ) - ) - - const byCategoryAndAttributes = filtersOptions.categories.flatMap((category) => - filtersOptions.attributesByCategory - .flatMap(({ attributes }) => attributes) - .flatMap((attribute) => [ - new URLSearchParams({ - categories: category.slug, - [`attr-${attribute.id.toString()}`]: 'yes', - }), - new URLSearchParams({ - categories: category.slug, - [`attr-${attribute.id.toString()}`]: 'no', - }), - ]) - ) - - const relevantCurrencies = [ - 'xmr', - 'btc', - ] as const satisfies (typeof filtersOptions.currencies)[number]['slug'][] - - const byCategoryAndAttributesAndRelevantCurrency = filtersOptions.categories.flatMap((category) => - filtersOptions.attributesByCategory - .flatMap(({ attributes }) => attributes) - .flatMap((attribute) => - relevantCurrencies.map( - (currency) => - new URLSearchParams({ - categories: category.slug, - currencies: currency, - [`attr-${attribute.id.toString()}`]: - attribute.type === 'GOOD' || attribute.type === 'INFO' ? 'yes' : 'no', - }) - ) + .flatMap((attribute) => + relevantCurrencies.map( + (currency) => + new URLSearchParams({ + categories: category.slug, + currencies: currency, + [`attr-${attribute.id.toString()}`]: + attribute.type === 'GOOD' || attribute.type === 'INFO' ? 'yes' : 'no', + }) ) - ) + ) + ) - const allQueryParams = [ - ...byCategory, - ...byVerificationStatus, - ...byKycLevel, - ...byCurrency, - ...withOneAttribute, - ...withoutOneAttribute, + const allQueryParams = [ + ...byCategory, + ...byVerificationStatus, + ...byKycLevel, + ...byCurrency, + ...withOneAttribute, + ...withoutOneAttribute, - ...byCategoryAndCurrency, - ...byCategoryAndAttributes, - ...byCategoryAndAttributesAndRelevantCurrency, - ] satisfies URLSearchParams[] + ...byCategoryAndCurrency, + ...byCategoryAndAttributes, + ...byCategoryAndAttributesAndRelevantCurrency, + ] satisfies URLSearchParams[] - return allQueryParams.map((queryParams) => { - const url = new URL(siteUrl) - url.search = queryParams.toString() - return url.href - }) - } catch (error) { - console.error('Failed to generate SEO sitemap URLs:', error) - return [] - } + return allQueryParams.map((queryParams) => { + const url = new URL(siteUrl) + url.search = queryParams.toString() + return url.href + }) }