366 lines
15 KiB
PHP
366 lines
15 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Folder;
|
|
use App\Models\FolderArt;
|
|
use App\Models\FolderBylaw;
|
|
use App\Models\FolderJudicialPrecedent;
|
|
use App\Models\FolderLegalOpinion;
|
|
use App\Traits\BaseApiResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class FolderController extends Controller
|
|
{
|
|
use BaseApiResponse;
|
|
|
|
public function index()
|
|
{
|
|
// Eager load everything to prevent N+1 Database issues
|
|
$folder = Folder::with(['arts', 'bylaws', 'judicialPrecedents', 'legalOpinions'])
|
|
->where('user_id', auth()->id())
|
|
->get()
|
|
->map(function ($q) {
|
|
return [
|
|
'id' => $q->id,
|
|
'name' => $q->name,
|
|
'count_of_arts' => $q->arts->count(),
|
|
'count_of_bylaws' => $q->bylaws->count(),
|
|
'count_of_judicials' => $q->judicialPrecedents->count(),
|
|
'count_of_opinions' => $q->legalOpinions->count(),
|
|
'created_at' => $q->created_at,
|
|
];
|
|
});
|
|
|
|
return $this->success($folder);
|
|
}
|
|
|
|
public function create(Request $request)
|
|
{
|
|
$validted = $request->validate([
|
|
'name' => 'required',
|
|
]);
|
|
|
|
Folder::create([
|
|
'user_id' => auth()->id(),
|
|
'name' => $validted['name'],
|
|
]);
|
|
|
|
return $this->success([], 'ایجاد شد', 'پوشه با موفقیت ایجاد شد.');
|
|
}
|
|
|
|
public function assign(Request $request)
|
|
{
|
|
$validted = $request->validate([
|
|
'folder_id' => 'required',
|
|
'art_id' => 'nullable',
|
|
'bylaw_document_id' => 'nullable',
|
|
'judicial_precedent_id' => 'nullable',
|
|
'legal_opinion_id' => 'nullable',
|
|
]);
|
|
|
|
// 🚨 SECURITY FIX: Check if the folder exists AND belongs to the logged-in user
|
|
if (Folder::where('id', $validted['folder_id'])->where('user_id', auth()->id())->count() == 0) {
|
|
return $this->failed([], 'پوشه مورد نظر یافت نشد یا شما دسترسی ندارید', 404);
|
|
}
|
|
|
|
if ($request->filled('art_id')) {
|
|
if (FolderArt::where('folder_id', $validted['folder_id'])->where('art_id', $validted['art_id'])->exists()) {
|
|
return $this->failed([], 'ارت مورد نظر قبلا اضافه شده است', 400);
|
|
}
|
|
FolderArt::create(['folder_id' => $validted['folder_id'], 'art_id' => $validted['art_id']]);
|
|
}
|
|
elseif ($request->filled('bylaw_document_id')) {
|
|
if (FolderBylaw::where('folder_id', $validted['folder_id'])->where('bylaw_document_id', $validted['bylaw_document_id'])->exists()) {
|
|
return $this->failed([], 'آییننامه قبلا اضافه شده است', 400);
|
|
}
|
|
FolderBylaw::create(['folder_id' => $validted['folder_id'], 'bylaw_document_id' => $validted['bylaw_document_id']]);
|
|
}
|
|
elseif ($request->filled('judicial_precedent_id')) {
|
|
if (FolderJudicialPrecedent::where('folder_id', $validted['folder_id'])->where('judicial_precedent_id', $validted['judicial_precedent_id'])->exists()) {
|
|
return $this->failed([], 'رأی قبلا اضافه شده است', 400);
|
|
}
|
|
FolderJudicialPrecedent::create(['folder_id' => $validted['folder_id'], 'judicial_precedent_id' => $validted['judicial_precedent_id']]);
|
|
}
|
|
elseif ($request->filled('legal_opinion_id')) {
|
|
if (FolderLegalOpinion::where('folder_id', $validted['folder_id'])->where('legal_opinion_id', $validted['legal_opinion_id'])->exists()) {
|
|
return $this->failed([], 'نظریه قبلا اضافه شده است', 400);
|
|
}
|
|
FolderLegalOpinion::create(['folder_id' => $validted['folder_id'], 'legal_opinion_id' => $validted['legal_opinion_id']]);
|
|
}
|
|
else {
|
|
return $this->failed([], 'موردی برای افزودن یافت نشد', 400);
|
|
}
|
|
|
|
return $this->success([], 'اضافه شد', 'با موفیت اضافه شد');
|
|
}
|
|
|
|
public function folder($id)
|
|
{
|
|
// Added 'arts.law.category' so we can fetch category_name without slowing down the DB
|
|
$folder = Folder::with([
|
|
'arts.chapter', 'arts.part', 'arts.volum', 'arts.law.category', 'arts.book', 'arts.section', 'arts.gate',
|
|
'bylaws.category', 'bylaws.approvalAuthority', 'bylaws.promulgationAuthority',
|
|
'judicialPrecedents.category',
|
|
'legalOpinions.category'
|
|
])->where('user_id', auth()->id())->find($id);
|
|
|
|
if (!$folder) {
|
|
return $this->failed([], 'پوشه یافت نشد یا شما دسترسی ندارید', 404);
|
|
}
|
|
|
|
$items = collect();
|
|
|
|
// 1. Process Arts
|
|
$arts = $folder->arts->map(function ($art) {
|
|
$text = $art->text ?? '';
|
|
$shortText = '';
|
|
if (strlen($text) > 50) {
|
|
$shortText = mb_substr($text, 0, 50);
|
|
$shortText = mb_substr($shortText, 0, mb_strrpos($shortText, ' ')).'...';
|
|
} else {
|
|
$shortText = $text;
|
|
}
|
|
$isLocked = ! auth()->user()->isSubscriber() && (bool) $art->law?->is_locked;
|
|
|
|
return [
|
|
'id' => $art->id,
|
|
'title' => $art->title,
|
|
'text' => $isLocked ? null : $shortText,
|
|
'number' => $art->number,
|
|
'is_locked' => $isLocked,
|
|
'type' => 'art',
|
|
'assigned_at' => $art->pivot->created_at,
|
|
|
|
'law_title' => $art->law?->title,
|
|
'category_name' => $art->law?->category?->name,
|
|
|
|
'law' => $art->law != null ? [
|
|
'id' => $art->law->id,
|
|
'title' => $art->law->title,
|
|
'number' => $art->law->number,
|
|
] : null,
|
|
|
|
'chapter' => $art->chapter != null ? [
|
|
'id' => $art->chapter->id,
|
|
'title' => $art->chapter->title,
|
|
'number' => $art->chapter->number,
|
|
] : null,
|
|
'part' => $art->part != null ? [
|
|
'id' => $art->part->id,
|
|
'title' => $art->part->title,
|
|
'number' => $art->part->number,
|
|
] : null,
|
|
'volum' => $art->volum != null ? [
|
|
'id' => $art->volum->id,
|
|
'title' => $art->volum->title,
|
|
'number' => $art->volum->number,
|
|
] : null,
|
|
'book' => $art->book != null ? [
|
|
'id' => $art->book->id,
|
|
'title' => $art->book->title,
|
|
'number' => $art->book->number,
|
|
] : null,
|
|
'section' => $art->section != null ? [
|
|
'id' => $art->section->id,
|
|
'title' => $art->section->title,
|
|
'number' => $art->section->number,
|
|
] : null,
|
|
'gate' => $art->gate != null ? [
|
|
'id' => $art->gate->id,
|
|
'title' => $art->gate->title,
|
|
'number' => $art->gate->number,
|
|
] : null,
|
|
];
|
|
});
|
|
$items = $items->concat($arts);
|
|
|
|
// 2. Process Bylaws
|
|
$bylawIds = $folder->bylaws->pluck('id')->toArray();
|
|
$allBylawNodes = collect();
|
|
if (!empty($bylawIds)) {
|
|
$allBylawNodes = DB::table('bylaw_nodes')
|
|
->whereIn('document_id', $bylawIds)
|
|
->orderBy('sort_order', 'asc')
|
|
->get();
|
|
}
|
|
|
|
$bylaws = $folder->bylaws->map(function ($bylaw) use ($allBylawNodes) {
|
|
$itemNodes = $allBylawNodes->where('document_id', $bylaw->id);
|
|
$formatted = $this->formatBylaw($bylaw, $itemNodes);
|
|
$formatted['type'] = 'bylaw';
|
|
$formatted['assigned_at'] = $bylaw->pivot->created_at;
|
|
return $formatted;
|
|
});
|
|
$items = $items->concat($bylaws);
|
|
|
|
// 3. Process Judicial Precedents
|
|
$judicials = $folder->judicialPrecedents->map(function ($judicial) {
|
|
$formatted = $this->formatJudicial($judicial);
|
|
$formatted['type'] = 'judicial_precedent';
|
|
$formatted['assigned_at'] = $judicial->pivot->created_at;
|
|
return $formatted;
|
|
});
|
|
$items = $items->concat($judicials);
|
|
|
|
// 4. Process Legal Opinions
|
|
$opinions = $folder->legalOpinions->map(function ($opinion) {
|
|
$formatted = $this->formatOpinion($opinion);
|
|
$formatted['type'] = 'legal_opinion';
|
|
$formatted['assigned_at'] = $opinion->pivot->created_at;
|
|
return $formatted;
|
|
});
|
|
$items = $items->concat($opinions);
|
|
|
|
// Sort everything together based on when it was added to the folder!
|
|
$sortedItems = $items->sortByDesc('assigned_at')->values()->toArray();
|
|
|
|
return $this->success($sortedItems);
|
|
}
|
|
|
|
public function delete_folder($id)
|
|
{
|
|
$folder = Folder::where('id', $id)->where('user_id', auth()->id())->first();
|
|
|
|
if (!$folder) {
|
|
return $this->failed('پوشه یافت نشد', 'پوشه مورد نظر یافت نشد یا شما دسترسی ندارید', 404);
|
|
}
|
|
|
|
$folder->delete();
|
|
return $this->success([], 'حذف شد', 'پوشه با موفقیت حذف شد');
|
|
}
|
|
|
|
private function checkFolderOwnership($folder_id)
|
|
{
|
|
return Folder::where('id', $folder_id)->where('user_id', auth()->id())->exists();
|
|
}
|
|
|
|
public function delete_art($id, $art_id)
|
|
{
|
|
if (!$this->checkFolderOwnership($id)) return $this->failed([], 'عدم دسترسی', 403);
|
|
|
|
if (FolderArt::where('folder_id', $id)->where('art_id', $art_id)->count() == 0) {
|
|
return $this->failed([], 'مورد نظر یافت نشد', 404);
|
|
}
|
|
FolderArt::where('folder_id', $id)->where('art_id', $art_id)->delete();
|
|
return $this->success([], 'حذف شد', 'با موفقیت حذف شد');
|
|
}
|
|
|
|
public function delete_bylaw($id, $bylaw_id)
|
|
{
|
|
if (!$this->checkFolderOwnership($id)) return $this->failed([], 'عدم دسترسی', 403);
|
|
|
|
if (FolderBylaw::where('folder_id', $id)->where('bylaw_document_id', $bylaw_id)->count() == 0) {
|
|
return $this->failed([], 'مورد نظر یافت نشد', 404);
|
|
}
|
|
FolderBylaw::where('folder_id', $id)->where('bylaw_document_id', $bylaw_id)->delete();
|
|
return $this->success([], 'حذف شد', 'با موفقیت حذف شد');
|
|
}
|
|
|
|
public function delete_judicial($id, $judicial_id)
|
|
{
|
|
if (!$this->checkFolderOwnership($id)) return $this->failed([], 'عدم دسترسی', 403);
|
|
|
|
if (FolderJudicialPrecedent::where('folder_id', $id)->where('judicial_precedent_id', $judicial_id)->count() == 0) {
|
|
return $this->failed([], 'مورد نظر یافت نشد', 404);
|
|
}
|
|
FolderJudicialPrecedent::where('folder_id', $id)->where('judicial_precedent_id', $judicial_id)->delete();
|
|
return $this->success([], 'حذف شد', 'با موفقیت حذف شد');
|
|
}
|
|
|
|
public function delete_opinion($id, $opinion_id)
|
|
{
|
|
if (!$this->checkFolderOwnership($id)) return $this->failed([], 'عدم دسترسی', 403);
|
|
|
|
if (FolderLegalOpinion::where('folder_id', $id)->where('legal_opinion_id', $opinion_id)->count() == 0) {
|
|
return $this->failed([], 'مورد نظر یافت نشد', 404);
|
|
}
|
|
FolderLegalOpinion::where('folder_id', $id)->where('legal_opinion_id', $opinion_id)->delete();
|
|
return $this->success([], 'حذف شد', 'با موفقیت حذف شد');
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* FORMATTING HELPERS
|
|
* ----------------------------------------------------------------- */
|
|
|
|
private function isLockedForCurrentUserGeneric($item): bool
|
|
{
|
|
if (auth()->check() && auth()->user() && method_exists(auth()->user(), 'isSubscriber')) {
|
|
return !auth()->user()->isSubscriber() && (bool) ($item->is_locked ?? false);
|
|
}
|
|
return (bool) ($item->is_locked ?? false);
|
|
}
|
|
|
|
private function formatBylaw($item, $itemNodes = null)
|
|
{
|
|
$isLocked = $this->isLockedForCurrentUserGeneric($item);
|
|
$description = $item->description;
|
|
|
|
$cleanDesc = trim(str_replace([' ', '‌', "\r", "\n", "\t", ' '], '', strip_tags($description ?? '')));
|
|
|
|
if (strlen($cleanDesc) < 5) {
|
|
if ($itemNodes === null || (is_object($itemNodes) && $itemNodes->isEmpty())) {
|
|
$dbNodes = DB::table('bylaw_nodes')->where('document_id', $item->id)->count();
|
|
if ($dbNodes > 0) {
|
|
$itemNodes = DB::table('bylaw_nodes')->where('document_id', $item->id)->orderBy('sort_order', 'asc')->get();
|
|
}
|
|
}
|
|
$nodeContents = [];
|
|
if ($itemNodes) {
|
|
foreach ($itemNodes as $node) {
|
|
$content = trim(strip_tags($node->node_content ?? ''));
|
|
if (!empty($content)) {
|
|
$nodeContents[] = $content;
|
|
}
|
|
}
|
|
}
|
|
$description = implode("\n\n", $nodeContents);
|
|
}
|
|
|
|
return [
|
|
'id' => $item->id,
|
|
'title' => $item->title,
|
|
'category_name' => optional($item->category)->name,
|
|
'approval_authority_name' => optional($item->approvalAuthority)->name,
|
|
'approval_date' => $item->approval_date,
|
|
'promulgation_number' => $item->promulgation_number,
|
|
'description' => $isLocked ? null : mb_substr($description, 0, 100) . '...',
|
|
'is_locked' => $isLocked,
|
|
];
|
|
}
|
|
|
|
private function formatJudicial($item)
|
|
{
|
|
$isLocked = $this->isLockedForCurrentUserGeneric($item);
|
|
|
|
return [
|
|
'id' => $item->id,
|
|
'title' => $item->subject,
|
|
'ruling_number' => $item->ruling_number,
|
|
'ruling_date' => $item->ruling_date,
|
|
'text' => $isLocked ? null : mb_substr($item->full_text, 0, 100) . '...',
|
|
'issuing_authority' => $item->issuing_authority,
|
|
'category_name' => optional($item->category)->name,
|
|
'is_locked' => $isLocked,
|
|
];
|
|
}
|
|
|
|
private function formatOpinion($item)
|
|
{
|
|
$isLocked = $this->isLockedForCurrentUserGeneric($item);
|
|
|
|
return [
|
|
'id' => $item->id,
|
|
'title' => $item->subject,
|
|
'opinion_number' => $item->opinion_number,
|
|
'opinion_date' => $item->opinion_date,
|
|
'text' => $isLocked ? null : mb_substr($item->full_text, 0, 100) . '...',
|
|
'issuing_authority' => $item->issuing_authority,
|
|
'category_name' => optional($item->category)->name,
|
|
'is_locked' => $isLocked,
|
|
];
|
|
}
|
|
}
|