Änderung: Erweiterung der Benutzerstatistiken im Admin-Bereich
Änderungen: - Neue Methode `getUserStatistics` im `AdminController` hinzugefügt, um Benutzerstatistiken abzurufen. - Implementierung der Logik zur Berechnung der Gesamtanzahl aktiver Benutzer, Geschlechterverteilung und Altersverteilung im `AdminService`. - Neue Route `/users/statistics` im `adminRouter` definiert, um auf die Benutzerstatistiken zuzugreifen. - Anpassungen der Navigationsstruktur und Übersetzungen für Benutzerstatistiken in den Sprachdateien aktualisiert. Diese Anpassungen verbessern die Analyse der Benutzerbasis und erweitern die Funktionalität des Admin-Bereichs.
This commit is contained in:
@@ -34,6 +34,9 @@ class AdminController {
|
||||
this.listUserRights = this.listUserRights.bind(this);
|
||||
this.addUserRight = this.addUserRight.bind(this);
|
||||
this.removeUserRight = this.removeUserRight.bind(this);
|
||||
|
||||
// Statistics
|
||||
this.getUserStatistics = this.getUserStatistics.bind(this);
|
||||
}
|
||||
|
||||
async getOpenInterests(req, res) {
|
||||
@@ -778,6 +781,20 @@ class AdminController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getUserStatistics(req, res) {
|
||||
try {
|
||||
const { userid: userId } = req.headers;
|
||||
const statistics = await AdminService.getUserStatistics(userId);
|
||||
res.status(200).json(statistics);
|
||||
} catch (error) {
|
||||
if (error.message === 'noaccess') {
|
||||
res.status(403).json({ error: 'Keine Berechtigung' });
|
||||
} else {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminController;
|
||||
|
||||
@@ -222,9 +222,22 @@ const menuStructure = {
|
||||
visible: ["mainadmin", "contactrequests"],
|
||||
path: "/admin/contacts"
|
||||
},
|
||||
useradministration: {
|
||||
users: {
|
||||
visible: ["mainadmin", "useradministration"],
|
||||
path: "/admin/users"
|
||||
children: {
|
||||
userlist: {
|
||||
visible: ["mainadmin", "useradministration"],
|
||||
path: "/admin/users"
|
||||
},
|
||||
userstatistics: {
|
||||
visible: ["mainadmin"],
|
||||
path: "/admin/users/statistics"
|
||||
},
|
||||
userrights: {
|
||||
visible: ["mainadmin", "rights"],
|
||||
path: "/admin/rights"
|
||||
}
|
||||
}
|
||||
},
|
||||
forum: {
|
||||
visible: ["mainadmin", "forum"],
|
||||
@@ -234,10 +247,6 @@ const menuStructure = {
|
||||
visible: ["mainadmin", "chatrooms"],
|
||||
path: "/admin/chatrooms"
|
||||
},
|
||||
userrights: {
|
||||
visible: ["mainadmin", "rights"],
|
||||
path: "/admin/rights"
|
||||
},
|
||||
interests: {
|
||||
visible: ["mainadmin", "interests"],
|
||||
path: "/admin/interests"
|
||||
|
||||
@@ -25,11 +25,9 @@ const UserParam = sequelize.define('user_param', {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
set(value) {
|
||||
console.log('.... [set param value]', value);
|
||||
if (value) {
|
||||
try {
|
||||
const encrypted = encrypt(value.toString());
|
||||
console.log('.... [encrypted param value]', encrypted);
|
||||
this.setDataValue('value', encrypted);
|
||||
} catch (error) {
|
||||
console.error('.... Error encrypting param value:', error);
|
||||
|
||||
@@ -17,6 +17,7 @@ router.delete('/chat/rooms/:id', authenticate, adminController.deleteRoom);
|
||||
|
||||
// --- Users Admin ---
|
||||
router.get('/users/search', authenticate, adminController.searchUsers);
|
||||
router.get('/users/statistics', authenticate, adminController.getUserStatistics);
|
||||
router.get('/users/:id', authenticate, adminController.getUser);
|
||||
router.put('/users/:id', authenticate, adminController.updateUser);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import FalukantStockType from "../models/falukant/type/stock.js";
|
||||
import RegionData from "../models/falukant/data/region.js";
|
||||
import BranchType from "../models/falukant/type/branch.js";
|
||||
import Room from '../models/chat/room.js';
|
||||
import UserParam from '../models/community/user_param.js';
|
||||
|
||||
class AdminService {
|
||||
async hasUserAccess(userId, section) {
|
||||
@@ -855,6 +856,111 @@ class AdminService {
|
||||
const Match3TileType = (await import('../models/match3/tileType.js')).default;
|
||||
return await Match3TileType.destroy({ where: { id } });
|
||||
}
|
||||
|
||||
async getUserStatistics(userId) {
|
||||
if (!(await this.hasUserAccess(userId, 'mainadmin'))) {
|
||||
throw new Error('noaccess');
|
||||
}
|
||||
|
||||
// Gesamtanzahl angemeldeter Benutzer
|
||||
const totalUsers = await User.count({
|
||||
where: { active: true }
|
||||
});
|
||||
|
||||
// Geschlechterverteilung - ohne raw: true um Entschlüsselung zu ermöglichen
|
||||
const genderStats = await UserParam.findAll({
|
||||
include: [{
|
||||
model: UserParamType,
|
||||
as: 'paramType',
|
||||
where: { description: 'gender' }
|
||||
}]
|
||||
});
|
||||
|
||||
const genderDistribution = {};
|
||||
for (const stat of genderStats) {
|
||||
const genderId = stat.value; // Dies ist die ID des Geschlechts
|
||||
if (genderId) {
|
||||
const genderValue = await UserParamValue.findOne({
|
||||
where: { id: genderId }
|
||||
});
|
||||
if (genderValue) {
|
||||
const gender = genderValue.value; // z.B. 'male', 'female'
|
||||
genderDistribution[gender] = (genderDistribution[gender] || 0) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Altersverteilung basierend auf Geburtsdatum - ohne raw: true um Entschlüsselung zu ermöglichen
|
||||
const birthdateStats = await UserParam.findAll({
|
||||
include: [{
|
||||
model: UserParamType,
|
||||
as: 'paramType',
|
||||
where: { description: 'birthdate' }
|
||||
}]
|
||||
});
|
||||
|
||||
const ageGroups = {
|
||||
'unter 12': 0,
|
||||
'12-14': 0,
|
||||
'14-16': 0,
|
||||
'16-18': 0,
|
||||
'18-21': 0,
|
||||
'21-25': 0,
|
||||
'25-30': 0,
|
||||
'30-40': 0,
|
||||
'40-50': 0,
|
||||
'50-60': 0,
|
||||
'über 60': 0
|
||||
};
|
||||
|
||||
const now = new Date();
|
||||
for (const stat of birthdateStats) {
|
||||
try {
|
||||
const birthdate = new Date(stat.value);
|
||||
if (isNaN(birthdate.getTime())) continue;
|
||||
|
||||
const age = now.getFullYear() - birthdate.getFullYear();
|
||||
const monthDiff = now.getMonth() - birthdate.getMonth();
|
||||
|
||||
let actualAge = age;
|
||||
if (monthDiff < 0 || (monthDiff === 0 && now.getDate() < birthdate.getDate())) {
|
||||
actualAge--;
|
||||
}
|
||||
|
||||
if (actualAge < 12) {
|
||||
ageGroups['unter 12']++;
|
||||
} else if (actualAge >= 12 && actualAge < 14) {
|
||||
ageGroups['12-14']++;
|
||||
} else if (actualAge >= 14 && actualAge < 16) {
|
||||
ageGroups['14-16']++;
|
||||
} else if (actualAge >= 16 && actualAge < 18) {
|
||||
ageGroups['16-18']++;
|
||||
} else if (actualAge >= 18 && actualAge < 21) {
|
||||
ageGroups['18-21']++;
|
||||
} else if (actualAge >= 21 && actualAge < 25) {
|
||||
ageGroups['21-25']++;
|
||||
} else if (actualAge >= 25 && actualAge < 30) {
|
||||
ageGroups['25-30']++;
|
||||
} else if (actualAge >= 30 && actualAge < 40) {
|
||||
ageGroups['30-40']++;
|
||||
} else if (actualAge >= 40 && actualAge < 50) {
|
||||
ageGroups['40-50']++;
|
||||
} else if (actualAge >= 50 && actualAge < 60) {
|
||||
ageGroups['50-60']++;
|
||||
} else {
|
||||
ageGroups['über 60']++;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten des Geburtsdatums:', error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totalUsers,
|
||||
genderDistribution,
|
||||
ageGroups
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default new AdminService();
|
||||
Reference in New Issue
Block a user