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:
orasche committed 2026-10-02 16:37:01 +02:00
1 parent 78af83d2e3
commit 872c6e715c
14 files changed
+842 -95

No files matched your search

@@ -17,13 +17,17 @@ return [
'typo3/cms-frontend/site',
],
],
'fecomment/submit' => [
'target' => \Evomedien\FeComment\Middleware\SubmitMiddleware::class,
// v2: the feedback API needs the logged-in FE user, so it runs
// AFTER frontend authentication (earlier the frontend.user
// attribute does not exist yet). Replaces the old anonymous
// submit endpoint.
'fecomment/feedback-api' => [
'target' => \Evomedien\FeComment\Middleware\FeedbackApiMiddleware::class,
'after' => [
'typo3/cms-core/normalized-params-attribute',
'typo3/cms-frontend/authentication',
],
'before' => [
'typo3/cms-frontend/site',
'typo3/cms-frontend/page-resolver',
],
],
],
@@ -0,0 +1,46 @@
<?php
/**
* One feedback item (page URL + rich-text note + attachments), owned by a
* FE user, belonging to a summary. Written from the front end.
*/
return [
'ctrl' => [
'title' => 'Feedback',
'label' => 'url',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'delete' => 'deleted',
'sortby' => 'sorting',
'hideTable' => true,
'iconfile' => 'EXT:fe_comment/Resources/Public/Icons/Extension.svg',
'security' => ['ignorePageTypeRestriction' => true],
],
'types' => [
'1' => ['showitem' => 'url, note, attachments, fe_user'],
],
'columns' => [
'summary' => [
'config' => ['type' => 'passthrough'],
],
'fe_user' => [
'label' => 'Author (frontend user)',
'config' => ['type' => 'group', 'allowed' => 'fe_users', 'maxitems' => 1, 'size' => 1],
],
'url' => [
'label' => 'Page URL',
'config' => ['type' => 'input', 'size' => 50, 'max' => 2048],
],
'note' => [
'label' => 'Note',
'config' => ['type' => 'text', 'rows' => 6, 'enableRichtext' => true],
],
'attachments' => [
'label' => 'Attachments',
'config' => [
'type' => 'file',
'maxitems' => 20,
],
],
],
];
@@ -0,0 +1,68 @@
<?php
/**
* One FE user's feedback pad. Created from the front end (plain inserts);
* this TCA exists so editors can READ and tidy submissions in the backend.
*/
return [
'ctrl' => [
'title' => 'Feedback summary',
'label' => 'status',
'label_alt' => 'fe_user,sent_at',
'label_alt_force' => true,
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'delete' => 'deleted',
'default_sortby' => 'tstamp DESC',
'iconfile' => 'EXT:fe_comment/Resources/Public/Icons/Extension.svg',
'security' => ['ignorePageTypeRestriction' => true],
],
'types' => [
'1' => ['showitem' => 'status, fe_user, recipients, general_notes, feedback_items'],
],
'columns' => [
'status' => [
'label' => 'Status',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
['label' => 'open', 'value' => 'open'],
['label' => 'sent', 'value' => 'sent'],
],
'default' => 'open',
],
],
'fe_user' => [
'label' => 'Author (frontend user)',
'config' => [
'type' => 'group',
'allowed' => 'fe_users',
'maxitems' => 1,
'size' => 1,
],
],
'general_notes' => [
'label' => 'General notes / instructions',
'config' => ['type' => 'text', 'rows' => 6, 'enableRichtext' => true],
],
'recipients' => [
'label' => 'Chosen recipients',
'config' => ['type' => 'input', 'size' => 50, 'readOnly' => true],
],
'sent_at' => [
'label' => 'Sent at',
'config' => ['type' => 'datetime', 'readOnly' => true, 'default' => 0],
],
'feedback_items' => [
'label' => 'Feedback items',
'config' => [
'type' => 'inline',
'foreign_table' => 'tx_fecomment_feedback',
'foreign_field' => 'summary',
'foreign_sortby' => 'sorting',
'appearance' => ['collapseAll' => true, 'expandSingle' => true],
],
],
],
];