Add team roles and content management updates

This commit is contained in:
AzuTear
2026-06-25 19:52:46 +02:00
parent 54293f4c45
commit 693769e5a8
126 changed files with 6966 additions and 738 deletions
@@ -16,6 +16,10 @@ export function useAdminOperationalSettings() {
const demoPasswordSet = ref(false)
const demoManagedByDatabase = ref(false)
const demoPasswordInput = ref('')
const twitchClientSecretSet = ref(false)
const twitchAuthConfigured = ref(false)
const twitchAuthManagedByDatabase = ref(false)
const twitchClientSecretInput = ref('')
const savedOperationalSnapshot = ref('')
const operationalForm = reactive<AdminOperationalSettingsForm>({
@@ -23,6 +27,9 @@ export function useAdminOperationalSettings() {
demoLoginIdentifier: '',
demoLoginTwitchUserId: '',
demoLoginDisplayName: '',
twitchClientId: '',
twitchRedirectUri: '',
twitchScope: '',
maintenanceModeEnabled: false,
maintenanceTitle: fallbackMaintenanceTitle,
maintenanceMessage: fallbackMaintenanceMessage,
@@ -52,6 +59,23 @@ export function useAdminOperationalSettings() {
),
)
const twitchAuthComplete = computed(() =>
Boolean(operationalForm.twitchClientId.trim())
&& (twitchClientSecretSet.value || Boolean(twitchClientSecretInput.value.trim()))
)
const twitchSecretHint = computed(() => {
if (twitchClientSecretInput.value.trim()) {
return 'Dieses neue Secret wird beim Speichern gesetzt.'
}
if (twitchClientSecretSet.value) {
return 'Client Secret ist gesetzt. Leer lassen, wenn es bleiben soll.'
}
return 'Noch kein Client Secret gesetzt. Beim ersten Speichern erforderlich.'
})
const operationalSummary = computed<AdminSettingsStatusSummary[]>(() => [
{
label: 'Demo Login',
@@ -73,6 +97,14 @@ export function useAdminOperationalSettings() {
: 'Öffentliche Seiten werden normal ausgeliefert.',
tone: operationalForm.maintenanceModeEnabled ? 'warning' : 'good',
},
{
label: 'Twitch OAuth',
value: twitchAuthConfigured.value ? 'Konfiguriert' : 'Fehlt',
note: twitchAuthConfigured.value
? twitchAuthManagedByDatabase.value ? 'Quelle: Datenbank' : 'Quelle: App-Konfiguration'
: 'Offizieller Twitch Login ist noch nicht aktiv.',
tone: twitchAuthConfigured.value ? 'good' : 'warning',
},
{
label: 'Passwort',
value: demoPasswordSet.value ? 'Gesetzt' : 'Fehlt',
@@ -91,12 +123,19 @@ export function useAdminOperationalSettings() {
operationalForm.demoLoginIdentifier = response.demoLoginEmail
operationalForm.demoLoginTwitchUserId = response.demoLoginTwitchUserId
operationalForm.demoLoginDisplayName = response.demoLoginDisplayName
operationalForm.twitchClientId = response.twitchClientId
operationalForm.twitchRedirectUri = response.twitchRedirectUri
operationalForm.twitchScope = response.twitchScope
operationalForm.maintenanceModeEnabled = response.maintenanceModeEnabled
operationalForm.maintenanceTitle = response.maintenanceTitle
operationalForm.maintenanceMessage = response.maintenanceMessage
demoPasswordSet.value = response.demoLoginPasswordSet
demoManagedByDatabase.value = response.demoLoginManagedByDatabase
twitchClientSecretSet.value = response.twitchClientSecretSet
twitchAuthConfigured.value = response.twitchAuthConfigured
twitchAuthManagedByDatabase.value = response.twitchAuthManagedByDatabase
demoPasswordInput.value = ''
twitchClientSecretInput.value = ''
rememberSavedOperationalSettings()
}
@@ -106,6 +145,10 @@ export function useAdminOperationalSettings() {
demoLoginIdentifier: operationalForm.demoLoginIdentifier,
demoLoginTwitchUserId: operationalForm.demoLoginTwitchUserId,
demoLoginDisplayName: operationalForm.demoLoginDisplayName,
twitchClientId: operationalForm.twitchClientId,
twitchRedirectUri: operationalForm.twitchRedirectUri,
twitchScope: operationalForm.twitchScope,
twitchClientSecretInput: twitchClientSecretInput.value,
maintenanceModeEnabled: operationalForm.maintenanceModeEnabled,
maintenanceTitle: operationalForm.maintenanceTitle,
maintenanceMessage: operationalForm.maintenanceMessage,
@@ -137,8 +180,8 @@ export function useAdminOperationalSettings() {
}
function validateOperationalSettings() {
if (demoPasswordInput.value.trim() && demoPasswordInput.value.trim().length < 12) {
operationalError.value = 'Das Demo-Passwort muss mindestens 12 Zeichen lang sein.'
if (demoPasswordInput.value.trim() && demoPasswordInput.value.trim().length < 10) {
operationalError.value = 'Das Demo-Passwort muss mindestens 10 Zeichen lang sein.'
return false
}
@@ -147,6 +190,24 @@ export function useAdminOperationalSettings() {
return false
}
const hasAnyTwitchAuthInput = Boolean(
operationalForm.twitchClientId.trim()
|| operationalForm.twitchRedirectUri.trim()
|| operationalForm.twitchScope.trim()
|| twitchClientSecretInput.value.trim()
|| twitchClientSecretSet.value,
)
if (hasAnyTwitchAuthInput && !operationalForm.twitchClientId.trim()) {
operationalError.value = 'Twitch OAuth braucht eine Client-ID.'
return false
}
if (operationalForm.twitchClientId.trim() && !twitchAuthComplete.value) {
operationalError.value = 'Twitch OAuth braucht beim ersten Speichern ein Client Secret.'
return false
}
return true
}
@@ -164,11 +225,14 @@ export function useAdminOperationalSettings() {
...operationalForm,
demoLoginEmail: operationalForm.demoLoginIdentifier,
demoLoginPassword: demoPasswordInput.value.trim() || undefined,
twitchClientSecret: twitchClientSecretInput.value.trim() || undefined,
})
demoPasswordSet.value = result.demoLoginPasswordSet
demoManagedByDatabase.value = true
twitchClientSecretSet.value = result.twitchClientSecretSet
demoPasswordInput.value = ''
twitchClientSecretInput.value = ''
await loadOperationalSettings({ silent: true })
clearSiteStatusCache()
operationalSuccess.value = 'Demo-Zugang und Wartungsmodus wurden gespeichert.'
@@ -187,6 +251,10 @@ export function useAdminOperationalSettings() {
operationalForm.demoLoginIdentifier,
operationalForm.demoLoginTwitchUserId,
operationalForm.demoLoginDisplayName,
operationalForm.twitchClientId,
operationalForm.twitchRedirectUri,
operationalForm.twitchScope,
twitchClientSecretInput.value,
operationalForm.maintenanceModeEnabled,
operationalForm.maintenanceTitle,
operationalForm.maintenanceMessage,
@@ -210,8 +278,14 @@ export function useAdminOperationalSettings() {
demoPasswordSet,
demoManagedByDatabase,
demoPasswordInput,
twitchClientSecretSet,
twitchAuthConfigured,
twitchAuthManagedByDatabase,
twitchClientSecretInput,
demoPasswordHint,
twitchSecretHint,
demoCredentialsComplete,
twitchAuthComplete,
operationalSummary,
hasUnsavedOperationalChanges,
loadOperationalSettings,