- aggiornata la grafica della Home di RISO
- Profilo Completition - Email Verificata - Invita un Amico (invio di email)
This commit is contained in:
1020
src/controllers/articleController.js
Normal file
1020
src/controllers/articleController.js
Normal file
File diff suppressed because it is too large
Load Diff
46
src/controllers/events.controller.js
Normal file
46
src/controllers/events.controller.js
Normal file
@@ -0,0 +1,46 @@
|
||||
// @ts-check
|
||||
const EventModel = require('../models/Event');
|
||||
const { pick } = require('../utils/pick');
|
||||
|
||||
async function listEvents(req, res) {
|
||||
const { limit = '6', page = '1', from, to, sort = 'start' } = /** @type {any} */ (req.query);
|
||||
const q = {};
|
||||
if (from) q.start = { ...(q.start || {}), $gte: new Date(from) };
|
||||
if (to) q.start = { ...(q.start || {}), $lte: new Date(to) };
|
||||
|
||||
const lim = Math.min(Number(limit) || 6, 50);
|
||||
const skip = (Math.max(Number(page) || 1, 1) - 1) * lim;
|
||||
|
||||
const [items, total] = await Promise.all([
|
||||
EventModel.find(q)
|
||||
.sort({ [sort]: 1 })
|
||||
.skip(skip)
|
||||
.limit(lim)
|
||||
.lean(),
|
||||
EventModel.countDocuments(q),
|
||||
]);
|
||||
|
||||
res.set('Cache-Control', 'public, max-age=30, stale-while-revalidate=120');
|
||||
return res.json({ items, total, page: Number(page), limit: lim });
|
||||
}
|
||||
|
||||
async function createEvent(req, res) {
|
||||
const data = pick(req.body, ['title', 'start', 'end', 'place', 'teaser', 'cover', 'to']);
|
||||
const doc = await EventModel.create(data);
|
||||
return res.status(201).json(doc);
|
||||
}
|
||||
|
||||
async function updateEvent(req, res) {
|
||||
const data = pick(req.body, ['title', 'start', 'end', 'place', 'teaser', 'cover', 'to']);
|
||||
const doc = await EventModel.findByIdAndUpdate(req.params.id, data, { new: true });
|
||||
if (!doc) return res.status(404).json({ message: 'Evento non trovato' });
|
||||
return res.json(doc);
|
||||
}
|
||||
|
||||
async function deleteEvent(req, res) {
|
||||
const r = await EventModel.findByIdAndDelete(req.params.id);
|
||||
if (!r) return res.status(404).json({ message: 'Evento non trovato' });
|
||||
return res.status(204).send();
|
||||
}
|
||||
|
||||
module.exports = { listEvents, createEvent, updateEvent, deleteEvent };
|
||||
18
src/controllers/home.controller.js
Normal file
18
src/controllers/home.controller.js
Normal file
@@ -0,0 +1,18 @@
|
||||
// @ts-check
|
||||
const { HomeModel } = require('../models/Home');
|
||||
|
||||
async function getHome(req, res) {
|
||||
const doc = await HomeModel.findOne({});
|
||||
if (!doc) return res.status(404).json({ message: 'Home non configurata' });
|
||||
res.set('Cache-Control', 'public, max-age=60, stale-while-revalidate=300');
|
||||
res.set('ETag', `"${doc.updatedAt?.getTime?.() || Date.now()}"`);
|
||||
return res.json(doc);
|
||||
}
|
||||
|
||||
async function upsertHome(req, res) {
|
||||
const payload = req.body || {};
|
||||
const doc = await HomeModel.findOneAndUpdate({}, payload, { upsert: true, new: true, setDefaultsOnInsert: true });
|
||||
return res.json(doc);
|
||||
}
|
||||
|
||||
module.exports = { getHome, upsertHome };
|
||||
20
src/controllers/newsletter.controller.js
Normal file
20
src/controllers/newsletter.controller.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// @ts-check
|
||||
async function subscribe(req, res) {
|
||||
const { email } = req.body || {};
|
||||
if (!email || !/.+@.+\..+/.test(email)) {
|
||||
return res.status(400).json({ message: 'Email non valida' });
|
||||
}
|
||||
// Integra qui Mailchimp/Sendinblue se necessario
|
||||
return res.status(200).json({ ok: true });
|
||||
}
|
||||
|
||||
async function unsubscribe(req, res) {
|
||||
const { email } = req.body || {};
|
||||
if (!email || !/.+@.+\..+/.test(email)) {
|
||||
return res.status(400).json({ message: 'Email non valida' });
|
||||
}
|
||||
// Integra qui Mailchimp/Sendinblue se necessario
|
||||
return res.status(200).json({ ok: true });
|
||||
}
|
||||
|
||||
module.exports = { subscribe, unsubscribe };
|
||||
41
src/controllers/posts.controller.js
Normal file
41
src/controllers/posts.controller.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// @ts-check
|
||||
const { PostModel } = require('../models/Post');
|
||||
const { pick } = require('../utils/pick');
|
||||
|
||||
async function listPosts(req, res) {
|
||||
const { limit = '3', page = '1', sort = '-date', category } = /** @type {any} */ (req.query);
|
||||
const q = {};
|
||||
if (category) q.category = category;
|
||||
|
||||
const lim = Math.min(Number(limit) || 3, 50);
|
||||
const skip = (Math.max(Number(page) || 1, 1) - 1) * lim;
|
||||
|
||||
const [items, total] = await Promise.all([
|
||||
PostModel.find(q).sort(sort).skip(skip).limit(lim).lean(),
|
||||
PostModel.countDocuments(q)
|
||||
]);
|
||||
|
||||
res.set('Cache-Control', 'public, max-age=30, stale-while-revalidate=120');
|
||||
return res.json({ items, total, page: Number(page), limit: lim });
|
||||
}
|
||||
|
||||
async function createPost(req, res) {
|
||||
const data = pick(req.body, ['title','date','category','teaser','cover','to','bodyMd']);
|
||||
const doc = await PostModel.create(data);
|
||||
return res.status(201).json(doc);
|
||||
}
|
||||
|
||||
async function updatePost(req, res) {
|
||||
const data = pick(req.body, ['title','date','category','teaser','cover','to','bodyMd']);
|
||||
const doc = await PostModel.findByIdAndUpdate(req.params.id, data, { new: true });
|
||||
if (!doc) return res.status(404).json({ message: 'Post non trovato' });
|
||||
return res.json(doc);
|
||||
}
|
||||
|
||||
async function deletePost(req, res) {
|
||||
const r = await PostModel.findByIdAndDelete(req.params.id);
|
||||
if (!r) return res.status(404).json({ message: 'Post non trovato' });
|
||||
return res.status(204).send();
|
||||
}
|
||||
|
||||
module.exports = { listPosts, createPost, updatePost, deletePost };
|
||||
294
src/controllers/telegram.controller.js
Normal file
294
src/controllers/telegram.controller.js
Normal file
@@ -0,0 +1,294 @@
|
||||
// telegram.controller.js
|
||||
const crypto = require('crypto');
|
||||
const axios = require('axios');
|
||||
const { User } = require('../models/user');
|
||||
|
||||
// Configurazione
|
||||
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
||||
const TELEGRAM_API_URL = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}`;
|
||||
|
||||
/**
|
||||
* Genera un token di verifica univoco
|
||||
*/
|
||||
exports.generateVerificationToken = async (req, res) => {
|
||||
try {
|
||||
const { username, idapp } = req.body;
|
||||
|
||||
if (!username) {
|
||||
return res.status(400).json({ error: 'Username richiesto' });
|
||||
}
|
||||
|
||||
// Verifica che l'utente esista
|
||||
const user = await User.findOne({ idapp, username });
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Utente non trovato' });
|
||||
}
|
||||
|
||||
// Verifica se già verificato
|
||||
if (user.profile?.username_telegram && user.profile?.teleg_id) {
|
||||
return res.status(400).json({ error: 'Account Telegram già collegato' });
|
||||
}
|
||||
|
||||
// Genera token univoco
|
||||
const token = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
// Salva SOLO sul database (non serve la Map in-memory!)
|
||||
await User.updateOne(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$set: {
|
||||
'profile.telegram_verification_token': token,
|
||||
'profile.telegram_verification_expires': new Date(Date.now() + 20 * 60 * 1000),
|
||||
'profile.telegram_verified': false,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
res.json({ token });
|
||||
} catch (error) {
|
||||
console.error('Errore generazione token:', error);
|
||||
return res.status(500).json({ error: 'Errore del server' });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Controlla se la verifica è stata completata
|
||||
*/
|
||||
exports.checkVerification = async (req, res) => {
|
||||
try {
|
||||
const { token } = req.query;
|
||||
|
||||
if (!token) {
|
||||
return res.status(400).json({ error: 'Token richiesto' });
|
||||
}
|
||||
|
||||
// Cerca l'utente con questo token DIRETTAMENTE sul DB
|
||||
const user = await User.findOne({
|
||||
'profile.telegram_verification_token': token,
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Token non valido', verified: false });
|
||||
}
|
||||
|
||||
// Verifica se è scaduto
|
||||
const now = new Date();
|
||||
if (now > user.profile.telegram_verification_expires) {
|
||||
// Pulisci il token scaduto
|
||||
await User.updateOne(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$unset: {
|
||||
'profile.telegram_verification_token': '',
|
||||
'profile.telegram_verification_expires': '',
|
||||
},
|
||||
}
|
||||
);
|
||||
return res.status(410).json({ error: 'Token scaduto', verified: false });
|
||||
}
|
||||
|
||||
// Controlla se è stato verificato
|
||||
const verified = !!(user.profile?.teleg_id && user.profile?.username_telegram);
|
||||
|
||||
res.json({
|
||||
verified: verified,
|
||||
username_telegram: user.profile?.username_telegram || null,
|
||||
teleg_id: user.profile?.teleg_id || null,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Errore verifica token:', error);
|
||||
return res.status(500).json({ error: 'Errore del server' });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Webhook del bot Telegram
|
||||
* Gestisce i messaggi /start con il token
|
||||
*/
|
||||
exports.telegramWebhook = async (req, res) => {
|
||||
try {
|
||||
const update = req.body;
|
||||
|
||||
// Gestisci solo messaggi con /start
|
||||
if (update.message && update.message.text && update.message.text.startsWith('/start')) {
|
||||
const chatId = update.message.chat.id;
|
||||
const userId = update.message.from.id;
|
||||
const username = update.message.from.username;
|
||||
const firstName = update.message.from.first_name;
|
||||
|
||||
// Estrai il token dal comando /start
|
||||
const parts = update.message.text.split(' ');
|
||||
const token = parts[1];
|
||||
|
||||
if (!token) {
|
||||
await sendTelegramMessage(
|
||||
chatId,
|
||||
"⚠️ Link di verifica non valido. Richiedi un nuovo link dall'applicazione."
|
||||
);
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
|
||||
// Cerca l'utente con questo token
|
||||
const user = await User.findOne({
|
||||
'profile.telegram_verification_token': token,
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
await sendTelegramMessage(
|
||||
chatId,
|
||||
"❌ Token non valido o scaduto. Richiedi un nuovo link dall'applicazione."
|
||||
);
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
|
||||
// Verifica scadenza
|
||||
const now = new Date();
|
||||
if (now > user.profile.telegram_verification_expires) {
|
||||
await User.updateOne(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$unset: {
|
||||
'profile.telegram_verification_token': '',
|
||||
'profile.telegram_verification_expires': '',
|
||||
},
|
||||
}
|
||||
);
|
||||
await sendTelegramMessage(
|
||||
chatId,
|
||||
"⏰ Il token è scaduto. Richiedi un nuovo link dall'applicazione."
|
||||
);
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
|
||||
// Verifica se già collegato
|
||||
if (user.profile?.teleg_id && user.profile?.username_telegram) {
|
||||
await sendTelegramMessage(chatId, '✅ Questo account è già stato verificato!');
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
|
||||
// Salva i dati Telegram e rimuovi il token
|
||||
await User.updateOne(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$set: {
|
||||
'profile.teleg_id': userId.toString(),
|
||||
'profile.username_telegram': username || firstName,
|
||||
},
|
||||
$unset: {
|
||||
'profile.telegram_verification_token': '',
|
||||
'profile.telegram_verification_expires': '',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Invia messaggio di conferma
|
||||
await sendTelegramMessage(
|
||||
chatId,
|
||||
`✅ Account verificato con successo!\n\n` +
|
||||
`Il tuo Telegram è stato collegato a: ${user.username}\n\n` +
|
||||
`Puoi ora tornare all'applicazione.`
|
||||
);
|
||||
}
|
||||
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
console.error('Errore webhook Telegram:', error);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Funzione helper per inviare messaggi Telegram
|
||||
*/
|
||||
async function sendTelegramMessage(chatId, text) {
|
||||
try {
|
||||
await axios.post(`${TELEGRAM_API_URL}/sendMessage`, {
|
||||
chat_id: chatId,
|
||||
text: text,
|
||||
parse_mode: 'HTML',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Errore invio messaggio Telegram:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura il webhook di Telegram (da eseguire una volta)
|
||||
*/
|
||||
exports.setupWebhook = async (req, res) => {
|
||||
try {
|
||||
/*const webhookUrl = `${process.env.APP_URL}/api/telegram/webhook`;
|
||||
|
||||
const response = await axios.post(`${TELEGRAM_API_URL}/setWebhook`, {
|
||||
url: webhookUrl,
|
||||
allowed_updates: ['message'],
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Webhook configurato',
|
||||
data: response.data,
|
||||
});*/
|
||||
} catch (error) {
|
||||
console.error('Errore setup webhook:', error);
|
||||
return res.status(500).json({ error: 'Errore configurazione webhook' });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Rimuovi collegamento Telegram
|
||||
*/
|
||||
exports.unlinkTelegram = async (req, res) => {
|
||||
try {
|
||||
const userId = req.user.id; // Assumi autenticazione middleware
|
||||
|
||||
await User.updateOne(
|
||||
{ _id: userId },
|
||||
{
|
||||
$unset: {
|
||||
'profile.teleg_id': '',
|
||||
'profile.username_telegram': '',
|
||||
'profile.telegram_verification_token': '',
|
||||
'profile.telegram_verification_expires': '',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
res.json({ success: true, message: 'Telegram scollegato' });
|
||||
} catch (error) {
|
||||
console.error('Errore unlink Telegram:', error);
|
||||
return res.status(500).json({ error: 'Errore del server' });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Salta la verifica Telegram
|
||||
*/
|
||||
exports.skipTelegramVerification = async (req, res) => {
|
||||
try {
|
||||
const { idapp } = req.body;
|
||||
|
||||
const user = await User.findOne({ idapp });
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Utente non trovato' });
|
||||
}
|
||||
|
||||
await User.updateOne(
|
||||
{ _id: user._id },
|
||||
{
|
||||
$set: {
|
||||
'profile.telegram_verification_skipped': true,
|
||||
},
|
||||
$unset: {
|
||||
'profile.telegram_verification_token': '',
|
||||
'profile.telegram_verification_expires': '',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
res.json({ success: true, message: 'Verifica Telegram saltata' });
|
||||
} catch (error) {
|
||||
console.error('Errore skip verifica:', error);
|
||||
return res.status(500).json({ error: 'Errore del server' });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user