- aggiornamenti guida RIS, FAQ

- Editor HTML aggiunto CSS e Script
- Statistiche
- CRISBalanceBar
- Inizio Sync... (ma disattivato)
This commit is contained in:
Surya Paolo
2025-12-02 22:16:29 +01:00
parent 81ae2df8ef
commit 6fe3ed7c8b
5 changed files with 717 additions and 533 deletions

View File

@@ -40,7 +40,8 @@ mongoose.plugin((schema) => {
mongoose.set('debug', false); mongoose.set('debug', false);
const UserSchema = new mongoose.Schema({ const UserSchema = new mongoose.Schema(
{
userId: { userId: {
type: String, type: String,
}, },
@@ -231,6 +232,7 @@ const UserSchema = new mongoose.Schema({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
deletedAt: Date,
sospeso: { sospeso: {
type: Boolean, type: Boolean,
}, },
@@ -580,7 +582,12 @@ const UserSchema = new mongoose.Schema({
version: { type: Number }, version: { type: Number },
insert_circuito_ita: { type: Boolean }, insert_circuito_ita: { type: Boolean },
}, },
}); updatedAt: { type: Date, default: Date.now },
},
{
timestamps: true, // Mongoose aggiorna automaticamente updatedAt
}
);
UserSchema.methods.toJSON = function () { UserSchema.methods.toJSON = function () {
const user = this; const user = this;
@@ -6960,7 +6967,6 @@ UserSchema.statics.isEnableToReceiveEmailByUsernameECmd = async function (idapp,
let ricevo = true; let ricevo = true;
if (cmd === shared_consts.CIRCUITCMD.SETFIDO) { if (cmd === shared_consts.CIRCUITCMD.SETFIDO) {
// Controllo se l'utente ha scelto di ricevere l'email // Controllo se l'utente ha scelto di ricevere l'email
} }
return ricevo; return ricevo;
@@ -6983,6 +6989,28 @@ UserSchema.statics.getTokenByUsernameAndCircuitName = async function (idapp, use
return user?.profile?.mycircuits?.[0]?.token || null; return user?.profile?.mycircuits?.[0]?.token || null;
}; };
UserSchema.statics.softDelete = async function(id) {
return this.findByIdAndUpdate(
id,
{
deleted: true,
deletedAt: new Date()
},
{ new: true }
);
};
UserSchema.statics.getUsersList = function(idapp) {
return this.find({
idapp: idapp,
$or: [
{ deleted: { $exists: false } },
{ deleted: false }
]
}).lean();
};
const User = mongoose.model('User', UserSchema); const User = mongoose.model('User', UserSchema);
class Hero { class Hero {
@@ -7039,7 +7067,7 @@ const FuncUsers = {
}, },
}; };
UserSchema.index({ 'tokens.token': 1, 'tokens.access': 1 }); UserSchema.index({ 'tokens.token': 1, 'tokens.access': 1, idapp: 1, deleted: 1, updatedAt: 1 });
module.exports = { module.exports = {
User, User,

View File

@@ -1,25 +1,25 @@
module.exports = { module.exports = {
list: [ list: [
{_id: 1, descr: 'Abbigliamento', icon: 'fas fa-tshirt', color: 'blue-7'}, {_id: 1, descr: 'Abbigliamento', icon: 'fas fa-tshirt', color: 'blue-7'},
{_id: 2, descr: 'Arredamento', icon: 'fas fa-chair', color: 'green-7'}, {_id: 2, descr: 'Arredamento', icon: 'fas fa-couch', color: 'brown-7'},
{_id: 3, descr: 'Auto e Moto', icon: 'fas fa-car', color: 'orange-7'}, {_id: 3, descr: 'Auto e Moto', icon: 'fas fa-car', color: 'grey-9'},
{_id: 4, descr: 'Artigianato', icon: 'fas fa-screwdriver', color: 'red-7'}, {_id: 4, descr: 'Artigianato', icon: 'fas fa-gem', color: 'amber-7'},
{_id: 5, descr: 'Bellezza e Igiene', icon: 'fas fa-spa', color: 'purple-7'}, {_id: 5, descr: 'Bellezza e Igiene', icon: 'fas fa-spa', color: 'pink-7'},
{_id: 6, descr: 'Bimbi', icon: 'fas fa-child', color: 'cyan-7'}, {_id: 6, descr: 'Bimbi', icon: 'fas fa-baby', color: 'cyan-7'},
{_id: 7, descr: 'Cibo'}, {_id: 7, descr: 'Cibo', icon: 'fas fa-utensils', color: 'orange-7'},
{_id: 8, descr: 'Collezionismo e Antiquariato'}, {_id: 8, descr: 'Collezionismo e Antiquariato', icon: 'fas fa-coins', color: 'brown-9'},
{_id: 9, descr: 'Elettronica di Consumo'}, {_id: 9, descr: 'Elettronica', icon: 'fas fa-laptop', color: 'blue-grey-8'},
{_id: 10, descr: 'Giochi', icon: 'fas fa-gamepad', color: 'purple-7'}, {_id: 10, descr: 'Giochi', icon: 'fas fa-gamepad', color: 'purple-7'},
{_id: 11, descr: 'Hobby', icon: 'fas fa-guitar', color: 'cyan-7'}, {_id: 11, descr: 'Hobby e Fai da Te', icon: 'fas fa-palette', color: 'deep-orange-6'},
{_id: 12, descr: 'Libri', icon: 'fas fa-book', color: 'indigo-7'}, {_id: 12, descr: 'Libri', icon: 'fas fa-book-open', color: 'indigo-7'},
{_id: 13, descr: 'Musica e Film', icon: 'fas fa-music', color: 'brown-7'}, {_id: 13, descr: 'Musica e Film', icon: 'fas fa-film', color: 'deep-purple-7'},
{_id: 14, descr: 'Scuola e Ufficio', icon: 'fas fa-graduation-cap', color: 'pink-7'}, {_id: 14, descr: 'Scuola e Ufficio', icon: 'fas fa-pen', color: 'blue-8'},
{_id: 15, descr: 'Sport', icon: 'fas fa-futbol', color: 'orange-7'}, {_id: 15, descr: 'Sport', icon: 'fas fa-bicycle', color: 'green-8'},
{_id: 16, descr: 'Un po\' di Tutto', icon: 'fas fa-globe-europe', color: 'red-7'}, {_id: 16, descr: 'Varie', icon: 'fas fa-box', color: 'grey-7'},
{_id: 17, descr: 'Attrezzature', icon: 'fas fa-tools', color: 'blue-7'}, {_id: 17, descr: 'Attrezzature', icon: 'fas fa-tools', color: 'grey-8'},
{_id: 18, descr: 'Animali', icon: 'fas fa-paw', color: 'green-7'}, {_id: 18, descr: 'Animali', icon: 'fas fa-paw', color: 'brown-6'},
{_id: 19, descr: 'Arte / Decorazioni', icon: 'fas fa-palette', color: 'purple-7'}, {_id: 19, descr: 'Arte e Decorazioni', icon: 'fas fa-palette', color: 'purple-6'},
{_id: 20, descr: 'Agricoltura', icon: 'fas fa-seedling', color: 'green-7'}, {_id: 20, descr: 'Agricoltura', icon: 'fas fa-seedling', color: 'green-7'},
{_id: 21, descr: 'Elettrodomestici', icon: 'fas fa-plug', color: 'blue-grey-7'},
], ],
}; };

29
src/routes/sync.js Normal file
View File

@@ -0,0 +1,29 @@
// server/routes/sync.js
const express = require('express');
const router = express.Router();
const SyncManager = require('../services/SyncManager');
const { authenticate_noerror_WithUserLean } = require('../middleware/authenticate');
router.post('/sync/:idapp', authenticate_noerror_WithUserLean, async (req, res) => {
try {
const { idapp } = req.params;
const { tables } = req.body; // { users: { lastSync: 0 }, groups: { lastSync: 123456 } }
const results = await SyncManager.sync(tables, idapp, req.user);
res.json({
success: true,
data: results,
serverTime: Date.now()
});
} catch (error) {
console.error('Sync error:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
module.exports = router;

125
src/services/SyncManager.js Normal file
View File

@@ -0,0 +1,125 @@
// server/services/SyncManager.js
class SyncManager {
constructor() {
this.syncConfig = {
resps: {
model: 'User',
method: 'getusersRespList',
trackChanges: true,
params: ['idapp'] // parametri necessari
},
workers: {
model: 'User',
method: 'getusersWorkersList',
trackChanges: true,
params: ['idapp']
},
groups: {
model: 'Group',
method: 'findAllIdApp',
trackChanges: true,
params: ['idapp']
},
mygroups: {
model: 'MyGroup',
method: 'findAllGroups',
trackChanges: true,
params: ['idapp']
},
products: {
model: 'Product',
method: 'findAllIdApp',
trackChanges: true,
params: ['idapp']
},
cart: {
model: 'Cart',
method: 'getCartByUserId',
trackChanges: true,
params: ['userId', 'idapp'],
requiresAuth: true
},
orderscart: {
model: 'OrdersCart',
method: 'getOrdersCartByUserId',
trackChanges: true,
params: ['userId', 'idapp'],
requiresAuth: true
}
};
}
async sync(syncRequest, idapp, user) {
const results = {};
const timestamp = Date.now();
for (const [tableName, params] of Object.entries(syncRequest)) {
const config = this.syncConfig[tableName];
if (!config) {
console.warn(`Tabella ${tableName} non configurata`);
continue;
}
// Controlla autenticazione
if (config.requiresAuth && !user) {
results[tableName] = {
data: null,
timestamp: timestamp,
fullSync: true
};
continue;
}
try {
const data = await this.fetchTableData(
tableName,
config,
params.lastSync,
idapp,
user
);
results[tableName] = {
data: data,
timestamp: timestamp,
fullSync: params.lastSync === 0 || !config.trackChanges
};
} catch (error) {
console.error(`Errore sync ${tableName}:`, error);
results[tableName] = {
error: error.message,
timestamp: timestamp
};
}
}
return results;
}
async fetchTableData(tableName, config, lastSync, idapp, user) {
const ModelClass = require(`../models/${config.model}`);
// Prepara parametri
const args = config.params.map(param => {
if (param === 'idapp') return idapp;
if (param === 'userId') return user?._id.toString() || '0';
return null;
});
// Prima sync o no trackChanges: tutti i dati
if (!config.trackChanges || lastSync === 0) {
return await ModelClass[config.method](...args);
}
// Sync incrementale
const query = {
idapp: idapp,
updatedAt: { $gt: new Date(parseInt(lastSync)) }
};
return await ModelClass.find(query).lean();
}
}
module.exports = new SyncManager();

View File

@@ -3331,11 +3331,13 @@ module.exports = {
if (params.sortBy && !params.searchByBoundariesMap) { if (params.sortBy && !params.searchByBoundariesMap) {
// maybe we want to sort by blog title or something // maybe we want to sort by blog title or something
const mysort = { $sort: params.sortBy }; const mysort = params.sortBy && Object.keys(params.sortBy).length > 0 ? { $sort: params.sortBy } : {};
// console.log('sortBy', params.sortBy); // console.log('sortBy', params.sortBy);
// console.table(mysort); // console.table(mysort);
if (mysort.$sort) {
query.push(mysort); query.push(mysort);
} }
}
query.push( query.push(
{ {