Änderung: Erweiterung der Benutzerkontoeinstellungen und Verbesserung der E-Mail-Verschlüsselung
Änderungen: - Implementierung von neuen Methoden `getAccountSettings` und `setAccountSettings` im `SettingsService`, um Benutzerkontoeinstellungen zu verwalten. - Anpassung der E-Mail-Verschlüsselung im `User`-Modell zur Verwendung von Buffer für die Speicherung und zur Verbesserung der Fehlerbehandlung bei der Entschlüsselung. - Hinzufügung eines neuen `immutable`-Feldes im `UserParamType`-Modell, um unveränderliche Einstellungen zu kennzeichnen. - Anpassungen in den Frontend-Komponenten zur Berücksichtigung von unveränderlichen Feldern und zur Verbesserung der Benutzeroberfläche. Diese Anpassungen verbessern die Sicherheit der Benutzerdaten und erweitern die Funktionalität der Kontoeinstellungen.
This commit is contained in:
@@ -11,13 +11,32 @@ const User = sequelize.define('user', {
|
|||||||
set(value) {
|
set(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
const encrypted = encrypt(value);
|
const encrypted = encrypt(value);
|
||||||
this.setDataValue('email', encrypted);
|
// Konvertiere Hex-String zu Buffer für die Speicherung
|
||||||
|
const buffer = Buffer.from(encrypted, 'hex');
|
||||||
|
this.setDataValue('email', buffer);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
const encrypted = this.getDataValue('email');
|
const encrypted = this.getDataValue('email');
|
||||||
if (encrypted) {
|
if (encrypted) {
|
||||||
return decrypt(encrypted);
|
try {
|
||||||
|
// Konvertiere Buffer zu String für die Entschlüsselung
|
||||||
|
const encryptedString = encrypted.toString('hex');
|
||||||
|
const decrypted = decrypt(encryptedString);
|
||||||
|
if (decrypted) {
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Email decryption failed, treating as plain text:', error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Versuche es als Klartext zu lesen
|
||||||
|
try {
|
||||||
|
return encrypted.toString('utf8');
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Email could not be read as plain text:', error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ const UserParamType = sequelize.define('user_param_type', {
|
|||||||
unit: {
|
unit: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: true
|
allowNull: true
|
||||||
|
},
|
||||||
|
immutable: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: false
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
tableName: 'user_param',
|
tableName: 'user_param',
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const settingsController = new SettingsController();
|
|||||||
router.post('/filter', authenticate, settingsController.filterSettings.bind(settingsController));
|
router.post('/filter', authenticate, settingsController.filterSettings.bind(settingsController));
|
||||||
router.post('/update', authenticate, settingsController.updateSetting.bind(settingsController));
|
router.post('/update', authenticate, settingsController.updateSetting.bind(settingsController));
|
||||||
router.post('/account', authenticate, settingsController.getAccountSettings.bind(settingsController));
|
router.post('/account', authenticate, settingsController.getAccountSettings.bind(settingsController));
|
||||||
|
router.post('/set-account', authenticate, settingsController.setAccountSettings.bind(settingsController));
|
||||||
router.post('/getparamvalues', settingsController.getTypeParamValues.bind(settingsController));
|
router.post('/getparamvalues', settingsController.getTypeParamValues.bind(settingsController));
|
||||||
router.post('/getparamvalueid', settingsController.getTypeParamValueId.bind(settingsController));
|
router.post('/getparamvalueid', settingsController.getTypeParamValueId.bind(settingsController));
|
||||||
router.post('/getparamvalue/:id', settingsController.getTypeParamValue.bind(settingsController));
|
router.post('/getparamvalue/:id', settingsController.getTypeParamValue.bind(settingsController));
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ class SettingsService extends BaseService{
|
|||||||
gender: field.gender,
|
gender: field.gender,
|
||||||
datatype: field.datatype,
|
datatype: field.datatype,
|
||||||
unit: field.unit,
|
unit: field.unit,
|
||||||
|
immutable: field.immutable,
|
||||||
value: field.user_params.length > 0 ? field.user_params[0].value : null,
|
value: field.user_params.length > 0 ? field.user_params[0].value : null,
|
||||||
options: options.map(opt => ({ id: opt.id, value: opt.value })),
|
options: options.map(opt => ({ id: opt.id, value: opt.value })),
|
||||||
visibility
|
visibility
|
||||||
@@ -117,6 +118,19 @@ class SettingsService extends BaseService{
|
|||||||
if (!paramType) {
|
if (!paramType) {
|
||||||
throw new Error('Parameter type not found');
|
throw new Error('Parameter type not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prüfe ob das Feld unveränderlich ist
|
||||||
|
if (paramType.immutable) {
|
||||||
|
const userParam = await UserParam.findOne({
|
||||||
|
where: { userId: user.id, paramTypeId: settingId }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wenn bereits ein Wert existiert, ist das Feld unveränderlich
|
||||||
|
if (userParam && userParam.value) {
|
||||||
|
throw new Error('This field cannot be changed. Please contact support for modifications.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const userParam = await UserParam.findOne({
|
const userParam = await UserParam.findOne({
|
||||||
where: { userId: user.id, paramTypeId: settingId }
|
where: { userId: user.id, paramTypeId: settingId }
|
||||||
});
|
});
|
||||||
@@ -257,6 +271,81 @@ class SettingsService extends BaseService{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAccountSettings(hashedUserId) {
|
||||||
|
try {
|
||||||
|
const user = await this.getUserByHashedId(hashedUserId);
|
||||||
|
if (!user) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Die Email wird automatisch durch den Getter entschlüsselt
|
||||||
|
// Falls die Entschlüsselung fehlschlägt, verwende null
|
||||||
|
let email = null;
|
||||||
|
try {
|
||||||
|
email = user.email; // Getter entschlüsselt automatisch
|
||||||
|
} catch (decryptError) {
|
||||||
|
console.warn('Email decryption failed, using null:', decryptError.message);
|
||||||
|
email = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
username: user.username,
|
||||||
|
email: email,
|
||||||
|
showinsearch: user.searchable
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting account settings:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async setAccountSettings({ userId, settings }) {
|
||||||
|
try {
|
||||||
|
const user = await this.getUserByHashedId(userId);
|
||||||
|
if (!user) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update username if provided
|
||||||
|
if (settings.username !== undefined) {
|
||||||
|
await user.update({ username: settings.username });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update email if provided
|
||||||
|
if (settings.email !== undefined) {
|
||||||
|
await user.update({ email: settings.email });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update searchable flag if provided
|
||||||
|
if (settings.showinsearch !== undefined) {
|
||||||
|
await user.update({ searchable: settings.showinsearch });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update password if provided and not empty
|
||||||
|
if (settings.newpassword && settings.newpassword.trim() !== '') {
|
||||||
|
if (!settings.oldpassword || settings.oldpassword.trim() === '') {
|
||||||
|
throw new Error('Old password is required to change password');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify old password
|
||||||
|
const bcrypt = await import('bcrypt');
|
||||||
|
const match = await bcrypt.compare(settings.oldpassword, user.password);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error('Old password is incorrect');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash new password
|
||||||
|
const hashedPassword = await bcrypt.hash(settings.newpassword, 10);
|
||||||
|
await user.update({ password: hashedPassword });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error setting account settings:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getVisibilities() {
|
async getVisibilities() {
|
||||||
return UserParamVisibilityType.findAll();
|
return UserParamVisibilityType.findAll();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const initializeTypes = async () => {
|
|||||||
};
|
};
|
||||||
const userParams = {
|
const userParams = {
|
||||||
language: { type: 'singleselect', setting: 'personal' },
|
language: { type: 'singleselect', setting: 'personal' },
|
||||||
birthdate: { type: 'date', setting: 'personal' },
|
birthdate: { type: 'date', setting: 'personal', immutable: true },
|
||||||
zip: { type: 'string', setting: 'personal' },
|
zip: { type: 'string', setting: 'personal' },
|
||||||
town: { type: 'string', setting: 'personal' },
|
town: { type: 'string', setting: 'personal' },
|
||||||
bodyheight: { type: 'float', setting: 'view', unit: 'cm' },
|
bodyheight: { type: 'float', setting: 'view', unit: 'cm' },
|
||||||
@@ -54,6 +54,7 @@ const initializeTypes = async () => {
|
|||||||
if (item.minAge) createItem.minAge = item.minAge;
|
if (item.minAge) createItem.minAge = item.minAge;
|
||||||
if (item.gender) createItem.gender = item.gender;
|
if (item.gender) createItem.gender = item.gender;
|
||||||
if (item.unit) createItem.unit = item.unit;
|
if (item.unit) createItem.unit = item.unit;
|
||||||
|
if (item.immutable) createItem.immutable = item.immutable;
|
||||||
await UserParamType.findOrCreate({
|
await UserParamType.findOrCreate({
|
||||||
where: { description: key },
|
where: { description: key },
|
||||||
defaults: createItem
|
defaults: createItem
|
||||||
|
|||||||
@@ -5,38 +5,52 @@
|
|||||||
<td>
|
<td>
|
||||||
<InputStringWidget v-if="setting.datatype == 'string'"
|
<InputStringWidget v-if="setting.datatype == 'string'"
|
||||||
:labelTr="`settings.personal.label.${setting.name}`"
|
:labelTr="`settings.personal.label.${setting.name}`"
|
||||||
:tooltipTr="`settings.personal.tooltip.${setting.name}`" :value=setting.value
|
:tooltipTr="setting.immutable ? $t('settings.immutable.tooltip') : `settings.personal.tooltip.${setting.name}`"
|
||||||
|
:value=setting.value
|
||||||
|
:disabled="setting.immutable && setting.value ? true : false"
|
||||||
:list="languagesList()" @input="handleInput(setting.id, $event)" />
|
:list="languagesList()" @input="handleInput(setting.id, $event)" />
|
||||||
|
|
||||||
<DateInputWidget v-else-if="setting.datatype == 'date'"
|
<DateInputWidget v-else-if="setting.datatype == 'date'"
|
||||||
:labelTr="`settings.personal.label.${setting.name}`"
|
:labelTr="`settings.personal.label.${setting.name}`"
|
||||||
:tooltipTr="`settings.personal.tooltip.${setting.name}`" :value=setting.value
|
:tooltipTr="setting.immutable ? $t('settings.immutable.tooltip') : `settings.personal.tooltip.${setting.name}`"
|
||||||
|
:value=setting.value
|
||||||
|
:disabled="setting.immutable && setting.value ? true : false"
|
||||||
@input="handleInput(setting.id, $event)" />
|
@input="handleInput(setting.id, $event)" />
|
||||||
|
|
||||||
<SelectDropdownWidget v-else-if="setting.datatype == 'singleselect'"
|
<SelectDropdownWidget v-else-if="setting.datatype == 'singleselect'"
|
||||||
:labelTr="`settings.personal.label.${setting.name}`"
|
:labelTr="`settings.personal.label.${setting.name}`"
|
||||||
:tooltipTr="`settings.personal.tooltip.${setting.name}`" :value=setting.value
|
:tooltipTr="setting.immutable ? $t('settings.immutable.tooltip') : `settings.personal.tooltip.${setting.name}`"
|
||||||
|
:value=setting.value
|
||||||
|
:disabled="setting.immutable && setting.value ? true : false"
|
||||||
:list="getSettingOptions(setting.name, setting.options)"
|
:list="getSettingOptions(setting.name, setting.options)"
|
||||||
@input="handleInput(setting.id, $event)" />
|
@input="handleInput(setting.id, $event)" />
|
||||||
|
|
||||||
<InputNumberWidget v-else-if="setting.datatype == 'int'"
|
<InputNumberWidget v-else-if="setting.datatype == 'int'"
|
||||||
:labelTr="`settings.personal.label.${setting.name}`"
|
:labelTr="`settings.personal.label.${setting.name}`"
|
||||||
:tooltipTr="`settings.personal.tooltip.${setting.name}`" :value="convertToInt(setting.value)"
|
:tooltipTr="setting.immutable ? $t('settings.immutable.tooltip') : `settings.personal.tooltip.${setting.name}`"
|
||||||
|
:value="convertToInt(setting.value)"
|
||||||
|
:disabled="setting.immutable && setting.value ? true : false"
|
||||||
min="0" max="200" @input="handleInput(setting.id, $event)" />
|
min="0" max="200" @input="handleInput(setting.id, $event)" />
|
||||||
|
|
||||||
<FloatInputWidget v-else-if="setting.datatype == 'float'"
|
<FloatInputWidget v-else-if="setting.datatype == 'float'"
|
||||||
:labelTr="`settings.personal.label.${setting.name}`"
|
:labelTr="`settings.personal.label.${setting.name}`"
|
||||||
:tooltipTr="`settings.personal.tooltip.${setting.name}`" :value="convertToFloat(setting.value)"
|
:tooltipTr="setting.immutable ? $t('settings.immutable.tooltip') : `settings.personal.tooltip.${setting.name}`"
|
||||||
|
:value="convertToFloat(setting.value)"
|
||||||
|
:disabled="setting.immutable && setting.value ? true : false"
|
||||||
@input="handleInput(setting.id, $event)" />
|
@input="handleInput(setting.id, $event)" />
|
||||||
|
|
||||||
<CheckboxWidget v-else-if="setting.datatype == 'bool'"
|
<CheckboxWidget v-else-if="setting.datatype == 'bool'"
|
||||||
:labelTr="`settings.personal.label.${setting.name}`"
|
:labelTr="`settings.personal.label.${setting.name}`"
|
||||||
:tooltipTr="`settings.personal.tooltip.${setting.name}`" :value="convertToBool(setting.value)"
|
:tooltipTr="setting.immutable ? $t('settings.immutable.tooltip') : `settings.personal.tooltip.${setting.name}`"
|
||||||
|
:value="convertToBool(setting.value)"
|
||||||
|
:disabled="setting.immutable && setting.value ? true : false"
|
||||||
@input="handleInput(setting.id, $event)" />
|
@input="handleInput(setting.id, $event)" />
|
||||||
|
|
||||||
<MultiselectWidget v-else-if="setting.datatype == 'multiselect'"
|
<MultiselectWidget v-else-if="setting.datatype == 'multiselect'"
|
||||||
:labelTr="`settings.personal.label.${setting.name}`"
|
:labelTr="`settings.personal.label.${setting.name}`"
|
||||||
:tooltipTr="`settings.personal.tooltip.${setting.name}`" :value="setting.value"
|
:tooltipTr="setting.immutable ? $t('settings.immutable.tooltip') : `settings.personal.tooltip.${setting.name}`"
|
||||||
|
:value="setting.value"
|
||||||
|
:disabled="setting.immutable && setting.value ? true : false"
|
||||||
:list="getSettingOptions(setting.name, setting.options)"
|
:list="getSettingOptions(setting.name, setting.options)"
|
||||||
@input="handleInput(setting.id, $event)" />
|
@input="handleInput(setting.id, $event)" />
|
||||||
|
|
||||||
@@ -51,6 +65,11 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
<td v-if="setting.immutable && setting.value">
|
||||||
|
<button @click="openContactDialog" class="contact-button">
|
||||||
|
{{ $t('settings.immutable.supportContact') }}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,6 +112,7 @@ export default {
|
|||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.fetchSettings();
|
await this.fetchSettings();
|
||||||
|
await this.fetchAccountData();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchSettings() {
|
async fetchSettings() {
|
||||||
@@ -111,6 +131,17 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async fetchAccountData() {
|
||||||
|
if (this.user && this.user.id) {
|
||||||
|
try {
|
||||||
|
const response = await apiClient.post('/api/settings/account', { userId: this.user.id });
|
||||||
|
this.userEmail = response.data.email;
|
||||||
|
this.userUsername = response.data.username;
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching account data:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
getSettingOptions(fieldName, options) {
|
getSettingOptions(fieldName, options) {
|
||||||
return options.map((option) => {
|
return options.map((option) => {
|
||||||
return {
|
return {
|
||||||
@@ -123,6 +154,14 @@ export default {
|
|||||||
if (['object', 'array'].includes(typeof value)) {
|
if (['object', 'array'].includes(typeof value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prüfe ob das Setting unveränderlich ist
|
||||||
|
const setting = this.settings.find(s => s.id === settingId);
|
||||||
|
if (setting && setting.immutable && setting.value) {
|
||||||
|
alert(this.$t('settings.immutable.tooltip'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userid = this.user.id;
|
const userid = this.user.id;
|
||||||
await apiClient.post('/api/settings/update', {
|
await apiClient.post('/api/settings/update', {
|
||||||
@@ -133,6 +172,9 @@ export default {
|
|||||||
this.fetchSettings();
|
this.fetchSettings();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error updating setting:', err);
|
console.error('Error updating setting:', err);
|
||||||
|
if (err.response && err.response.data && err.response.data.error) {
|
||||||
|
alert(err.response.data.error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
languagesList() {
|
languagesList() {
|
||||||
@@ -168,10 +210,35 @@ export default {
|
|||||||
console.error('Error updating visibility:', err);
|
console.error('Error updating visibility:', err);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
openContactDialog() {
|
||||||
|
// Erstelle vorgefertigte Daten für Support-Anfrage
|
||||||
|
const prefilledData = {
|
||||||
|
email: this.userEmail || "",
|
||||||
|
name: this.userUsername || "",
|
||||||
|
message: this.createSupportMessage(),
|
||||||
|
acceptDataSave: true
|
||||||
|
};
|
||||||
|
this.$root.$refs.contactDialog.open(prefilledData);
|
||||||
|
},
|
||||||
|
createSupportMessage() {
|
||||||
|
// Erstelle eine vorgefertigte Nachricht für unveränderliche Felder
|
||||||
|
const immutableFields = this.settings.filter(s => s.immutable && s.value);
|
||||||
|
if (immutableFields.length === 0) {
|
||||||
|
return this.$t('settings.immutable.supportMessage.general');
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldNames = immutableFields.map(field =>
|
||||||
|
this.$t(`settings.personal.label.${field.name}`)
|
||||||
|
).join(', ');
|
||||||
|
|
||||||
|
return this.$t('settings.immutable.supportMessage.specific', { fields: fieldNames });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
settings: [],
|
settings: [],
|
||||||
|
userEmail: "",
|
||||||
|
userUsername: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -181,4 +248,23 @@ export default {
|
|||||||
label {
|
label {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contact-button {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-button:active {
|
||||||
|
background-color: #004085;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" :checked="value" @change="updateValue($event.target.checked)" :title="$t(tooltipTr)" />
|
<input type="checkbox" :checked="value" :disabled="disabled" @change="updateValue($event.target.checked)" :title="$t(tooltipTr)" />
|
||||||
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
@@ -26,6 +26,11 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: false,
|
required: false,
|
||||||
default: 10
|
default: 10
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<label>
|
<label>
|
||||||
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
||||||
<input type="date" v-model="internalValue" :placeholder="$t(labelTr)" :title="$t(tooltipTr)"
|
<input type="date" v-model="internalValue" :placeholder="$t(labelTr)" :title="$t(tooltipTr)"
|
||||||
@change="updateValue($event.target.value)" />
|
:disabled="disabled" @change="updateValue($event.target.value)" />
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -28,6 +28,11 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: false,
|
required: false,
|
||||||
default: 10
|
default: 10
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<label>
|
<label>
|
||||||
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
||||||
<input type="number" :value="formattedValue" :placeholder="$t(labelTr)" :title="$t(tooltipTr)"
|
<input type="number" :value="formattedValue" :placeholder="$t(labelTr)" :title="$t(tooltipTr)"
|
||||||
@change="updateValue($event.target.value)" :step="step" />
|
:disabled="disabled" @change="updateValue($event.target.value)" :step="step" />
|
||||||
<span v-if="postfix">{{ postfix }}</span>
|
<span v-if="postfix">{{ postfix }}</span>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
@@ -37,6 +37,11 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dropdown-container">
|
<div class="dropdown-container">
|
||||||
<div class="dropdown-header" @click="toggleDropdown">
|
<div class="dropdown-header" @click="disabled ? null : toggleDropdown" :class="{ disabled: disabled }">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td v-for="(column, index) in columns" :key="column.field">
|
<td v-for="(column, index) in columns" :key="column.field">
|
||||||
@@ -48,6 +48,11 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: "Select an option",
|
default: "Select an option",
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
data() {
|
data() {
|
||||||
@@ -63,6 +68,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleDropdown() {
|
toggleDropdown() {
|
||||||
|
if (this.disabled) return;
|
||||||
this.isOpen = !this.isOpen;
|
this.isOpen = !this.isOpen;
|
||||||
},
|
},
|
||||||
selectOption(option) {
|
selectOption(option) {
|
||||||
@@ -129,4 +135,10 @@ tr:hover {
|
|||||||
background-color: #e0e0e0;
|
background-color: #e0e0e0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-header.disabled {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #999;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<label>
|
<label>
|
||||||
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
||||||
<input type="number" :value="value" :title="$t(tooltipTr)" :min="min" :max="max"
|
<input type="number" :value="value" :title="$t(tooltipTr)" :min="min" :max="max"
|
||||||
@change="updateValue($event.target.value)" />
|
:disabled="disabled" @change="updateValue($event.target.value)" />
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -34,6 +34,11 @@ export default {
|
|||||||
max: {
|
max: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: false
|
required: false
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<label>
|
<label>
|
||||||
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
||||||
<input type="text" :value="value" :placeholder="$t(labelTr)" :title="$t(tooltipTr)"
|
<input type="text" :value="value" :placeholder="$t(labelTr)" :title="$t(tooltipTr)"
|
||||||
@change="validateAndUpdate($event.target.value)" />
|
:disabled="disabled" @change="validateAndUpdate($event.target.value)" />
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -31,6 +31,11 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: null
|
default: null
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
:preserve-search="true"
|
:preserve-search="true"
|
||||||
:placeholder="$t('select_option')"
|
:placeholder="$t('select_option')"
|
||||||
:track-by="'value'"
|
:track-by="'value'"
|
||||||
|
:disabled="disabled"
|
||||||
>
|
>
|
||||||
<template #option="{ option }">
|
<template #option="{ option }">
|
||||||
<span v-if="option && option.value">{{ getTranslation(option) }}</span>
|
<span v-if="option && option.value">{{ getTranslation(option) }}</span>
|
||||||
@@ -42,6 +43,11 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
default: () => [] // Standardwert hinzufügen, um undefined zu vermeiden
|
default: () => [] // Standardwert hinzufügen, um undefined zu vermeiden
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<label>
|
<label>
|
||||||
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
|
||||||
<select :title="$t(tooltipTr)" :value="value" @change="updateValue($event.target.value)">
|
<select :title="$t(tooltipTr)" :value="value" :disabled="disabled" @change="updateValue($event.target.value)">
|
||||||
<option v-if="allowNone" :value="noneValue">{{ $t('none') }}</option>
|
<option v-if="allowNone" :value="noneValue">{{ $t('none') }}</option>
|
||||||
<option v-for="item in list" :key="item.value" :value="item.value">
|
<option v-for="item in list" :key="item.value" :value="item.value">
|
||||||
{{ item.captionTr ? $t(item.captionTr) : item.caption }}
|
{{ item.captionTr ? $t(item.captionTr) : item.caption }}
|
||||||
@@ -44,6 +44,11 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -40,11 +40,12 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
open() {
|
open(prefilledData = {}) {
|
||||||
this.email = "";
|
// Verwende vorgefertigte Daten oder Standardwerte
|
||||||
this.name = "";
|
this.email = prefilledData.email || "";
|
||||||
this.message = "";
|
this.name = prefilledData.name || "";
|
||||||
this.acceptDataSave = false;
|
this.message = prefilledData.message || "";
|
||||||
|
this.acceptDataSave = prefilledData.acceptDataSave || false;
|
||||||
this.error = "";
|
this.error = "";
|
||||||
this.$refs.dialog.open();
|
this.$refs.dialog.open();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -167,6 +167,14 @@
|
|||||||
},
|
},
|
||||||
"flirt": {
|
"flirt": {
|
||||||
"title": "Flirt"
|
"title": "Flirt"
|
||||||
|
},
|
||||||
|
"immutable": {
|
||||||
|
"tooltip": "Dieses Feld kann nicht geändert werden. Für Änderungen wenden Sie sich bitte an den Support.",
|
||||||
|
"supportContact": "Support kontaktieren",
|
||||||
|
"supportMessage": {
|
||||||
|
"general": "Hallo,\n\nich möchte eine Änderung an meinen unveränderlichen Profildaten beantragen.\n\nBitte kontaktieren Sie mich für weitere Details.\n\nMit freundlichen Grüßen",
|
||||||
|
"specific": "Hallo,\n\nich möchte eine Änderung an folgenden unveränderlichen Profildaten beantragen: {fields}\n\nBitte kontaktieren Sie mich für weitere Details.\n\nMit freundlichen Grüßen"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,6 +167,14 @@
|
|||||||
},
|
},
|
||||||
"flirt": {
|
"flirt": {
|
||||||
"title": "Flirt"
|
"title": "Flirt"
|
||||||
|
},
|
||||||
|
"immutable": {
|
||||||
|
"tooltip": "This field cannot be changed. Please contact support for modifications.",
|
||||||
|
"supportContact": "Contact Support",
|
||||||
|
"supportMessage": {
|
||||||
|
"general": "Hello,\n\nI would like to request a change to my immutable profile data.\n\nPlease contact me for further details.\n\nBest regards",
|
||||||
|
"specific": "Hello,\n\nI would like to request a change to the following immutable profile data: {fields}\n\nPlease contact me for further details.\n\nBest regards"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,15 +11,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label><span>{{ $t("settings.account.newpassword") }} </span><input type="password" v-model="newpassword"
|
<label><span>{{ $t("settings.account.newpassword") }} </span><input type="password" v-model="newpassword"
|
||||||
:placeholder="$t('settings.account.newpassword')" /></label>
|
:placeholder="$t('settings.account.newpassword')" autocomplete="new-password" /></label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label><span>{{ $t("settings.account.newpasswordretype") }} </span><input type="password"
|
<label><span>{{ $t("settings.account.newpasswordretype") }} </span><input type="password"
|
||||||
v-model="newpasswordretype" :placeholder="$t('settings.account.newpasswordretype')" /></label>
|
v-model="newpasswordretype" :placeholder="$t('settings.account.newpasswordretype')" autocomplete="new-password" /></label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label><span>{{ $t("settings.account.oldpassword") }} </span><input type="password"
|
<label><span>{{ $t("settings.account.oldpassword") }} </span><input type="password"
|
||||||
v-model="oldpassword" :placeholder="$t('settings.account.oldpassword')" /></label>
|
v-model="oldpassword" :placeholder="$t('settings.account.oldpassword')" autocomplete="current-password" /></label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button @click="changeAccount">{{ $t("settings.account.changeaction") }}</button>
|
<button @click="changeAccount">{{ $t("settings.account.changeaction") }}</button>
|
||||||
@@ -50,13 +50,74 @@ export default {
|
|||||||
oldpassword: "",
|
oldpassword: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {},
|
methods: {
|
||||||
|
async changeAccount() {
|
||||||
|
try {
|
||||||
|
// Prüfe ob ein neues Passwort eingegeben wurde
|
||||||
|
const hasNewPassword = this.newpassword && this.newpassword.trim() !== '';
|
||||||
|
|
||||||
|
if (hasNewPassword) {
|
||||||
|
// Validiere Passwort-Wiederholung nur wenn ein neues Passwort eingegeben wurde
|
||||||
|
if (this.newpassword !== this.newpasswordretype) {
|
||||||
|
alert('Die Passwörter stimmen nicht überein.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe ob das alte Passwort eingegeben wurde
|
||||||
|
if (!this.oldpassword || this.oldpassword.trim() === '') {
|
||||||
|
alert('Bitte geben Sie Ihr aktuelles Passwort ein, um das Passwort zu ändern.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bereite die Daten für den API-Aufruf vor
|
||||||
|
const accountData = {
|
||||||
|
userId: this.user.id,
|
||||||
|
settings: {
|
||||||
|
username: this.username,
|
||||||
|
email: this.email,
|
||||||
|
showinsearch: this.showInSearch
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Füge Passwort-Daten nur hinzu, wenn ein neues Passwort eingegeben wurde
|
||||||
|
if (hasNewPassword) {
|
||||||
|
accountData.settings.newpassword = this.newpassword;
|
||||||
|
accountData.settings.oldpassword = this.oldpassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API-Aufruf zum Speichern der Account-Einstellungen
|
||||||
|
await apiClient.post('/api/settings/set-account', accountData);
|
||||||
|
|
||||||
|
alert('Account-Einstellungen erfolgreich gespeichert!');
|
||||||
|
|
||||||
|
// Leere die Passwort-Felder nach erfolgreichem Speichern
|
||||||
|
this.newpassword = '';
|
||||||
|
this.newpasswordretype = '';
|
||||||
|
this.oldpassword = '';
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler beim Speichern der Account-Einstellungen:', error);
|
||||||
|
if (error.response && error.response.data && error.response.data.error) {
|
||||||
|
alert('Fehler: ' + error.response.data.error);
|
||||||
|
} else {
|
||||||
|
alert('Ein Fehler ist aufgetreten beim Speichern der Account-Einstellungen.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
const response = await apiClient.post('/api/settings/account', { userId: this.user.id });
|
const response = await apiClient.post('/api/settings/account', { userId: this.user.id });
|
||||||
console.log(response.data);
|
console.log(response.data);
|
||||||
this.username = response.data.username;
|
this.username = response.data.username;
|
||||||
this.showInSearch = response.data.showinsearch;
|
this.showInSearch = response.data.showinsearch;
|
||||||
this.email = response.data.email;
|
this.email = response.data.email;
|
||||||
|
|
||||||
|
// Stelle sicher, dass Passwort-Felder leer sind
|
||||||
|
this.newpassword = '';
|
||||||
|
this.newpasswordretype = '';
|
||||||
|
this.oldpassword = '';
|
||||||
|
|
||||||
console.log(this.showInSearch);
|
console.log(this.showInSearch);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user