feat(users): govern profiles and access

Normalize fixed profile fields, profile actions, and the five-column capability matrix for comments, uploads, and downloads.
This commit is contained in:
2026-08-13 00:24:54 +08:00
parent 0b06b2c7df
commit 8241570ca2
67 changed files with 780 additions and 1127 deletions
+84 -35
View File
@@ -390,27 +390,41 @@
}
},
openMedia: function (opts, cb) {
opts = opts || {};
if (!window.wp || !wp.media) {
alert('Media library unavailable');
return;
uploadFile: function (kind, file) {
var upload = (cfg.uploads || {})[kind] || null;
if (!upload || !upload.url || !file) {
return Promise.reject(new Error(i18n.error || 'Upload unavailable'));
}
var frame = wp.media({
title: opts.title || i18n.pickImage || 'Select',
button: { text: opts.button || 'OK' },
multiple: !!opts.multiple,
library: opts.library || { type: 'image' },
});
frame.on('select', function () {
var selection = frame.state().get('selection');
var files = selection.map(function (att) {
var a = att.toJSON();
return { id: a.id, url: a.url, title: a.title || '' };
if (upload.maxSize && file.size > upload.maxSize) {
return Promise.reject(new Error('File is too large'));
}
var body = new FormData();
body.append('file', file);
return fetch(upload.url, {
method: 'POST',
credentials: 'same-origin',
headers: { 'X-WP-Nonce': cfg.restNonce || '' },
body: body,
}).then(function (response) {
return response.json().catch(function () { return {}; }).then(function (payload) {
if (!response.ok || !payload || !payload.success) {
throw new Error((payload && payload.message) || i18n.error || 'Upload failed');
}
return payload;
});
cb(opts.multiple ? files : files[0]);
});
frame.open();
},
pickUpload: function (kind, accept) {
return new Promise(function (resolve) {
var input = document.createElement('input');
input.type = 'file';
input.accept = accept;
input.addEventListener('change', function () {
resolve(input.files && input.files[0] ? input.files[0] : null);
}, { once: true });
input.click();
});
},
bindFeatured: function () {
@@ -431,24 +445,21 @@
return;
}
if (act === 'image') {
self.openMedia({ title: i18n.pickImage, multiple: false }, function (file) {
if (file) {
self.setFeatured('image', { url: file.url, id: file.id });
}
});
self.pickUpload('image', 'image/*').then(function (file) {
if (!file) return null;
return self.uploadFile('image', file);
}).then(function (file) {
if (file) self.setFeatured('image', { url: file.url, id: file.attachment_id });
}).catch(function (error) { alert(error.message || i18n.error || 'Upload failed'); });
return;
}
if (act === 'slide') {
self.openMedia({ title: i18n.pickImage, multiple: true }, function (files) {
if (files && files.length) {
self.setFeatured(
'slide',
files.map(function (f) {
return { url: f.url, id: f.id };
})
);
}
});
self.pickUpload('image', 'image/*').then(function (file) {
if (!file) return null;
return self.uploadFile('image', file);
}).then(function (file) {
if (file) self.setFeatured('slide', [{ url: file.url, id: file.attachment_id }]);
}).catch(function (error) { alert(error.message || i18n.error || 'Upload failed'); });
return;
}
if (act === 'video') {
@@ -456,9 +467,12 @@
if (!url) {
return;
}
self.openMedia({ title: i18n.pickVideo || 'Poster', multiple: false }, function (file) {
self.pickUpload('image', 'image/*').then(function (file) {
if (!file) return null;
return self.uploadFile('image', file);
}).then(function (file) {
self.setFeatured('video', { url: url, pic: file ? file.url : '' });
});
}).catch(function (error) { alert(error.message || i18n.error || 'Upload failed'); });
}
});
},
@@ -520,6 +534,32 @@
list.appendChild(node);
});
}
var uploadBtn = qs('[data-pay-download-upload]', box);
if (uploadBtn && list && tpl) {
uploadBtn.addEventListener('click', function () {
App.pickUpload('resource', '*/*').then(function (file) {
if (!file) return null;
uploadBtn.disabled = true;
return App.uploadFile('resource', file);
}).then(function (file) {
if (!file) return;
var node = tpl.content.cloneNode(true);
var idx = list.querySelectorAll('[data-pay-download-item]').length;
qsa('[data-name]', node).forEach(function (input) {
input.name = 'aksrt_pay[downloads][' + idx + '][' + input.getAttribute('data-name') + ']';
});
var url = qs('[data-pay-download-url]', node);
var label = qs('[data-pay-download-label]', node);
if (url) url.value = file.url || '';
if (label) label.value = file.name || '';
list.appendChild(node);
}).catch(function (error) {
alert(error.message || i18n.error || 'Upload failed');
}).finally(function () {
uploadBtn.disabled = false;
});
});
}
if (list) {
list.addEventListener('click', function (e) {
var rm = e.target.closest('[data-pay-download-remove]');
@@ -541,6 +581,15 @@
return;
}
e.preventDefault();
if (btn.hasAttribute('data-insert-upload-image')) {
App.pickUpload('image', 'image/*').then(function (file) {
if (!file) return null;
return App.uploadFile('image', file);
}).then(function (file) {
if (file && file.url) insertEditorContent('<img src="' + file.url.replace(/"/g, '&quot;') + '" alt="">');
}).catch(function (error) { alert(error.message || i18n.error || 'Upload failed'); });
return;
}
var type = btn.getAttribute('data-insert-shortcode');
if (type === 'hide') {
insertEditorContent('[hidecontent type="login"]' + (i18n.hidePlaceholder || '隐藏内容') + '[/hidecontent]');