feat(bots): Implement comprehensive bot system with autonomous posting, content management, and API endpoints
- Add bot management system with creation, suspension, and reinstatement functionality - Implement autonomous bot posting with scheduling, rate limiting, and content generation - Add content fetching system supporting RSS feeds and multiple content sources - Implement LLM-based content generation with customizable bot personalities - Add mention handling and automated response system for bot interactions - Implement API key management with encryption using AUTH_SECRET for simplified deployment - Add comprehensive bot logging system for activity tracking and error monitoring - Create bot administration pages and settings UI for managing bot configurations - Add database migrations for bot system schema including users, sources, and content items - Implement cron job system for automated bot operations and scheduled tasks - Add extensive test coverage with unit and property-based tests for core bot modules - Simplify encryption by deriving keys from AUTH_SECRET instead of separate environment variable - Implement automatic content fetching on post trigger with retry logic - Add Reddit-specific link preview handling using oEmbed API for reliable metadata extraction - Create utility scripts for bot inspection and cleanup operations - Add comprehensive bot system documentation and improvement tracking
This commit is contained in:
@@ -29,13 +29,15 @@ export async function GET(request: Request, context: RouteContext) {
|
||||
}
|
||||
|
||||
// Get followers
|
||||
const userFollowers = await db.query.follows.findMany({
|
||||
where: eq(follows.followingId, user.id),
|
||||
with: {
|
||||
follower: true,
|
||||
},
|
||||
limit,
|
||||
});
|
||||
const userFollowers = await db
|
||||
.select({
|
||||
id: follows.id,
|
||||
follower: users,
|
||||
})
|
||||
.from(follows)
|
||||
.innerJoin(users, eq(follows.followerId, users.id))
|
||||
.where(eq(follows.followingId, user.id))
|
||||
.limit(limit);
|
||||
|
||||
return NextResponse.json({
|
||||
followers: userFollowers.map(f => ({
|
||||
@@ -44,6 +46,7 @@ export async function GET(request: Request, context: RouteContext) {
|
||||
displayName: f.follower.displayName,
|
||||
avatarUrl: f.follower.avatarUrl,
|
||||
bio: f.follower.bio,
|
||||
isBot: f.follower.isBot,
|
||||
})),
|
||||
nextCursor: userFollowers.length === limit ? userFollowers[userFollowers.length - 1]?.id : null,
|
||||
});
|
||||
|
||||
@@ -29,13 +29,15 @@ export async function GET(request: Request, context: RouteContext) {
|
||||
}
|
||||
|
||||
// Get local following
|
||||
const userFollowing = await db.query.follows.findMany({
|
||||
where: eq(follows.followerId, user.id),
|
||||
with: {
|
||||
following: true,
|
||||
},
|
||||
limit,
|
||||
});
|
||||
const userFollowing = await db
|
||||
.select({
|
||||
id: follows.id,
|
||||
following: users,
|
||||
})
|
||||
.from(follows)
|
||||
.innerJoin(users, eq(follows.followingId, users.id))
|
||||
.where(eq(follows.followerId, user.id))
|
||||
.limit(limit);
|
||||
|
||||
const localFollowing = userFollowing.map(f => ({
|
||||
id: f.following.id,
|
||||
@@ -44,6 +46,7 @@ export async function GET(request: Request, context: RouteContext) {
|
||||
avatarUrl: f.following.avatarUrl,
|
||||
bio: f.following.bio,
|
||||
isRemote: false,
|
||||
isBot: f.following.isBot,
|
||||
}));
|
||||
|
||||
// Get remote following
|
||||
|
||||
@@ -119,20 +119,39 @@ export async function GET(request: Request, context: RouteContext) {
|
||||
}
|
||||
|
||||
// Return user profile (without sensitive data)
|
||||
return NextResponse.json({
|
||||
user: {
|
||||
id: user.id,
|
||||
handle: user.handle,
|
||||
displayName: user.displayName,
|
||||
bio: user.bio,
|
||||
avatarUrl: user.avatarUrl,
|
||||
headerUrl: user.headerUrl,
|
||||
followersCount: user.followersCount,
|
||||
followingCount: user.followingCount,
|
||||
postsCount: user.postsCount,
|
||||
createdAt: user.createdAt,
|
||||
// Include bot info if this is a bot account
|
||||
const userResponse: Record<string, unknown> = {
|
||||
id: user.id,
|
||||
handle: user.handle,
|
||||
displayName: user.displayName,
|
||||
bio: user.bio,
|
||||
avatarUrl: user.avatarUrl,
|
||||
headerUrl: user.headerUrl,
|
||||
followersCount: user.followersCount,
|
||||
followingCount: user.followingCount,
|
||||
postsCount: user.postsCount,
|
||||
createdAt: user.createdAt,
|
||||
website: user.website,
|
||||
movedTo: user.movedTo,
|
||||
isBot: user.isBot,
|
||||
};
|
||||
|
||||
// If this is a bot, include owner info
|
||||
if (user.isBot && user.botOwnerId) {
|
||||
const owner = await db.query.users.findFirst({
|
||||
where: eq(users.id, user.botOwnerId),
|
||||
});
|
||||
if (owner) {
|
||||
userResponse.botOwner = {
|
||||
id: owner.id,
|
||||
handle: owner.handle,
|
||||
displayName: owner.displayName,
|
||||
avatarUrl: owner.avatarUrl,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json({ user: userResponse });
|
||||
} catch (error) {
|
||||
console.error('Get user error:', error);
|
||||
return NextResponse.json({ error: 'Failed to get user' }, { status: 500 });
|
||||
|
||||
@@ -20,6 +20,7 @@ export async function GET(request: NextRequest) {
|
||||
bio: users.bio,
|
||||
avatarUrl: users.avatarUrl,
|
||||
createdAt: users.createdAt,
|
||||
isBot: users.isBot,
|
||||
})
|
||||
.from(users)
|
||||
.where(sql`${users.isSuspended} IS FALSE`)
|
||||
|
||||
Reference in New Issue
Block a user