fe_comment v2: FE-user feedback tickets with summary, uploads and API
- Replace the v1 submit endpoint with a full JSON API under
/api/fe-comment/ (state, feedback create/update/delete, uploads,
summary notes/recipients, submit), guarded by frontend login and a
configurable FE user group; unauthorized callers get {"allowed":false}
- New models: tx_fecomment_summary (one open ticket per user, status
open/sent) and tx_fecomment_feedback (url, RTE note, FAL attachments),
both editable in the backend on the ticket storage page
- FeedbackApiMiddleware registered after frontend authentication (the
frontend.user attribute does not exist earlier); uploads land in
fileadmin/fe_comment/summary-<uid>/ with mime/extension check, 20 MB cap
- Submit sends one HTML mail (author block, items with attachment links,
reply-to = FE user mail) to selected recipients with mailTo fallback,
then closes the summary
- felogin wired React-compatible: felogin.pid=520 plus headless FeLogin
JSON templates via site settings - felogin v14 and EXT:headless both
claim templateRootPaths.10, the felogin.view.* settings feed exactly
that index, so the structured JSON form (incl. __RequestToken) wins
- Read the sys_file_reference insert id before syncAttachmentCount():
DBAL throws "no identity value" once the count UPDATE has run
- migrations: drop_fecomment_tables.php (repairs the no-uid tables,
only drops when empty), check_feuser.php (login diagnosis),
fec_login_test.sh / fec_api_test.sh (curl chains incl. CSRF token flow)
This commit is contained in:
1 parent
78af83d2e3
commit
872c6e715c
14 files changed
+842
-95
No files matched your search
@@ -56,6 +56,37 @@ final class ExtensionSettings
|
||||
return (bool)($this->settings['enabled'] ?? true);
|
||||
}
|
||||
|
||||
/** FE user group required to use the widget; 0 = any logged-in user. */
|
||||
public function feUserGroup(): int
|
||||
{
|
||||
return (int)($this->settings['feUserGroup'] ?? 0);
|
||||
}
|
||||
|
||||
/** Storage pid for the feedback records (backend visibility). */
|
||||
public function storagePid(): int
|
||||
{
|
||||
return (int)($this->settings['storagePid'] ?? 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selectable recipients, parsed from "Label <mail>; Label2 <mail2>".
|
||||
* The index doubles as the id the widget sends back.
|
||||
*
|
||||
* @return array<int,array{label:string,email:string}>
|
||||
*/
|
||||
public function recipients(): array
|
||||
{
|
||||
$recipients = [];
|
||||
foreach (GeneralUtility::trimExplode(';', (string)($this->settings['recipients'] ?? ''), true) as $entry) {
|
||||
if (preg_match('/^(.*)<([^>]+)>\s*$/', $entry, $m) && GeneralUtility::validEmail(trim($m[2]))) {
|
||||
$recipients[] = ['label' => trim($m[1]) ?: trim($m[2]), 'email' => trim($m[2])];
|
||||
} elseif (GeneralUtility::validEmail(trim($entry))) {
|
||||
$recipients[] = ['label' => trim($entry), 'email' => trim($entry)];
|
||||
}
|
||||
}
|
||||
return $recipients;
|
||||
}
|
||||
|
||||
/** true = headless: TYPO3 injects nothing, the front end embeds the widget itself. */
|
||||
public function jsonOutput(): bool
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user