- 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.
429 lines
14 KiB
JavaScript
429 lines
14 KiB
JavaScript
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;
|