Spaces:
Sleeping
Sleeping
Create server/index.js
Browse files- server/index.js +100 -0
server/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
require('dotenv').config();
|
| 2 |
+
const express = require('express');
|
| 3 |
+
const path = require('path');
|
| 4 |
+
const cors = require('cors');
|
| 5 |
+
const { createClient } = require('@supabase/supabase-js');
|
| 6 |
+
const { google } = require('googleapis');
|
| 7 |
+
const multer = require('multer');
|
| 8 |
+
const stream = require('stream');
|
| 9 |
+
|
| 10 |
+
const app = express();
|
| 11 |
+
const PORT = process.env.PORT || 7860;
|
| 12 |
+
const upload = multer({ storage: multer.memoryStorage() });
|
| 13 |
+
|
| 14 |
+
app.use(cors());
|
| 15 |
+
app.use(express.json());
|
| 16 |
+
app.use(express.static(path.join(__dirname, '../public')));
|
| 17 |
+
|
| 18 |
+
const supabase = createClient(
|
| 19 |
+
process.env.SUPABASE_URL,
|
| 20 |
+
process.env.SUPABASE_SERVICE_KEY
|
| 21 |
+
);
|
| 22 |
+
|
| 23 |
+
const oauth2Client = new google.auth.OAuth2(
|
| 24 |
+
process.env.GOOGLE_CLIENT_ID,
|
| 25 |
+
process.env.GOOGLE_CLIENT_SECRET,
|
| 26 |
+
process.env.GOOGLE_REDIRECT_URI
|
| 27 |
+
);
|
| 28 |
+
|
| 29 |
+
// 1. Connect Drive
|
| 30 |
+
app.get('/api/drive/connect', (req, res) => {
|
| 31 |
+
const { user_id } = req.query;
|
| 32 |
+
const url = oauth2Client.generateAuthUrl({
|
| 33 |
+
access_type: 'offline',
|
| 34 |
+
scope: ['https://www.googleapis.com/auth/drive.file'],
|
| 35 |
+
state: user_id,
|
| 36 |
+
prompt: 'consent'
|
| 37 |
+
});
|
| 38 |
+
res.redirect(url);
|
| 39 |
+
});
|
| 40 |
+
|
| 41 |
+
// 2. Callback
|
| 42 |
+
app.get('/api/drive/callback', async (req, res) => {
|
| 43 |
+
const { code, state: user_id } = req.query;
|
| 44 |
+
try {
|
| 45 |
+
const { tokens } = await oauth2Client.getToken(code);
|
| 46 |
+
oauth2Client.setCredentials(tokens);
|
| 47 |
+
|
| 48 |
+
const drive = google.drive({ version: 'v3', auth: oauth2Client });
|
| 49 |
+
const folder = await drive.files.create({
|
| 50 |
+
resource: { name: 'AI Generations (App)', mimeType: 'application/vnd.google-apps.folder' },
|
| 51 |
+
fields: 'id'
|
| 52 |
+
});
|
| 53 |
+
|
| 54 |
+
await supabase.from('drive_accounts').upsert({
|
| 55 |
+
user_id: user_id,
|
| 56 |
+
folder_id: folder.data.id,
|
| 57 |
+
refresh_token: tokens.refresh_token
|
| 58 |
+
});
|
| 59 |
+
|
| 60 |
+
res.redirect('/?drive_success=true');
|
| 61 |
+
} catch (error) {
|
| 62 |
+
console.error(error);
|
| 63 |
+
res.redirect('/?drive_error=true');
|
| 64 |
+
}
|
| 65 |
+
});
|
| 66 |
+
|
| 67 |
+
// 3. Upload
|
| 68 |
+
app.post('/api/drive/upload', upload.single('image'), async (req, res) => {
|
| 69 |
+
const token = req.headers.authorization?.split(' ')[1];
|
| 70 |
+
const { data: { user } } = await supabase.auth.getUser(token);
|
| 71 |
+
if (!user) return res.status(401).json({ error: 'Unauthorized' });
|
| 72 |
+
|
| 73 |
+
const { data: driveData } = await supabase
|
| 74 |
+
.from('drive_accounts').select('*').eq('user_id', user.id).single();
|
| 75 |
+
|
| 76 |
+
if (!driveData) return res.status(400).json({ error: 'Drive not connected' });
|
| 77 |
+
|
| 78 |
+
oauth2Client.setCredentials({ refresh_token: driveData.refresh_token });
|
| 79 |
+
const drive = google.drive({ version: 'v3', auth: oauth2Client });
|
| 80 |
+
const bufferStream = new stream.PassThrough();
|
| 81 |
+
bufferStream.end(req.file.buffer);
|
| 82 |
+
|
| 83 |
+
const file = await drive.files.create({
|
| 84 |
+
resource: { name: `gen_${Date.now()}.png`, parents: [driveData.folder_id] },
|
| 85 |
+
media: { mimeType: 'image/png', body: bufferStream },
|
| 86 |
+
fields: 'id, webViewLink'
|
| 87 |
+
});
|
| 88 |
+
|
| 89 |
+
await supabase.from('generations').insert({
|
| 90 |
+
user_id: user.id,
|
| 91 |
+
prompt: req.body.prompt,
|
| 92 |
+
drive_file_id: file.data.id,
|
| 93 |
+
drive_view_link: file.data.webViewLink
|
| 94 |
+
});
|
| 95 |
+
|
| 96 |
+
res.json({ success: true, link: file.data.webViewLink });
|
| 97 |
+
});
|
| 98 |
+
|
| 99 |
+
app.get('*', (req, res) => res.sendFile(path.join(__dirname, '../public/index.html')));
|
| 100 |
+
app.listen(PORT, '0.0.0.0', () => console.log(`Running on ${PORT}`));
|