114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
|
|
import { z } from 'astro/zod'
|
||
|
|
import { ActionError } from 'astro:actions'
|
||
|
|
import { pick } from 'lodash-es'
|
||
|
|
|
||
|
|
import { getKycLevelInfo } from '../../constants/kycLevels'
|
||
|
|
import { getVerificationStatusInfo } from '../../constants/verificationStatus'
|
||
|
|
import { defineProtectedAction } from '../../lib/defineProtectedAction'
|
||
|
|
import { prisma } from '../../lib/prisma'
|
||
|
|
import { zodUrlOptionalProtocol } from '../../lib/zodUtils'
|
||
|
|
|
||
|
|
import type { Prisma } from '@prisma/client'
|
||
|
|
|
||
|
|
export const apiServiceActions = {
|
||
|
|
get: defineProtectedAction({
|
||
|
|
accept: 'json',
|
||
|
|
permissions: 'guest',
|
||
|
|
input: z.object({
|
||
|
|
id: z.coerce.number().int().positive().optional(),
|
||
|
|
slug: z
|
||
|
|
.string()
|
||
|
|
.min(1)
|
||
|
|
.max(2048)
|
||
|
|
.regex(/^[a-z0-9-]+$/, 'Allowed characters: lowercase letters, numbers, and hyphens')
|
||
|
|
.optional(),
|
||
|
|
url: zodUrlOptionalProtocol.optional(),
|
||
|
|
}),
|
||
|
|
handler: async (input) => {
|
||
|
|
if (!input.id && !input.slug && !input.url) {
|
||
|
|
throw new ActionError({
|
||
|
|
code: 'BAD_REQUEST',
|
||
|
|
message: 'At least one of the following parameters is required: id, slug, url',
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
const urlVariants = input.url
|
||
|
|
? [input.url]
|
||
|
|
.flatMap((url) =>
|
||
|
|
[
|
||
|
|
url,
|
||
|
|
url.startsWith('http://') ? url.replace('http://', 'https://') : undefined,
|
||
|
|
url.startsWith('https://') ? url.replace('https://', 'http://') : undefined,
|
||
|
|
].filter((url) => url !== undefined)
|
||
|
|
)
|
||
|
|
.flatMap((url) => [url, url.endsWith('/') ? url.slice(0, -1) : `${url}/`])
|
||
|
|
: undefined
|
||
|
|
|
||
|
|
const service = await prisma.service.findFirst({
|
||
|
|
where: {
|
||
|
|
OR: [
|
||
|
|
...(input.id ? ([{ id: input.id }] satisfies Prisma.ServiceWhereInput[]) : []),
|
||
|
|
...(input.slug ? ([{ slug: input.slug }] satisfies Prisma.ServiceWhereInput[]) : []),
|
||
|
|
...(urlVariants
|
||
|
|
? ([
|
||
|
|
{ serviceUrls: { hasSome: urlVariants } },
|
||
|
|
{ onionUrls: { hasSome: urlVariants } },
|
||
|
|
{ i2pUrls: { hasSome: urlVariants } },
|
||
|
|
] satisfies Prisma.ServiceWhereInput[])
|
||
|
|
: []),
|
||
|
|
],
|
||
|
|
},
|
||
|
|
select: {
|
||
|
|
id: true,
|
||
|
|
name: true,
|
||
|
|
slug: true,
|
||
|
|
description: true,
|
||
|
|
kycLevel: true,
|
||
|
|
verificationStatus: true,
|
||
|
|
categories: {
|
||
|
|
select: {
|
||
|
|
name: true,
|
||
|
|
slug: true,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
serviceUrls: true,
|
||
|
|
onionUrls: true,
|
||
|
|
i2pUrls: true,
|
||
|
|
tosUrls: true,
|
||
|
|
referral: true,
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
if (!service) {
|
||
|
|
throw new ActionError({
|
||
|
|
code: 'NOT_FOUND',
|
||
|
|
message: 'Service not found',
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
id: service.id,
|
||
|
|
slug: service.slug,
|
||
|
|
name: service.name,
|
||
|
|
description: service.description,
|
||
|
|
verificationStatus: service.verificationStatus,
|
||
|
|
verificationStatusInfo: pick(getVerificationStatusInfo(service.verificationStatus), [
|
||
|
|
'value',
|
||
|
|
'slug',
|
||
|
|
'label',
|
||
|
|
'labelShort',
|
||
|
|
'description',
|
||
|
|
]),
|
||
|
|
kycLevel: service.kycLevel,
|
||
|
|
kycLevelInfo: pick(getKycLevelInfo(service.kycLevel.toString()), ['value', 'name', 'description']),
|
||
|
|
categories: service.categories,
|
||
|
|
serviceUrls: [...service.serviceUrls, ...service.onionUrls, ...service.i2pUrls].map(
|
||
|
|
(url) => url + (service.referral ?? '')
|
||
|
|
),
|
||
|
|
tosUrls: service.tosUrls,
|
||
|
|
kycnotmeUrl: `https://kycnot.me/service/${service.slug}`,
|
||
|
|
}
|
||
|
|
},
|
||
|
|
}),
|
||
|
|
}
|