All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 20s
341 lines
13 KiB
JavaScript
341 lines
13 KiB
JavaScript
$(document).ready(function() {
|
|
var users = [];
|
|
var folders = [];
|
|
var assignedFolders = [];
|
|
var selectedUserId = "";
|
|
|
|
$.get('/api/auth/me')
|
|
.done(function(user) {
|
|
if(user.role !== 'admin') {
|
|
alert('Kein Zugriff!');
|
|
window.location.href = '/';
|
|
return;
|
|
}
|
|
refreshDashboard();
|
|
$('body').removeClass('is-preload');
|
|
})
|
|
.fail(function() { window.location.href = '/'; });
|
|
|
|
$('#logout-btn').click(function(e) {
|
|
e.preventDefault();
|
|
$.post('/api/auth/logout').done(function() { window.location.href = '/'; });
|
|
});
|
|
|
|
function refreshDashboard() {
|
|
$.when(loadUsers(), loadFolders()).done(function() {
|
|
renderUsers();
|
|
renderUserSelect();
|
|
renderFolders();
|
|
if (selectedUserId) {
|
|
loadAssignments(selectedUserId);
|
|
}
|
|
});
|
|
}
|
|
|
|
function loadUsers() {
|
|
return $.get('/api/admin/users').done(function(data) {
|
|
users = data || [];
|
|
}).fail(function(xhr) {
|
|
$('#users-tbody').html(
|
|
'<tr><td colspan="6" style="color:#e44d26;">Fehler beim Laden: HTTP ' +
|
|
xhr.status + '</td></tr>'
|
|
);
|
|
});
|
|
}
|
|
|
|
function loadFolders() {
|
|
return $.get('/api/admin/folders').done(function(data) {
|
|
folders = data || [];
|
|
}).fail(function() {
|
|
$('#folders-overview').html('<p style="color:#e44d26;">Ordner konnten nicht geladen werden.</p>');
|
|
});
|
|
}
|
|
|
|
function getRoleBadge(role, expired) {
|
|
if (expired) return $('<span></span>').addClass('badge badge-expired').text('abgelaufen');
|
|
return $('<span></span>').addClass('badge badge-' + (role || 'client')).text(role || 'client');
|
|
}
|
|
|
|
function renderUsers() {
|
|
var $tbody = $('#users-tbody').empty();
|
|
if (!users.length) {
|
|
$tbody.html('<tr><td colspan="6" style="text-align:center;">Keine Nutzer gefunden</td></tr>');
|
|
return;
|
|
}
|
|
|
|
users.forEach(function(u) {
|
|
var role = u.role || 'client';
|
|
var created = u.created_at ? new Date(u.created_at).toLocaleDateString('de-DE') : '-';
|
|
var status = created;
|
|
if (role === 'client' && u.expires_at) {
|
|
status = (u.expired ? 'Abgelaufen: ' : 'Bis: ') +
|
|
new Date(u.expires_at).toLocaleDateString('de-DE');
|
|
}
|
|
|
|
var $row = $('<tr></tr>');
|
|
var $userCell = $('<td></td>').text(u.username + ' ').append(getRoleBadge(role, u.expired));
|
|
var $foldersCell = $('<td></td>');
|
|
if (u.folders && u.folders.length) {
|
|
u.folders.forEach(function(folder) {
|
|
$('<span></span>').addClass('badge folder-badge').text(folder).appendTo($foldersCell);
|
|
});
|
|
} else {
|
|
$foldersCell.append($('<span></span>').addClass('muted').text('Keine privaten Ordner'));
|
|
}
|
|
|
|
var $actions = $('<td></td>');
|
|
$('<button type="button" class="btn-small user-access">Zugriff</button>')
|
|
.data('user-id', u.id)
|
|
.appendTo($actions);
|
|
$('<button type="button" class="btn-small user-password">PW</button>')
|
|
.data('user-id', u.id)
|
|
.data('username', u.username)
|
|
.appendTo($actions);
|
|
$('<button type="button" class="btn-small btn-danger user-delete">Loeschen</button>')
|
|
.data('user-id', u.id)
|
|
.data('username', u.username)
|
|
.appendTo($actions);
|
|
|
|
$row.append($('<td></td>').text(u.id));
|
|
$row.append($userCell);
|
|
$row.append($('<td></td>').text(role));
|
|
$row.append($('<td></td>').text(status));
|
|
$row.append($foldersCell);
|
|
$row.append($actions);
|
|
$tbody.append($row);
|
|
});
|
|
}
|
|
|
|
function renderUserSelect() {
|
|
var $select = $('#user-select').html('<option value="">Nutzer waehlen...</option>');
|
|
users.forEach(function(u) {
|
|
if ((u.role || 'client') === 'admin') return;
|
|
$('<option></option>')
|
|
.val(u.id)
|
|
.text(u.username + ' (' + (u.role || 'client') + ')')
|
|
.appendTo($select);
|
|
});
|
|
if (selectedUserId) $select.val(selectedUserId);
|
|
}
|
|
|
|
function renderFolders() {
|
|
var $wrap = $('#folders-overview').empty();
|
|
if (!folders.length) {
|
|
$wrap.html('<p class="muted">Keine Unterordner im Bilderpfad gefunden.</p>');
|
|
return;
|
|
}
|
|
|
|
folders.forEach(function(folder) {
|
|
var $card = $('<div></div>').addClass('folder-card');
|
|
$('<h3></h3>').text(folder.name).appendTo($card);
|
|
|
|
var $meta = $('<div></div>').addClass('folder-meta').appendTo($card);
|
|
$('<span></span>').addClass('folder-pill').text((folder.image_count || 0) + ' Bilder').appendTo($meta);
|
|
$('<span></span>').addClass('folder-pill').text('privat').appendTo($meta);
|
|
$('<span></span>').addClass('folder-pill').text((folder.assigned_users || []).length + ' Freigaben').appendTo($meta);
|
|
|
|
var $assigned = $('<div></div>').appendTo($card);
|
|
if (folder.assigned_users && folder.assigned_users.length) {
|
|
folder.assigned_users.forEach(function(user) {
|
|
$('<span></span>').addClass('badge folder-badge').text(user.username).appendTo($assigned);
|
|
});
|
|
} else {
|
|
$assigned.append($('<span></span>').addClass('muted').text('Noch niemandem freigegeben'));
|
|
}
|
|
|
|
var $actions = $('<div></div>').addClass('folder-actions').appendTo($card);
|
|
$('<button type="button" class="btn-small folder-preview-btn">Ansehen</button>')
|
|
.data('folder', folder.name)
|
|
.appendTo($actions);
|
|
$('<button type="button" class="btn-small folder-assign-btn">Freigaben</button>')
|
|
.data('folder', folder.name)
|
|
.appendTo($actions);
|
|
|
|
$wrap.append($card);
|
|
});
|
|
}
|
|
|
|
function renderAccessList() {
|
|
var $list = $('#folder-access-list').empty();
|
|
if (!folders.length) {
|
|
$list.html('<p class="muted">Keine Unterordner gefunden.</p>');
|
|
return;
|
|
}
|
|
|
|
folders.forEach(function(folder) {
|
|
var checked = assignedFolders.indexOf(folder.name) !== -1;
|
|
var $label = $('<label></label>').addClass('access-item');
|
|
$('<input type="checkbox" />')
|
|
.val(folder.name)
|
|
.prop('checked', checked)
|
|
.appendTo($label);
|
|
$('<span></span>').text(folder.name + ' (' + (folder.image_count || 0) + ')').appendTo($label);
|
|
$list.append($label);
|
|
});
|
|
}
|
|
|
|
function loadAssignments(userId) {
|
|
selectedUserId = String(userId || "");
|
|
if (!selectedUserId) {
|
|
$('#folder-table-wrap').hide();
|
|
assignedFolders = [];
|
|
return;
|
|
}
|
|
|
|
$('#user-select').val(selectedUserId);
|
|
$.get('/api/admin/assign?user_id=' + encodeURIComponent(selectedUserId)).done(function(data) {
|
|
assignedFolders = data || [];
|
|
renderAccessList();
|
|
$('#folder-table-wrap').show();
|
|
}).fail(function() {
|
|
assignedFolders = [];
|
|
renderAccessList();
|
|
$('#folder-table-wrap').show();
|
|
});
|
|
}
|
|
|
|
function saveAssignments() {
|
|
if (!selectedUserId) return;
|
|
assignedFolders = [];
|
|
$('#folder-access-list input:checked').each(function() {
|
|
assignedFolders.push($(this).val());
|
|
});
|
|
$.ajax({
|
|
url: '/api/admin/assign',
|
|
type: 'POST',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify({ user_id: selectedUserId, folders: assignedFolders })
|
|
}).done(function() {
|
|
$('#assign-status').text('Gespeichert').show().delay(1200).fadeOut();
|
|
refreshDashboard();
|
|
}).fail(function(xhr) {
|
|
alert((xhr.responseJSON && xhr.responseJSON.error) || 'Speichern fehlgeschlagen');
|
|
});
|
|
}
|
|
|
|
$('#users-tbody').on('click', '.user-access', function() {
|
|
loadAssignments($(this).data('user-id'));
|
|
document.getElementById('user-select').scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
});
|
|
|
|
$('#user-select').change(function() {
|
|
loadAssignments($(this).val());
|
|
});
|
|
|
|
$('#folder-access-list').on('change', 'input[type="checkbox"]', saveAssignments);
|
|
|
|
$('#folders-overview').on('click', '.folder-assign-btn', function() {
|
|
var folder = $(this).data('folder');
|
|
if (!selectedUserId) {
|
|
alert('Bitte zuerst einen Nutzer in der Ordner-Zuweisung waehlen.');
|
|
return;
|
|
}
|
|
var $checkbox = $('#folder-access-list input').filter(function() {
|
|
return $(this).val() === folder;
|
|
});
|
|
if ($checkbox.length) {
|
|
$checkbox.prop('checked', !$checkbox.prop('checked')).trigger('change');
|
|
}
|
|
});
|
|
|
|
$('#folders-overview').on('click', '.folder-preview-btn', function() {
|
|
var folder = $(this).data('folder');
|
|
$('#folder-preview-title').text('Ordnerinhalt: ' + folder);
|
|
$('#folder-preview-note').text('Lade Bilder...');
|
|
$('#folder-preview').empty();
|
|
$.get('/api/admin/folders/' + encodeURIComponent(folder) + '/images').done(function(images) {
|
|
$('#folder-preview-note').text((images || []).length + ' Bilder im Ordner');
|
|
var $preview = $('#folder-preview').empty();
|
|
if (!images || !images.length) {
|
|
$preview.html('<p class="muted">Dieser Ordner ist leer.</p>');
|
|
return;
|
|
}
|
|
images.forEach(function(img) {
|
|
var $link = $('<a></a>').attr({ href: img.full_url, target: '_blank', rel: 'noopener' });
|
|
$('<img />').attr({ src: img.thumb_url, alt: img.name, title: img.name }).appendTo($link);
|
|
$preview.append($link);
|
|
});
|
|
}).fail(function(xhr) {
|
|
$('#folder-preview-note').text((xhr.responseJSON && xhr.responseJSON.error) || 'Ordner konnte nicht geladen werden.');
|
|
});
|
|
});
|
|
|
|
$('#create-user-form').submit(function(e) {
|
|
e.preventDefault();
|
|
var username = $('#new-username').val().trim();
|
|
var password = $('#new-password').val();
|
|
var role = $('#new-role').val();
|
|
if (!username || !password) {
|
|
alert('Bitte Username und Passwort eingeben.');
|
|
return;
|
|
}
|
|
$.ajax({
|
|
url: '/api/admin/users',
|
|
type: 'POST',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify({ username: username, password: password, role: role })
|
|
}).done(function() {
|
|
$('#new-username, #new-password').val('');
|
|
refreshDashboard();
|
|
}).fail(function(xhr) {
|
|
var msg = (xhr.responseJSON && xhr.responseJSON.error) || 'Unbekannter Fehler';
|
|
alert('Fehler beim Erstellen: ' + msg);
|
|
});
|
|
});
|
|
|
|
$('#users-tbody').on('click', '.user-delete', function() {
|
|
var id = $(this).data('user-id');
|
|
var name = $(this).data('username');
|
|
if (!confirm('Nutzer "' + name + '" wirklich loeschen?')) return;
|
|
$.ajax({ url: '/api/admin/users/' + id, type: 'DELETE' })
|
|
.done(refreshDashboard)
|
|
.fail(function(err) { alert(err.responseJSON ? err.responseJSON.error : 'Fehler'); });
|
|
});
|
|
|
|
$('#users-tbody').on('click', '.user-password', function() {
|
|
var id = $(this).data('user-id');
|
|
var name = $(this).data('username');
|
|
var newPw = prompt('Neues Passwort fuer "' + name + '":');
|
|
if (!newPw) return;
|
|
$.ajax({
|
|
url: '/api/admin/users/' + id + '/password',
|
|
type: 'PUT',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify({ new_password: newPw })
|
|
}).done(function() {
|
|
alert('Passwort geaendert.');
|
|
}).fail(function(err) {
|
|
alert(err.responseJSON ? err.responseJSON.error : 'Fehler');
|
|
});
|
|
});
|
|
|
|
$('#sync-site').click(function() {
|
|
$('#sync-status').text('Sync laeuft...');
|
|
$('#sync-site').prop('disabled', true);
|
|
$.post('/api/admin/sync')
|
|
.done(function(resp) {
|
|
$('#sync-status').text(resp.message || 'Sync gestartet.');
|
|
})
|
|
.fail(function(xhr) {
|
|
var msg = (xhr.responseJSON && (xhr.responseJSON.error || xhr.responseJSON.details)) || 'Sync fehlgeschlagen';
|
|
$('#sync-status').text(msg);
|
|
})
|
|
.always(function() {
|
|
$('#sync-site').prop('disabled', false);
|
|
});
|
|
});
|
|
|
|
$('#admin-pw-form').submit(function(e) {
|
|
e.preventDefault();
|
|
$.post('/api/auth/change-password', {
|
|
old_password: $('#admin-pw-old').val(),
|
|
new_password: $('#admin-pw-new').val()
|
|
}).done(function() {
|
|
alert('Passwort geaendert.');
|
|
$('#admin-pw-old, #admin-pw-new').val('');
|
|
}).fail(function(xhr) {
|
|
alert(xhr.responseJSON ? xhr.responseJSON.error : 'Fehler');
|
|
});
|
|
});
|
|
});
|