修改自动推广的相关任务
This commit is contained in:
@@ -8,14 +8,17 @@ use think\Response;
|
||||
use app\common\UnsubscribeService;
|
||||
|
||||
/**
|
||||
* 推广邮件退订入口(公开访问,无需登录)
|
||||
* 推广 / 约稿邮件退订入口(公开访问,无需登录)
|
||||
*
|
||||
* 路由:
|
||||
* GET /api/Unsubscribe/index?id=&t= 展示确认页
|
||||
* POST /api/Unsubscribe/confirm?id=&t= 执行退订
|
||||
* GET /api/Unsubscribe/index?k=&id=&t= 展示确认页
|
||||
* POST /api/Unsubscribe/confirm?k=&id=&t= 执行退订
|
||||
*
|
||||
* k = expert → 操作 t_expert.unsubscribed
|
||||
* k = user → 操作 t_user.unsubscribed
|
||||
*
|
||||
* 安全:
|
||||
* - URL 内带 sha256 签名 (id, email, secret),防伪造
|
||||
* - URL 内带 sha256 签名 (kind, id, email, secret),防伪造
|
||||
* - 必须确认页二次点击才执行(防爬虫预取链接误退订)
|
||||
*/
|
||||
class Unsubscribe extends Controller
|
||||
@@ -25,51 +28,77 @@ class Unsubscribe extends Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$kind = UnsubscribeService::normalizeKind($this->request->param('k', UnsubscribeService::KIND_EXPERT));
|
||||
$id = intval($this->request->param('id', 0));
|
||||
$token = trim((string)$this->request->param('t', ''));
|
||||
|
||||
$expert = $id > 0 ? Db::name('expert')->where('expert_id', $id)->find() : null;
|
||||
if (!$expert) {
|
||||
$audience = $this->loadAudience($kind, $id);
|
||||
if (!$audience) {
|
||||
return $this->html($this->pageInvalid(), 404);
|
||||
}
|
||||
if (!UnsubscribeService::verifyToken($id, (string)$expert['email'], $token)) {
|
||||
if (!UnsubscribeService::verifyToken($kind, $id, (string)$audience['email'], $token)) {
|
||||
return $this->html($this->pageInvalid(), 403);
|
||||
}
|
||||
if (!empty($expert['unsubscribed'])) {
|
||||
return $this->html($this->pageAlreadyDone((string)$expert['email']));
|
||||
if (!empty($audience['unsubscribed'])) {
|
||||
return $this->html($this->pageAlreadyDone((string)$audience['email']));
|
||||
}
|
||||
|
||||
return $this->html($this->pageConfirm(
|
||||
$kind,
|
||||
$id,
|
||||
$token,
|
||||
(string)$expert['email'],
|
||||
(string)($expert['name'] ?? '')
|
||||
(string)$audience['email'],
|
||||
(string)$audience['name']
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 真正执行退订(POST 推荐;GET 也允许,以兼容部分邮件客户端禁止表单提交)
|
||||
* 真正执行退订(POST 推荐;GET 也允许)
|
||||
*/
|
||||
public function confirm()
|
||||
{
|
||||
$kind = UnsubscribeService::normalizeKind($this->request->param('k', UnsubscribeService::KIND_EXPERT));
|
||||
$id = intval($this->request->param('id', 0));
|
||||
$token = trim((string)$this->request->param('t', ''));
|
||||
|
||||
$expert = $id > 0 ? Db::name('expert')->where('expert_id', $id)->find() : null;
|
||||
if (!$expert) {
|
||||
$audience = $this->loadAudience($kind, $id);
|
||||
if (!$audience) {
|
||||
return $this->html($this->pageInvalid(), 404);
|
||||
}
|
||||
if (!UnsubscribeService::verifyToken($id, (string)$expert['email'], $token)) {
|
||||
if (!UnsubscribeService::verifyToken($kind, $id, (string)$audience['email'], $token)) {
|
||||
return $this->html($this->pageInvalid(), 403);
|
||||
}
|
||||
|
||||
if (empty($expert['unsubscribed'])) {
|
||||
Db::name('expert')->where('expert_id', $id)->update([
|
||||
if (empty($audience['unsubscribed'])) {
|
||||
$table = $kind === UnsubscribeService::KIND_USER ? 'user' : 'expert';
|
||||
$pk = $kind === UnsubscribeService::KIND_USER ? 'user_id' : 'expert_id';
|
||||
Db::name($table)->where($pk, $id)->update([
|
||||
'unsubscribed' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->html($this->pageSuccess((string)$expert['email']));
|
||||
return $this->html($this->pageSuccess((string)$audience['email']));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 kind 加载受众的最少必要信息(id, email, name, unsubscribed)
|
||||
*/
|
||||
private function loadAudience($kind, $id)
|
||||
{
|
||||
if ($id <= 0) return null;
|
||||
|
||||
if ($kind === UnsubscribeService::KIND_USER) {
|
||||
$row = Db::name('user')
|
||||
->where('user_id', $id)
|
||||
->field('user_id, email, realname AS name, unsubscribed')
|
||||
->find();
|
||||
} else {
|
||||
$row = Db::name('expert')
|
||||
->where('expert_id', $id)
|
||||
->field('expert_id, email, name, unsubscribed')
|
||||
->find();
|
||||
}
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
// ==================== HTML 页面 ====================
|
||||
@@ -107,8 +136,9 @@ class Unsubscribe extends Controller
|
||||
. '<body><div class="wrap">' . $bodyHtml . '</div></body></html>';
|
||||
}
|
||||
|
||||
private function pageConfirm($id, $token, $email, $name)
|
||||
private function pageConfirm($kind, $id, $token, $email, $name)
|
||||
{
|
||||
$kindSafe = htmlspecialchars($kind, ENT_QUOTES, 'UTF-8');
|
||||
$idSafe = intval($id);
|
||||
$tokenSafe = htmlspecialchars($token, ENT_QUOTES, 'UTF-8');
|
||||
$emailSafe = htmlspecialchars($email, ENT_QUOTES, 'UTF-8');
|
||||
@@ -120,6 +150,7 @@ class Unsubscribe extends Controller
|
||||
. '</span> from all promotion and invitation emails sent by TMR Journals. '
|
||||
. 'After unsubscribing you will no longer receive marketing emails from us.</p>'
|
||||
. '<form method="post" action="confirm" style="margin-top:24px;">'
|
||||
. '<input type="hidden" name="k" value="' . $kindSafe . '">'
|
||||
. '<input type="hidden" name="id" value="' . $idSafe . '">'
|
||||
. '<input type="hidden" name="t" value="' . $tokenSafe . '">'
|
||||
. '<button type="submit" class="btn btn-primary">Confirm unsubscribe</button>'
|
||||
|
||||
Reference in New Issue
Block a user