Spaces:
Running
Running
refactor(cart): add global mongodb cart sync and remove legacy logic
Browse files- bot/bot.js +1 -36
- index.js +39 -0
- models/User.js +20 -0
bot/bot.js
CHANGED
|
@@ -915,36 +915,7 @@ if (process.env.BOT_TOKEN && process.env.BOT_TOKEN !== 'YOUR_TELEGRAM_BOT_TOKEN'
|
|
| 915 |
}
|
| 916 |
});
|
| 917 |
|
| 918 |
-
// Eski ai_regenerate va ai_save_last
|
| 919 |
-
bot.action('ai_regenerate', async (ctx) => {
|
| 920 |
-
if (!isAdmin(ctx)) return;
|
| 921 |
-
const state = appState[ctx.from.id];
|
| 922 |
-
if (state && state.lastPrompt) {
|
| 923 |
-
const finalPrompt = state.templateBase
|
| 924 |
-
? state.templateBase + ', ' + translatePrompt(state.lastPrompt)
|
| 925 |
-
: translatePrompt(state.lastPrompt);
|
| 926 |
-
ctx.answerCbQuery('π Qayta yaratilmoqda...');
|
| 927 |
-
try { ctx.deleteMessage(); } catch(e) {}
|
| 928 |
-
await generateAIBannerVariants(ctx, finalPrompt, state.lastPrompt);
|
| 929 |
-
} else {
|
| 930 |
-
ctx.answerCbQuery('Avval tavsif yozing');
|
| 931 |
-
}
|
| 932 |
-
});
|
| 933 |
-
|
| 934 |
-
bot.action('ai_save_last', async (ctx) => {
|
| 935 |
-
if (!isAdmin(ctx)) return;
|
| 936 |
-
const state = appState[ctx.from.id];
|
| 937 |
-
if (state && state.lastImageUrl) {
|
| 938 |
-
try {
|
| 939 |
-
const bannerCount = await Banner.countDocuments({ isActive: true });
|
| 940 |
-
await new Banner({ imageUrl: state.lastImageUrl, title: state.lastPrompt || '', order: bannerCount }).save();
|
| 941 |
-
ctx.answerCbQuery('β
Saqlandi!');
|
| 942 |
-
try { await ctx.deleteMessage(); } catch(e) {}
|
| 943 |
-
ctx.reply('β
AI banner saqlandi va ilovada ko\'rinadi!', getMainMenu());
|
| 944 |
-
} catch(e) { ctx.answerCbQuery('Xato'); }
|
| 945 |
-
}
|
| 946 |
-
delete appState[ctx.from.id];
|
| 947 |
-
});
|
| 948 |
|
| 949 |
// ==========================================
|
| 950 |
// MATN XABARLARI
|
|
@@ -1252,12 +1223,6 @@ if (process.env.BOT_TOKEN && process.env.BOT_TOKEN !== 'YOUR_TELEGRAM_BOT_TOKEN'
|
|
| 1252 |
state.pushImage = imgUrl;
|
| 1253 |
appState[userId] = { ...state, step: 'push_confirm' };
|
| 1254 |
ctx.reply(`π’ Siz quyidagi xabarni BARCHA mijoz telefonlariga (Push) yubormoqchisiz:\n\n*Sarlavha:* ${state.pushTitle}\n*Matn:* ${state.pushMessage}\n*Rasm:* Ulangan\n\nβ
Xabarni tasdiqlaysizmi? (ha / yo'q)`, { parse_mode: 'Markdown' });
|
| 1255 |
-
} else if(state.step === 'adding_banner') {
|
| 1256 |
-
// Eski usul (backward compat)
|
| 1257 |
-
const bannerCount = await Banner.countDocuments({ isActive: true });
|
| 1258 |
-
await new Banner({ imageUrl: imgUrl, order: bannerCount }).save();
|
| 1259 |
-
ctx.reply('β
Yangi banner saqlandi va dasturga chiqdi!', getMainMenu());
|
| 1260 |
-
delete appState[userId];
|
| 1261 |
}
|
| 1262 |
});
|
| 1263 |
|
|
|
|
| 915 |
}
|
| 916 |
});
|
| 917 |
|
| 918 |
+
// Eski ai_regenerate va ai_save_last funksiyalari xavfsizlik va optimizatsiya maqsadida o'chirildi (V3.6)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 919 |
|
| 920 |
// ==========================================
|
| 921 |
// MATN XABARLARI
|
|
|
|
| 1223 |
state.pushImage = imgUrl;
|
| 1224 |
appState[userId] = { ...state, step: 'push_confirm' };
|
| 1225 |
ctx.reply(`π’ Siz quyidagi xabarni BARCHA mijoz telefonlariga (Push) yubormoqchisiz:\n\n*Sarlavha:* ${state.pushTitle}\n*Matn:* ${state.pushMessage}\n*Rasm:* Ulangan\n\nβ
Xabarni tasdiqlaysizmi? (ha / yo'q)`, { parse_mode: 'Markdown' });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1226 |
}
|
| 1227 |
});
|
| 1228 |
|
index.js
CHANGED
|
@@ -251,6 +251,45 @@ app.get('/api/image/:fileId', async (req, res) => {
|
|
| 251 |
}
|
| 252 |
});
|
| 253 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
const PORT = process.env.PORT || 7860;
|
| 255 |
app.listen(PORT, '0.0.0.0', () => {
|
| 256 |
console.log(`Server is running on port ${PORT}`);
|
|
|
|
| 251 |
}
|
| 252 |
});
|
| 253 |
|
| 254 |
+
// ==========================================
|
| 255 |
+
// USER & CART SYNC (GLOBAL CART API) A-Variant
|
| 256 |
+
// ==========================================
|
| 257 |
+
const User = require('./models/User');
|
| 258 |
+
|
| 259 |
+
app.post('/api/users/login', async (req, res) => {
|
| 260 |
+
try {
|
| 261 |
+
const { uid, email, name } = req.body;
|
| 262 |
+
if (!uid) return res.status(400).json({ message: "UID majburiy" });
|
| 263 |
+
let user = await User.findOne({ uid });
|
| 264 |
+
if (!user) {
|
| 265 |
+
user = new User({ uid, email, name, cart: [] });
|
| 266 |
+
await user.save();
|
| 267 |
+
}
|
| 268 |
+
res.json({ message: "Muvaffaqiyatli", user });
|
| 269 |
+
} catch (e) { res.status(500).json({ error: e.message }); }
|
| 270 |
+
});
|
| 271 |
+
|
| 272 |
+
app.post('/api/users/sync-cart', async (req, res) => {
|
| 273 |
+
try {
|
| 274 |
+
const { uid, cart } = req.body;
|
| 275 |
+
if (!uid) return res.status(400).json({ message: "UID majburiy" });
|
| 276 |
+
const user = await User.findOneAndUpdate(
|
| 277 |
+
{ uid },
|
| 278 |
+
{ cart: cart || [], lastSyncedAt: Date.now() },
|
| 279 |
+
{ new: true, upsert: true } // agar avval topilmasa o'zi yaratadi
|
| 280 |
+
);
|
| 281 |
+
res.json({ message: "Sinxronlandi", cart: user.cart });
|
| 282 |
+
} catch (e) { res.status(500).json({ error: e.message }); }
|
| 283 |
+
});
|
| 284 |
+
|
| 285 |
+
app.get('/api/users/cart/:uid', async (req, res) => {
|
| 286 |
+
try {
|
| 287 |
+
const user = await User.findOne({ uid: req.params.uid });
|
| 288 |
+
if (!user) return res.json({ cart: [] });
|
| 289 |
+
res.json({ cart: user.cart });
|
| 290 |
+
} catch (e) { res.status(500).json({ error: e.message }); }
|
| 291 |
+
});
|
| 292 |
+
|
| 293 |
const PORT = process.env.PORT || 7860;
|
| 294 |
app.listen(PORT, '0.0.0.0', () => {
|
| 295 |
console.log(`Server is running on port ${PORT}`);
|
models/User.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const mongoose = require('mongoose');
|
| 2 |
+
|
| 3 |
+
const cartItemSchema = new mongoose.Schema({
|
| 4 |
+
productId: { type: String, required: true },
|
| 5 |
+
name: { type: String, required: true },
|
| 6 |
+
imageUrl: { type: String },
|
| 7 |
+
price: { type: Number, required: true },
|
| 8 |
+
size: { type: String },
|
| 9 |
+
quantity: { type: Number, default: 1 }
|
| 10 |
+
}, { _id: false });
|
| 11 |
+
|
| 12 |
+
const userSchema = new mongoose.Schema({
|
| 13 |
+
uid: { type: String, required: true, unique: true }, // Firebase dan kelgan takrorlanmas ID
|
| 14 |
+
email: { type: String },
|
| 15 |
+
name: { type: String },
|
| 16 |
+
cart: [cartItemSchema], // Snapshot usulida saqlanadigan savatcha
|
| 17 |
+
lastSyncedAt: { type: Date, default: Date.now }
|
| 18 |
+
});
|
| 19 |
+
|
| 20 |
+
module.exports = mongoose.model('User', userSchema);
|