2024-08-19 20:06:38 +02:00
import {
apiRoute ,
applyConfig ,
auth ,
handleZodError ,
idValidator ,
} from "@/api" ;
2024-05-06 09:16:33 +02:00
import { zValidator } from "@hono/zod-validator" ;
import { and , gt , gte , lt , sql } from "drizzle-orm" ;
import { z } from "zod" ;
2024-06-08 06:57:29 +02:00
import { RolePermissions , Users } from "~/drizzle/schema" ;
2024-05-29 02:59:49 +02:00
import { Timeline } from "~/packages/database-interface/timeline" ;
import { User } from "~/packages/database-interface/user" ;
2024-05-06 09:16:33 +02:00
export const meta = applyConfig ( {
allowedMethods : [ "GET" ] ,
ratelimits : {
max : 60 ,
duration : 60 ,
} ,
route : "/api/v1/accounts/:id/followers" ,
auth : {
required : false ,
oauthPermissions : [ "read:accounts" ] ,
} ,
2024-06-08 06:57:29 +02:00
permissions : {
required : [
2024-06-13 04:26:43 +02:00
RolePermissions . ViewAccountFollows ,
RolePermissions . ViewAccounts ,
2024-06-08 06:57:29 +02:00
] ,
} ,
2024-05-06 09:16:33 +02:00
} ) ;
export const schemas = {
query : z.object ( {
max_id : z.string ( ) . regex ( idValidator ) . optional ( ) ,
since_id : z.string ( ) . regex ( idValidator ) . optional ( ) ,
min_id : z.string ( ) . regex ( idValidator ) . optional ( ) ,
limit : z.coerce.number ( ) . int ( ) . min ( 1 ) . max ( 40 ) . optional ( ) . default ( 20 ) ,
} ) ,
param : z.object ( {
id : z.string ( ) . uuid ( ) ,
} ) ,
} ;
2024-08-19 20:06:38 +02:00
export default apiRoute ( ( app ) = >
2024-05-06 09:16:33 +02:00
app . on (
meta . allowedMethods ,
meta . route ,
zValidator ( "query" , schemas . query , handleZodError ) ,
zValidator ( "param" , schemas . param , handleZodError ) ,
2024-06-08 06:57:29 +02:00
auth ( meta . auth , meta . permissions ) ,
2024-05-06 09:16:33 +02:00
async ( context ) = > {
const { id } = context . req . valid ( "param" ) ;
const { max_id , since_id , min_id , limit } =
context . req . valid ( "query" ) ;
const otherUser = await User . fromId ( id ) ;
// TODO: Add follower/following privacy settings
2024-06-13 04:26:43 +02:00
if ( ! otherUser ) {
2024-08-19 21:03:59 +02:00
return context . json ( { error : "User not found" } , 404 ) ;
2024-06-13 04:26:43 +02:00
}
2024-05-06 09:16:33 +02:00
const { objects , link } = await Timeline . getUserTimeline (
and (
max_id ? lt ( Users . id , max_id ) : undefined ,
since_id ? gte ( Users . id , since_id ) : undefined ,
min_id ? gt ( Users . id , min_id ) : undefined ,
sql ` EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${ otherUser . id } AND "Relationships"."ownerId" = ${ Users . id } AND "Relationships"."following" = true) ` ,
) ,
limit ,
context . req . url ,
) ;
2024-08-19 21:03:59 +02:00
return context . json (
2024-06-13 04:26:43 +02:00
await Promise . all ( objects . map ( ( object ) = > object . toApi ( ) ) ) ,
2024-05-06 09:16:33 +02:00
200 ,
{
Link : link ,
} ,
) ;
} ,
2024-08-19 20:06:38 +02:00
) ,
) ;