gmail-to-exchange365
Version:
Complete Gmail to Exchange 365 migration tool with UI - Migrate emails, attachments, and folders seamlessly
153 lines (131 loc) • 4.56 kB
text/typescript
import { Router, Request, Response } from "express";
import { generateGoogleAuthUrl, exchangeGoogleCode } from "./googleAuth";
import { getMSAuthUrl, exchangeMSCode } from "./msAuth";
import { migrateUser } from "./migrator";
import { UserSession } from "./types";
const router = Router();
// Extend Express Request to include session
interface SessionRequest extends Request {
session: any;
}
// Home page
router.get("/", (req: Request, res: Response) => {
res.sendFile("index.html", { root: __dirname + "/../ui" });
});
// Google OAuth
router.get("/google/auth", (req: Request, res: Response) => {
const authUrl = generateGoogleAuthUrl();
res.redirect(authUrl);
});
router.get("/google/callback", async (req: SessionRequest, res: Response) => {
try {
const code = req.query.code as string;
if (!code) {
return res.redirect("/?error=no_code");
}
const tokens = await exchangeGoogleCode(code);
req.session.google = tokens;
req.session.save(() => {
res.redirect("/?google=connected");
});
} catch (error: any) {
console.error("Google OAuth error:", error);
res.redirect("/?error=google_auth_failed");
}
});
// Microsoft OAuth
router.get("/ms/auth", (req: Request, res: Response) => {
const authUrl = getMSAuthUrl();
res.redirect(authUrl);
});
router.get("/ms/callback", async (req: SessionRequest, res: Response) => {
try {
const code = req.query.code as string;
if (!code) {
return res.redirect("/?error=no_code");
}
const tokens = await exchangeMSCode(code);
req.session.ms = tokens;
req.session.save(() => {
res.redirect("/?ms=connected");
});
} catch (error: any) {
console.error("Microsoft OAuth error:", error);
res.redirect("/?error=ms_auth_failed");
}
});
// Check auth status
router.get("/api/status", (req: SessionRequest, res: Response) => {
res.json({
google: !!req.session.google,
ms: !!req.session.ms
});
});
// Start migration
router.post("/api/migrate", async (req: SessionRequest, res: Response) => {
try {
if (!req.session.google || !req.session.ms) {
return res.status(400).json({
error: "Both Google and Microsoft accounts must be connected"
});
}
// Set up Server-Sent Events for progress updates
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
const options = {
batchSize: req.body.batchSize || 10,
delayBetweenBatches: req.body.delayBetweenBatches || 1000,
retryAttempts: req.body.retryAttempts || 3,
retryDelay: req.body.retryDelay || 5000
};
await migrateUser(
req.session.google,
req.session.ms,
(current, total, message) => {
const progress = {
current,
total,
percentage: total > 0 ? Math.round((current / total) * 100) : 0,
message: message || `Migrated ${current}/${total} emails`
};
res.write(`data: ${JSON.stringify(progress)}\n\n`);
},
options
);
res.write(`data: ${JSON.stringify({ completed: true })}\n\n`);
res.end();
} catch (error: any) {
console.error("Migration error:", error);
res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
res.end();
}
});
// Pause migration (would need to store migrator instance in production)
router.post("/api/migrate/pause", (req: SessionRequest, res: Response) => {
// In a real implementation, you'd store the migrator instance
// and call pause() on it
res.json({ message: "Migration paused" });
});
// Resume migration
router.post("/api/migrate/resume", (req: SessionRequest, res: Response) => {
// In a real implementation, you'd store the migrator instance
// and call resume() on it
res.json({ message: "Migration resumed" });
});
// Stop migration
router.post("/api/migrate/stop", (req: SessionRequest, res: Response) => {
// In a real implementation, you'd store the migrator instance
// and call stop() on it
res.json({ message: "Migration stopped" });
});
// Logout
router.post("/api/logout", (req: SessionRequest, res: Response) => {
req.session.destroy((err: any) => {
if (err) {
return res.status(500).json({ error: "Failed to logout" });
}
res.json({ message: "Logged out successfully" });
});
});
export default router;