@tushar-br/desktop 1.0.234 → 1.0.237
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @tushar-br/desktop might be problematic. Click here for more details.
- package/package.json +1 -1
- package/staging_area/desktop/resume web/dist/assets/explorer/thispc/1771614269438_ENGLISH__diplomaitmorbi.netlify.app.pdf.ts_part_1 +0 -0
- package/staging_area/desktop/resume web/AUTO_SAVE_FEATURE.md +0 -128
- package/staging_area/desktop/resume web/Add Certificate.bat +0 -5
- package/staging_area/desktop/resume web/Add Post.bat +0 -46
- package/staging_area/desktop/resume web/Add Project.bat +0 -5
- package/staging_area/desktop/resume web/Add Status.bat +0 -41
- package/staging_area/desktop/resume web/BOOK_EDITOR_COMPLETE.md +0 -100
- package/staging_area/desktop/resume web/BOOK_EDITOR_TEST.md +0 -82
- package/staging_area/desktop/resume web/BOOK_FINAL.md +0 -120
- package/staging_area/desktop/resume web/BOOK_FINAL_SUMMARY.md +0 -290
- package/staging_area/desktop/resume web/BOOK_FIXES.md +0 -196
- package/staging_area/desktop/resume web/BOOK_README.md +0 -250
- package/staging_area/desktop/resume web/CHANGELOG.md +0 -29
- package/staging_area/desktop/resume web/api/chat-admin-otp.ts +0 -62
- package/staging_area/desktop/resume web/api/chat-admin-verify.ts +0 -41
- package/staging_area/desktop/resume web/api/chat-telegram-alert.ts +0 -30
- package/staging_area/desktop/resume web/api/cloudinary.ts +0 -98
- package/staging_area/desktop/resume web/api/email-notification.ts +0 -82
- package/staging_area/desktop/resume web/api/groq-chat.ts +0 -113
- package/staging_area/desktop/resume web/api/imagekit-auth.ts +0 -37
- package/staging_area/desktop/resume web/book.html +0 -527
- package/staging_area/desktop/resume web/chat-database.rules.json +0 -16
- package/staging_area/desktop/resume web/chat-firestore.rules +0 -18
- package/staging_area/desktop/resume web/database.rules.json +0 -8
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
# 📚 Book Editor - Professional Edition
|
|
2
|
-
|
|
3
|
-
## ✨ NEW DESIGN - Much Better!
|
|
4
|
-
|
|
5
|
-
### ✅ What Changed:
|
|
6
|
-
- ❌ **Removed** folder/file manager (not needed)
|
|
7
|
-
- ✅ **Added** professional SVG icons (no emojis!)
|
|
8
|
-
- ✅ **Added** beautiful White & Black themes
|
|
9
|
-
- ✅ **Single page** - simple and clean
|
|
10
|
-
- ✅ **Auto-save** - saves automatically every 30 seconds
|
|
11
|
-
- ✅ **Local storage** - works offline too!
|
|
12
|
-
|
|
13
|
-
## 🎨 Features
|
|
14
|
-
|
|
15
|
-
### Two Beautiful Themes:
|
|
16
|
-
1. **Light Theme** (White) - Clean, professional, easy on eyes
|
|
17
|
-
2. **Dark Theme** (Black) - Modern, sleek, perfect for night
|
|
18
|
-
|
|
19
|
-
### Two Modes:
|
|
20
|
-
1. **Text Editor** - Write notes with line numbers
|
|
21
|
-
2. **Painting** - Draw with brush tools
|
|
22
|
-
|
|
23
|
-
### Professional Icons:
|
|
24
|
-
- 💾 Save → Clean save icon
|
|
25
|
-
- 📝 Text → Document icon
|
|
26
|
-
- 🎨 Paint → Brush icon
|
|
27
|
-
- ☀️/🌙 Theme → Sun/Moon toggle
|
|
28
|
-
- 🗑️ Clear → Trash icon
|
|
29
|
-
|
|
30
|
-
## 🚀 Setup (One-Time)
|
|
31
|
-
|
|
32
|
-
### Step 1: Setup Database
|
|
33
|
-
1. Go to: https://kyfhibapmdcnlyjuenod.supabase.co
|
|
34
|
-
2. Click **SQL Editor**
|
|
35
|
-
3. Copy this SQL:
|
|
36
|
-
|
|
37
|
-
```sql
|
|
38
|
-
CREATE TABLE IF NOT EXISTS book_content (
|
|
39
|
-
id INTEGER PRIMARY KEY DEFAULT 1,
|
|
40
|
-
text_content TEXT DEFAULT '',
|
|
41
|
-
canvas_data TEXT DEFAULT '',
|
|
42
|
-
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
43
|
-
CONSTRAINT single_row CHECK (id = 1)
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
INSERT INTO book_content (id, text_content, canvas_data, updated_at)
|
|
47
|
-
VALUES (1, '', '', NOW())
|
|
48
|
-
ON CONFLICT (id) DO NOTHING;
|
|
49
|
-
|
|
50
|
-
ALTER TABLE book_content ENABLE ROW LEVEL SECURITY;
|
|
51
|
-
|
|
52
|
-
CREATE POLICY "Enable all operations for book_content" ON book_content
|
|
53
|
-
FOR ALL USING (true) WITH CHECK (true);
|
|
54
|
-
|
|
55
|
-
CREATE INDEX IF NOT EXISTS idx_book_content_updated_at ON book_content(updated_at DESC);
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
4. Click **RUN**
|
|
59
|
-
|
|
60
|
-
### Step 2: Open the App
|
|
61
|
-
- Double-click `book.html`
|
|
62
|
-
- Or drag to browser
|
|
63
|
-
|
|
64
|
-
## 🎯 How to Use
|
|
65
|
-
|
|
66
|
-
1. **Write Text:**
|
|
67
|
-
- Click "Text" mode
|
|
68
|
-
- Start typing
|
|
69
|
-
- Line numbers appear automatically
|
|
70
|
-
- Auto-saves every 30 seconds
|
|
71
|
-
|
|
72
|
-
2. **Draw:**
|
|
73
|
-
- Click "Paint" mode
|
|
74
|
-
- Choose brush size (slider)
|
|
75
|
-
- Pick color
|
|
76
|
-
- Draw on canvas
|
|
77
|
-
- Auto-saves
|
|
78
|
-
|
|
79
|
-
3. **Change Theme:**
|
|
80
|
-
- Click sun/moon icon (top right)
|
|
81
|
-
- Switches between white and black
|
|
82
|
-
- Theme preference is saved
|
|
83
|
-
|
|
84
|
-
4. **Save Manually:**
|
|
85
|
-
- Click "Save" button
|
|
86
|
-
- Saves to Supabase cloud
|
|
87
|
-
- Also saves locally
|
|
88
|
-
|
|
89
|
-
## 🎨 Theme Details
|
|
90
|
-
|
|
91
|
-
### Light Theme (White):
|
|
92
|
-
- Background: Pure white
|
|
93
|
-
- Text: Black
|
|
94
|
-
- Clean and professional
|
|
95
|
-
- Perfect for daytime
|
|
96
|
-
|
|
97
|
-
### Dark Theme (Black):
|
|
98
|
-
- Background: Deep black (#0a0a0f)
|
|
99
|
-
- Text: White
|
|
100
|
-
- Accent: Cyan (#00e5ff)
|
|
101
|
-
- Perfect for night work
|
|
102
|
-
|
|
103
|
-
## 💾 Storage
|
|
104
|
-
|
|
105
|
-
### Dual Storage System:
|
|
106
|
-
1. **Local Storage** (Browser)
|
|
107
|
-
- Instant save
|
|
108
|
-
- Works offline
|
|
109
|
-
- Auto-saves every 30 seconds
|
|
110
|
-
|
|
111
|
-
2. **Supabase Cloud**
|
|
112
|
-
- Manual save (click Save button)
|
|
113
|
-
- Syncs across devices
|
|
114
|
-
- Backup in cloud
|
|
115
|
-
|
|
116
|
-
## ⌨️ Keyboard Shortcuts
|
|
117
|
-
- **Ctrl + S** - Save to cloud
|
|
118
|
-
|
|
119
|
-
## 📱 Mobile Support
|
|
120
|
-
- ✅ Fully responsive
|
|
121
|
-
- ✅ Touch drawing works perfectly
|
|
122
|
-
- ✅ All icons visible
|
|
123
|
-
- ✅ Theme toggle works
|
|
124
|
-
|
|
125
|
-
## 🎯 UI Layout
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
┌──────────────────────────────────────────────┐
|
|
129
|
-
│ [💾 Save] [Text|Paint] [☀️/🌙] │ ← Top Bar
|
|
130
|
-
├──────────────────────────────────────────────┤
|
|
131
|
-
│ │
|
|
132
|
-
│ TEXT MODE: PAINTING MODE: │
|
|
133
|
-
│ ┌──┬─────────┐ ┌────────────────────┐ │
|
|
134
|
-
│ │1 │ Text... │ │ [Brush] [Color] │ │
|
|
135
|
-
│ │2 │ │ ├────────────────────┤ │
|
|
136
|
-
│ │3 │ │ │ │ │
|
|
137
|
-
│ └──┴─────────┘ │ Canvas │ │
|
|
138
|
-
│ └────────────────────┘ │
|
|
139
|
-
└──────────────────────────────────────────────┘
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## ✨ Professional Features
|
|
143
|
-
|
|
144
|
-
### Text Editor:
|
|
145
|
-
- Line numbers (auto-updating)
|
|
146
|
-
- Monospace font (Courier New)
|
|
147
|
-
- Smooth scrolling
|
|
148
|
-
- Auto-save
|
|
149
|
-
- Theme-aware colors
|
|
150
|
-
|
|
151
|
-
### Painting:
|
|
152
|
-
- Brush size: 1-30px
|
|
153
|
-
- Color picker
|
|
154
|
-
- Smooth drawing
|
|
155
|
-
- Touch support
|
|
156
|
-
- Clear canvas option
|
|
157
|
-
- Theme-aware background
|
|
158
|
-
|
|
159
|
-
### UI/UX:
|
|
160
|
-
- Clean, modern design
|
|
161
|
-
- Smooth transitions
|
|
162
|
-
- Professional icons (SVG)
|
|
163
|
-
- Responsive layout
|
|
164
|
-
- No clutter
|
|
165
|
-
|
|
166
|
-
## 🔧 Technical Improvements
|
|
167
|
-
|
|
168
|
-
### Old Version:
|
|
169
|
-
- ❌ Emoji icons (looked unprofessional)
|
|
170
|
-
- ❌ Complex file manager
|
|
171
|
-
- ❌ Multiple files confusion
|
|
172
|
-
- ❌ Only one theme
|
|
173
|
-
|
|
174
|
-
### New Version:
|
|
175
|
-
- ✅ SVG icons (professional)
|
|
176
|
-
- ✅ Single page (simple)
|
|
177
|
-
- ✅ Two beautiful themes
|
|
178
|
-
- ✅ Auto-save
|
|
179
|
-
- ✅ Local + Cloud storage
|
|
180
|
-
- ✅ Better performance
|
|
181
|
-
|
|
182
|
-
## 🎨 Color Scheme
|
|
183
|
-
|
|
184
|
-
### Light Theme:
|
|
185
|
-
- Background: `#ffffff` (white)
|
|
186
|
-
- Secondary: `#f8f9fa` (light gray)
|
|
187
|
-
- Text: `#000000` (black)
|
|
188
|
-
- Accent: `#0066cc` (blue)
|
|
189
|
-
- Border: `#dee2e6` (gray)
|
|
190
|
-
|
|
191
|
-
### Dark Theme:
|
|
192
|
-
- Background: `#0a0a0f` (deep black)
|
|
193
|
-
- Secondary: `#1a1a1f` (dark gray)
|
|
194
|
-
- Text: `#ffffff` (white)
|
|
195
|
-
- Accent: `#00e5ff` (cyan)
|
|
196
|
-
- Border: `#2a2a2f` (dark gray)
|
|
197
|
-
|
|
198
|
-
## 📊 What Gets Saved
|
|
199
|
-
|
|
200
|
-
In Supabase:
|
|
201
|
-
- Your text content
|
|
202
|
-
- Your canvas drawing (as image)
|
|
203
|
-
- Last update time
|
|
204
|
-
|
|
205
|
-
In Browser:
|
|
206
|
-
- Same as above
|
|
207
|
-
- Theme preference
|
|
208
|
-
- Auto-saved every 30 seconds
|
|
209
|
-
|
|
210
|
-
## 🐛 Troubleshooting
|
|
211
|
-
|
|
212
|
-
### Not saving to cloud?
|
|
213
|
-
- Check internet connection
|
|
214
|
-
- Make sure you ran the SQL setup
|
|
215
|
-
- Click Save button manually
|
|
216
|
-
|
|
217
|
-
### Theme not changing?
|
|
218
|
-
- Click the sun/moon icon (top right)
|
|
219
|
-
- Should switch instantly
|
|
220
|
-
|
|
221
|
-
### Canvas not drawing?
|
|
222
|
-
- Make sure you're in Paint mode
|
|
223
|
-
- Try different brush size
|
|
224
|
-
- Check if touch is working
|
|
225
|
-
|
|
226
|
-
## ✅ Summary
|
|
227
|
-
|
|
228
|
-
### What You Get:
|
|
229
|
-
- ✅ Single clean page
|
|
230
|
-
- ✅ Professional SVG icons
|
|
231
|
-
- ✅ Beautiful white theme
|
|
232
|
-
- ✅ Beautiful black theme
|
|
233
|
-
- ✅ Auto-save (every 30s)
|
|
234
|
-
- ✅ Manual save button
|
|
235
|
-
- ✅ Text editor with line numbers
|
|
236
|
-
- ✅ Painting canvas
|
|
237
|
-
- ✅ Mobile support
|
|
238
|
-
- ✅ Offline support
|
|
239
|
-
|
|
240
|
-
### No More:
|
|
241
|
-
- ❌ Emoji icons
|
|
242
|
-
- ❌ File manager complexity
|
|
243
|
-
- ❌ Multiple files confusion
|
|
244
|
-
- ❌ Single theme limitation
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
**File:** `book.html`
|
|
249
|
-
**Status:** ✅ Complete & Professional
|
|
250
|
-
**Design:** Much better than before!
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Portfolio Task Completion Report
|
|
2
|
-
|
|
3
|
-
All pending tasks have been completed. Below is a summary of the changes made:
|
|
4
|
-
|
|
5
|
-
## 1. Footer Layout Fix
|
|
6
|
-
- **Issue**: The `CreativeFooter` SVG animation (Black Hole effect) was causing layout shifts and extra whitespace at the bottom.
|
|
7
|
-
- **Fix**:
|
|
8
|
-
- Wrapped the black hole section in an `overflow: hidden` container.
|
|
9
|
-
- Adjusted the `marginTop` and `bottom` positioning to ensure it aligns perfectly with the content above without leaking out.
|
|
10
|
-
- Reduced the width from `180%` to `150%` and centered it to prevent horizontal scrolling issues.
|
|
11
|
-
- Smoothed out the glow and shadows for a cleaner look.
|
|
12
|
-
|
|
13
|
-
## 2. New Premium Background
|
|
14
|
-
- **Action**: Generated a unique, custom portfolio background image.
|
|
15
|
-
- **Design**: "Premium High-Tech Cybernetic Abstract" – features deep navy/charcoal tones, neon data streams, and hexagonal grid patterns.
|
|
16
|
-
- **Implementation**: Saved as `portfolio-bg-new.png` and updated `index.css` to use it site-wide.
|
|
17
|
-
|
|
18
|
-
## 3. Smooth Navigation & Aesthetics
|
|
19
|
-
- **Smooth Scroll**: Implemented `scroll-behavior: smooth` globally on both the body and the main desktop scroll container (`.main-col`).
|
|
20
|
-
- **Custom Scrollbar**: Added a premium-themed custom scrollbar for desktop users that matches the cyan-to-purple accent colors.
|
|
21
|
-
- **Improved "About" Page**: Added new service cards (Mobile App Development & Cyber Security) to give the portfolio a more professional and complete feel.
|
|
22
|
-
|
|
23
|
-
## 4. Pending Tasks Check
|
|
24
|
-
- Verified all main pages (`Home`, `About`, `Projects`, `Resume`, `Status`, `Certificates`) for functionality and responsiveness.
|
|
25
|
-
- Ensured the "OS Launch" section correctly leads to `os.html`.
|
|
26
|
-
- Cleaned up ad-hoc margins that were causing inconsistent spacing between the Bio and Footer sections.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
*All changes have been implemented and verified.*
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { VercelRequest, VercelResponse } from "@vercel/node";
|
|
2
|
-
import { initializeApp, getApps, getApp } from "firebase/app";
|
|
3
|
-
import { getFirestore, collection, addDoc, getDocs, query, where, deleteDoc } from "firebase/firestore";
|
|
4
|
-
|
|
5
|
-
const firebaseConfig = {
|
|
6
|
-
apiKey: "AIzaSyCRt9MewdayUI-5p3OnAU7rYn8ea_7QsAg",
|
|
7
|
-
projectId: "tusharbr-online",
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// Initialize Firebase internally for the API
|
|
11
|
-
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApp();
|
|
12
|
-
const db = getFirestore(app);
|
|
13
|
-
|
|
14
|
-
const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN || "8763391781:AAFntuiLaMbRqOgjVseTqaSRt4IF5AKCMeU";
|
|
15
|
-
const CHAT_ID = process.env.TELEGRAM_CHAT_ID || "6486049131";
|
|
16
|
-
const ADMIN_SECRET = process.env.ADMIN_SECRET_KEY || "TUSHAR2026"; // Change to your preferred secure key
|
|
17
|
-
|
|
18
|
-
export default async function handler(req: VercelRequest, res: VercelResponse) {
|
|
19
|
-
if (req.method !== "POST") return res.status(405).json({ error: "Method not allowed" });
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const { adminKey } = req.body;
|
|
23
|
-
|
|
24
|
-
if (adminKey !== ADMIN_SECRET) {
|
|
25
|
-
return res.status(401).json({ error: "Invalid Admin Key" });
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Generate 6 digit OTP
|
|
29
|
-
const otp = Math.floor(100000 + Math.random() * 900000).toString();
|
|
30
|
-
const expireTime = Date.now() + 5 * 60 * 1000; // 5 minutes
|
|
31
|
-
|
|
32
|
-
// Clear old OTPs
|
|
33
|
-
const oldOtps = await getDocs(collection(db, "admin_otp"));
|
|
34
|
-
for (const doc of oldOtps.docs) {
|
|
35
|
-
await deleteDoc(doc.ref);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Save to Firestore
|
|
39
|
-
await addDoc(collection(db, "admin_otp"), {
|
|
40
|
-
otp_code: otp,
|
|
41
|
-
expire_time: expireTime
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Send via Telegram
|
|
45
|
-
const message = `🔐 Admin Login Attempt\nYour OTP is: ${otp}\nExpires in 5 minutes.`;
|
|
46
|
-
const tgUrl = `https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`;
|
|
47
|
-
|
|
48
|
-
await fetch(tgUrl, {
|
|
49
|
-
method: "POST",
|
|
50
|
-
headers: { "Content-Type": "application/json" },
|
|
51
|
-
body: JSON.stringify({
|
|
52
|
-
chat_id: CHAT_ID,
|
|
53
|
-
text: message
|
|
54
|
-
})
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
res.status(200).json({ success: true, message: "OTP sent to Telegram" });
|
|
58
|
-
} catch (err: any) {
|
|
59
|
-
console.error(err);
|
|
60
|
-
res.status(500).json({ error: "Internal server error", details: err.message });
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { VercelRequest, VercelResponse } from "@vercel/node";
|
|
2
|
-
import { initializeApp, getApps, getApp } from "firebase/app";
|
|
3
|
-
import { getFirestore, collection, getDocs, deleteDoc } from "firebase/firestore";
|
|
4
|
-
|
|
5
|
-
const firebaseConfig = {
|
|
6
|
-
apiKey: "AIzaSyCRt9MewdayUI-5p3OnAU7rYn8ea_7QsAg",
|
|
7
|
-
projectId: "tusharbr-online",
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApp();
|
|
11
|
-
const db = getFirestore(app);
|
|
12
|
-
|
|
13
|
-
export default async function handler(req: VercelRequest, res: VercelResponse) {
|
|
14
|
-
if (req.method !== "POST") return res.status(405).json({ error: "Method not allowed" });
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
const { otpEntered } = req.body;
|
|
18
|
-
|
|
19
|
-
const oldOtps = await getDocs(collection(db, "admin_otp"));
|
|
20
|
-
let isValid = false;
|
|
21
|
-
|
|
22
|
-
for (const doc of oldOtps.docs) {
|
|
23
|
-
const data = doc.data();
|
|
24
|
-
if (data.otp_code === otpEntered && Date.now() < data.expire_time) {
|
|
25
|
-
isValid = true;
|
|
26
|
-
}
|
|
27
|
-
// Cleanup
|
|
28
|
-
await deleteDoc(doc.ref);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!isValid) {
|
|
32
|
-
return res.status(401).json({ error: "Invalid or expired OTP" });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Success response - token could be handed over for more robust auth
|
|
36
|
-
res.status(200).json({ success: true, message: "OTP Verified", token: "SECRET_ADMIN_TOKEN_123" });
|
|
37
|
-
} catch (err: any) {
|
|
38
|
-
console.error(err);
|
|
39
|
-
res.status(500).json({ error: "Internal server error" });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { VercelRequest, VercelResponse } from "@vercel/node";
|
|
2
|
-
|
|
3
|
-
const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN || "8763391781:AAFntuiLaMbRqOgjVseTqaSRt4IF5AKCMeU";
|
|
4
|
-
const CHAT_ID = process.env.TELEGRAM_CHAT_ID || "6486049131";
|
|
5
|
-
|
|
6
|
-
export default async function handler(req: VercelRequest, res: VercelResponse) {
|
|
7
|
-
if (req.method !== "POST") return res.status(405).json({ error: "Method not allowed" });
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
const { message } = req.body;
|
|
11
|
-
|
|
12
|
-
const tgUrl = `https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`;
|
|
13
|
-
|
|
14
|
-
await fetch(tgUrl, {
|
|
15
|
-
method: "POST",
|
|
16
|
-
headers: { "Content-Type": "application/json" },
|
|
17
|
-
body: JSON.stringify({
|
|
18
|
-
chat_id: CHAT_ID,
|
|
19
|
-
text: message,
|
|
20
|
-
parse_mode: 'Markdown',
|
|
21
|
-
disable_web_page_preview: true
|
|
22
|
-
})
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
res.status(200).json({ success: true, message: "Telegram Alert Sent" });
|
|
26
|
-
} catch (err: any) {
|
|
27
|
-
console.error(err);
|
|
28
|
-
res.status(500).json({ error: "Internal server error" });
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { v2 as cloudinary } from 'cloudinary';
|
|
2
|
-
import type { VercelRequest, VercelResponse } from '@vercel/node';
|
|
3
|
-
|
|
4
|
-
export default async function handler(req: VercelRequest, res: VercelResponse) {
|
|
5
|
-
// Allow CORS
|
|
6
|
-
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
7
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
8
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT');
|
|
9
|
-
res.setHeader('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Authorization');
|
|
10
|
-
|
|
11
|
-
if (req.method === 'OPTIONS') {
|
|
12
|
-
return res.status(200).end();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Use process.env variables from Vercel securely
|
|
16
|
-
const cloudName = process.env.VITE_CLOUDINARY_CLOUD_NAME || process.env.CLOUDINARY_CLOUD_NAME;
|
|
17
|
-
const apiKey = process.env.CLOUDINARY_API_KEY;
|
|
18
|
-
const apiSecret = process.env.CLOUDINARY_API_SECRET;
|
|
19
|
-
|
|
20
|
-
if (!cloudName || !apiKey || !apiSecret) {
|
|
21
|
-
return res.status(500).json({ error: 'Cloudinary credentials missing in Vercel Environment.' });
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
cloudinary.config({
|
|
25
|
-
cloud_name: cloudName,
|
|
26
|
-
api_key: apiKey,
|
|
27
|
-
api_secret: apiSecret,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const { action } = req.query;
|
|
31
|
-
|
|
32
|
-
if (action === 'sign') {
|
|
33
|
-
const timestamp = Math.round(new Date().getTime() / 1000);
|
|
34
|
-
const { folder = 'chats/anon', resource_type = 'image' } = req.query;
|
|
35
|
-
|
|
36
|
-
// Sign with folder so Cloudinary enforces correct folder placement
|
|
37
|
-
const paramsToSign: Record<string, any> = {
|
|
38
|
-
timestamp,
|
|
39
|
-
folder: folder as string,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const signature = cloudinary.utils.api_sign_request(paramsToSign, apiSecret);
|
|
43
|
-
|
|
44
|
-
return res.status(200).json({ signature, timestamp, apiKey, cloudName });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (action === 'images' || action === 'delete') {
|
|
48
|
-
const authHeader = req.headers['authorization'];
|
|
49
|
-
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
50
|
-
return res.status(401).json({ error: 'UNAUTHORIZED: MISSING TOKEN' });
|
|
51
|
-
}
|
|
52
|
-
const idToken = authHeader.split('Bearer ')[1];
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const fbRes = await fetch(`https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=AIzaSyD4vkALQGpzs1SwN5bM-Nag-eV-fnYnNTk`, {
|
|
56
|
-
method: 'POST',
|
|
57
|
-
headers: { 'Content-Type': 'application/json' },
|
|
58
|
-
body: JSON.stringify({ idToken })
|
|
59
|
-
});
|
|
60
|
-
if (!fbRes.ok) return res.status(401).json({ error: 'UNAUTHORIZED: INVALID TOKEN' });
|
|
61
|
-
const fbData = await fbRes.json();
|
|
62
|
-
if (!fbData.users || !fbData.users[0] || fbData.users[0].email !== 'rathodtushar1442@gmail.com') {
|
|
63
|
-
return res.status(403).json({ error: 'FORBIDDEN: UNAUTHORIZED USER ACCOUNT' });
|
|
64
|
-
}
|
|
65
|
-
} catch (error) {
|
|
66
|
-
return res.status(500).json({ error: 'INTERNAL ERROR: TOKEN VALIDATION FAILED' });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (action === 'images') {
|
|
70
|
-
try {
|
|
71
|
-
// Fetch ALL resource types (image, video, raw) from the uploads folder
|
|
72
|
-
const result = await cloudinary.search
|
|
73
|
-
.expression('folder:uploads/* OR folder:uploads')
|
|
74
|
-
.sort_by('created_at', 'desc')
|
|
75
|
-
.max_results(200)
|
|
76
|
-
.execute();
|
|
77
|
-
return res.status(200).json({ images: result.resources });
|
|
78
|
-
} catch (err: any) {
|
|
79
|
-
return res.status(500).json({ error: err.message });
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (action === 'delete') {
|
|
84
|
-
const { public_id, resource_type = 'image' } = req.query;
|
|
85
|
-
if (!public_id) return res.status(400).json({ error: 'Missing public_id' });
|
|
86
|
-
try {
|
|
87
|
-
const result = await cloudinary.uploader.destroy(public_id as string, {
|
|
88
|
-
resource_type: resource_type as any
|
|
89
|
-
});
|
|
90
|
-
return res.status(200).json({ result });
|
|
91
|
-
} catch (err: any) {
|
|
92
|
-
return res.status(500).json({ error: err.message });
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return res.status(400).json({ error: 'Invalid action parameter.' });
|
|
98
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import nodemailer from 'nodemailer';
|
|
2
|
-
|
|
3
|
-
export default async function handler(req: any, res: any) {
|
|
4
|
-
// Allow CORS
|
|
5
|
-
res.setHeader('Access-Control-Allow-Credentials', true);
|
|
6
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
7
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT');
|
|
8
|
-
res.setHeader(
|
|
9
|
-
'Access-Control-Allow-Headers',
|
|
10
|
-
'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
if (req.method === 'OPTIONS') {
|
|
14
|
-
res.status(200).end();
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (req.method !== 'POST') {
|
|
19
|
-
return res.status(405).json({ error: 'Method Not Allowed' });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const { imageUrls, message, toEmail } = req.body;
|
|
23
|
-
|
|
24
|
-
if (!imageUrls || !toEmail) {
|
|
25
|
-
return res.status(400).json({ error: 'Missing required fields' });
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
const transporter = nodemailer.createTransport({
|
|
30
|
-
service: 'gmail',
|
|
31
|
-
auth: {
|
|
32
|
-
user: process.env.EMAIL_USER, // Your Gmail address
|
|
33
|
-
pass: process.env.EMAIL_PASS, // Your App Password
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const htmlContent = `
|
|
38
|
-
<div style="font-family: Arial, sans-serif; padding: 20px; color: #333;">
|
|
39
|
-
<p>Hi <strong>Tushar</strong>,</p>
|
|
40
|
-
|
|
41
|
-
<p>You have received a new upload from your website.</p>
|
|
42
|
-
|
|
43
|
-
<hr />
|
|
44
|
-
|
|
45
|
-
<p><strong>Message</strong></p>
|
|
46
|
-
<p>${message || 'No additional message'}</p>
|
|
47
|
-
|
|
48
|
-
<hr />
|
|
49
|
-
|
|
50
|
-
<p><strong>Uploaded Image</strong></p>
|
|
51
|
-
|
|
52
|
-
${imageUrls.map((url: string) => `
|
|
53
|
-
<img src="${url}" alt="Uploaded Image" style="max-width:100%; border-radius:10px; margin:12px 0; display:block;" />
|
|
54
|
-
<p>
|
|
55
|
-
<a href="${url}" target="_blank" style="display: inline-block; padding: 10px 15px; background-color: #0072FF; color: white; text-decoration: none; border-radius: 5px;">
|
|
56
|
-
Download image
|
|
57
|
-
</a>
|
|
58
|
-
</p>
|
|
59
|
-
`).join('')}
|
|
60
|
-
|
|
61
|
-
<hr />
|
|
62
|
-
|
|
63
|
-
<p style="font-size:12px; color:#777;">
|
|
64
|
-
tusharbr.vercel.app<br />
|
|
65
|
-
Private Upload System
|
|
66
|
-
</p>
|
|
67
|
-
</div>
|
|
68
|
-
`;
|
|
69
|
-
|
|
70
|
-
await transporter.sendMail({
|
|
71
|
-
from: `"Tusharbr Secure Upload" <${process.env.EMAIL_USER}>`,
|
|
72
|
-
to: toEmail,
|
|
73
|
-
subject: 'New Image Uploaded Successfully',
|
|
74
|
-
html: htmlContent,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
res.status(200).json({ success: true, message: 'Email sent successfully' });
|
|
78
|
-
} catch (error: any) {
|
|
79
|
-
console.error("Email Error:", error);
|
|
80
|
-
res.status(500).json({ error: 'Failed to send email', details: error.message });
|
|
81
|
-
}
|
|
82
|
-
}
|