Implement login functionality in ChatInput and chat store. Update input handling to support username and password prompts, enhance message sending logic, and ensure proper command handling during login. Adjust broadcast logic to manage login states and provide appropriate feedback to users.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
<div class="chat-input-container">
|
<div class="chat-input-container">
|
||||||
<input
|
<input
|
||||||
v-model="message"
|
v-model="message"
|
||||||
type="text"
|
:type="inputType"
|
||||||
:placeholder="inputPlaceholder"
|
:placeholder="inputPlaceholder"
|
||||||
@keyup.enter="sendMessage"
|
@keyup.enter="sendMessage"
|
||||||
/>
|
/>
|
||||||
@@ -47,11 +47,22 @@ const chatStore = useChatStore();
|
|||||||
const message = ref('');
|
const message = ref('');
|
||||||
const showSmileys = ref(false);
|
const showSmileys = ref(false);
|
||||||
const hasConversation = computed(() => !!chatStore.currentConversation);
|
const hasConversation = computed(() => !!chatStore.currentConversation);
|
||||||
const inputPlaceholder = computed(() =>
|
const isAwaitingUsername = computed(() => chatStore.awaitingLoginUsername);
|
||||||
hasConversation.value
|
const isAwaitingPassword = computed(() => chatStore.awaitingLoginPassword);
|
||||||
|
|
||||||
|
const inputPlaceholder = computed(() => {
|
||||||
|
if (isAwaitingUsername.value) {
|
||||||
|
return 'Admin-Username eingeben';
|
||||||
|
}
|
||||||
|
if (isAwaitingPassword.value) {
|
||||||
|
return 'Admin-Passwort eingeben';
|
||||||
|
}
|
||||||
|
return hasConversation.value
|
||||||
? 'Nachricht senden oder /Befehl eingeben'
|
? 'Nachricht senden oder /Befehl eingeben'
|
||||||
: 'Nur /Befehle eingeben (z.B. /login, /stat help)'
|
: 'Nur /Befehle eingeben (z.B. /login, /stat help)';
|
||||||
);
|
});
|
||||||
|
|
||||||
|
const inputType = computed(() => (isAwaitingPassword.value ? 'password' : 'text'));
|
||||||
|
|
||||||
// Smiley-Definitionen (wie im Original)
|
// Smiley-Definitionen (wie im Original)
|
||||||
const smileys = {
|
const smileys = {
|
||||||
@@ -81,7 +92,10 @@ function sendMessage() {
|
|||||||
const trimmed = message.value.trim();
|
const trimmed = message.value.trim();
|
||||||
if (!trimmed) return;
|
if (!trimmed) return;
|
||||||
const isCommand = trimmed.startsWith('/');
|
const isCommand = trimmed.startsWith('/');
|
||||||
if (!isCommand && !hasConversation.value) {
|
const canSendPlain =
|
||||||
|
hasConversation.value || isAwaitingUsername.value || isAwaitingPassword.value;
|
||||||
|
|
||||||
|
if (!isCommand && !canSendPlain) {
|
||||||
chatStore.errorMessage = 'Ohne aktive Konversation sind nur /Befehle erlaubt.';
|
chatStore.errorMessage = 'Ohne aktive Konversation sind nur /Befehle erlaubt.';
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (chatStore.errorMessage === 'Ohne aktive Konversation sind nur /Befehle erlaubt.') {
|
if (chatStore.errorMessage === 'Ohne aktive Konversation sind nur /Befehle erlaubt.') {
|
||||||
@@ -90,8 +104,9 @@ function sendMessage() {
|
|||||||
}, 4000);
|
}, 4000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chatStore.sendMessage(chatStore.currentConversation, trimmed);
|
const suppressLocal = isCommand || isAwaitingUsername.value || isAwaitingPassword.value;
|
||||||
|
chatStore.sendMessage(chatStore.currentConversation, trimmed, { suppressLocal });
|
||||||
message.value = '';
|
message.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
const unreadChatsCount = ref(0);
|
const unreadChatsCount = ref(0);
|
||||||
const errorMessage = ref(null);
|
const errorMessage = ref(null);
|
||||||
const remainingSecondsToTimeout = ref(1800);
|
const remainingSecondsToTimeout = ref(1800);
|
||||||
|
const awaitingLoginUsername = ref(false);
|
||||||
|
const awaitingLoginPassword = ref(false);
|
||||||
const searchData = ref({
|
const searchData = ref({
|
||||||
nameIncludes: '',
|
nameIncludes: '',
|
||||||
minAge: null,
|
minAge: null,
|
||||||
@@ -293,7 +295,20 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
break;
|
break;
|
||||||
case 'commandResult': {
|
case 'commandResult': {
|
||||||
const lines = Array.isArray(data.lines) ? data.lines : [];
|
const lines = Array.isArray(data.lines) ? data.lines : [];
|
||||||
// Command output is global and must not pollute per-conversation history.
|
const kind = data.kind || 'info';
|
||||||
|
|
||||||
|
if (kind === 'loginPromptUsername') {
|
||||||
|
awaitingLoginUsername.value = true;
|
||||||
|
awaitingLoginPassword.value = false;
|
||||||
|
} else if (kind === 'loginPromptPassword') {
|
||||||
|
awaitingLoginUsername.value = false;
|
||||||
|
awaitingLoginPassword.value = true;
|
||||||
|
} else if (kind === 'loginSuccess' || kind === 'loginError' || kind === 'loginAbort' || kind === 'loginLogout') {
|
||||||
|
awaitingLoginUsername.value = false;
|
||||||
|
awaitingLoginPassword.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command-Ausgaben immer global anzeigen, nicht im Chatverlauf.
|
||||||
errorMessage.value = lines.join(' | ');
|
errorMessage.value = lines.join(' | ');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
errorMessage.value = null;
|
errorMessage.value = null;
|
||||||
@@ -360,7 +375,7 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendMessage(toUserName, message) {
|
function sendMessage(toUserName, message, options = {}) {
|
||||||
if (!socket.value || !socket.value.connected) {
|
if (!socket.value || !socket.value.connected) {
|
||||||
console.error('Socket.IO nicht verbunden');
|
console.error('Socket.IO nicht verbunden');
|
||||||
return;
|
return;
|
||||||
@@ -375,8 +390,10 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
messageId
|
messageId
|
||||||
});
|
});
|
||||||
|
|
||||||
// Lokal hinzufügen (außer bei Commands, die serverseitig beantwortet werden)
|
const suppressLocal = !!options.suppressLocal || isCommand || awaitingLoginUsername.value || awaitingLoginPassword.value;
|
||||||
if (!isCommand) {
|
|
||||||
|
// Lokal hinzufügen (außer bei Commands oder sensiblen Eingaben wie Login)
|
||||||
|
if (!isCommand && !suppressLocal) {
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
from: userName.value,
|
from: userName.value,
|
||||||
message: trimmed,
|
message: trimmed,
|
||||||
@@ -673,6 +690,8 @@ export const useChatStore = defineStore('chat', () => {
|
|||||||
remainingSecondsToTimeout,
|
remainingSecondsToTimeout,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
searchData,
|
searchData,
|
||||||
|
awaitingLoginUsername,
|
||||||
|
awaitingLoginPassword,
|
||||||
// Computed
|
// Computed
|
||||||
currentConversationWith,
|
currentConversationWith,
|
||||||
// Actions
|
// Actions
|
||||||
|
|||||||
@@ -320,9 +320,9 @@ export function setupBroadcast(io, __dirname) {
|
|||||||
downloadCountries();
|
downloadCountries();
|
||||||
setInterval(downloadCountries, 24 * 60 * 60 * 1000); // Täglich aktualisieren
|
setInterval(downloadCountries, 24 * 60 * 60 * 1000); // Täglich aktualisieren
|
||||||
|
|
||||||
function sendCommandResult(socket, lines) {
|
function sendCommandResult(socket, lines, kind = 'info') {
|
||||||
const payload = Array.isArray(lines) ? lines : [String(lines)];
|
const payload = Array.isArray(lines) ? lines : [String(lines)];
|
||||||
socket.emit('commandResult', { lines: payload });
|
socket.emit('commandResult', { lines: payload, kind });
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasRight(client, right) {
|
function hasRight(client, right) {
|
||||||
@@ -536,15 +536,21 @@ export function setupBroadcast(io, __dirname) {
|
|||||||
function executeCommand(socket, client, rawInput) {
|
function executeCommand(socket, client, rawInput) {
|
||||||
const input = rawInput.trim();
|
const input = rawInput.trim();
|
||||||
|
|
||||||
if (client.pendingChatLogin) {
|
if (!input.startsWith('/')) return false;
|
||||||
|
|
||||||
|
const parts = input.split(/\s+/);
|
||||||
|
const command = parts[0].toLowerCase();
|
||||||
|
|
||||||
|
// Laufender Login-Dialog: Nur Eingaben ohne Slash als Username/Passwort behandeln.
|
||||||
|
if (client.pendingChatLogin && !input.startsWith('/')) {
|
||||||
if (client.pendingChatLogin.step === 'username') {
|
if (client.pendingChatLogin.step === 'username') {
|
||||||
const enteredUser = input;
|
const enteredUser = input;
|
||||||
if (!enteredUser) {
|
if (!enteredUser) {
|
||||||
sendCommandResult(socket, 'Username darf nicht leer sein. Bitte Username eingeben:');
|
sendCommandResult(socket, 'Username darf nicht leer sein. Bitte Username eingeben:', 'loginPromptUsername');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
client.pendingChatLogin = { step: 'password', username: enteredUser };
|
client.pendingChatLogin = { step: 'password', username: enteredUser };
|
||||||
sendCommandResult(socket, 'Passwort eingeben:');
|
sendCommandResult(socket, 'Passwort eingeben:', 'loginPromptPassword');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,32 +559,33 @@ export function setupBroadcast(io, __dirname) {
|
|||||||
const auth = verifyChatUser(username, input);
|
const auth = verifyChatUser(username, input);
|
||||||
client.pendingChatLogin = null;
|
client.pendingChatLogin = null;
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
sendCommandResult(socket, 'Login fehlgeschlagen. Benutzername oder Passwort falsch.');
|
sendCommandResult(socket, 'Login fehlgeschlagen. Benutzername oder Passwort falsch.', 'loginError');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.chatAuth = auth;
|
client.chatAuth = auth;
|
||||||
sendCommandResult(
|
sendCommandResult(
|
||||||
socket,
|
socket,
|
||||||
`Login erfolgreich als ${auth.username}. Rechte: ${Array.from(auth.rights).join(', ') || 'keine'}`
|
`Login erfolgreich als ${auth.username}. Rechte: ${Array.from(auth.rights).join(', ') || 'keine'}`,
|
||||||
|
'loginSuccess'
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} else if (client.pendingChatLogin && input.startsWith('/')) {
|
||||||
|
// Ein neuer /Befehl bricht den Login-Vorgang ab.
|
||||||
|
client.pendingChatLogin = null;
|
||||||
|
sendCommandResult(socket, 'Login-Vorgang abgebrochen.', 'loginAbort');
|
||||||
|
// und läuft unten als normaler Befehl weiter
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!input.startsWith('/')) return false;
|
|
||||||
|
|
||||||
const parts = input.split(/\s+/);
|
|
||||||
const command = parts[0].toLowerCase();
|
|
||||||
|
|
||||||
if (command === '/login') {
|
if (command === '/login') {
|
||||||
const username = (parts[1] || '').trim();
|
const username = (parts[1] || '').trim();
|
||||||
if (username) {
|
if (username) {
|
||||||
client.pendingChatLogin = { step: 'password', username };
|
client.pendingChatLogin = { step: 'password', username };
|
||||||
sendCommandResult(socket, 'Passwort eingeben:');
|
sendCommandResult(socket, 'Passwort eingeben:', 'loginPromptPassword');
|
||||||
} else {
|
} else {
|
||||||
client.pendingChatLogin = { step: 'username', username: '' };
|
client.pendingChatLogin = { step: 'username', username: '' };
|
||||||
sendCommandResult(socket, 'Username eingeben:');
|
sendCommandResult(socket, 'Username eingeben:', 'loginPromptUsername');
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -591,20 +598,35 @@ export function setupBroadcast(io, __dirname) {
|
|||||||
socket,
|
socket,
|
||||||
wasLoggedIn
|
wasLoggedIn
|
||||||
? 'Admin/Command-Login wurde abgemeldet.'
|
? 'Admin/Command-Login wurde abgemeldet.'
|
||||||
: 'Es war kein Admin/Command-Login aktiv.'
|
: 'Es war kein Admin/Command-Login aktiv.',
|
||||||
|
'loginLogout'
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command === '/whoami-rights') {
|
if (command === '/whoami-rights') {
|
||||||
if (!client.chatAuth) {
|
if (!client.chatAuth) {
|
||||||
sendCommandResult(socket, 'Nicht per Command-Login angemeldet.');
|
sendCommandResult(socket, 'Nicht per Command-Login angemeldet.', 'whoami');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
sendCommandResult(socket, [
|
sendCommandResult(socket, [
|
||||||
`Angemeldet als: ${client.chatAuth.username}`,
|
`Angemeldet als: ${client.chatAuth.username}`,
|
||||||
`Rechte: ${Array.from(client.chatAuth.rights).join(', ') || 'keine'}`
|
`Rechte: ${Array.from(client.chatAuth.rights).join(', ') || 'keine'}`
|
||||||
]);
|
], 'whoami');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command === '/help' || command === '/?') {
|
||||||
|
sendCommandResult(socket, [
|
||||||
|
'Verfügbare Befehle:',
|
||||||
|
'/login [username] - Admin-/Command-Login starten',
|
||||||
|
'/logout-admin - Admin-/Command-Login beenden',
|
||||||
|
'/whoami-rights - Aktuelle Admin-Rechte anzeigen',
|
||||||
|
'/stat help - Hilfe zu Statistikbefehlen',
|
||||||
|
'/all-stats - Zusammenfassung wichtiger Statistiken',
|
||||||
|
'/kick <username> - Benutzer aus dem Chat werfen',
|
||||||
|
'/help oder /? - Diese Hilfe'
|
||||||
|
], 'help');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +645,7 @@ export function setupBroadcast(io, __dirname) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendCommandResult(socket, `Unbekannter Befehl: ${command}`);
|
sendCommandResult(socket, `Unbekannter Befehl: ${command}`, 'unknown');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user