Enhance API key handling in settings and vocab services: Update key retrieval logic to improve validation and status reporting. Introduce new localization strings for key status messages in English, German, and Spanish. Update LanguageAssistantView to display key status dynamically, enhancing user feedback on API key management.
This commit is contained in:
@@ -428,14 +428,16 @@ class SettingsService extends BaseService{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasKey = Boolean(keyRow && keyRow.value && String(keyRow.value).trim());
|
const hasStoredKey = Boolean(keyRow && keyRow.getDataValue('value') && String(keyRow.getDataValue('value')).trim());
|
||||||
|
const hasReadableKey = Boolean(keyRow && keyRow.value && String(keyRow.value).trim());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled: parsed.enabled !== false,
|
enabled: parsed.enabled !== false,
|
||||||
baseUrl: parsed.baseUrl || '',
|
baseUrl: parsed.baseUrl || '',
|
||||||
model: parsed.model || 'gpt-4o-mini',
|
model: parsed.model || 'gpt-4o-mini',
|
||||||
hasKey,
|
hasKey: hasStoredKey,
|
||||||
keyLast4: parsed.keyLast4 || null
|
keyLast4: parsed.keyLast4 || null,
|
||||||
|
keyStatus: hasStoredKey ? (hasReadableKey ? 'stored' : 'invalid') : 'missing'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import UserParam from '../models/community/user_param.js';
|
|||||||
import { sequelize } from '../utils/sequelize.js';
|
import { sequelize } from '../utils/sequelize.js';
|
||||||
import { notifyUser } from '../utils/socket.js';
|
import { notifyUser } from '../utils/socket.js';
|
||||||
import { Op } from 'sequelize';
|
import { Op } from 'sequelize';
|
||||||
import { decrypt } from '../utils/encryption.js';
|
|
||||||
|
|
||||||
export default class VocabService {
|
export default class VocabService {
|
||||||
async _getUserByHashedId(hashedUserId) {
|
async _getUserByHashedId(hashedUserId) {
|
||||||
@@ -56,7 +55,7 @@ export default class VocabService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const decryptedKey = keyRow?.value ? decrypt(keyRow.value) : null;
|
const decryptedKey = keyRow?.value ? String(keyRow.value).trim() : null;
|
||||||
const hasKey = Boolean(decryptedKey && String(decryptedKey).trim());
|
const hasKey = Boolean(decryptedKey && String(decryptedKey).trim());
|
||||||
const enabled = parsed.enabled !== false;
|
const enabled = parsed.enabled !== false;
|
||||||
const baseUrl = String(parsed.baseUrl || '').trim();
|
const baseUrl = String(parsed.baseUrl || '').trim();
|
||||||
|
|||||||
@@ -169,7 +169,10 @@
|
|||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"saved": "Einstellungen gespeichert.",
|
"saved": "Einstellungen gespeichert.",
|
||||||
"saveError": "Speichern fehlgeschlagen.",
|
"saveError": "Speichern fehlgeschlagen.",
|
||||||
"confirmClear": "API-Schlüssel wirklich löschen?"
|
"confirmClear": "API-Schlüssel wirklich löschen?",
|
||||||
|
"keyStatusStored": "API-Schlüssel gespeichert.",
|
||||||
|
"keyStatusInvalid": "Ein gespeicherter API-Schlüssel ist vorhanden, kann aber nicht gelesen werden. Bitte neu speichern.",
|
||||||
|
"keyStatusMissing": "Derzeit ist kein API-Schlüssel gespeichert."
|
||||||
},
|
},
|
||||||
"interests": {
|
"interests": {
|
||||||
"title": "Interessen",
|
"title": "Interessen",
|
||||||
|
|||||||
@@ -169,7 +169,10 @@
|
|||||||
"save": "Save",
|
"save": "Save",
|
||||||
"saved": "Settings saved.",
|
"saved": "Settings saved.",
|
||||||
"saveError": "Could not save.",
|
"saveError": "Could not save.",
|
||||||
"confirmClear": "Really delete the API key?"
|
"confirmClear": "Really delete the API key?",
|
||||||
|
"keyStatusStored": "API key stored.",
|
||||||
|
"keyStatusInvalid": "A stored API key exists, but it cannot be read. Please save it again.",
|
||||||
|
"keyStatusMissing": "No API key is currently stored."
|
||||||
},
|
},
|
||||||
"interests": {
|
"interests": {
|
||||||
"title": "Interests",
|
"title": "Interests",
|
||||||
|
|||||||
@@ -169,7 +169,10 @@
|
|||||||
"save": "Guardar",
|
"save": "Guardar",
|
||||||
"saved": "Ajustes guardados.",
|
"saved": "Ajustes guardados.",
|
||||||
"saveError": "No se pudo guardar.",
|
"saveError": "No se pudo guardar.",
|
||||||
"confirmClear": "¿Eliminar realmente la clave API?"
|
"confirmClear": "¿Eliminar realmente la clave API?",
|
||||||
|
"keyStatusStored": "Clave API guardada.",
|
||||||
|
"keyStatusInvalid": "Existe una clave API guardada, pero no se puede leer. Guárdala de nuevo.",
|
||||||
|
"keyStatusMissing": "Actualmente no hay ninguna clave API guardada."
|
||||||
},
|
},
|
||||||
"interests": {
|
"interests": {
|
||||||
"title": "Intereses",
|
"title": "Intereses",
|
||||||
|
|||||||
@@ -51,6 +51,9 @@
|
|||||||
:placeholder="apiKeyPlaceholder"
|
:placeholder="apiKeyPlaceholder"
|
||||||
/>
|
/>
|
||||||
<span class="language-assistant-settings__hint">{{ $t('settings.languageAssistant.apiKeyHint') }}</span>
|
<span class="language-assistant-settings__hint">{{ $t('settings.languageAssistant.apiKeyHint') }}</span>
|
||||||
|
<span class="language-assistant-settings__hint" :class="`language-assistant-settings__key-status language-assistant-settings__key-status--${keyStatus}`">
|
||||||
|
{{ keyStatusLabel }}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -84,6 +87,7 @@ export default {
|
|||||||
},
|
},
|
||||||
hasKey: false,
|
hasKey: false,
|
||||||
keyLast4: null,
|
keyLast4: null,
|
||||||
|
keyStatus: 'missing',
|
||||||
saving: false,
|
saving: false,
|
||||||
loadError: null
|
loadError: null
|
||||||
};
|
};
|
||||||
@@ -100,6 +104,14 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.$t('settings.languageAssistant.apiKeyPlaceholderNew');
|
return this.$t('settings.languageAssistant.apiKeyPlaceholderNew');
|
||||||
|
},
|
||||||
|
keyStatusLabel() {
|
||||||
|
const statusKey = {
|
||||||
|
stored: 'settings.languageAssistant.keyStatusStored',
|
||||||
|
invalid: 'settings.languageAssistant.keyStatusInvalid',
|
||||||
|
missing: 'settings.languageAssistant.keyStatusMissing'
|
||||||
|
}[this.keyStatus] || 'settings.languageAssistant.keyStatusMissing';
|
||||||
|
return this.$t(statusKey);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
@@ -115,6 +127,7 @@ export default {
|
|||||||
this.form.model = data.model || 'gpt-4o-mini';
|
this.form.model = data.model || 'gpt-4o-mini';
|
||||||
this.hasKey = data.hasKey;
|
this.hasKey = data.hasKey;
|
||||||
this.keyLast4 = data.keyLast4;
|
this.keyLast4 = data.keyLast4;
|
||||||
|
this.keyStatus = data.keyStatus || (data.hasKey ? 'stored' : 'missing');
|
||||||
this.form.apiKey = '';
|
this.form.apiKey = '';
|
||||||
this.form.clearKey = false;
|
this.form.clearKey = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -208,6 +221,18 @@ export default {
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
.language-assistant-settings__key-status {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.language-assistant-settings__key-status--stored {
|
||||||
|
color: #2e7d32;
|
||||||
|
}
|
||||||
|
.language-assistant-settings__key-status--invalid {
|
||||||
|
color: #c62828;
|
||||||
|
}
|
||||||
|
.language-assistant-settings__key-status--missing {
|
||||||
|
color: #8a6d3b;
|
||||||
|
}
|
||||||
.language-assistant-settings__toggle {
|
.language-assistant-settings__toggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user