419 lines
14 KiB
PHP
419 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Law;
|
|
use App\Models\Notification;
|
|
use App\Models\Category;
|
|
use App\Models\RecentArt;
|
|
use App\Models\SubscribePlan;
|
|
use App\Models\UserSubscriber;
|
|
use App\Services\AppMarketPurchaseVerifier;
|
|
use App\Traits\BaseApiResponse;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
class HomeController extends Controller
|
|
{
|
|
use BaseApiResponse;
|
|
|
|
public function __construct(private AppMarketPurchaseVerifier $marketVerifier)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* LEGACY API: Standard Home (No auto-grant)
|
|
*/
|
|
public function index()
|
|
{
|
|
$user = auth()->user();
|
|
|
|
$this->refreshMarketSubscriptionAfterResponse($user);
|
|
|
|
$recent = RecentArt::query()->where('user_id', $user->id)->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->law?->id,
|
|
'name' => $q->law?->title,
|
|
'is_locked' => $q->law?->is_locked,
|
|
];
|
|
});
|
|
|
|
$laws = Law::orderBy('created_at')->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'name' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
];
|
|
});
|
|
|
|
$categories = ['hagigi', 'kifari'];
|
|
$lawsByCategory = [];
|
|
|
|
foreach ($categories as $category) {
|
|
$lawsByCategory[$category] = Law::whereHas('category', function ($q) use ($category) {
|
|
$q->where('type', $category);
|
|
})->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'title' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
'category_id' => $q->category_id,
|
|
'price' => $q->price,
|
|
'image' => $q->image,
|
|
'type' => 'law',
|
|
];
|
|
});
|
|
}
|
|
|
|
$free_law = Law::where('is_locked', false)->orderBy('created_at')->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'name' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
];
|
|
});
|
|
|
|
// Fetch Active Subscription & Calculate Remaining Days
|
|
$activeSubscribers = $user->userSubscribers()
|
|
->with('subscribe')
|
|
->where('expired_at', '>=', now())
|
|
->get();
|
|
|
|
$current_plan = null;
|
|
|
|
if ($activeSubscribers->isNotEmpty()) {
|
|
$latestSubscription = $activeSubscribers->sortByDesc('expired_at')->first();
|
|
$expiredDays = $activeSubscribers->sum(function ($subscriber) {
|
|
return $subscriber->expired_at->diffInDays(now());
|
|
});
|
|
|
|
// Accurately check if the active plan is free
|
|
$isFree = (bool) (
|
|
$latestSubscription->is_free ||
|
|
($latestSubscription->subscribe && $latestSubscription->subscribe->is_free)
|
|
);
|
|
|
|
$current_plan = [
|
|
'id' => $latestSubscription->id,
|
|
'name' => $latestSubscription->subscribe->name ?? 'Subscription',
|
|
'price' => $latestSubscription->subscribe->price ?? 0,
|
|
'expired_day' => $expiredDays,
|
|
'is_free' => $isFree,
|
|
];
|
|
}
|
|
|
|
$unread_notifications_count = Notification::unreadForUser($user->id)->count();
|
|
|
|
return $this->success([
|
|
'recent' => $recent,
|
|
'laws' => $lawsByCategory,
|
|
'last_law' => $laws,
|
|
'free' => $free_law,
|
|
'current_plan' => $current_plan,
|
|
'unread_notifications_count' => $unread_notifications_count,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* V2 API: Home V2 (No auto-grant)
|
|
*/
|
|
public function homeV2()
|
|
{
|
|
$user = auth()->user();
|
|
|
|
$this->refreshMarketSubscriptionAfterResponse($user);
|
|
|
|
$recent = RecentArt::query()->where('user_id', $user->id)->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->law?->id,
|
|
'name' => $q->law?->title,
|
|
'is_locked' => $q->law?->is_locked,
|
|
];
|
|
});
|
|
|
|
$laws = Law::orderBy('created_at')->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'name' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
];
|
|
});
|
|
|
|
$categories = ['hagigi', 'kifari'];
|
|
$lawsByCategory = [];
|
|
|
|
foreach ($categories as $category) {
|
|
$lawsByCategory[$category] = Law::whereHas('category', function ($q) use ($category) {
|
|
$q->where('type', $category);
|
|
})->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'title' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
'category_id' => $q->category_id,
|
|
'price' => $q->price,
|
|
'image' => $q->image,
|
|
'type' => 'law',
|
|
];
|
|
});
|
|
}
|
|
|
|
$free_law = Law::where('is_locked', false)->orderBy('created_at')->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'name' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
];
|
|
});
|
|
|
|
// Fetch Active Subscription & Calculate Remaining Days
|
|
$activeSubscribers = $user->userSubscribers()
|
|
->with('subscribe')
|
|
->where('expired_at', '>=', now())
|
|
->get();
|
|
|
|
$current_plan = null;
|
|
|
|
if ($activeSubscribers->isNotEmpty()) {
|
|
$latestSubscription = $activeSubscribers->sortByDesc('expired_at')->first();
|
|
$expiredDays = $activeSubscribers->sum(function ($subscriber) {
|
|
return $subscriber->expired_at->diffInDays(now());
|
|
});
|
|
|
|
// Accurately check if the active plan is free
|
|
$isFree = (bool) (
|
|
$latestSubscription->is_free ||
|
|
($latestSubscription->subscribe && $latestSubscription->subscribe->is_free)
|
|
);
|
|
|
|
$current_plan = [
|
|
'id' => $latestSubscription->id,
|
|
'name' => $latestSubscription->subscribe->name ?? 'Subscription',
|
|
'price' => $latestSubscription->subscribe->price ?? 0,
|
|
'expired_day' => $expiredDays,
|
|
'is_free' => $isFree,
|
|
];
|
|
}
|
|
|
|
$unread_notifications_count = Notification::unreadForUser($user->id)->count();
|
|
|
|
$homeData = [
|
|
'recent' => $recent,
|
|
'laws' => $lawsByCategory,
|
|
'last_law' => $laws,
|
|
'free' => $free_law,
|
|
'current_plan' => $current_plan,
|
|
'unread_notifications_count' => $unread_notifications_count,
|
|
];
|
|
|
|
return $this->success([
|
|
'home' => $homeData,
|
|
'hoqoqi_list' => $this->getCategoryList(1), // Category 1
|
|
'keyfari_list' => $this->getCategoryList(2), // Category 2
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* V3 API: Home V3 (WITH Auto-Grant Free Subscription Logic)
|
|
*/
|
|
public function homeV3()
|
|
{
|
|
$user = auth()->user();
|
|
|
|
// --- NEW IN V3: Check and grant free subscription for existing logged-in users ---
|
|
$this->checkAndGrantFreeSubscription($user);
|
|
|
|
$this->refreshMarketSubscriptionAfterResponse($user);
|
|
|
|
$recent = RecentArt::query()->where('user_id', $user->id)->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->law?->id,
|
|
'name' => $q->law?->title,
|
|
'is_locked' => $q->law?->is_locked,
|
|
];
|
|
});
|
|
|
|
$laws = Law::orderBy('created_at')->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'name' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
];
|
|
});
|
|
|
|
$categories = ['hagigi', 'kifari'];
|
|
$lawsByCategory = [];
|
|
|
|
foreach ($categories as $category) {
|
|
$lawsByCategory[$category] = Law::whereHas('category', function ($q) use ($category) {
|
|
$q->where('type', $category);
|
|
})->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'title' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
'category_id' => $q->category_id,
|
|
'price' => $q->price,
|
|
'image' => $q->image,
|
|
'type' => 'law',
|
|
];
|
|
});
|
|
}
|
|
|
|
$free_law = Law::where('is_locked', false)->orderBy('created_at')->get()->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'name' => $q->title,
|
|
'is_locked' => $q->is_locked,
|
|
];
|
|
});
|
|
|
|
// Fetch Active Subscription & Calculate Remaining Days
|
|
$activeSubscribers = $user->userSubscribers()
|
|
->with('subscribe')
|
|
->where('expired_at', '>=', now())
|
|
->get();
|
|
|
|
$current_plan = null;
|
|
|
|
if ($activeSubscribers->isNotEmpty()) {
|
|
$latestSubscription = $activeSubscribers->sortByDesc('expired_at')->first();
|
|
$expiredDays = $activeSubscribers->sum(function ($subscriber) {
|
|
return $subscriber->expired_at->diffInDays(now());
|
|
});
|
|
|
|
// Accurately check if the active plan is free
|
|
$isFree = (bool) (
|
|
$latestSubscription->is_free ||
|
|
($latestSubscription->subscribe && $latestSubscription->subscribe->is_free)
|
|
);
|
|
|
|
$current_plan = [
|
|
'id' => $latestSubscription->id,
|
|
'name' => $latestSubscription->subscribe->name ?? 'Subscription',
|
|
'price' => $latestSubscription->subscribe->price ?? 0,
|
|
'expired_day' => $expiredDays,
|
|
'is_free' => $isFree,
|
|
];
|
|
}
|
|
|
|
$unread_notifications_count = Notification::unreadForUser($user->id)->count();
|
|
|
|
$homeData = [
|
|
'recent' => $recent,
|
|
'laws' => $lawsByCategory,
|
|
'last_law' => $laws,
|
|
'free' => $free_law,
|
|
'current_plan' => $current_plan,
|
|
'unread_notifications_count' => $unread_notifications_count,
|
|
];
|
|
|
|
return $this->success([
|
|
'home' => $homeData,
|
|
'hoqoqi_list' => $this->getCategoryList(1), // Category 1
|
|
'keyfari_list' => $this->getCategoryList(2), // Category 2
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Helper methods below
|
|
*/
|
|
private function getCategoryList(int $categoryId)
|
|
{
|
|
$type = $categoryId === 1 ? 'hagigi' : 'kifari';
|
|
|
|
$categories = Category::with(['laws'])->where('type', $type)->get()->pluck('id');
|
|
$items = Law::query()->whereIn('category_id', $categories)->get();
|
|
|
|
$data = [];
|
|
$user = auth()->user();
|
|
|
|
foreach ($items as $item) {
|
|
$data[] = [
|
|
'id' => $item->id,
|
|
'title' => $item->title,
|
|
'number' => $item->number,
|
|
'type' => 'laws',
|
|
'is_locked' => $user->isSubscriber() !== false ? false : Law::where('id', $item->id)->first()?->is_locked,
|
|
'image' => $item?->image,
|
|
'law' => $item?->title,
|
|
'count_art' => $item->arts->count(),
|
|
'count_volums' => $item->volums->count(),
|
|
'price' => $item->price,
|
|
];
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function checkAndGrantFreeSubscription($user): void
|
|
{
|
|
$hasUsedFreePlan = $user->userSubscribers()
|
|
->whereHas('subscribe', function ($query) {
|
|
$query->where('is_free', true);
|
|
})->exists();
|
|
|
|
if (!$hasUsedFreePlan) {
|
|
$freePlan = SubscribePlan::where('is_free', true)->where('is_active', true)->first();
|
|
|
|
if ($freePlan) {
|
|
$user->userSubscribers()->create([
|
|
'subscribe_plan_id' => $freePlan->id,
|
|
'expired_at' => now()->addDays($freePlan->expired_day + 1),
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function refreshMarketSubscriptionAfterResponse($user): void
|
|
{
|
|
$cacheKey = "home-market-refresh-user-{$user->id}";
|
|
$this->refreshMarketSubscription($user);
|
|
|
|
if (!Cache::add($cacheKey, true, now()->addHours(24))) {
|
|
return;
|
|
}
|
|
|
|
app()->terminating(function () use ($user) {
|
|
$this->refreshMarketSubscription($user);
|
|
});
|
|
}
|
|
|
|
private function refreshMarketSubscription($user): void
|
|
{
|
|
$bazaarSubscription = $user->userSubscribers()
|
|
->whereNotNull('purchase_token')
|
|
->whereNotNull('subscription_id')
|
|
->where(function ($query) {
|
|
$query->where('market_provider', 'bazaar')
|
|
->orWhereNull('market_provider');
|
|
})
|
|
->latest()
|
|
->first();
|
|
|
|
if ($bazaarSubscription && $this->shouldRefreshMarketSubscription($bazaarSubscription) && $this->marketVerifier->refreshBazaarSubscriber($bazaarSubscription)) {
|
|
return;
|
|
}
|
|
|
|
$myketSubscription = $user->userSubscribers()
|
|
->where('market_provider', 'myket')
|
|
->whereNotNull('purchase_token')
|
|
->whereNotNull('product_id')
|
|
->latest()
|
|
->first();
|
|
|
|
if ($myketSubscription && $this->shouldRefreshMarketSubscription($myketSubscription)) {
|
|
$this->marketVerifier->refreshMyketSubscriber($myketSubscription);
|
|
}
|
|
}
|
|
|
|
private function shouldRefreshMarketSubscription(UserSubscriber $subscriber): bool
|
|
{
|
|
if ($subscriber->expired_at && $subscriber->expired_at->lessThanOrEqualTo(now())) {
|
|
return true;
|
|
}
|
|
|
|
return !$subscriber->last_verified_at || $subscriber->last_verified_at->lessThan(now()->subHours(12));
|
|
}
|
|
}
|