Backend (src/routes/learningAI.js): - POST /api/admin/learning/ai-generate * Accepts: topic text, uploaded file (PDF/TXT/MD/HTML), or Nextcloud WebDAV path * Extracts text from PDFs via pdf-parse; plain text read directly * Fetches WebDAV files using stored Nextcloud credentials * Prompts AI to return structured JSON: title, subject, body (HTML), questions[] * Strips code fences, falls back to regex JSON extraction if needed - POST /api/admin/learning/ai-refine — refine existing body with instructions - GET /api/admin/learning/webdav-browse — PROPFIND-based Nextcloud file browser - POST /api/admin/learning/webdav-path — save user's default browse path Frontend: - AI Generate button in CMS editor header (gradient purple→blue) - Panel with 3 source tabs: By Topic / Upload File / Nextcloud - Drag-and-drop file dropzone with DataTransfer API support - WebDAV file browser: navigate folders, select files, breadcrumb path - Options: question count, content type (article/quiz/pearl), model selector, instructions - Refine Current Body: prompt-driven AI rewrite of existing content - Generated content auto-fills title, subject, type, Tiptap body, quiz questions Settings: - Nextcloud section: "Learning Hub Default Browse Path" field (shown when connected) - Saves to webdav_learning_path column via /api/admin/learning/webdav-path DB: ALTER TABLE users ADD COLUMN IF NOT EXISTS webdav_learning_path TEXT
75 lines
3.2 KiB
JavaScript
75 lines
3.2 KiB
JavaScript
(function() {
|
|
var _inited = false;
|
|
document.addEventListener('tabChanged', function(e) {
|
|
if (e.detail.tab !== 'settings' || _inited) return;
|
|
_inited = true;
|
|
function loadNextcloudStatus() {
|
|
fetch('/api/auth/me', { headers: getAuthHeaders() })
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
var pathSection = document.getElementById('nc-webdav-path-section');
|
|
if (data.user && data.user.nextcloud_url) {
|
|
document.getElementById('nc-status').innerHTML = '✅ Connected to <strong>' + data.user.nextcloud_url + '</strong> as ' + data.user.nextcloud_user;
|
|
document.getElementById('nc-url').value = data.user.nextcloud_url;
|
|
document.getElementById('nc-user').value = data.user.nextcloud_user;
|
|
document.getElementById('btn-nc-disconnect').classList.remove('hidden');
|
|
if (pathSection) {
|
|
pathSection.classList.remove('hidden');
|
|
var pathEl = document.getElementById('nc-webdav-path');
|
|
if (pathEl) pathEl.value = data.user.webdav_learning_path || '';
|
|
}
|
|
} else {
|
|
document.getElementById('nc-status').textContent = 'Not connected';
|
|
document.getElementById('btn-nc-disconnect').classList.add('hidden');
|
|
if (pathSection) pathSection.classList.add('hidden');
|
|
}
|
|
});
|
|
}
|
|
|
|
window.loadNextcloudStatus = loadNextcloudStatus;
|
|
|
|
document.getElementById('btn-nc-connect').addEventListener('click', function() {
|
|
var url = document.getElementById('nc-url').value.trim().replace(/\/+$/, '');
|
|
var user = document.getElementById('nc-user').value.trim();
|
|
var pass = document.getElementById('nc-pass').value.trim();
|
|
|
|
if (!url || !user || !pass) { showToast('Fill all Nextcloud fields', 'error'); return; }
|
|
|
|
showLoading('Connecting to Nextcloud...');
|
|
|
|
fetch('/api/nextcloud/connect', {
|
|
method: 'POST',
|
|
headers: getAuthHeaders(),
|
|
body: JSON.stringify({ nextcloudUrl: url, username: user, appPassword: pass })
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
hideLoading();
|
|
if (data.success) {
|
|
showToast(data.message, 'success');
|
|
loadNextcloudStatus();
|
|
document.getElementById('nc-pass').value = '';
|
|
} else {
|
|
showToast(data.error || 'Connection failed', 'error');
|
|
}
|
|
})
|
|
.catch(function(err) { hideLoading(); showToast(err.message, 'error'); });
|
|
});
|
|
|
|
document.getElementById('btn-nc-disconnect').addEventListener('click', function() {
|
|
fetch('/api/nextcloud/disconnect', { method: 'POST', headers: getAuthHeaders() })
|
|
.then(function() { showToast('Disconnected', 'info'); loadNextcloudStatus(); });
|
|
});
|
|
|
|
document.getElementById('btn-nc-save-path').addEventListener('click', function() {
|
|
var p = (document.getElementById('nc-webdav-path').value || '').trim();
|
|
fetch('/api/admin/learning/webdav-path', {
|
|
method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({ path: p })
|
|
}).then(function(r) { return r.json(); })
|
|
.then(function(d) { d.success ? showToast('Path saved', 'success') : showToast(d.error || 'Failed', 'error'); })
|
|
.catch(function() { showToast('Failed to save', 'error'); });
|
|
});
|
|
|
|
console.log('✅ Nextcloud module loaded');
|
|
});
|
|
})();
|