XenForo одобрява потребители, но мълчи - ето как му дадох глас

Функцията си стоеше в кода от години. Просто никой не беше дръпнал ключа, който я пуска.
Форумите с ръчно одобрение на регистрации имат тих проблем, за който никой не пише - потребителят чака в опашката, admin-ът го одобрява, и... нищо. Никакъв имейл. Човекът разбира, че е одобрен, само ако сам се сети да опита да влезе отново.
Мислех, че липсва вградена функция. Грешах - XenForo си има готов темплейт
Code:
user_account_approved
Диагнозата
Копах директно в
Code:
src/XF/ApprovalQueue/User.php
Code:
public function actionApprove(\XF\Entity\User $user)
{
$user->user_state = 'valid';
$user->save();
$notify = $this->getInput('notify', $user->user_id);
if ($notify && $user->email)
{
\XF::app()->mailer()->newMail()
->setTemplate('user_account_approved', ['user' => $user])
->setToUser($user)
->send();
}
// (съкратено - методът продължава с логване и trigger на completion actions,
// без връзка с темата тук)
}
Имейлът се праща само ако
Code:
$notify
Code:
approval_queue_macros
Code:
notify
Кодът е там, работи технически, но никога не се задейства през нормалния интерфейс.
Решението - малък addon, не пипане на core
Правилото е просто - никога не редактираш core файлове на XenForo директно, защото следващият ъпдейт ще ти ги презапише. Вместо да пипам
Code:
ApprovalQueue/User.php
Всеки път, когато Entity се запази, XenForo хвърля събитие
Code:
entity_post_save
Code:
$entity->isStateChanged('user_state', 'moderated') === 'leave'
Code:
isStateChanged()
Code:
'leave'
Code:
moderated
Code:
user_state === 'valid'
Code:
rejected
Файловете
addon.json
Code:
{
"title": "ApprovalMail - Автоматичен имейл при одобрение",
"description": "Праща имейл автоматично при всяко одобрение на потребител от опашката за модерация, без нужда от checkbox. Използва собствен темплейт и фрази, не пипа core.",
"version_id": 1000070,
"version_string": "1.0.0",
"dev": "AiFlux (Тони Ангелчовски)",
"dev_url": "https://dtgarage.eu/",
"require": {
"XF": [2021570, "2.2.15+"]
},
"icon": "icon.png",
"modifier": "AiFlux",
"support_url": "https://dtgarage.eu/forums/"
}
Дребна подробност, която се бърка често -
Code:
version_id
Code:
70
Code:
1000070
Code:
2021570
Listener/UserListener.php
Code:
<?php
namespace Flux\ApprovalMail\Listener;
use XF\Entity\User;
use XF\Mvc\Entity\Entity;
class UserListener
{
/**
* Тригърва се при всяко entity_post_save за XF:User.
* Праща собствения flux_approvalmail_notice имейл автоматично,
* когато потребител излиза от опашката за одобрение с валиден статус.
*/
public static function postSave(Entity $entity)
{
if (!$entity instanceof User)
{
return;
}
$leftModerated = $entity->isStateChanged('user_state', 'moderated') === 'leave';
if (!$leftModerated || $entity->user_state !== 'valid' || !$entity->email)
{
return;
}
\XF::app()->mailer()->newMail()
->setTemplate('flux_approvalmail_notice', ['user' => $entity])
->setToUser($entity)
->queue();
}
}
Забележете
Code:
queue()
Code:
send()
Code:
send()
Code:
queue()
Code:
xf_mail_queue
_data/ - декларативната част
Code:
code_event_listeners.xml
Code:
XF:User
Code:
entity_post_save
Code:
structure()->shortName
Code:
<?xml version="1.0" encoding="utf-8"?>
<code_event_listeners>
<listener event_id="entity_post_save" execute_order="10" callback_class="Flux\ApprovalMail\Listener\UserListener" callback_method="postSave" active="1" hint="XF:User" description="Праща имейл flux_approvalmail_notice когато потребител излезе от опашката за одобрение с валиден статус."/>
</code_event_listeners>
Code:
templates.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<templates>
<template type="email" title="flux_approvalmail_notice" version_id="1000070" version_string="1.0.0"><![CDATA[<xf:title>{{ phrase('flux_approvalmail_notice_subject', {'board_title': $xf.options.boardTitle}) }}</xf:title>
{{ phrase('flux_approvalmail_notice_body_html', {
'username': $user.username,
'board_title': $xf.options.boardTitle
})|raw }}
<p><a href="{{ link('canonical:index') }}">{{ phrase('flux_approvalmail_notice_visit_link', {'board_title': $xf.options.boardTitle}) }}</a></p>
]]></template>
</templates>
Code:
phrases.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<phrases>
<phrase title="flux_approvalmail_notice_subject" version_id="1000070" version_string="1.0.0"><![CDATA[Вратата е отворена - {board_title}]]></phrase>
<phrase title="flux_approvalmail_notice_body_html" version_id="1000070" version_string="1.0.0"><![CDATA[<p>{username}, портата е отворена.</p><p>Профилът ти в {board_title} мина проверка и вече е активен. Влизаш като редовен - четеш, пишеш, участваш без ограничения.</p>]]></phrase>
<phrase title="flux_approvalmail_notice_visit_link" version_id="1000070" version_string="1.0.0"><![CDATA[Влез в {board_title}]]></phrase>
</phrases>
Структурата в готовия архив:
Code:
upload/src/addons/Flux/ApprovalMail/
├── addon.json
├── icon.png (128x128, по избор)
├── Listener/
│ └── UserListener.php
└── _data/
├── code_event_listeners.xml
├── templates.xml
└── phrases.xml
Онова
Code:
upload/
Code:
Flux/
Инсталация - истинският начин, не заобиколка
Първия път го регистрирах през ръчни INSERT-и в базата, директно от терминала. Не защото е "правилният" начин - а защото
Code:
dev mode
За споделяне обаче addon-ът трябва да минава през истинския install flow. С
Code:
_data/
Хакът, който спасява продукцията днес, и пакетът, който даваш на други хора, рядко са едно и също нещо.
Защо не пипнах core фразите изобщо
Първата ми версия просто презаписваше
Code:
user_account_approved_subject
Code:
user_account_approved_body_html
Защото не са мои. Таблицата
Code:
xf_phrase
Code:
XF
Отделен капан е
Code:
visit_board_html
Затова финалната версия не се бори с чужди фрази - носи собствен темплейт
Code:
flux_approvalmail_notice
Code:
str_replace
Проверка
Тествано конкретно на XenForo 2.2.15.
- Създай тестов потребител в moderated статус.
- Смени му user_state на valid и запази.
- Провери xf_mail_queue в базата - трябва да се появи нов ред за този потребител.
- Изчакай cron-а или го дръпни ръчно, за да излезе имейлът от опашката.
- Ако нищо не идва - виж Admin CP → Tools → Server Error Log за изключения от Flux\ApprovalMail.
На 2.3 event системата може да се държи различно (XenForo сменят детайли по мажорни версии) - не съм тествал там, затова изисквам в
Code:
addon.json
Защо изобщо си струва
Малка функция, но затваря дупка, която повечето admin-и на модерирани форуми дори не знаят, че имат - потребителят чака в тишина, а системата има всичко нужно да му каже "готово", просто никой не е дръпнал ключа.
30-40 реда код, нула пипане на core файлове, изцяло upgrade-safe.
Понякога решението не е да напишеш нова функция - а да намериш защо старата вече съществуваща никога не се е задействала.
Готовият пакет е качен в ресурсите: ApprovalMail 1.0.0 - zip-ът е с
upload/ структурата отгоре, инсталира се направо от Admin CP.XenForo 2 - ApprovalMail - Автоматичен имейл при одобрение
На форум с ръчно одобрение на регистрации потребителят чака в опашката, админът го одобрява, и нищо не се случва. Никакъв имейл. Човекът разбира, че е одобрен, само ако сам се сети да опита да влезе пак. XenForo има код за този имейл, но той се...
dtgarage.eu
Ключови думи: XenForo, addon, ApprovalMail, одобрение на потребители, entity_post_save, code event listener, isStateChanged, mail queue, phrase система, upgrade-safe addon, администрация на форум, PHP, MySQL
Източници: XenForo 2.2.15 source - src/XF/ApprovalQueue/User.php, src/XF/Mvc/Entity/Entity.php, темплейт approval_queue_macros; собствена реализация и тестване на dtgarage.eu
toni@dtgarage:~$ whoami
Тони Ангелчовски | Ексклузивно за DTGaraGe
toni@dtgarage:~$ cat LICENSE
Копирането и препубликуването без разрешение не е позволено.
toni@dtgarage:~$ ./support.sh
Подкрепи DTGaraGe и независимото техническо съдържание
toni@dtgarage:~$ █
Тони Ангелчовски | Ексклузивно за DTGaraGe
toni@dtgarage:~$ cat LICENSE
toni@dtgarage:~$ ./support.sh
toni@dtgarage:~$ █
Last edited: