semi working scheduling
This commit is contained in:
@@ -28,9 +28,10 @@ export async function POST(req: NextRequest) {
|
||||
{ status: 409 }
|
||||
);
|
||||
|
||||
await database.users.insertOne({ email, password, name });
|
||||
await database.users.insertOne({ email, password, name, platforms: [] });
|
||||
|
||||
const sessionId = (await database.sessions.insertOne({ email })).insertedId;
|
||||
const sessionId = (await database.sessions.insertOne({ user: email }))
|
||||
.insertedId;
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MongoClient } from 'mongodb';
|
||||
import config from './env';
|
||||
import { Session, User } from '@/utils';
|
||||
import { Schedule, Session, User } from '@/utils';
|
||||
|
||||
const client = new MongoClient(config.mongoUrl);
|
||||
|
||||
@@ -9,4 +9,5 @@ const db = client.db('klayrion');
|
||||
export default {
|
||||
users: db.collection<User>('users'),
|
||||
sessions: db.collection<Session>('sessions'),
|
||||
schedules: db.collection<Schedule>('schedules'),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { TwitterApi } from 'twitter-api-v2';
|
||||
import config from '@/app/api/env';
|
||||
import { inspect } from 'util';
|
||||
import { PostRequest } from '@/utils';
|
||||
import database from '../database';
|
||||
import { format } from 'date-fns';
|
||||
import cron from 'node-cron';
|
||||
|
||||
export default async function post({ platforms, content }: PostRequest) {
|
||||
try {
|
||||
for (const platform of platforms) {
|
||||
switch (platform.platform) {
|
||||
// X / Twitter
|
||||
case 'x':
|
||||
const twitterClient = new TwitterApi({
|
||||
appKey: config.twitter.key,
|
||||
appSecret: config.twitter.secret,
|
||||
accessToken: platform.token,
|
||||
accessSecret: platform.secret,
|
||||
});
|
||||
|
||||
await twitterClient.v2.tweet(content);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(inspect(err, true, null, true));
|
||||
}
|
||||
}
|
||||
|
||||
export async function processTasks() {
|
||||
try {
|
||||
const scheduled = format(new Date(), 'y-MM-d-hh:mm');
|
||||
|
||||
const tasks = await database.schedules
|
||||
.find({
|
||||
scheduled,
|
||||
})
|
||||
.toArray();
|
||||
|
||||
for (const task of tasks) {
|
||||
post(task);
|
||||
}
|
||||
|
||||
database.schedules.deleteMany({
|
||||
scheduled,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error processing tasks:', error);
|
||||
}
|
||||
}
|
||||
|
||||
cron.schedule('*/1 * * * *', processTasks);
|
||||
+58
-31
@@ -1,38 +1,14 @@
|
||||
import { NextResponse, NextRequest } from 'next/server';
|
||||
import { TwitterApi } from 'twitter-api-v2';
|
||||
import config from '@/app/api/env';
|
||||
import { PostRequest } from '@/utils';
|
||||
import { inspect } from 'util';
|
||||
import database from '../database';
|
||||
import { PostRequest, Schedule } from '@/utils';
|
||||
import post from './post';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { use } from 'react';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const { content, platforms }: PostRequest = await req.json();
|
||||
const request: PostRequest = await req.json();
|
||||
|
||||
try {
|
||||
for (const platform of platforms) {
|
||||
switch (platform.platform) {
|
||||
// X / Twitter
|
||||
case 'x':
|
||||
const twitterClient = new TwitterApi({
|
||||
appKey: config.twitter.key,
|
||||
appSecret: config.twitter.secret,
|
||||
accessToken: platform.token,
|
||||
accessSecret: platform.secret,
|
||||
});
|
||||
|
||||
await twitterClient.v2.tweet(content);
|
||||
|
||||
default:
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: 'Not implemented',
|
||||
},
|
||||
{ status: 501 }
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(inspect(err, true, null, true));
|
||||
}
|
||||
post(request);
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
@@ -41,3 +17,54 @@ export async function POST(req: NextRequest) {
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
export async function PUT(req: NextRequest) {
|
||||
const request: Schedule = await req.json();
|
||||
|
||||
database.schedules.insertOne(request);
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: 'ok',
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const sessionId = new URL(req.url).searchParams.get('id');
|
||||
|
||||
if (typeof sessionId !== 'string')
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: 'Invalid structure, required param `id=`',
|
||||
},
|
||||
{ status: 400 }
|
||||
);
|
||||
|
||||
const session = await database.sessions.findOne({
|
||||
_id: new ObjectId(sessionId),
|
||||
});
|
||||
|
||||
if (!session)
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: 'Invalid session',
|
||||
},
|
||||
{ status: 404 }
|
||||
);
|
||||
|
||||
const schedules = await database.schedules
|
||||
.find({
|
||||
account: session.user,
|
||||
})
|
||||
.toArray();
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: 'ok',
|
||||
schedules,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,9 @@ export async function POST(req: NextRequest) {
|
||||
{ status: 401 }
|
||||
);
|
||||
|
||||
const sessionId = (await database.sessions.insertOne({ email })).insertedId;
|
||||
const sessionId = (
|
||||
await database.sessions.insertOne({ user: user._id.toString() })
|
||||
).insertedId;
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useCalendarApp, ScheduleXCalendar } from '@schedule-x/react';
|
||||
import { createViewWeek } from '@schedule-x/calendar';
|
||||
|
||||
@@ -19,6 +20,9 @@ import { PlusCircle, Trash } from 'lucide-react';
|
||||
|
||||
import { format, parse } from 'date-fns';
|
||||
import PostDialog, { today } from '@/components/postDialog';
|
||||
import axios from 'axios';
|
||||
import Cookies from 'js-cookie';
|
||||
import { Schedule } from '@/utils';
|
||||
|
||||
function closestChild(children: any, clientX: number, clientY: number) {
|
||||
let closestElement = null;
|
||||
@@ -43,6 +47,7 @@ function CalendarApp() {
|
||||
const eventsService = useState(() => createEventsServicePlugin())[0];
|
||||
const dragAndDrop = useState(() => createDragAndDropPlugin())[0];
|
||||
const [eventCount, setEventCount] = useState(0);
|
||||
const sessionId = Cookies.get('session_id') || '';
|
||||
|
||||
const calendar = useCalendarApp({
|
||||
views: [createViewWeek()],
|
||||
@@ -51,6 +56,30 @@ function CalendarApp() {
|
||||
isDark: true,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
axios.get(`/api/posts/?id=${sessionId}`).then((response) => {
|
||||
for (const [id, sched] of (
|
||||
response.data.schedules as Schedule[]
|
||||
).entries()) {
|
||||
const date = parse(
|
||||
sched.scheduled,
|
||||
'y-MM-dd hh:mm',
|
||||
new Date()
|
||||
);
|
||||
const end = new Date(date);
|
||||
end.setHours(date.getHours() + 1);
|
||||
|
||||
calendar.events.add({
|
||||
title: 'Post',
|
||||
id,
|
||||
start: format(date, 'y-MM-dd hh:mm'),
|
||||
end: format(end, 'y-MM-dd hh:mm'),
|
||||
});
|
||||
setEventCount(eventCount + 1);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
const [newPostDialogOpen, setNewPostDialogOpen] = useState(false);
|
||||
const [date, setDate] = useState<Date>(today);
|
||||
const [selected, setSelected] = useState<string | null | undefined>(null);
|
||||
|
||||
@@ -6,14 +6,27 @@ import App from '@/components/app';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { cookies } from 'next/headers';
|
||||
import axios from 'axios';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
async function getSession(sessionId: string) {
|
||||
try {
|
||||
return (
|
||||
await axios.get(`http:/localhost:3000/api/session/?id=${sessionId}`)
|
||||
).data;
|
||||
} catch {
|
||||
redirect('/login');
|
||||
}
|
||||
}
|
||||
|
||||
export default async function Dashboard() {
|
||||
const cookieStore = await cookies();
|
||||
const sessionId = cookieStore.get('session_id')?.value;
|
||||
const sessionId = cookieStore.get('session_id')?.value || '';
|
||||
|
||||
const data = (
|
||||
await axios.get(`http:/localhost:3000/api/session/?id=${sessionId}`)
|
||||
).data.dashboard;
|
||||
const data = await getSession(sessionId);
|
||||
|
||||
if (!data) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (
|
||||
<App>
|
||||
|
||||
+26
-24
@@ -16,6 +16,30 @@ export default function Login() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
||||
const handleLogin = () => {
|
||||
async () => {
|
||||
try {
|
||||
const { sessionId } = (
|
||||
await axios.post('/api/session/', {
|
||||
email,
|
||||
password,
|
||||
})
|
||||
).data;
|
||||
|
||||
cookies.set('session_id', sessionId);
|
||||
|
||||
router.replace('/dashboard');
|
||||
} catch (err: any) {
|
||||
toast({
|
||||
title: 'Uh oh! Something went wrong.',
|
||||
description: err.response
|
||||
? err.response.data.message
|
||||
: String(err),
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-black w-full h-screen flex justify-center items-center">
|
||||
<div className="text-center">
|
||||
@@ -36,32 +60,10 @@ export default function Login() {
|
||||
type="password"
|
||||
placeholder="Your password"
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
onClick={handleLogin}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="mt-5 w-80 mx-auto"
|
||||
onClick={async () => {
|
||||
try {
|
||||
const { sessionId } = (
|
||||
await axios.post('/api/session/', {
|
||||
email,
|
||||
password,
|
||||
})
|
||||
).data;
|
||||
|
||||
cookies.set('session_id', sessionId);
|
||||
|
||||
router.replace('/dashboard');
|
||||
} catch (err: any) {
|
||||
toast({
|
||||
title: 'Uh oh! Something went wrong.',
|
||||
description: err.response
|
||||
? err.response.data.message
|
||||
: String(err),
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Button className="mt-5 w-80 mx-auto" onClick={handleLogin}>
|
||||
Log in
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,8 @@ import { CalendarEventExternal } from '@schedule-x/calendar';
|
||||
import { Textarea } from './ui/textarea';
|
||||
import { Label } from './ui/label';
|
||||
import { useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import { Schedule } from '@/utils';
|
||||
|
||||
type PostDialogProps = {
|
||||
newPostDialogOpen: boolean;
|
||||
@@ -42,7 +44,7 @@ export default function PostDialog({
|
||||
setNewPostDialogOpen,
|
||||
date,
|
||||
setDate,
|
||||
setEvents,
|
||||
setEvents: addEvent,
|
||||
eventId,
|
||||
}: PostDialogProps) {
|
||||
const [content, setContent] = useState('');
|
||||
@@ -123,12 +125,18 @@ export default function PostDialog({
|
||||
const end = new Date(date);
|
||||
end.setHours(date.getHours() + 1);
|
||||
|
||||
setEvents({
|
||||
addEvent({
|
||||
title: 'Post',
|
||||
id: eventId,
|
||||
start: format(date, 'y-MM-dd hh:mm'),
|
||||
end: format(end, 'y-MM-dd hh:mm'),
|
||||
});
|
||||
axios.put('http://localhost:3000/api/posts', {
|
||||
scheduled: format(date, 'y-MM-dd hh:mm'),
|
||||
account: '',
|
||||
platforms: [],
|
||||
content,
|
||||
} satisfies Schedule);
|
||||
|
||||
setNewPostDialogOpen(false);
|
||||
}}
|
||||
|
||||
+9
-1
@@ -1,3 +1,5 @@
|
||||
import { ObjectId } from 'mongodb';
|
||||
|
||||
export type PlatformKind = 'x' | 'linkedin';
|
||||
|
||||
export interface Platform {
|
||||
@@ -7,6 +9,7 @@ export interface Platform {
|
||||
}
|
||||
|
||||
export interface PostRequest {
|
||||
account: string;
|
||||
content: string;
|
||||
platforms: Platform[];
|
||||
}
|
||||
@@ -15,6 +18,11 @@ export interface User {
|
||||
name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
platforms: Platform[];
|
||||
}
|
||||
|
||||
export type Session = { email: string };
|
||||
export interface Schedule extends PostRequest {
|
||||
scheduled: string;
|
||||
}
|
||||
|
||||
export type Session = { user: string };
|
||||
|
||||
Reference in New Issue
Block a user