feat(pay): enforce VIP free-download daily quota like zibll
This commit is contained in:
@@ -171,6 +171,14 @@ class AKSRT_Content_Visibility {
|
||||
]);
|
||||
}
|
||||
|
||||
// Zibll daily free-download quota.
|
||||
if ($cost <= 0 && function_exists('aksrt_check_free_download_quota')) {
|
||||
$quota = aksrt_check_free_download_quota($uid, $cost);
|
||||
if (is_wp_error($quota)) {
|
||||
return $quota;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($paid_settings['download_credit']) && $cost > 0) {
|
||||
$balance = class_exists('AKSRT_Credits') ? AKSRT_Credits::balance($uid) : 0;
|
||||
if ($balance < $cost) {
|
||||
|
||||
@@ -124,10 +124,13 @@ class AKSRT_Download {
|
||||
'post_id' => $post_id,
|
||||
'price' => (float) $meta['price'],
|
||||
'cost' => $cost,
|
||||
'require_login' => !empty($paid_settings['download_login']) || !empty($meta['require_login']),
|
||||
'require_login' => !empty($paid_settings['download_login']) || !empty($meta['require_login']) || (!empty($paid_settings['free_logged_show']) && $cost <= 0),
|
||||
'require_captcha' => $need_captcha,
|
||||
'logged_in' => $uid > 0,
|
||||
'balance' => $uid > 0 && class_exists('AKSRT_Credits') ? AKSRT_Credits::balance($uid) : 0,
|
||||
'free_limit' => $uid > 0 && function_exists('aksrt_get_user_free_download_limit') ? aksrt_get_user_free_download_limit($uid) : 0,
|
||||
'free_used' => $uid > 0 && function_exists('aksrt_get_user_free_downloaded_number') ? aksrt_get_user_free_downloaded_number($uid) : 0,
|
||||
'free_surplus' => $uid > 0 && function_exists('aksrt_get_free_download_surplus') ? aksrt_get_free_download_surplus($uid) : null,
|
||||
'sources' => array_map(function ($row, $idx) {
|
||||
$extract_code = trim((string) ($row['extract_code'] ?? ''));
|
||||
return [
|
||||
@@ -162,6 +165,17 @@ class AKSRT_Download {
|
||||
if (is_wp_error($gate)) return $gate;
|
||||
|
||||
$paid_settings = AKSRT_Settings::get_paid_content_settings();
|
||||
$uid = get_current_user_id();
|
||||
$cost = aksrt_resource_download_cost($post);
|
||||
|
||||
// Daily free-download quota (Zibll).
|
||||
if ($cost <= 0 && $uid > 0 && function_exists('aksrt_check_free_download_quota')) {
|
||||
$quota = aksrt_check_free_download_quota($uid, $cost);
|
||||
if (is_wp_error($quota)) {
|
||||
return $quota;
|
||||
}
|
||||
}
|
||||
|
||||
$need_captcha = !empty($paid_settings['download_captcha']) || !empty($meta['require_captcha']);
|
||||
// 下载双开关:cms_features.download_captcha(或单资源强制)且场景未停用。
|
||||
if ($need_captcha && function_exists('aksrt_require_captcha')) {
|
||||
@@ -176,8 +190,6 @@ class AKSRT_Download {
|
||||
}
|
||||
}
|
||||
|
||||
$uid = get_current_user_id();
|
||||
$cost = aksrt_resource_download_cost($post);
|
||||
if ($cost > 0 && $uid > 0 && class_exists('AKSRT_Credits')) {
|
||||
$deducted = AKSRT_Credits::deduct($uid, $cost, 'download', ['type' => 'post', 'id' => $post_id]);
|
||||
if (is_wp_error($deducted)) return $deducted;
|
||||
@@ -191,6 +203,11 @@ class AKSRT_Download {
|
||||
return $token;
|
||||
}
|
||||
|
||||
// Record free download against daily quota after token issued.
|
||||
if ($cost <= 0 && $uid > 0 && function_exists('aksrt_record_user_free_download')) {
|
||||
aksrt_record_user_free_download($uid, $post_id);
|
||||
}
|
||||
|
||||
$dl_url = home_url('/' . self::ENDPOINT . '/' . $token);
|
||||
if ($uid > 0 && function_exists('aksrt_add_user_notification')) {
|
||||
aksrt_add_user_notification($uid, [
|
||||
|
||||
@@ -149,6 +149,160 @@ function aksrt_get_vip_badge_text(): string {
|
||||
return sanitize_text_field($vip_settings['badge_text'] ?? 'VIP');
|
||||
}
|
||||
|
||||
/**
|
||||
* Daily free-download limit for a user (0 = unlimited).
|
||||
* Aligns with zibll pay_download_limit / pay_download_limit_vip_{n}.
|
||||
*/
|
||||
if (!function_exists('aksrt_get_user_free_download_limit')) {
|
||||
function aksrt_get_user_free_download_limit(int $user_id = 0): int {
|
||||
if ($user_id <= 0) {
|
||||
$user_id = get_current_user_id();
|
||||
}
|
||||
if ($user_id <= 0 || !class_exists('AKSRT_Settings')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$vip = AKSRT_Settings::get_payment_vip_settings();
|
||||
$level = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level($user_id) : 0;
|
||||
$levels = is_array($vip['levels'] ?? null) ? $vip['levels'] : [];
|
||||
$benefit = is_array($vip['benefit'] ?? null) ? $vip['benefit'] : [];
|
||||
|
||||
if ($level >= 1 && !empty($levels[$level]['enabled'])) {
|
||||
return max(0, (int) ($levels[$level]['download_limit'] ?? 0));
|
||||
}
|
||||
|
||||
return max(0, (int) ($benefit['download_limit'] ?? 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download speed cap in KB/s for a user (0 = unlimited).
|
||||
*/
|
||||
if (!function_exists('aksrt_get_user_download_speed')) {
|
||||
function aksrt_get_user_download_speed(int $user_id = 0): int {
|
||||
if ($user_id <= 0) {
|
||||
$user_id = get_current_user_id();
|
||||
}
|
||||
if ($user_id <= 0 || !class_exists('AKSRT_Settings')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$vip = AKSRT_Settings::get_payment_vip_settings();
|
||||
$level = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level($user_id) : 0;
|
||||
$levels = is_array($vip['levels'] ?? null) ? $vip['levels'] : [];
|
||||
$benefit = is_array($vip['benefit'] ?? null) ? $vip['benefit'] : [];
|
||||
|
||||
if ($level >= 1 && !empty($levels[$level]['enabled'])) {
|
||||
return max(0, (int) ($levels[$level]['download_speed'] ?? 0));
|
||||
}
|
||||
|
||||
return max(0, (int) ($benefit['download_speed'] ?? 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count free downloads used today for a user (zibll pay_down_number).
|
||||
*/
|
||||
if (!function_exists('aksrt_get_user_free_downloaded_number')) {
|
||||
function aksrt_get_user_free_downloaded_number(int $user_id = 0): int {
|
||||
if ($user_id <= 0) {
|
||||
$user_id = get_current_user_id();
|
||||
}
|
||||
if ($user_id <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$day = current_time('Y-m-d');
|
||||
$mate = get_user_meta($user_id, 'aksrt_pay_down_number', true);
|
||||
if (!is_array($mate) || empty($mate[$day]) || !is_array($mate[$day])) {
|
||||
return 0;
|
||||
}
|
||||
return count($mate[$day]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a free download for daily quota (zibll pay_down_number).
|
||||
*/
|
||||
if (!function_exists('aksrt_record_user_free_download')) {
|
||||
function aksrt_record_user_free_download(int $user_id, int $post_id): void {
|
||||
if ($user_id <= 0 || $post_id <= 0) {
|
||||
return;
|
||||
}
|
||||
$day = current_time('Y-m-d');
|
||||
$mate = get_user_meta($user_id, 'aksrt_pay_down_number', true);
|
||||
if (!is_array($mate)) {
|
||||
$mate = [];
|
||||
}
|
||||
// Drop old days to keep meta small.
|
||||
foreach (array_keys($mate) as $k) {
|
||||
if ($k !== $day) {
|
||||
unset($mate[$k]);
|
||||
}
|
||||
}
|
||||
if (!isset($mate[$day]) || !is_array($mate[$day])) {
|
||||
$mate[$day] = [];
|
||||
}
|
||||
$mate[$day][(string) $post_id] = 1;
|
||||
update_user_meta($user_id, 'aksrt_pay_down_number', $mate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a free download is allowed under daily quota.
|
||||
* Paid downloads (cost > 0) always pass.
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
if (!function_exists('aksrt_check_free_download_quota')) {
|
||||
function aksrt_check_free_download_quota(int $user_id, int $cost = 0) {
|
||||
if ($cost > 0) {
|
||||
return true;
|
||||
}
|
||||
if ($user_id <= 0) {
|
||||
return true; // login gate handled elsewhere
|
||||
}
|
||||
|
||||
$limit = aksrt_get_user_free_download_limit($user_id);
|
||||
if ($limit <= 0) {
|
||||
return true; // unlimited
|
||||
}
|
||||
|
||||
$used = aksrt_get_user_free_downloaded_number($user_id);
|
||||
if ($used >= $limit) {
|
||||
return new WP_Error(
|
||||
'aksrt_download_limit',
|
||||
__('您今日下载免费资源个数已超限,请明日再下载。', 'aksrt'),
|
||||
[
|
||||
'status' => 429,
|
||||
'limit' => $limit,
|
||||
'used' => $used,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaining free downloads today (null = unlimited).
|
||||
*/
|
||||
if (!function_exists('aksrt_get_free_download_surplus')) {
|
||||
function aksrt_get_free_download_surplus(int $user_id = 0): ?int {
|
||||
if ($user_id <= 0) {
|
||||
$user_id = get_current_user_id();
|
||||
}
|
||||
$limit = aksrt_get_user_free_download_limit($user_id);
|
||||
if ($limit <= 0) {
|
||||
return null;
|
||||
}
|
||||
$used = aksrt_get_user_free_downloaded_number($user_id);
|
||||
return max(0, $limit - $used);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 渲染 VIP 徽标 HTML
|
||||
*
|
||||
|
||||
@@ -282,7 +282,23 @@ $currency = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name()
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="resource-download-box__guarantees">
|
||||
<?php
|
||||
if (is_user_logged_in() && $cost <= 0 && function_exists('aksrt_get_user_free_download_limit')) {
|
||||
$dl_limit = aksrt_get_user_free_download_limit();
|
||||
if ($dl_limit > 0) {
|
||||
$dl_used = function_exists('aksrt_get_user_free_downloaded_number') ? aksrt_get_user_free_downloaded_number() : 0;
|
||||
$dl_surplus = max(0, $dl_limit - $dl_used);
|
||||
$vip_lv = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level() : 0;
|
||||
if ($dl_surplus <= 0) {
|
||||
echo '<div class="resource-download-box__quota-notice"><span class="badg c-red btn-block">' . esc_html__('您今日下载免费资源个数已超限,请明日再下载。', 'aksrt') . '</span></div>';
|
||||
} else {
|
||||
$who = $vip_lv > 0 ? esc_html__('您是尊贵的会员,', 'aksrt') : esc_html__('您', 'aksrt');
|
||||
echo '<div class="resource-download-box__quota-notice"><span class="badg c-red btn-block">' . $who . esc_html(sprintf(__('今日还可下载 %s 个免费资源', 'aksrt'), number_format_i18n($dl_surplus))) . '</span></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="resource-download-box__guarantees">
|
||||
<?php
|
||||
if (function_exists('aksrt_get_pay_service_html')) {
|
||||
echo aksrt_get_pay_service_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
Reference in New Issue
Block a user