Files
yourpart3/backend/controllers/navigationController.js
Torsten Schulz (local) e1b3dfb00a Refactor navigation structure to enhance language learning features
- Renamed 'vocabtrainer' to 'sprachenlernen' in the navigation structure for better clarity.
- Introduced a nested structure under 'sprachenlernen' for 'vocabtrainer' and 'sprachkurse', improving organization of language-related resources.
- Updated internationalization files for both German and English to reflect the new naming and structure, ensuring consistency across the application.
2026-01-19 11:24:46 +01:00

429 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import User from '../models/community/user.js';
import UserParam from '../models/community/user_param.js';
import UserRight from '../models/community/user_right.js';
import UserRightType from '../models/type/user_right.js';
import UserParamType from '../models/type/user_param.js';
import FalukantUser from '../models/falukant/data/user.js';
import VocabService from '../services/vocabService.js';
const menuStructure = {
home: {
visible: ["all"],
children: {},
path: "/",
icon: "logo_mono.png"
},
friends: {
visible: ["all"],
children: {
manageFriends: {
visible: ["all"],
path: "/friends",
icon: "friends24.png"
}
},
showLoggedinFriends: 1,
icon: "friends24.png"
},
socialnetwork: {
visible: ["all"],
icon: "socialnetwork.png",
children: {
guestbook: {
visible: ["all"],
path: "/socialnetwork/guestbook"
},
blog: {
visible: ["all"],
path: "/blogs"
},
usersearch: {
visible: ["all"],
path: "/socialnetwork/search"
},
forum: {
visible: ["all"],
path: "/socialnetwork/forum",
showForums: 1
},
gallery: {
visible: ["all"],
path: "/socialnetwork/gallery"
},
sprachenlernen: {
visible: ["all"],
children: {
vocabtrainer: {
visible: ["all"],
path: "/socialnetwork/vocab",
children: {}
},
sprachkurse: {
visible: ["all"],
path: "/socialnetwork/vocab/courses"
}
}
},
blockedUsers: {
visible: ["all"],
path: "/socialnetwork/blocked"
},
oneTimeInvitation: {
visible: ["all"],
path: "/socialnetwork/onetimeinvitation"
},
diary: {
visible: ["all"],
path: "/socialnetwork/diary"
},
erotic: {
visible: ["over18"],
children: {
pictures: {
visible: ["over18"],
path: "/socialnetwork/erotic/pictures"
},
videos: {
visible: ["over18"],
path: "/socialnetwork/erotic/videos"
}
}
}
}
},
chats: {
visible: ["over12"],
icon: "chat.png",
children: {
multiChat: {
visible: ["over12"],
action: "openMultiChat",
view: "window",
class: "multiChatDialog",
icon: "multichat24.png"
},
randomChat: {
visible: ["over12"],
action: "openRanomChat",
view: "window",
class: "randomChatDialog"
},
eroticChat: {
visible: ["over18"],
action: "openEroticChat",
view: "window",
class: "eroticChatWindow"
}
}
},
falukant: {
visible: ["all"],
icon: "falukant16.png",
children: {
create: {
visible: ["nofalukantaccount"],
path: "/falukant/create"
},
overview: {
visible: ["hasfalukantaccount"],
path: "/falukant/home"
},
towns: {
visible: ["hasfalukantaccount"],
path: "/falukant/branch"
},
family: {
visible: ["hasfalukantaccount"],
path: "/falukant/family"
},
house: {
visible: ["hasfalukantaccount"],
path: "/falukant/house"
},
nobility: {
visible: ["hasfalukantaccount"],
path: "/falukant/nobility"
},
church: {
visible: ["hasfalukantaccount"],
path: "/falukant/church"
},
politics: {
visible: ["hasfalukantaccount"],
path: "/falukant/politics"
},
education: {
visible: ["hasfalukantaccount"],
path: "/falukant/education"
},
health: {
visible: ["hasfalukantaccount"],
path: "/falukant/health"
},
bank: {
visible: ["hasfalukantaccount"],
path: "/falukant/bank"
},
darknet: {
visible: ["hasfalukantaccount"],
path: "/falukant/darknet"
},
reputation: {
visible: ["hasfalukantaccount"],
path: "/falukant/reputation"
},
moneyhistory: {
visible: ["hasfalukantaccount"],
path: "/falukant/moneyhistory"
}
}
},
minigames: {
visible: ["all"],
icon: "minigames16.png",
children: {
match3: {
visible: ["all"],
path: "/minigames/match3"
},
taxi: {
visible: ["all"],
path: "/minigames/taxi"
}
}
},
settings: {
visible: ["all"],
icon: "settings16.png",
children: {
homepage: {
visible: ["all"],
path: "/settings/homepage"
},
account: {
visible: ["all"],
path: "/settings/account"
},
personal: {
visible: ["all"],
path: "/settings/personal"
},
view: {
visible: ["all"],
path: "/settings/view"
},
interests: {
visible: ["all"],
path: "/settings/interests"
},
flirt: {
visible: ["over14"],
path: "/settings/flirt"
},
sexuality: {
visible: ["over14"],
path: "/settings/sexuality"
},
notifications: {
visible: ["all"],
path: "/settings/notifications"
}
}
},
administration: {
visible: ["anyadmin"],
children: {
contactrequests: {
visible: ["mainadmin", "contactrequests"],
path: "/admin/contacts"
},
users: {
visible: ["mainadmin", "useradministration"],
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"],
path: "/admin/forum"
},
chatrooms: {
visible: ["mainadmin", "chatrooms"],
path: "/admin/chatrooms"
},
servicesStatus: {
visible: ["mainadmin"],
path: "/admin/services/status"
},
interests: {
visible: ["mainadmin", "interests"],
path: "/admin/interests"
},
falukant: {
visible: ["mainadmin", "falukant"],
children: {
logentries: {
visible: ["mainadmin", "falukant"],
path: "/admin/falukant/logentries"
},
edituser: {
visible: ["mainadmin", "falukant"],
path: "/admin/falukant/edituser"
},
database: {
visible: ["mainadmin", "falukant"],
path: "/admin/falukant/database"
},
mapEditor: {
visible: ["mainadmin", "falukant"],
path: "/admin/falukant/map"
},
createNPC: {
visible: ["mainadmin", "falukant"],
path: "/admin/falukant/create-npc"
},
}
},
minigames: {
visible: ["mainadmin", "match3"],
children: {
match3: {
visible: ["mainadmin", "match3"],
path: "/admin/minigames/match3"
},
taxiTools: {
visible: ["mainadmin", "taxi"],
path: "/admin/minigames/taxi-tools"
}
}
}
}
}
};
class NavigationController {
constructor() {
this.menu = this.menu.bind(this);
this.vocabService = new VocabService();
}
calculateAge(birthDate) {
const today = new Date();
const birthDateObj = new Date(birthDate);
let age = today.getFullYear() - birthDateObj.getFullYear();
const monthDiff = today.getMonth() - birthDateObj.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDateObj.getDate())) {
age--;
}
return age;
}
async filterMenu(menu, rights, age, userId) {
const filteredMenu = {};
try {
const hasFalukantAccount = await this.hasFalukantAccount(userId);
for (const [key, value] of Object.entries(menu)) {
if (value.visible.includes("all")
|| value.visible.some(v => rights.includes(v)) || (value.visible.includes("anyadmin") && rights.length > 0)
|| (value.visible.includes("over14") && age >= 14)
|| (value.visible.includes("over12") && age >= 12)
|| (value.visible.includes("over18") && age >= 18)
|| (value.visible.includes('nofalukantaccount') && !hasFalukantAccount)
|| (value.visible.includes('hasfalukantaccount') && hasFalukantAccount)) {
const { visible, ...itemWithoutVisible } = value;
filteredMenu[key] = { ...itemWithoutVisible };
if (value.children) {
filteredMenu[key].children = await this.filterMenu(value.children, rights, age, userId);
}
}
}
} catch (error) {
console.error('Error filtering menu:', error);
// Return empty menu if filtering fails
return {};
}
return filteredMenu;
}
async menu(req, res) {
try {
const { userid } = req.params;
const user = await User.findOne({ where: { hashedId: userid } });
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
const userRights = await UserRight.findAll({
where: { userId: user.id },
include: [{
model: UserRightType,
as: 'rightType',
required: false
}]
});
const userBirthdateParams = await UserParam.findAll({
where: { userId: user.id },
include: [
{
model: UserParamType,
as: 'paramType',
where: { description: 'birthdate' }
}
]
});
const birthDate = userBirthdateParams.length > 0 ? userBirthdateParams[0].value : (new Date()).toDateString();
const age = this.calculateAge(birthDate);
const rights = userRights.map(ur => ur.rightType?.title).filter(Boolean);
const filteredMenu = await this.filterMenu(menuStructure, rights, age, user.id);
// Dynamisches Submenü: Treffpunkt → Sprachen lernen → Vokabeltrainer → (Neue Sprache + abonnierte/angelegte)
// Wichtig: "Neue Sprache" soll IMMER sichtbar sein auch wenn die DB-Abfrage (noch) fehlschlägt.
if (filteredMenu?.socialnetwork?.children?.sprachenlernen?.children?.vocabtrainer) {
const children = {
newLanguage: { path: '/socialnetwork/vocab/new' },
};
try {
const langs = await this.vocabService.listLanguagesForMenu(user.id);
for (const l of langs) {
children[`lang_${l.id}`] = { path: `/socialnetwork/vocab/${l.id}`, label: l.name };
}
} catch (e) {
console.warn('[menu] Konnte Vokabeltrainer-Sprachen nicht laden:', e?.message || e);
}
filteredMenu.socialnetwork.children.sprachenlernen.children.vocabtrainer.children = children;
}
res.status(200).json(filteredMenu);
} catch (error) {
console.error('Error fetching menu:', error);
// Return a minimal working menu instead of 500 error
res.status(200).json({
home: { path: "/", icon: "logo_mono.png" },
settings: { path: "/settings", icon: "settings16.png", children: {} }
});
}
}
async hasFalukantAccount(userId) {
try {
const falukantUser = await FalukantUser.findOne({ where: { userId: userId } });
return falukantUser !== null;
} catch (error) {
console.error('Error checking falukant account:', error);
return false; // Fallback: assume no falukant account if error occurs
}
}
}
export default NavigationController;