Release 202505311001

This commit is contained in:
pluja
2025-05-31 10:01:35 +00:00
parent 22944fcdb3
commit e16c9b64ed
8 changed files with 89 additions and 42 deletions

View File

@@ -46,6 +46,9 @@ export const apiServiceActions = {
const service = await prisma.service.findFirst({
where: {
listedAt: { lte: new Date() },
serviceVisibility: { in: ['PUBLIC', 'ARCHIVED', 'UNLISTED'] },
OR: [
...(input.id ? ([{ id: input.id }] satisfies Prisma.ServiceWhereInput[]) : []),
...(input.slug ? ([{ slug: input.slug }] satisfies Prisma.ServiceWhereInput[]) : []),
@@ -76,10 +79,20 @@ export const apiServiceActions = {
i2pUrls: true,
tosUrls: true,
referral: true,
listedAt: true,
verifiedAt: true,
serviceVisibility: true,
},
})
if (!service) {
if (
!service ||
(service.serviceVisibility !== 'PUBLIC' &&
service.serviceVisibility !== 'ARCHIVED' &&
service.serviceVisibility !== 'UNLISTED') ||
!service.listedAt ||
service.listedAt > new Date()
) {
throw new ActionError({
code: 'NOT_FOUND',
message: 'Service not found',
@@ -91,6 +104,7 @@ export const apiServiceActions = {
slug: service.slug,
name: service.name,
description: service.description,
serviceVisibility: service.serviceVisibility,
verificationStatus: service.verificationStatus,
verificationStatusInfo: pick(getVerificationStatusInfo(service.verificationStatus), [
'value',
@@ -99,9 +113,11 @@ export const apiServiceActions = {
'labelShort',
'description',
]),
verifiedAt: service.verifiedAt,
kycLevel: service.kycLevel,
kycLevelInfo: pick(getKycLevelInfo(service.kycLevel.toString()), ['value', 'name', 'description']),
categories: service.categories,
listedAt: service.listedAt,
serviceUrls: [...service.serviceUrls, ...service.onionUrls, ...service.i2pUrls].map(
(url) => url + (service.referral ?? '')
),

View File

@@ -1,10 +1,4 @@
import {
Currency,
ServiceSuggestionStatus,
ServiceSuggestionType,
ServiceVisibility,
VerificationStatus,
} from '@prisma/client'
import { Currency } from '@prisma/client'
import { z } from 'astro/zod'
import { ActionError } from 'astro:actions'
import { formatDistanceStrict } from 'date-fns'
@@ -118,9 +112,9 @@ export const serviceSuggestionActions = {
const serviceSuggestion = await prisma.serviceSuggestion.create({
data: {
type: ServiceSuggestionType.EDIT_SERVICE,
type: 'EDIT_SERVICE',
notes: combinedNotes,
status: ServiceSuggestionStatus.PENDING,
status: 'PENDING',
userId: context.locals.user.id,
serviceId: service.id,
},
@@ -229,12 +223,12 @@ export const serviceSuggestionActions = {
kycLevel: input.kycLevel,
acceptedCurrencies: input.acceptedCurrencies,
imageUrl,
verificationStatus: VerificationStatus.COMMUNITY_CONTRIBUTED,
verificationStatus: 'COMMUNITY_CONTRIBUTED',
overallScore: 0,
privacyScore: 0,
trustScore: 0,
listedAt: new Date(),
serviceVisibility: ServiceVisibility.UNLISTED,
serviceVisibility: 'UNLISTED',
categories: {
connect: input.categories.map((id) => ({ id })),
},
@@ -250,8 +244,8 @@ export const serviceSuggestionActions = {
const serviceSuggestion = await tx.serviceSuggestion.create({
data: {
notes: input.notes,
type: ServiceSuggestionType.CREATE_SERVICE,
status: ServiceSuggestionStatus.PENDING,
type: 'CREATE_SERVICE',
status: 'PENDING',
userId: context.locals.user.id,
serviceId: service.id,
},

View File

@@ -15,17 +15,31 @@ const links = [
icon: 'ri:git-repository-line',
external: true,
},
...(Astro.url.origin !== new URL(ONION_ADDRESS).origin
? [
{
href: ONION_ADDRESS,
label: 'Tor',
icon: 'onion',
external: true,
},
]
: []),
...(Astro.url.origin !== new URL(I2P_ADDRESS).origin
? [
{
href: I2P_ADDRESS,
label: 'I2P',
icon: 'i2p',
external: true,
},
]
: []),
{
href: ONION_ADDRESS,
label: 'Tor',
icon: 'onion',
external: true,
},
{
href: I2P_ADDRESS,
label: 'I2P',
icon: 'i2p',
external: true,
href: '/docs/api',
label: 'API',
icon: 'ri:plug-line',
external: false,
},
{
href: '/about',

View File

@@ -65,7 +65,7 @@ export const {
value: 'ARCHIVED',
slug: 'archived',
label: 'Archived',
description: 'No longer operational',
description: 'No longer operational.',
longDescription:
'Archived service, no longer exists or ceased operations. Information may be outdated.',
icon: 'ri:archive-line',

View File

@@ -1,8 +1,8 @@
---
import { RELEASE_DATE, RELEASE_NUMBER } from 'astro:env/server'
import TimeFormatted from '../../components/TimeFormatted.astro'
import MiniLayout from '../../layouts/MiniLayout.astro'
import { timeAgo } from '../../lib/timeAgo'
const releaseDate =
RELEASE_DATE && !isNaN(new Date(RELEASE_DATE).getTime()) ? new Date(RELEASE_DATE) : undefined
@@ -37,7 +37,7 @@ const releaseDate =
{
!!releaseDate && (
<p class="text-day-500 mt-2">
(<TimeFormatted date={releaseDate} hourPrecision daysUntilDate={Infinity} />)
(<time datetime={releaseDate.toISOString()}>{timeAgo.format(releaseDate, 'round')}</time>)
</p>
)
}

View File

@@ -10,6 +10,7 @@ icon: 'ri:plug-line'
import { SOURCE_CODE_URL } from 'astro:env/server'
import { kycLevels } from '../../constants/kycLevels'
import { verificationStatuses } from '../../constants/verificationStatus'
import { serviceVisibilities } from '../../constants/serviceVisibility'
Access basic service data via our public API.
@@ -41,6 +42,7 @@ type ServiceResponse = {
slug: string
name: string
description: string
serviceVisibility: 'PUBLIC' | 'ARCHIVED' | 'UNLISTED'
verificationStatus: 'VERIFICATION_SUCCESS' | 'APPROVED' | 'COMMUNITY_CONTRIBUTED' | 'VERIFICATION_FAILED'
verificationStatusInfo: {
value: 'VERIFICATION_SUCCESS' | 'APPROVED' | 'COMMUNITY_CONTRIBUTED' | 'VERIFICATION_FAILED'
@@ -49,6 +51,7 @@ type ServiceResponse = {
labelShort: string
description: string
}
verifiedAt: Date | null
kycLevel: 0 | 1 | 2 | 3 | 4
kycLevelInfo: {
value: 0 | 1 | 2 | 3 | 4
@@ -59,13 +62,14 @@ type ServiceResponse = {
name: string
slug: string
}[]
listedAt: Date
serviceUrls: string[]
tosUrls: string[]
kycnotmeUrl: `https://kycnot.me/service/${service.slug}`
}
```
### KYC Levels
#### KYC Levels
<ul>
{kycLevels.map((level) => (
@@ -75,7 +79,7 @@ type ServiceResponse = {
))}
</ul>
### Verification Status
#### Verification Status
<ul>
{verificationStatuses.map((status) => (
@@ -85,7 +89,19 @@ type ServiceResponse = {
))}
</ul>
### Example Request
#### Service Visibility
<ul>
{serviceVisibilities.filter((visibility) => visibility.value === 'PUBLIC' || visibility.value === 'ARCHIVED' || visibility.value === 'UNLISTED').map((visibility) => (
<li key={visibility.value}>
<strong>{visibility.value}</strong>: {visibility.longDescription}
</li>
))}
</ul>
### Examples
#### Request
```zsh
curl -X QUERY https://kycnot.me/api/v1/service/get \
@@ -93,12 +109,13 @@ curl -X QUERY https://kycnot.me/api/v1/service/get \
-d '{"slug": "my-example-service"}'
```
### Example Response
#### Response
```json
{
"name": "My Example Service",
"description": "This is a description of my example service",
"serviceVisibility": "PUBLIC",
"verificationStatus": "VERIFICATION_SUCCESS",
"verificationStatusInfo": {
"value": "VERIFICATION_SUCCESS",
@@ -107,6 +124,7 @@ curl -X QUERY https://kycnot.me/api/v1/service/get \
"labelShort": "Verified",
"description": "Thoroughly tested and verified by the team. But things might change, this is not a guarantee."
},
"verifiedAt": "2025-01-20T07:12:29.393Z",
"kycLevel": 0,
"kycLevelInfo": {
"value": 0,
@@ -119,6 +137,7 @@ curl -X QUERY https://kycnot.me/api/v1/service/get \
"slug": "exchange"
}
],
"listedAt": "2025-05-31T19:09:18.043Z",
"serviceUrls": [
"https://example.com",
"http://c9ikae0fdidzh1ufrzp022e5uqfvz6ofxlkycz59cvo6fdxjgx7ekl9e.onion"
@@ -128,7 +147,7 @@ curl -X QUERY https://kycnot.me/api/v1/service/get \
}
```
### Error Responses
#### Error Responses
**404 Not Found**: Service not found

View File

@@ -218,16 +218,12 @@ const servicesQMatch = filters.q ? await findServicesBySimilarity(filters.q) : n
const where = {
id: servicesQMatch ? { in: servicesQMatch.map(({ id }) => id) } : undefined,
listedAt: {
lte: new Date(),
},
listedAt: { lte: new Date() },
categories: filters.categories.length ? { some: { slug: { in: filters.categories } } } : undefined,
verificationStatus: {
in: includeScams ? uniq([...filters.verification, 'VERIFICATION_FAILED'] as const) : filters.verification,
},
serviceVisibility: {
in: ['PUBLIC', 'ARCHIVED'],
},
serviceVisibility: { in: ['PUBLIC', 'ARCHIVED'] },
overallScore: { gte: filters['min-score'] },
acceptedCurrencies: filters.currencies.length
? filters['currency-mode'] === 'and'
@@ -319,9 +315,8 @@ const [categories, [services, totalServices], countCommunityOnly, attributes] =
select: {
services: {
where: {
serviceVisibility: {
in: ['PUBLIC', 'ARCHIVED'],
},
serviceVisibility: { in: ['PUBLIC', 'ARCHIVED'] },
listedAt: { lte: new Date() },
},
},
},

View File

@@ -94,7 +94,16 @@ const user = await Astro.locals.banners.try('user', async () => {
},
},
},
where: { service: { serviceVisibility: 'PUBLIC' } },
where: {
service: {
listedAt: {
lte: new Date(),
},
serviceVisibility: {
in: ['PUBLIC', 'ARCHIVED'],
},
},
},
orderBy: { createdAt: 'desc' },
take: 5,
},