routing improved, settings initialized
This commit is contained in:
@@ -18,8 +18,12 @@ export const login = async (req, res) => {
|
|||||||
const result = await userService.loginUser({ username, password });
|
const result = await userService.loginUser({ username, password });
|
||||||
res.status(200).json(result);
|
res.status(200).json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (error.message === 'credentialsinvalid') {
|
||||||
|
res.status(404).json({ error: error.message })
|
||||||
|
} else {
|
||||||
res.status(500).json({ error: error.message });
|
res.status(500).json({ error: error.message });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const forgotPassword = async (req, res) => {
|
export const forgotPassword = async (req, res) => {
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import User from '../models/community/user.js';
|
||||||
|
import UserRight from '../models/community/user_right.js';
|
||||||
|
import UserRightType from '../models/type/user_right.js';
|
||||||
|
|
||||||
const menuStructure = {
|
const menuStructure = {
|
||||||
home: {
|
home: {
|
||||||
visible: ["all"],
|
visible: ["all"],
|
||||||
@@ -49,7 +53,7 @@ const menuStructure = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
chats: {
|
chats: {
|
||||||
visible: ["all"],
|
visible: ["over12"],
|
||||||
children: {
|
children: {
|
||||||
multiChat: {
|
multiChat: {
|
||||||
visible: ["over12"],
|
visible: ["over12"],
|
||||||
@@ -138,11 +142,11 @@ const menuStructure = {
|
|||||||
},
|
},
|
||||||
personal: {
|
personal: {
|
||||||
visible: ["all"],
|
visible: ["all"],
|
||||||
path: "/settings/account"
|
path: "/settings/personal"
|
||||||
},
|
},
|
||||||
view: {
|
view: {
|
||||||
visible: ["all"],
|
visible: ["all"],
|
||||||
path: "/settings/account"
|
path: "/settings/view"
|
||||||
},
|
},
|
||||||
interrests: {
|
interrests: {
|
||||||
visible: ["all"],
|
visible: ["all"],
|
||||||
@@ -202,7 +206,41 @@ const menuStructure = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filterMenu = (menu, rights) => {
|
||||||
|
const filteredMenu = {};
|
||||||
|
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))) {
|
||||||
|
const { visible, ...itemWithoutVisible } = value;
|
||||||
|
filteredMenu[key] = { ...itemWithoutVisible };
|
||||||
|
if (value.children) {
|
||||||
|
filteredMenu[key].children = filterMenu(value.children, rights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredMenu;
|
||||||
|
};
|
||||||
|
|
||||||
export const menu = async (req, res) => {
|
export const menu = async (req, res) => {
|
||||||
|
try {
|
||||||
const { userid } = req.params;
|
const { userid } = req.params;
|
||||||
res.status(200).json({ userId: userid });
|
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'
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
const rights = userRights.map(ur => ur.rightType.title);
|
||||||
|
const filteredMenu = filterMenu(menuStructure, rights);
|
||||||
|
res.status(200).json(filteredMenu);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching menu:', error);
|
||||||
|
res.status(500).json({ error: 'An error occurred while fetching the menu' });
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -28,9 +28,6 @@ const User = sequelize.define('user', {
|
|||||||
password: {
|
password: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
set(value) {
|
|
||||||
this.setDataValue('password', bcrypt.hashSync(value, 10));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
registrationDate: {
|
registrationDate: {
|
||||||
type: DataTypes.DATE,
|
type: DataTypes.DATE,
|
||||||
|
|||||||
32
backend/models/community/user_right.js
Normal file
32
backend/models/community/user_right.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { sequelize } from '../../utils/sequelize.js';
|
||||||
|
import { DataTypes } from 'sequelize';
|
||||||
|
import User from './user.js';
|
||||||
|
import UserRightType from '../type/user_right.js';
|
||||||
|
|
||||||
|
const UserRight = sequelize.define('user_right', {
|
||||||
|
userId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
references: {
|
||||||
|
model: User,
|
||||||
|
key: 'id'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rightTypeId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
references: {
|
||||||
|
model: UserRightType,
|
||||||
|
key: 'id'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
tableName: 'user_right',
|
||||||
|
schema: 'community',
|
||||||
|
underscored: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
UserRight.belongsTo(User, { foreignKey: 'userId' });
|
||||||
|
UserRight.belongsTo(UserRightType, { foreignKey: 'rightTypeId', as: 'rightType' });
|
||||||
|
|
||||||
|
export default UserRight;
|
||||||
@@ -2,12 +2,18 @@ import User from './community/user.js';
|
|||||||
import UserParam from './community/user_param.js';
|
import UserParam from './community/user_param.js';
|
||||||
import UserParamType from './type/user_param.js';
|
import UserParamType from './type/user_param.js';
|
||||||
import Login from './logs/login.js';
|
import Login from './logs/login.js';
|
||||||
|
import UserRightType from './type/user_right.js';
|
||||||
|
import UserRight from './community/user_right.js';
|
||||||
|
import SettingsType from './type/settings_type.js';
|
||||||
|
|
||||||
const models = {
|
const models = {
|
||||||
User,
|
User,
|
||||||
UserParam,
|
UserParam,
|
||||||
UserParamType,
|
UserParamType,
|
||||||
Login
|
Login,
|
||||||
|
UserRightType,
|
||||||
|
UserRight,
|
||||||
|
SettingsType,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default models;
|
export default models;
|
||||||
|
|||||||
15
backend/models/type/settings_type.js
Normal file
15
backend/models/type/settings_type.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { sequelize } from '../../utils/sequelize.js';
|
||||||
|
import { DataTypes } from 'sequelize';
|
||||||
|
|
||||||
|
const SettingsType = sequelize.define('settings_type', {
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
tableName: 'settings',
|
||||||
|
schema: 'type',
|
||||||
|
underscored: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export default SettingsType;
|
||||||
@@ -1,15 +1,39 @@
|
|||||||
import { sequelize } from '../../utils/sequelize.js';
|
import { sequelize } from '../../utils/sequelize.js';
|
||||||
import { DataTypes } from 'sequelize';
|
import { DataTypes } from 'sequelize';
|
||||||
|
import SettingsType from './settings_type.js';
|
||||||
|
|
||||||
const UserParamType = sequelize.define('user_param_type', {
|
const UserParamType = sequelize.define('user_param_type', {
|
||||||
description: {
|
description: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false
|
allowNull: false
|
||||||
|
},
|
||||||
|
minAge: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: true
|
||||||
|
},
|
||||||
|
gender: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true
|
||||||
|
},
|
||||||
|
datatype: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 'string'
|
||||||
|
},
|
||||||
|
settingsTypeId: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
references: {
|
||||||
|
model: SettingsType,
|
||||||
|
key: 'id'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
tableName: 'user_param',
|
tableName: 'user_param',
|
||||||
schema: 'type',
|
schema: 'type',
|
||||||
underscored: true
|
underscored: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
UserParamType.belongsTo(SettingsType, { foreignKey: 'settingsTypeId' });
|
||||||
|
|
||||||
export default UserParamType;
|
export default UserParamType;
|
||||||
|
|||||||
15
backend/models/type/user_right.js
Normal file
15
backend/models/type/user_right.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { sequelize } from '../../utils/sequelize.js';
|
||||||
|
import { DataTypes } from 'sequelize';
|
||||||
|
|
||||||
|
const UserRightType = sequelize.define('user_right_type', {
|
||||||
|
title: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
tableName: 'user_right',
|
||||||
|
schema: 'type',
|
||||||
|
underscored: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UserRightType;
|
||||||
@@ -4,24 +4,30 @@ import User from '../models/community/user.js';
|
|||||||
import UserParam from '../models/community/user_param.js';
|
import UserParam from '../models/community/user_param.js';
|
||||||
import UserParamType from '../models/type/user_param.js';
|
import UserParamType from '../models/type/user_param.js';
|
||||||
import { sendAccountActivationEmail, sendPasswordResetEmail } from './emailService.js';
|
import { sendAccountActivationEmail, sendPasswordResetEmail } from './emailService.js';
|
||||||
|
import { sequelize } from '../utils/sequelize.js';
|
||||||
|
import { encrypt, generateIv } from '../utils/encryption.js';
|
||||||
|
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
|
|
||||||
export const registerUser = async ({ email, username, password, language }) => {
|
export const registerUser = async ({ email, username, password, language }) => {
|
||||||
const [results] = await sequelize.query(
|
const iv = generateIv();
|
||||||
'SELECT * FROM "community"."user" WHERE pgp_sym_decrypt("email", :key) = :email',
|
const encryptedEmail = encrypt(email, iv);
|
||||||
|
|
||||||
|
const results = await sequelize.query(
|
||||||
|
`SELECT * FROM "community"."user" WHERE public.pgp_sym_decrypt("email"::bytea, :key::text) = :email`,
|
||||||
{
|
{
|
||||||
replacements: { key: process.env.SECRET_KEY, email },
|
replacements: { key: process.env.SECRET_KEY, email },
|
||||||
type: sequelize.QueryTypes.SELECT
|
type: sequelize.QueryTypes.SELECT
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (results.length > 0) {
|
console.log(results);
|
||||||
|
if (results.length && results.length > 0) {
|
||||||
throw new Error('Email already in use');
|
throw new Error('Email already in use');
|
||||||
}
|
}
|
||||||
const iv = generateIv();
|
|
||||||
const encryptedEmail = encrypt(email, iv);
|
|
||||||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||||||
const resetToken = uuidv4();
|
const resetToken = uuidv4();
|
||||||
|
|
||||||
const user = await User.create({
|
const user = await User.create({
|
||||||
email: encryptedEmail,
|
email: encryptedEmail,
|
||||||
iv: iv.toString('hex'),
|
iv: iv.toString('hex'),
|
||||||
@@ -31,17 +37,21 @@ export const registerUser = async ({ email, username, password, language }) => {
|
|||||||
active: false,
|
active: false,
|
||||||
registration_date: new Date()
|
registration_date: new Date()
|
||||||
});
|
});
|
||||||
|
|
||||||
const languageType = await UserParamType.findOne({ where: { description: 'language' } });
|
const languageType = await UserParamType.findOne({ where: { description: 'language' } });
|
||||||
if (!languageType) {
|
if (!languageType) {
|
||||||
throw new Error('Language type not found');
|
throw new Error('Language type not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await UserParam.create({
|
await UserParam.create({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
paramTypeId: languageType.id,
|
paramTypeId: languageType.id,
|
||||||
value: language
|
value: language
|
||||||
});
|
});
|
||||||
|
|
||||||
const activationLink = `${process.env.FRONTEND_URL}/activate?token=${resetToken}`;
|
const activationLink = `${process.env.FRONTEND_URL}/activate?token=${resetToken}`;
|
||||||
await sendAccountActivationEmail(email, activationLink, username, resetToken, language);
|
await sendAccountActivationEmail(email, activationLink, username, resetToken, language);
|
||||||
|
|
||||||
return { id: user.hashedId, username: user.username, active: user.active };
|
return { id: user.hashedId, username: user.username, active: user.active };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,10 +62,22 @@ export const loginUser = async ({ username, password }) => {
|
|||||||
throw new Error('credentialsinvalid');
|
throw new Error('credentialsinvalid');
|
||||||
}
|
}
|
||||||
const match = await bcrypt.compare(password, user.password);
|
const match = await bcrypt.compare(password, user.password);
|
||||||
|
console.log(match, password, user.password, await bcrypt.hash(password, saltRounds));
|
||||||
if (!match) {
|
if (!match) {
|
||||||
throw new Error('credentialsinvalid');
|
throw new Error('credentialsinvalid');
|
||||||
}
|
}
|
||||||
return { id: user.hashedId, username: user.username, active: user.active };
|
const neededParams = await UserParam.findAll({
|
||||||
|
where: {
|
||||||
|
userId: user.id
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
model: UserParamType,
|
||||||
|
where: {
|
||||||
|
description: ['birthdate', 'gender']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { id: user.hashedId, username: user.username, active: user.active, forwardDataInput: neededParams.length < 2 };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handleForgotPassword = async ({ email }) => {
|
export const handleForgotPassword = async ({ email }) => {
|
||||||
|
|||||||
18
backend/utils/initializeSettings.js
Normal file
18
backend/utils/initializeSettings.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import SettingsType from "../models/type/settings_type.js";
|
||||||
|
|
||||||
|
const initializeSettings = async () => {
|
||||||
|
await SettingsType.findOrCreate({
|
||||||
|
where: { name: 'personal' },
|
||||||
|
defaults: { name: 'personal' }
|
||||||
|
});
|
||||||
|
await SettingsType.findOrCreate({
|
||||||
|
where: { name: 'view' },
|
||||||
|
defaults: { name: 'view' }
|
||||||
|
});
|
||||||
|
await SettingsType.findOrCreate({
|
||||||
|
where: { name: 'sexuality' },
|
||||||
|
defaults: { name: 'sexuality' }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default initializeSettings;
|
||||||
@@ -1,9 +1,86 @@
|
|||||||
import UserParamType from '../models/type/user_param.js';
|
import UserParamType from '../models/type/user_param.js';
|
||||||
|
import SettingsType from '../models/type/settings_type.js'; // Importiere SettingsType
|
||||||
|
|
||||||
const initializeTypes = async () => {
|
const initializeTypes = async () => {
|
||||||
|
const settingsTypes = await SettingsType.findAll();
|
||||||
|
const settingsTypeMap = settingsTypes.reduce((map, type) => {
|
||||||
|
map[type.name] = type.id;
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const getSettingsTypeId = (name) => settingsTypeMap[name];
|
||||||
|
|
||||||
await UserParamType.findOrCreate({
|
await UserParamType.findOrCreate({
|
||||||
where: { description: 'language' },
|
where: { description: 'language' },
|
||||||
defaults: { description: 'language' }
|
defaults: { description: 'language', datatype: 'string', settingsTypeId: getSettingsTypeId('personal') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'birthdate' },
|
||||||
|
defaults: { description: 'birthdate', datatype: 'date', settingsTypeId: getSettingsTypeId('personal') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'zip' },
|
||||||
|
defaults: { description: 'zip', datatype: 'string', settingsTypeId: getSettingsTypeId('personal') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'town' },
|
||||||
|
defaults: { description: 'town', datatype: 'string', settingsTypeId: getSettingsTypeId('personal') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'bodyheight' },
|
||||||
|
defaults: { description: 'bodyheight', datatype: 'float', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'weight' },
|
||||||
|
defaults: { description: 'weight', datatype: 'float', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'eyecolor' },
|
||||||
|
defaults: { description: 'eyecolor', datatype: 'string', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'haircolor' },
|
||||||
|
defaults: { description: 'haircolor', datatype: 'string', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'hairlength' },
|
||||||
|
defaults: { description: 'hairlength', datatype: 'int', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'skincolor' },
|
||||||
|
defaults: { description: 'skincolor', datatype: 'int', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'freckles' },
|
||||||
|
defaults: { description: 'freckles', datatype: 'int', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'piercings' },
|
||||||
|
defaults: { description: 'piercings', datatype: 'bool', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'tattoos' },
|
||||||
|
defaults: { description: 'tattoos', datatype: 'bool', settingsTypeId: getSettingsTypeId('view') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'sexualpreference' },
|
||||||
|
defaults: { description: 'sexualpreference', minAge: 14, datatype: 'int', settingsTypeId: getSettingsTypeId('sexuality') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'gender' },
|
||||||
|
defaults: { description: 'gender', datatype: 'string', settingsTypeId: getSettingsTypeId('personal') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'pubichair' },
|
||||||
|
defaults: { description: 'pubichair', minAge: 14, datatype: 'int', settingsTypeId: getSettingsTypeId('sexuality') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'penislength' },
|
||||||
|
defaults: { description: 'penislength', minAge: 14, gender: 'm', datatype: 'int', settingsTypeId: getSettingsTypeId('sexuality') }
|
||||||
|
});
|
||||||
|
await UserParamType.findOrCreate({
|
||||||
|
where: { description: 'brasize' },
|
||||||
|
defaults: { description: 'brasize', minAge: 14, gender: 'f', datatype: 'string', settingsTypeId: getSettingsTypeId('sexuality') }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
39
backend/utils/initializeUserRights.js
Normal file
39
backend/utils/initializeUserRights.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import UserRightType from "../models/type/user_right.js";
|
||||||
|
|
||||||
|
const initializeUserRights = async() => {
|
||||||
|
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "mainadmin"},
|
||||||
|
defaults: { title: "mainadmin"}
|
||||||
|
});
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "contactrequests"},
|
||||||
|
defaults: { title: "contactrequests"}
|
||||||
|
});
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "useradministration"},
|
||||||
|
defaults: { title: "useradministration"}
|
||||||
|
});
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "forum"},
|
||||||
|
defaults: { title: "forum"}
|
||||||
|
});
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "rights"},
|
||||||
|
defaults: { title: "rights"}
|
||||||
|
});
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "interrests"},
|
||||||
|
defaults: { title: "interrests"}
|
||||||
|
});
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "falukant"},
|
||||||
|
defaults: { title: "falukant"}
|
||||||
|
});
|
||||||
|
await UserRightType.findOrCreate({
|
||||||
|
where: { title: "developer"},
|
||||||
|
defaults: { title: "developer"}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default initializeUserRights;
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
import { initializeDatabase } from './sequelize.js';
|
import { initializeDatabase } from './sequelize.js';
|
||||||
import initializeTypes from './initializeTypes.js';
|
import initializeTypes from './initializeTypes.js';
|
||||||
|
import initializeSettings from './initializeSettings.js';
|
||||||
|
import initializeUserRights from './initializeUserRights.js';
|
||||||
|
|
||||||
const syncDatabase = async () => {
|
const syncDatabase = async () => {
|
||||||
try {
|
try {
|
||||||
await initializeDatabase();
|
await initializeDatabase();
|
||||||
|
await initializeSettings();
|
||||||
await initializeTypes();
|
await initializeTypes();
|
||||||
|
await initializeUserRights();
|
||||||
console.log('All models were synchronized successfully.');
|
console.log('All models were synchronized successfully.');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Unable to synchronize the database:', error);
|
console.error('Unable to synchronize the database:', error);
|
||||||
|
|||||||
1
frontend/src/assets/images
Symbolic link
1
frontend/src/assets/images
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../public/images
|
||||||
@@ -1,42 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="item in menu" :key="item.text">
|
<li v-for="(item, key) in menu" :key="key" class="mainmenuitem">
|
||||||
<a href="#">{{ $t(`navigation.${item.text}`) }}</a>
|
<a :href="item.path" v-if="item.path" class="menuitem">{{ $t(`navigation.${key}`) }}</a>
|
||||||
<ul v-if="item.submenu">
|
<span v-if="!item.path" class="menuitem">{{ $t(`navigation.${key}`) }}</span>
|
||||||
<li v-for="subitem in item.submenu" :key="subitem.text">
|
<ul v-if="item.children" class="submenu1">
|
||||||
<a href="#">{{ $t(`navigation.${subitem.text}`) }}</a>
|
<li v-for="(subitem, subkey) in item.children" :key="subitem.text">
|
||||||
|
<a :href="subitem.path" v-if="subitem.path">{{ $t(`navigation.m-${key}.${subkey}`) }}</a>
|
||||||
|
<span v-if="!subitem.path">{{ $t(`navigation.m-${key}.${subkey}`) }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="right-block">
|
<div class="right-block">
|
||||||
<button @click="accessMailbox">{{ $t('navigation.mailbox') }}</button>
|
<span @click="accessMailbox" class="mailbox"></span>
|
||||||
<button @click="logout">{{ $t('navigation.logout') }}</button>
|
<span class="logoutblock">
|
||||||
|
<span class="username">{{ user.username }} </span>
|
||||||
|
<span @click="logout" class="menuitem">{{ $t('navigation.logout') }}</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters, mapActions } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppNavigation',
|
name: 'AppNavigation',
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('menu'),
|
...mapGetters(['menu', 'user']),
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if(this.$store.getters.hashedId) {
|
if (this.user && this.user.hashedId) {
|
||||||
this.$store.dispatch('loadMenu');
|
this.loadMenu();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
accessMailbox() {
|
...mapActions(['loadMenu', 'logout']),
|
||||||
alert('Accessing Mailbox...');
|
|
||||||
},
|
|
||||||
logout() {
|
|
||||||
this.$store.dispatch('logout');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -45,37 +45,87 @@ export default {
|
|||||||
@import '../assets/styles.scss';
|
@import '../assets/styles.scss';
|
||||||
|
|
||||||
nav,
|
nav,
|
||||||
nav > ul{
|
nav>ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background-color: #F9A22C;
|
background-color: #F9A22C;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
padding: 10px;
|
padding: 0;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
li {
|
|
||||||
margin: 5px 0;
|
nav>ul>li {
|
||||||
|
padding: 0 1em;
|
||||||
|
line-height: 2.5em;
|
||||||
|
transition: background-color 0.25s;
|
||||||
}
|
}
|
||||||
a {
|
|
||||||
|
nav>ul>li:hover {
|
||||||
|
background-color: #D37C06;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
nav>ul>li:hover > span {
|
||||||
color: #000000;
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav>ul>li:hover > ul{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-block {
|
.right-block {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
button {
|
|
||||||
background-color: #495057;
|
.logoutblock {
|
||||||
color: white;
|
display: flex;
|
||||||
border: none;
|
flex-direction: column;
|
||||||
padding: 5px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
button:hover {
|
|
||||||
background-color: #6c757d;
|
.menuitem {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #7E471B;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailbox {
|
||||||
|
background-image: url('@/assets/images/icons/message24.png');
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
padding-left: 24px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainmenuitem {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu1 {
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid #7E471B;
|
||||||
|
background-color: #F9A22C;
|
||||||
|
display: none;
|
||||||
|
left: 0;
|
||||||
|
top: 2.5em;
|
||||||
|
}
|
||||||
|
.submenu1 > li {
|
||||||
|
padding: 0.5em;
|
||||||
|
line-height: 1em;
|
||||||
|
color: #7E471B;
|
||||||
|
}
|
||||||
|
.submenu1>li:hover {
|
||||||
|
color: #000000;
|
||||||
|
background-color: #D37C06;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"error": {
|
"error": {
|
||||||
"title": "Fehler aufgetreten",
|
"title": "Fehler aufgetreten",
|
||||||
"close": "Schließen"
|
"close": "Schließen",
|
||||||
|
"credentialsinvalid": "Die Zugangsdaten sind nicht korrekt."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,44 @@
|
|||||||
{
|
{
|
||||||
|
"navigation": {
|
||||||
"home": "Startseite",
|
"home": "Startseite",
|
||||||
"about": "Über uns",
|
"logout": "Abmelden",
|
||||||
"services": "Dienstleistungen",
|
"friends": "Freunde",
|
||||||
"team": "Team",
|
"socialnetwork": "Treffpunkt",
|
||||||
"company": "Firma",
|
"chats": "Chats",
|
||||||
"consulting": "Beratung",
|
"falukant": "Falukant",
|
||||||
"development": "Entwicklung",
|
"minigames": "Minispiele",
|
||||||
"mailbox": "Briefkasten",
|
"settings": "Einstellungen",
|
||||||
"logout": "Abmelden"
|
"administration": "Verwaltung",
|
||||||
|
"m-chats": {
|
||||||
|
"multiChat": "Multiuser-Chat",
|
||||||
|
"randomChat": "Zufalls-Singlechat"
|
||||||
|
},
|
||||||
|
"m-socialnetwork": {
|
||||||
|
"guestbook": "Gästebuch",
|
||||||
|
"usersearch": "Benutzersuche",
|
||||||
|
"forum": "Forum",
|
||||||
|
"gallery": "Galerie",
|
||||||
|
"blockedUsers": "Blockierte Benutzer",
|
||||||
|
"oneTimeInvitation": "Einmal-Einladungen",
|
||||||
|
"diary": "Tagebuch"
|
||||||
|
},
|
||||||
|
"m-settings": {
|
||||||
|
"homepage": "Startseite",
|
||||||
|
"account": "Account",
|
||||||
|
"personal": "Persönliches",
|
||||||
|
"view": "Aussehen",
|
||||||
|
"interrests": "Interessen",
|
||||||
|
"notifications": "Benachrichtigungen",
|
||||||
|
"sexuality": "Sexualität"
|
||||||
|
},
|
||||||
|
"m-administration": {
|
||||||
|
"contactrequests": "Kontaktanfragen",
|
||||||
|
"useradministration": "Benutzerverwaltung",
|
||||||
|
"forum": "Forum",
|
||||||
|
"userrights": "Benutzerrechte",
|
||||||
|
"interrests": "Interessen",
|
||||||
|
"falukant": "Falukant"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
|
import store from '../store';
|
||||||
import HomeView from '../views/HomeView.vue';
|
import HomeView from '../views/HomeView.vue';
|
||||||
import ActivateView from '../views/auth/ActivateView.vue';
|
import ActivateView from '../views/auth/ActivateView.vue';
|
||||||
|
import PeronalSettingsView from '../views/settings/PersonalView.vue';
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@@ -12,9 +14,16 @@ const routes = [
|
|||||||
path: '/activate',
|
path: '/activate',
|
||||||
name: 'Activate page',
|
name: 'Activate page',
|
||||||
component: ActivateView
|
component: ActivateView
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings/personal',
|
||||||
|
name: 'Personal settings',
|
||||||
|
component: PeronalSettingsView,
|
||||||
|
meta: { requiresAuth: true }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(process.env.BASE_URL),
|
history: createWebHistory(process.env.BASE_URL),
|
||||||
routes
|
routes
|
||||||
@@ -24,10 +33,10 @@ router.beforeEach((to, from, next) => {
|
|||||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
if (!store.getters.isLoggedIn) {
|
if (!store.getters.isLoggedIn) {
|
||||||
next('/');
|
next('/');
|
||||||
} else if (!store.user.active) {
|
} else if (!store.getters.user.active) {
|
||||||
next();
|
|
||||||
} else {
|
|
||||||
next('/activate');
|
next('/activate');
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
import dialogs from './modules/dialogs';
|
import dialogs from './modules/dialogs';
|
||||||
import loadMenu from '../utils/menuLoader.js';
|
import loadMenu from '../utils/menuLoader.js';
|
||||||
|
import router from '../router';
|
||||||
|
|
||||||
const store = createStore({
|
const store = createStore({
|
||||||
state: {
|
state: {
|
||||||
@@ -43,13 +44,14 @@ const store = createStore({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async login({ commit, dispatch }, user) { // Dispatch hinzufügen
|
async login({ commit, dispatch }, user) {
|
||||||
commit('dologin', user);
|
commit('dologin', user);
|
||||||
await dispatch('loadMenu'); // Korrekte Verwendung von dispatch
|
await dispatch('loadMenu');
|
||||||
dispatch('startMenuReload');
|
dispatch('startMenuReload');
|
||||||
},
|
},
|
||||||
logout({ commit }) {
|
logout({ commit }) {
|
||||||
commit('dologout');
|
commit('dologout');
|
||||||
|
router.push('/');
|
||||||
},
|
},
|
||||||
loadLoginState({ commit }) {
|
loadLoginState({ commit }) {
|
||||||
commit('loadLoginState');
|
commit('loadLoginState');
|
||||||
@@ -69,7 +71,7 @@ const store = createStore({
|
|||||||
startMenuReload({ dispatch }) {
|
startMenuReload({ dispatch }) {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
dispatch('loadMenu');
|
dispatch('loadMenu');
|
||||||
}, 5000);
|
}, 10000);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import store from '../store';
|
|||||||
|
|
||||||
const loadMenu = async () => {
|
const loadMenu = async () => {
|
||||||
try {
|
try {
|
||||||
console.log(store.getters.user);
|
|
||||||
const userId = store.getters.user ? store.getters.user.id : null;
|
const userId = store.getters.user ? store.getters.user.id : null;
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
throw new Error('User ID not found');
|
throw new Error('User ID not found');
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export default {
|
|||||||
const response = await apiClient.post('/api/auth/activate', { token: this.token });
|
const response = await apiClient.post('/api/auth/activate', { token: this.token });
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
this.user.active = true;
|
this.user.active = true;
|
||||||
this.$router.push('/'); // Redirect to login after activation
|
this.$router.push('/settings/personal');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error activating account:', error);
|
console.error('Error activating account:', error);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
<RandomChatDialog ref="randomChatDialog" />
|
<RandomChatDialog ref="randomChatDialog" />
|
||||||
<RegisterDialog ref="registerDialog" />
|
<RegisterDialog ref="registerDialog" />
|
||||||
<PasswordResetDialog ref="passwordResetDialog" />
|
<PasswordResetDialog ref="passwordResetDialog" />
|
||||||
|
<ErrorDialog ref="errorDialog" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ import RegisterDialog from '@/dialogues/auth/RegisterDialog.vue';
|
|||||||
import PasswordResetDialog from '@/dialogues/auth/PasswordResetDialog.vue';
|
import PasswordResetDialog from '@/dialogues/auth/PasswordResetDialog.vue';
|
||||||
import apiClient from '@/utils/axios.js';
|
import apiClient from '@/utils/axios.js';
|
||||||
import { mapActions } from 'vuex';
|
import { mapActions } from 'vuex';
|
||||||
|
import ErrorDialog from '@/dialogues/standard/ErrorDialog.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HomeNoLoginView',
|
name: 'HomeNoLoginView',
|
||||||
@@ -60,6 +62,7 @@ export default {
|
|||||||
RandomChatDialog,
|
RandomChatDialog,
|
||||||
RegisterDialog,
|
RegisterDialog,
|
||||||
PasswordResetDialog,
|
PasswordResetDialog,
|
||||||
|
ErrorDialog,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['login']),
|
...mapActions(['login']),
|
||||||
@@ -73,8 +76,16 @@ export default {
|
|||||||
this.$refs.passwordResetDialog.open();
|
this.$refs.passwordResetDialog.open();
|
||||||
},
|
},
|
||||||
async doLogin() {
|
async doLogin() {
|
||||||
|
try {
|
||||||
const response = await apiClient.post('/api/auth/login', { username: this.username, password: this.password });
|
const response = await apiClient.post('/api/auth/login', { username: this.username, password: this.password });
|
||||||
this.login(response.data);
|
this.login(response.data);
|
||||||
|
if (response.data.forwardDataInput) {
|
||||||
|
console.log(response.data);
|
||||||
|
this.$router.push({ path: '/settings/personal' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.$refs.errorDialog.open(`tr:error.${error.response.data.error}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
11
frontend/src/views/settings/PersonalView.vue
Normal file
11
frontend/src/views/settings/PersonalView.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
Persönliche Einstellungen
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'PersonalSettingsView',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user