Initial commit

This commit is contained in:
Ahrom
2025-11-16 12:43:07 +03:30
commit 4bbe56b83f
16778 changed files with 1914371 additions and 0 deletions

24
app/Console/Kernel.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*/
protected function schedule(Schedule $schedule): void
{
// $schedule->command('inspire')->hourly();
}
/** php artisan words:process */
protected function commands(): void
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* The list of the inputs that are never flashed to the session on validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->reportable(function (Throwable $e) {
//
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Exports;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class BlogImagesExport implements FromCollection, WithHeadings
{
protected $data;
public function __construct(Collection $data)
{
$this->data = $data;
}
public function collection()
{
return $this->data;
}
public function headings(): array
{
return [
'Blog ID',
'Image Source',
'Width',
'Height',
];
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\Blog;
use App\Http\Controllers\Controller;
use Morilog\Jalali\Jalalian;
use Carbon\Carbon;
class BlogLast extends Controller
{
public function yesterdayPosts()
{
try {
$blogs = Blog::where('status' , 1)->orderByDesc('created_at')->get()->take(20);
$blogArray = [];
foreach ($blogs as $blog) {
$tehranTime = Carbon::parse($blog->created_at)->setTimezone('Asia/Tehran');
$blogArray[] = [
'success' => true,
'title' => $blog->subject,
'published_at' => jalaliDate($tehranTime, '%d %B، %Y'),
'published_at_time' => $tehranTime->format('H:i'),
'original_time' => $blog->created_at->format('H:i'),
];
}
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'مشکلی در دریافت اطلاعات پیش آمده: ' . $e->getMessage()
], 500);
}
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\Blog;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class BlogsController extends Controller
{
public function index()
{
try {
$blogs = Blog::where('notBlog' , null)->where('status' , 1)->orderByDesc('created_at')->get()->take(5);
$blogArray= [] ;
foreach ($blogs as $key => $blog) {
$blogArray []= [
'success' => true,
'title' => $blog->subject,
'published_at' => $blog->created_at,
];
}
return response()->json([
'data' => $blogArray ,
'message' => 'اطلاعات با موفقیت ارسال شد'
], 200);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'مشکلی در دریافت اطلاعات پیش آمده: ' . $e->getMessage()
], 500);
}
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\Blog;
use App\Models\Category;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class NewsAhrom extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
try {
$news_ahrom = Blog::where('notBlog' , 1)->where('status' , 1)->orderByDesc('created_at')->get()->take(5);
$news_ahromArray= [] ;
foreach ($news_ahrom as $key => $new) {
$check = Category::where('id' , $new['category_array'])->first();
if ( $check->slug == 'ahrom') {
$news_ahromArray []= [
'success' => true,
'title' => $blog->subject,
'published_at' => $blog->created_at,
];
}
}
return response()->json([
'data' => $news_ahromArray ,
'message' => 'اطلاعات با موفقیت ارسال شد'
], 200);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'مشکلی در دریافت اطلاعات پیش آمده: ' . $e->getMessage()
], 500);
}
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\Blog;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class NewsController extends Controller
{
public function index()
{
try {
$news = Blog::where('notBlog' , 1)->where('status' , 1)->orderByDesc('created_at')->get()->take(5);
$newsArray= [] ;
foreach ($news as $key => $new) {
$newsArray []= [
'success' => true,
'title' => $new->subject,
'published_at' => $new->created_at,
];
}
return response()->json([
'data' => $newsArray ,
'message' => 'اطلاعات با موفقیت ارسال شد'
], 200);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'مشکلی در دریافت اطلاعات پیش آمده: ' . $e->getMessage()
], 500);
}
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace App\Http\Controllers;
use App\Models\Blog;
use Illuminate\Support\Facades\Log;
class BlogController extends Controller
{
public function fixContentIds()
{
$blogs = Blog::withoutGlobalScope('filtered')->get();
$updatedCount = 0;
foreach ($blogs as $blog) {
$oldContent = $blog->content;
$oldImage = $blog->image;
$contentChanged = false;
$imageChanged = false;
$patterns = [
'/https?:\/\/ahrom\.net\/mag\/images\//',
'/\/\/ahrom\.net\/mag\/images\//',
'/http:\/\/www\.ahrom\.net\/mag\/images\//',
'/https:\/\/www\.ahrom\.net\/mag\/images\//',
'/ahrom\.net\/mag\/images\//'
];
$newContent = preg_replace(
$patterns,
'https://ahromstorage.ir/ahrominvest/mag/images/',
$oldContent
);
$newContent = preg_replace_callback(
'/(https:\/\/ahromstorage\.ir\/ahrominvest\/mag\/images\/.*?)\.webp/i',
function($matches) {
return str_replace('.webp', '.jpg', $matches[0]);
},
$newContent
);
$newImage = $oldImage;
if (!empty($oldImage) && preg_match('/\.webp$/i', $oldImage)) {
$newImage = preg_replace('/\.webp$/i', '.jpg', $oldImage);
$imageChanged = true;
}
if ($newContent !== $oldContent) {
$contentChanged = true;
}
if ($contentChanged || $imageChanged) {
$blog->content = $newContent;
if ($imageChanged) {
$blog->image = $newImage;
}
$blog->save();
$updatedCount++;
$changes = [];
if ($contentChanged) $changes[] = 'content';
if ($imageChanged) $changes[] = 'image';
Log::info("Updated " . implode(' and ', $changes) . " in blog ID: {$blog->id}");
}
}
return response()->json([
'status' => 'completed',
'updated_count' => $updatedCount,
'total_blogs' => count($blogs),
'message' => $updatedCount > 0
? "Successfully updated {$updatedCount} blogs (content and/or image fields)"
: 'No matching URLs or webp images found to replace'
]);
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}

View File

@@ -0,0 +1,149 @@
<?php
namespace App\Http\Controllers;
use App\Models\Blog;
use App\Models\Category;
use Illuminate\Http\Request;
class SitemapController extends Controller
{
public function index()
{
ob_clean();
$blogs = Blog::query()
->where('status', 1)
->whereNull('notBlog')
->orderBy('published_at', 'desc')
->paginate(500, ['*'], 'page', $page ?? 1)
->withQueryString();
$news = Blog::query()
->where('status', 1)
->where('notBlog', 1)
->orderBy('published_at', 'desc')
->paginate(500, ['*'], 'page', $page ?? 1)
->withQueryString();
$totalPagespost = $blogs->lastPage();
$totalPagenews = $news->lastPage();
return response()->view('sitemap.index' , ['news' => $totalPagenews , 'countNews' => count($news) , 'blogs' => $totalPagespost , 'countBlogs' => count($blogs) ])->header('Content-Type', 'text/xml');
}
public function posts($page = null)
{
if ($page == 1) {
return redirect()->route('post.sitemap');
}
ob_clean();
$blogs = Blog::query()
->where('status', 1)
->whereNull('notBlog')
->orderBy('published_at', 'desc')
->paginate(500, ['*'], 'page', $page ?? 1)
->withQueryString();
$blogImages = [];
foreach ($blogs as $blog) {
$content = $blog->content;
if (empty($content)) {
continue;
}
$pattern = '/<img[^>]+src="([^">]+)"/i';
preg_match_all($pattern, $content, $matches);
$extractedImages = $matches[1] ?? [];
$blogImages[$blog->id] = $extractedImages;
}
return response()->view('sitemap.posts', compact('blogs', 'blogImages'))->header('Content-Type', 'text/xml');
}
public function news($page = null)
{
if ($page == 1) {
return redirect()->route('news.sitemap');
}
ob_clean();
$news = Blog::query()
->where('status', 1)
->where('notBlog', 1)
->orderBy('published_at', 'desc')
->paginate(500, ['*'], 'page', $page ?? 1)
->withQueryString();
$blogImages = [];
foreach ($news as $blog) {
$content = $blog->content;
if (empty($content)) {
continue;
}
$pattern = '/<img[^>]+src="([^">]+)"/i';
preg_match_all($pattern, $content, $matches);
$extractedImages = $matches[1] ?? [];
$blogImages[$blog->id] = $extractedImages;
}
return response()->view('sitemap.news', compact('news', 'blogImages'))->header('Content-Type', 'text/xml');
}
public function page()
{
ob_clean();
$blogs = Blog::all();
$latestTimestamp = null;
foreach ($blogs as $blog) {
$createdTimestamp = strtotime($blog->published_at);
$updatedTimestamp = strtotime($blog->updated_at);
if ($latestTimestamp === null || $createdTimestamp > $latestTimestamp || $updatedTimestamp > $latestTimestamp) {
$latestTimestamp = max($createdTimestamp, $updatedTimestamp);
}
}
$latestCarbon = \Carbon\Carbon::createFromTimestamp($latestTimestamp, 'Asia/Tehran');
return response()->view('sitemap.page', ['latestTimestamp' => $latestCarbon])->header('Content-Type', 'text/xml');
}
public function postcategory()
{
ob_clean();
$categories = Category::where('parent' , null )->get();
return response()->view('sitemap.postcategory', ['categories' => $categories])->header('Content-Type', 'text/xml');
}
public function newscategory()
{
ob_clean();
$categories = Category::all();
return response()->view('sitemap.newscategory', ['categories' => $categories])->header('Content-Type', 'text/xml');
}
}

71
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,71 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array<int, class-string|string>
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
* The application's middleware aliases.
*
* Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
*
* @var array<string, class-string|string>
*/
protected $middlewareAliases = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'detail' => \App\Http\Middleware\DetailMiddleware::class,
'ensureslash' =>\App\Http\Middleware\EnsureSlashAtEnd::class,
];
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*/
protected function redirectTo(Request $request): ?string
{
return $request->expectsJson() ? null : route('panel.login');
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array<int, string>
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureSlashAtEnd
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->ajax()) {
return $next($request);
}
$path = $request->path();
$query = $request->getQueryString();
if ($path !== '' && !str_ends_with($request->getRequestUri(), '/')) {
$newUrl = $request->getSchemeAndHttpHost().'/'.$path.'/';
if ($query) {
$newUrl .= '?'.$query;
}
dd(redirect()->to('/'.$newUrl, 301) ,$newUrl );
return redirect()->to('/'.$newUrl, 301);
}
return $next($request);
}
protected function isLivewireRequest(Request $request): bool
{
return str_starts_with($request->path(), 'livewire/') ||
$request->hasHeader('X-Livewire');
}
protected function isStaticFile(Request $request): bool
{
$path = $request->getPathInfo();
return preg_match('/\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$/', $path);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
class PreventRequestsDuringMaintenance extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array<int, string>
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string ...$guards): Response
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array<int, string>
*/
protected $except = [
'current_password',
'password',
'password_confirmation',
];
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustHosts as Middleware;
class TrustHosts extends Middleware
{
/**
* Get the host patterns that should be trusted.
*
* @return array<int, string|null>
*/
public function hosts(): array
{
return [
$this->allSubdomainsOfApplicationUrl(),
];
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array<int, string>|string|null
*/
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
use App\Models\History;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class UserHitory
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
History::create(['user_agent' => $request->userAgent(), 'ip' => $request->ip(),'blog_link'=>$request->url()]);
return $next($request);
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Routing\Middleware\ValidateSignature as Middleware;
class ValidateSignature extends Middleware
{
/**
* The names of the query string parameters that should be ignored.
*
* @var array<int, string>
*/
protected $except = [
// 'fbclid',
// 'utm_campaign',
// 'utm_content',
// 'utm_medium',
// 'utm_source',
// 'utm_term',
];
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
*/
protected $except = [
'livewire/*'
];
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class DetailMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$slug = $request->slug;
if ( $slug == 'dictionary' && strpos($slug, 'dictionary') == 0) {
return redirect()->route('dictionary.main');
}
return $next($request);
}
}

View File

@@ -0,0 +1,514 @@
<?php
namespace App\Livewire;
use App\Models\Blog;
use App\Models\Category;
use Illuminate\Support\Str;
use Livewire\Component;
use Livewire\WithPagination;
use Livewire\Attributes\Layout;
use Illuminate\Support\Facades\URL;
use Illuminate\Pagination\Paginator;
class CategoryBlog extends Component
{
use WithPagination;
public $slug;
public $title;
public $page;
public $category;
public $is_news = false;
public $categories = [];
public $categoriesNotBlog = [];
public $blogOrNotBlog;
public $parentCategories = [];
public $childCategories = [];
public $subChildCategories = [];
public $selectedCategoryId = null;
public $selectedTopLevelCategoryId = null;
public $selectedSecondLevelCategory = null;
public $topParent = null;
public $selectedUrl;
public $allParentsWithChildren;
public $selectedThirdLevelCategory;
public function mount($slug = null, $page = 1)
{
$this->slug = $slug;
$this->page = $page;
$this->is_news = request()->is('category/news*');
// گرفتن همه دسته‌های والد (باکس ۱)
if ($this->is_news) {
$operation = "!=";
} else {
$operation = "=";
}
$this->parentCategories = Category::where('parent_id', $operation, null)
->whereNull('parent_below')
->where('status', 1)
->where('is_news', $this->is_news ? 1 : 0)
->orderBy('title')
->get();
if ($this->slug == 'all') {
$this->category = [
"id" => 0,
"title" => "همه",
"slug" => "all",
"is_news" => 0,
"status" => 1,
];
$this->childCategories = collect();
$this->subChildCategories = collect();
// مقداردهی متغیرهای انتخاب شده
$this->selectedCategoryId = null;
$this->selectedTopLevelCategoryId = null;
$this->selectedSecondLevelCategory = null;
} else {
$query = Category::query();
if ($this->is_news) {
$query->where('is_news', 1);
} else {
$query->where('is_news', 0);
}
$category = $query->with('parent')->where('slug', $this->slug)->first();
if (!$category) {
abort(404, 'دسته‌بندی مورد نظر یافت نشد');
}
$this->category = $category;
// پیدا کردن والد سطح اول (top-level parent) دسته انتخاب شده
$topParent = $category;
while ($topParent && ($topParent->parent_id !== null || $topParent->parent_below !== null)) {
if ($topParent->parent_id !== null) {
$topParent = Category::find($topParent->parent_id);
} elseif ($topParent->parent_below !== null) {
$topParent = Category::find($topParent->parent_below);
} else {
break;
}
}
$this->topParent = $topParent;
$this->selectedCategoryId = $category->id; // دسته انتخاب شده (باکس سوم یا خودش)
$this->selectedTopLevelCategoryId = $topParent ? $topParent->id : null;
if (!$this->is_news) {
// باکس دوم: زیردسته‌های والد سطح اول
if ($topParent) {
$this->childCategories = Category::where(function($query) use ($topParent) {
$query->where('parent_id', $topParent->id)
->orWhere('parent_below', $topParent->id);
})
->where('status', 1)
->orderBy('title')
->get();
if ($category->id == $topParent->id) {
// دسته انتخاب شده، دسته والد سطح اول است (باکس سوم خالی)
$this->selectedSecondLevelCategory = null;
$this->subChildCategories = collect();
} elseif ($this->childCategories->contains('id', $category->id)) {
// دسته انتخاب شده، یک زیردسته از باکس دوم است
$this->selectedSecondLevelCategory = $category;
$this->subChildCategories = Category::where(function($query) use ($category) {
$query->where('parent_id', $category->id)
->orWhere('parent_below', $category->id);
})
->where('status', 1)
->orderBy('title')
->get();
} else {
// دسته انتخاب شده، زیردسته ای از باکس سوم است (یا پایین‌تر)
// باید والد سطح دوم اون دسته رو پیدا کنیم تا باکس سوم درست نمایش داده بشه
$secondLevelParent = $category->parent_id ? Category::find($category->parent_id) : Category::find($category->parent_below);
if ($secondLevelParent) {
$this->selectedSecondLevelCategory = $secondLevelParent;
$this->subChildCategories = Category::where(function($query) use ($secondLevelParent) {
$query->where('parent_id', $secondLevelParent->id)
->orWhere('parent_below', $secondLevelParent->id);
})
->where('status', 1)
->orderBy('title')
->get();
} else {
$this->selectedSecondLevelCategory = null;
$this->subChildCategories = collect();
}
if ($this->selectedSecondLevelCategory && $category->id != $this->selectedSecondLevelCategory->id) {
$this->selectedThirdLevelCategory = $category;
} else {
$this->selectedThirdLevelCategory = null;
}
}
} else {
$this->childCategories = collect();
$this->subChildCategories = collect();
$this->selectedSecondLevelCategory = null;
}
} else {
$this->subChildCategories = collect();
$this->childCategories = collect();
$this->selectedTopLevelCategoryId = $category->id ?? null;
}
}
$this->title = $this->category['title'];
$this->loadCategories();
//
// // اگر دسته انتخاب شده والد است (parent_id و parent_below هر دو null)
// if ($category->parent_id === null && $category->parent_below === null) {
// // باکس ۲: زیردسته‌های دسته والد انتخاب شده
// $this->childCategories = Category::where(function($query) use ($category) {
// $query->where('parent_id', $category->id)
// ->orWhere('parent_below', $category->id);
// })
// ->where('status', 1)
// ->orderBy('title')
// ->get();
//
// $this->subChildCategories = collect();
// } else {
// // دسته انتخاب شده زیردسته است
// // باکس ۲: زیردسته‌های دسته والد آن زیردسته (پیدا کردن دسته والد)
// $parent = Category::find($category->parent_id ?: $category->parent_below);
// if ($parent) {
// $this->childCategories = Category::where(function($query) use ($parent) {
// $query->where('parent_id', $parent->id)
// ->orWhere('parent_below', $parent->id);
// })
// ->where('status', 1)
// ->orderBy('title')
// ->get();
// } else {
// $this->childCategories = collect();
// }
//
// // باکس ۳: زیردسته‌های زیردسته انتخاب شده
// $this->subChildCategories = Category::where(function($query) use ($category) {
// $query->where('parent_id', $category->id)
// ->orWhere('parent_below', $category->id);
// })
// ->where('status', 1)
// ->orderBy('title')
// ->get();
// }
// }
// $this->title = $this->category['title'];
// $this->loadCategories();
}
protected function loadCategories()
{
// if ($this->category['slug'] == 'news') {
//
// $this->categories = Category::where('is_news', ($this->is_news ? 1 : 0))
// ->where('parent_id' , '!=' , null)
// ->whereNull('parent_below')
// ->where('status', 1)
// ->orderBy('title')
// ->get();
// }elseif($this->category['slug'] == 'all'){
// $this->categories = Category::where('is_news', ($this->is_news ? 1 : 0))
// ->whereNull('parent_id')
// ->whereNull('parent_below')
// ->where('status', 1)
// ->orderBy('title')
// ->get();
// } else {
//// $this->categories = collect([$this->category]);
// if ($this->is_news) {
// $operation = "!=";
// } else {
// $operation = "=";
// }
// $this->categories = Category::with('parent')->where('is_news', ($this->is_news ? 1 : 0))
// ->where('parent_id', $operation, null)
// ->whereNull('parent_below')
// ->where('status', 1)
// ->orderBy('title')
// ->get();
//
// $this->categoriesNotBlog = Category::where(function($query) {
// $query->where('parent_id', $this->category['id'])
// ->orWhere('parent_below', $this->category['id']);
// })
// ->where('status', 1)
// ->orderBy('title')
// ->get();
// }
}
public function goToCategory($catId, $is_news)
{
$this->slug = null;
if (!$is_news && $catId == 0) {
$this->slug = 'all';
} elseif ($is_news && $catId == 0) {
$this->slug = 'news';
} else {
$SSCategory = Category::findOrFail($catId);
$this->slug = $SSCategory->slug;
}
$this->page = 1;
$this->is_news = $is_news;
// گرفتن همه دسته‌های والد (باکس ۱)
if ($this->is_news) {
$operation = "!=";
} else {
$operation = "=";
}
$this->parentCategories = Category::where('parent_id', $operation, null)
->whereNull('parent_below')
->where('status', 1)
->where('is_news', $this->is_news ? 1 : 0)
->orderBy('title')
->get();
$allParentsWithChildren = Category::where('parent_id', $operation, null)
->whereNull('parent_below')
->where('status', 1)
->where('is_news', $this->is_news ? 1 : 0)
->orderBy('title')
->with('childrenRecursive')
->get();
if ($this->slug == 'all') {
$this->category = collect([
"id" => 0,
"title" => "همه",
"slug" => "all",
"is_news" => 0,
"status" => 1,
]);
$this->childCategories = collect();
$this->subChildCategories = collect();
// مقداردهی متغیرهای انتخاب شده
$this->selectedCategoryId = null;
$this->selectedTopLevelCategoryId = null;
$this->selectedSecondLevelCategory = null;
} else {
$query = Category::query();
if ($this->is_news) {
$query->where('is_news', 1);
} else {
$query->where('is_news', 0);
}
$category = $query->with('parent')->where('slug', $this->slug)->first();
if (!$category) {
abort(404, 'دسته‌بندی مورد نظر یافت نشد');
}
$this->category = $category;
// پیدا کردن والد سطح اول (top-level parent) دسته انتخاب شده
$topParent = $category;
while ($topParent && ($topParent->parent_id !== null || $topParent->parent_below !== null)) {
if ($topParent->parent_id !== null) {
$topParent = Category::find($topParent->parent_id);
} elseif ($topParent->parent_below !== null) {
$topParent = Category::find($topParent->parent_below);
} else {
break;
}
}
$this->topParent = $topParent;
$this->selectedCategoryId = $category->id; // دسته انتخاب شده (باکس سوم یا خودش)
$this->selectedTopLevelCategoryId = $topParent ? $topParent->id : null;
if (!$this->is_news) {
// باکس دوم: زیردسته‌های والد سطح اول
if ($topParent) {
$this->childCategories = Category::where(function($query) use ($topParent) {
$query->where('parent_id', $topParent->id)
->orWhere('parent_below', $topParent->id);
})
->where('status', 1)
->orderBy('title')
->get();
if ($category->id == $topParent->id) {
// دسته انتخاب شده، دسته والد سطح اول است (باکس سوم خالی)
$this->selectedSecondLevelCategory = null;
$this->subChildCategories = collect();
} elseif ($this->childCategories->contains('id', $category->id)) {
// دسته انتخاب شده، یک زیردسته از باکس دوم است
$this->selectedSecondLevelCategory = $category;
$this->subChildCategories = Category::where(function($query) use ($category) {
$query->where('parent_id', $category->id)
->orWhere('parent_below', $category->id);
})
->where('status', 1)
->orderBy('title')
->get();
} else {
// دسته انتخاب شده، زیردسته ای از باکس سوم است (یا پایین‌تر)
// باید والد سطح دوم اون دسته رو پیدا کنیم تا باکس سوم درست نمایش داده بشه
$secondLevelParent = $category->parent_id ? Category::find($category->parent_id) : Category::find($category->parent_below);
if ($secondLevelParent) {
$this->selectedSecondLevelCategory = $secondLevelParent;
$this->subChildCategories = Category::where(function($query) use ($secondLevelParent) {
$query->where('parent_id', $secondLevelParent->id)
->orWhere('parent_below', $secondLevelParent->id);
})
->where('status', 1)
->orderBy('title')
->get();
} else {
$this->selectedSecondLevelCategory = null;
$this->subChildCategories = collect();
}
}
} else {
$this->childCategories = collect();
$this->subChildCategories = collect();
$this->selectedSecondLevelCategory = null;
}
} else {
$this->subChildCategories = collect();
$this->childCategories = collect();
$this->selectedTopLevelCategoryId = $category->id ?? null;
}
}
$this->title = $this->category['title'];
$this->loadCategories();
return true;
}
public function loadCategoriesAndChilds ()
{
if ($this->is_news) {
$operation = "!=";
} else {
$operation = "=";
}
$allParentsWithChildren = Category::where('parent_id', $operation, null)
->whereNull('parent_below')
->where('status', 1)
->where('is_news', $this->is_news ? 1 : 0)
->orderBy('title')
->with('childrenRecursive')
->get();
return response()->json($allParentsWithChildren);
}
public function generateSlugAndNavigate($catId, $isNews)
{
$slug = null;
if (!$isNews && $catId == 0) {
$slug = 'all';
} elseif ($isNews && $catId == 0) {
$slug = 'news';
} else {
$category = Category::findOrFail($catId);
$slug = $category->slug;
}
// Generate the target URL
$url = $isNews
? $slug != 'news' ? route('NewsCategory.show', ['slug' => $slug]) . "/" : route('NewsCategory.index').'/'
: route('CategoryBlog.index', ['slug' => $slug]) . "/";
// Emit event to frontend for Livewire navigate
$this->dispatch('navigate-to', $url);
return;
}
#[Layout('components.layouts.app')]
public function render()
{
if ($this->page == 1 && str_contains(URL::current(), '/page/1')) {
if ($this->is_news) {
return redirect()->route('NewsCategory.index', ['slug' => $this->slug]);
} else {
return redirect()->route('CategoryBlog.index', ['slug' => $this->slug]);
}
}
$categoryIds = [];
if ($this->slug == 'all') {
$this->blogOrNotBlog = 'blog';
$blogs = Blog::query()
->where('status', 1)
->whereNull('notBlog')
->orderByDesc('published_at')
->paginate(18, ['*'], 'page', $this->page);
} else {
$category = $this->category;
if ($category instanceof Category) {
$categoryIds = $category->getAllDescendantIds();
$categoryIds[] = $category->id;
} else {
$categoryIds = [$category['id']];
}
if ($this->is_news) {
$this->blogOrNotBlog = 'notblog';
$blogs = Blog::query()
->where('status', 1)
->where('notBlog', 1)
->where(function ($query) use ($categoryIds) {
$query->where(function ($q) use ($categoryIds) {
foreach ($categoryIds as $categoryId) {
$q->orWhereJsonContains('category_array', (string)$categoryId);
}
});
})
->orderByDesc('published_at')
->paginate(18, ['*'], 'page', $this->page);
} else {
$this->blogOrNotBlog = 'blog';
$blogs = Blog::query()
->where('status', 1)
->whereNull('notBlog')
->where(function ($query) use ($categoryIds) {
$query->where(function ($q) use ($categoryIds) {
foreach ($categoryIds as $categoryId) {
$q->orWhereJsonContains('category_array', (string)$categoryId);
}
});
})
->orderByDesc('published_at')
->paginate(18, ['*'], 'page', $this->page);
}
}
if ($this->is_news && isset($this->category['slug']) && $this->category['slug'] == 'news') {
$this->blogOrNotBlog = 'notblog';
$blogs = Blog::query()
->where('status', 1)
->where('notBlog', 1)
->orderByDesc('published_at')
->paginate(18, ['*'], 'page', $this->page);
}
$blogs->setPageName('page');
if ($this->is_news) {
$blogs->setPath(route('NewsCategory.index', ['slug' => $this->slug]));
} else {
$blogs->setPath(route('CategoryBlog.index', ['slug' => $this->slug]));
}
Paginator::defaultView('custom-pagination');
return view('livewire.category-blog', [
'blogs' => $blogs,
]);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public function render()
{
return view('livewire.create-post');
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\Layout;
use App\Models\Dictionary as ModelDirection;
class Dictionary extends Component
{
public $dictionareis;
#[Layout('components.layouts.app')]
public function render()
{
$this->dictionareis = ModelDirection::orderBy('id', 'desc')->get();
return view('livewire.dictionary');
}
}

118
app/Livewire/Home.php Normal file
View File

@@ -0,0 +1,118 @@
<?php
namespace App\Livewire;
use App\Models\Blog;
use Livewire\Component;
use App\Models\Category;
use Illuminate\Http\Request;
use Livewire\Attributes\Layout;
use Illuminate\Support\Facades\Http;
class Home extends Component
{
public $image;
public $blogs;
public $news;
public $blogs2;
public $blog_array = [];
public $news_array = [];
public $categories = [];
public $categorieNews = [];
public $lastNewsPosts = [];
public $lastNewsArticles = [];
public $lightmags = [];
public $lightnews = [];
public $selectedCategoryPosts = null;
public $selectedCategoryNews = null;
public $selectedRoutePosts = null;
public $selectedRouteNews = null;
public function mount(Request $request)
{
$allBlogs = Blog::where('status', 1)->orderBy('published_at', 'desc')->get();
$this->lightmags = $allBlogs->whereNull('notBlog')->take(50);
$this->lightnews = $allBlogs->where('notBlog', 1)->take(50);
$allCategroyBuilder = Category::where('status', 1);
$allCategroyNewsBuilder = Category::where('status', 1);
$this->blogs2 = Blog::where('status', 1)->where('notBlog', null)->where('chosen', 1)->orderBy('created_at', 'desc')->get()->take(5);
$this->lastNewsPosts = $allBlogs->whereNull('notBlog')->take(4);
$this->lastNewsArticles = $allBlogs->where('notBlog', 1)->take(4);
$this->blogs = $allBlogs->where('chosen', 0)->where('notBlog', null);
$this->news = $allBlogs->where('chosen', 0)->where('notBlog', 1);
$this->categories = $allCategroyBuilder->with(['blogs' => function ($q) {
$q->where('status', 1);
}])->where('parent_below', null)->where('parent_id', null)->where('parent', null)->get();
$this->categorieNews = $allCategroyNewsBuilder->where('is_news', 1)->where('parent_below', null)->where('parent_id', '!=', null)->where('parent', null)->get();
}
public function selectCategory($categoryId, $type = 'posts')
{
$category = Category::find($categoryId);
if ($type === 'posts') {
$this->selectedCategoryPosts = $categoryId;
if (isset($category)) {
$this->selectedRoutePosts = route('CategoryBlog.index', ['slug' => $category->slug]) . "/";
}
} else {
$this->selectedCategoryNews = $categoryId;
if (isset($category)) {
$this->selectedRouteNews = route('NewsCategory.show', ['slug' => $category->slug]) . "/";
}
}
}
public function resetCategory($type = 'posts')
{
$this->selectedRoutePosts = null;
$this->selectedRouteNews = null;
if ($type === 'posts') {
$this->selectedCategoryPosts = null;
} else {
$this->selectedCategoryNews = null;
}
}
public function getCategoryItems($categoryId = null, $type = 'posts')
{
if ($type === 'posts') {
$query = Blog::where('status', 1)->whereNull('notBlog');
if ($categoryId) {
$query->where(function($q) use ($categoryId) {
$q->where('category_id', $categoryId)
->orWhereJsonContains('category_array', (string)$categoryId);
});
}
return $query->orderByDesc('published_at')
->take(4)
->get();
} else {
$query = Blog::where('status', 1)->where('notBlog', 1);
if ($categoryId) {
$query->where(function($q) use ($categoryId) {
$q->where('category_id', $categoryId)
->orWhereJsonContains('category_array', (string)$categoryId);
});
}
return $query->orderByDesc('published_at')
->take(4)
->get();
}
}
#[Layout('components.layouts.app')]
public function render()
{
return view('livewire.home');
}
}

BIN
app/Livewire/Home/0.tar.gz Normal file

Binary file not shown.

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Livewire\Home\Auth;
use Livewire\Component;
class LoginPage extends Component
{
public function render()
{
return view('livewire.home.auth.login-page');
}
}

View File

@@ -0,0 +1,195 @@
<?php
namespace App\Livewire\Home;
use App\Models\Blog;
use App\Models\Comment;
use Livewire\Component;
use App\Models\Category;
use Livewire\Attributes\On;
use Livewire\Attributes\Rule;
use Livewire\Attributes\Layout;
use Illuminate\Support\Facades\Cookie;
class DetailNoBlog extends Component
{
public $categoryparentslug;
public $categoryunderparentslug;
public $slug;
public $blog;
public $blog_id;
public $like_status;
public $comments;
public $comment_name = 'کاربر';
#[Rule('required')]
public $comment_message;
public $comment_name_reply = 'کاربر';
public $comment_message_reply;
public $lastNews;
public $lastNews2;
public $specialNews;
public $questions = [];
public $breadcrumbs = [];
public $cookie;
public $pendingComments = [];
public function mount($categoryparentslug = null, $categoryunderparentslug = null, $slug = null)
{
$this->categoryparentslug = $categoryparentslug;
$this->categoryunderparentslug = $categoryunderparentslug;
$this->slug = $slug;
if (is_null($this->categoryparentslug) || is_null($this->categoryunderparentslug) || is_null($this->slug)) {
return abort('404');
}
if (Blog::where('slug', $this->slug)->first()) {
$this->blog = Blog::where('slug', $this->slug)->where('status', 1)->first();
if (is_null($this->blog)) {
$softDeletedBlog = Blog::withTrashed()->where('slug', $slug)->whereNotNull('deleted_at')->first();
if (!is_null($softDeletedBlog)) {
return abort(410);
} else {
return abort(404);
}
}
$this->blog_id = $this->blog->id;
} else {
return abort('404');
}
$this->categoryunderparentslug = Category::where('slug', $this->categoryunderparentslug)->first();
$this->blog->increment('views');
$this->slug = $slug;
$this->blog_id = $this->blog->id;
$this->lastNews = Blog::query()->where('status', 1)->where('notBlog', null)->orderBy('created_at', 'desc')->get()->take(5);
$this->lastNews2 = Blog::query()->where('status', 1)->where('notBlog', 1)->orderBy('created_at', 'desc')->get()->take(5);
$this->specialNews = Blog::query()->where('status', 1)->where('notBlog', null)->where('chosen', 1)->orderBy('created_at', 'desc')->get()->take(5);
}
#[Rule('required')]
public $image_url;
public function comment()
{
$this->validate();
$comment_id = Comment::create(['name' => $this->comment_name, 'message' => $this->comment_message, 'blog_id' => $this->blog_id, 'ip' => request()->ip(), 'user_agent' => request()->userAgent(), 'image_url' => $this->image_url]);
$this->comment_message = null;
$this->comment_name = 'کاربر';
$this->dispatch('reset');
$newComment = Comment::find($comment_id->id);
$this->storeCommentInCookie($newComment->toArray());
}
public function reply($id, $parent_id)
{
if ($this->comment_message_reply) {
$comment_id = Comment::create(['name' => $this->comment_name_reply, 'message' => $this->comment_message_reply, 'blog_id' => $this->blog_id, 'ip' => request()->ip(), 'user_agent' => request()->userAgent(), 'parent_id' => $id, 'type' => 2, 'image_url' => $this->image_url]);
Comment::where('id', $id)->increment('reply');
$this->comment_message_reply = null;
$this->comment_name_reply = 'کاربر';
$this->dispatch('reset');
$this->storeCommentInCookie($comment_id->toArray());
}
}
private function storeCommentInCookie($comment)
{
$comments = json_decode(Cookie::get('pending_comments', '[]'), true);
$comments[] = $comment;
Cookie::queue('pending_comments', json_encode($comments), 60 * 24 * 7);
}
public $loadedimage;
public $loadedtitle;
public $loadedslug;
public $loadedpreview;
public $loadedContent;
public $isLoading = false;
#[On('loadBlogContent')]
public function loadBlogContent($slug)
{
$this->isLoading = true;
$blog = Blog::where('slug', $slug)->first();
if ($blog) {
$this->loadedContent = $blog->subject;
$this->loadedslug = $slug;
$this->loadedtitle = $blog->subject;
$this->loadedimage = $blog->image;
$this->loadedpreview = $blog->preview;
$this->dispatch('blogContentLoaded', [
'slug' => $slug,
'title' => $blog->subject,
'image' => $blog->image,
'preview' => $blog->preview,
]);
} else {
$this->loadedContent = 'محتوا یافت نشد.';
}
$this->isLoading = false;
}
#[Layout('components.layouts.app')]
public function render()
{
$this->comments = Comment::query()
->where('blog_id', $this->blog_id)
->where('status', 1)
->where('type', 0)
->whereHas('blog', function ($q) {
$q->where('status', 1);
})
->get();
$this->like_status = session()->get('blog-' . $this->blog_id);
$this->pendingComments = json_decode(Cookie::get('pending_comments', '[]'), true);
foreach ($this->pendingComments as $key => $comment) {
if ($this->blog->id != $comment['blog_id']) {
unset($this->pendingComments[$key]);
} else {
$checkCookie = Comment::where('id', $comment['id'])->first();
if (!is_null($checkCookie)) {
if ($checkCookie->status == 1 || $checkCookie->status == 2) {
Cookie::queue(Cookie::forget('pending_comments'));
break;
}
}
}
}
$pendingCommentsCollection = collect($this->pendingComments)->map(function ($comment) {
if (!isset($comment['id'])) {
$comment['id'] = 'temp_' . uniqid();
}
$model = new Comment();
$model->forceFill($comment);
return $model;
});
$combinedCollection = $this->comments->merge($pendingCommentsCollection);
$flattenedArray = $combinedCollection
->map(function ($comment) {
return $comment->toArray();
})
->all();
usort($flattenedArray, function ($a, $b) {
return $a['id'] <=> $b['id'];
});
$this->comments = $flattenedArray;
return view('livewire.home.detail-no-blog');
}
}

View File

@@ -0,0 +1,233 @@
<?php
namespace App\Livewire\Home;
use App\Models\Ads;
use App\Models\Blog;
use App\Models\Page;
use App\Models\Comment;
use Livewire\Component;
use Livewire\Attributes\On;
use Livewire\Attributes\Rule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Session;
use Illuminate\Support\Facades\Cookie;
class DetailPage extends Component
{
public $blog;
public $slug;
public $blog_id;
public $like_status;
public $comments;
public $comment_name = 'کاربر';
#[Rule('required')]
public $comment_message;
public $comment_name_reply = 'کاربر';
public $comment_message_reply;
public $lastNews;
public $lastNews2;
public $specialNews;
public $questions = [];
public $breadcrumbs = [];
public $allComments = [];
#[Rule('required')]
public $image_url;
public $cookie;
public $pendingComments = [];
public $ads = [];
public $ip = '';
public $adscount = [];
public function mount($slug)
{
$this->blog = Blog::with('questions') ->where('slug', $slug) ->where('status', 1) ->first();
if (is_null($this->blog)) {
$softDeletedBlog = Blog::withTrashed()->where('slug', $slug)->whereNotNull('deleted_at')->first();
if (!is_null($softDeletedBlog)) {
return abort(410);
}
return abort(404);
}
$this->blog->increment('views');
$this->slug = $slug;
$this->blog_id = $this->blog->id;
$this->questions = $this->blog->questions;
$allBlogs = Blog::where('status', 1)->orderBy('published_at', 'desc')->get();
$this->lastNews = $allBlogs->whereNull('notBlog')->take(5);
$this->lastNews2 = $allBlogs->where('notBlog', 1)->take(5);
$this->specialNews = $allBlogs->whereNull('notBlog')->where('chosen', 1)->take(5);
$this->loadAds($slug);
}
protected function loadAds($currentBlogSlug)
{
$allAds = Ads::where('status', 1)
->whereJsonContains('pages', (string)1)
->orderBy('orders', 'desc')
->get();
$sidebarAds = $allAds->filter(function($ad) {
return collect([9, 10])->contains(function($subcat) use ($ad) {
return in_array($subcat, $ad->subcategories ?? []);
});
});
$contentAds = $allAds->filter(function($ad) {
return collect([13, 14])->contains(function($subcat) use ($ad) {
return in_array($subcat, $ad->subcategories ?? []);
});
});
$sidebarAds = $this->filterUnauthorizedAds($sidebarAds, $currentBlogSlug);
$contentAds = $this->filterUnauthorizedAds($contentAds, $currentBlogSlug);
$this->ads = [
'sidebar' => $sidebarAds->first(),
'content' => $contentAds->take(5)
];
$this->adscount = $contentAds->count() + ($sidebarAds->count() > 0 ? 1 : 0);
}
protected function filterUnauthorizedAds($ads, $currentBlogSlug)
{
return $ads->reject(function ($ad) use ($currentBlogSlug) {
if (empty($ad->unauthorized)) {
return false;
}
$unauthorizedSlugs = $ad->unauthorized;
if (is_array($unauthorizedSlugs)) {
return collect($unauthorizedSlugs)->contains(function ($item) use ($currentBlogSlug) {
return (is_array($item) && isset($item['unauthorize']) && $item['unauthorize'] === $currentBlogSlug) ||
($item === $currentBlogSlug);
});
}
return is_string($unauthorizedSlugs) && $unauthorizedSlugs === $currentBlogSlug;
});
}
public function comment()
{
$this->validate();
$comment = Comment::create([
'name' => $this->comment_name,
'message' => $this->comment_message,
'blog_id' => $this->blog_id,
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
'image_url' => $this->image_url
]);
$this->reset(['comment_message', 'comment_name']);
$this->dispatch('reset');
$this->storeCommentInCookie($comment->toArray());
}
public function reply($id, $parent_id)
{
if ($this->comment_message_reply) {
$comment = Comment::create([
'name' => $this->comment_name_reply,
'message' => $this->comment_message_reply,
'blog_id' => $this->blog_id,
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
'parent_id' => $id,
'type' => 2,
'image_url' => $this->image_url
]);
Comment::where('id', $id)->increment('reply');
$this->reset(['comment_message_reply', 'comment_name_reply']);
$this->dispatch('reset');
$this->storeCommentInCookie($comment->toArray());
}
}
private function storeCommentInCookie($comment)
{
$comments = json_decode(Cookie::get('pending_comments', '[]'), true);
$comments[] = $comment;
Cookie::queue('pending_comments', json_encode($comments), 60 * 24 * 7);
}
public $loadedimage;
public $loadedtitle;
public $loadedslug;
public $loadedpreview;
public $loadedContent;
public $isLoading = false;
#[On('loadBlogContent')]
public function loadBlogContent($slug)
{
$this->isLoading = true;
$blog = Blog::where('slug', $slug)->first();
if ($blog) {
$this->loadedContent = $blog->subject;
$this->loadedslug = $slug;
$this->loadedtitle = $blog->subject;
$this->loadedimage = $blog->image;
$this->loadedpreview = $blog->preview;
$this->dispatch('blogContentLoaded', [
'slug' => $slug,
'title' => $blog->subject,
'image' => $blog->image,
'preview' => $blog->preview,
]);
} else {
$this->loadedContent = 'محتوا یافت نشد.';
}
$this->isLoading = false;
}
#[Layout('components.layouts.app')]
public function render()
{
$approvedComments = Comment::with('blog')
->where('blog_id', $this->blog_id)
->where('status', 1)
->where('type', 0)
->whereHas('blog', fn($q) => $q->where('status', 1))
->get();
$this->pendingComments = collect(json_decode(Cookie::get('pending_comments', '[]'), true))
->filter(fn($comment) => $this->blog->id == $comment['blog_id'])
->each(function ($comment) {
if (isset($comment['id']) && $check = Comment::find($comment['id'])) {
if ($check->status == 1 || $check->status == 2) {
Cookie::queue(Cookie::forget('pending_comments'));
}
}
});
$this->comments = $approvedComments
->merge($this->pendingComments->map(function ($comment) {
$model = new Comment();
$model->forceFill($comment + ['id' => $comment['id'] ?? 'temp_' . uniqid()]);
return $model;
}))
->sortBy('id')
->values()
->toArray();
$this->like_status = session()->get('blog-' . $this->blog_id);
return view('livewire.home.detail-page');
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Livewire\Home;
use Livewire\Component;
use Livewire\Attributes\Layout;
use App\Models\Dictionary as ModelDirection;
class Dictionary extends Component
{
public $dictionary;
public function mount($id)
{
$this->dictionary = ModelDirection::where('id', $id)->first();
if (is_null($this->dictionary)) {
return abort('404');
}
}
#[Layout('components.layouts.app')]
public function render()
{
return view('livewire.home.dictionary');
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Livewire\Home;
use App\Models\Blog;
use App\Models\Category;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Session;
use Livewire\Component;
use Illuminate\Support\Facades\Cache;
#[Layout('components.layouts.home.master')]
class IndexPage extends Component
{
public $blogs;
public $categories;
public $like_status;
public function mount()
{
// استفاده از Cache برای کاهش Query های سنگین
$this->blogs = Cache::remember('home_blogs', 60, function() {
return Blog::query()
->where('status', 1)
->where('notBlog', null)
->whereHas('category', function ($q) {
$q->where('status', 1);
})
->paginate(10); // 10 مطلب در هر صفحه
});
$this->categories = Category::where('status', 1)->get();
}
public function render()
{
// دیگر نیازی به اجرای دوباره Query در render نیست
return view('livewire.home.index-page', [
'blogs' => $this->blogs
]);
}
public function like($id)
{
$this->like_status = session()->get('blog-' . $id);
if ($this->like_status == 'dislike') {
Blog::where('id', $id)->increment('likes');
} else {
Blog::where('id', $id)->decrement('likes');
}
$sesion_value = $this->like_status == 'like' ? 'dislike' : 'like';
session()->put('blog-' . $id, $sesion_value);
}
}

118
app/Livewire/Home2.php Normal file
View File

@@ -0,0 +1,118 @@
<?php
namespace App\Livewire;
use App\Models\Blog;
use Livewire\Component;
use App\Models\Category;
use Illuminate\Http\Request;
use Livewire\Attributes\Layout;
use Illuminate\Support\Facades\Http;
class Home2 extends Component
{
public $image;
public $blogs;
public $news;
public $blogs2;
public $blog_array = [];
public $news_array = [];
public $categories = [];
public $categorieNews = [];
public $lastNewsPosts = [];
public $lastNewsArticles = [];
public $lightmags = [];
public $lightnews = [];
public $selectedCategoryPosts = null;
public $selectedCategoryNews = null;
public $selectedRoutePosts = null;
public $selectedRouteNews = null;
public function mount(Request $request)
{
$allBlogs = Blog::where('status', 1)->orderBy('published_at', 'desc')->get();
$this->lightmags = $allBlogs->whereNull('notBlog')->take(50);
$this->lightnews = $allBlogs->where('notBlog', 1)->take(50);
$allCategroy = Category::where('status', 1)->get();
$this->blogs2 = Blog::where('status', 1)->where('notBlog', null)->where('chosen', 1)->orderBy('created_at', 'desc')->get()->take(5);
$this->lastNewsPosts = $allBlogs->whereNull('notBlog')->take(4);
$this->lastNewsArticles = $allBlogs->where('notBlog', 1)->take(4);
$this->blogs = $allBlogs->where('chosen', 0)->where('notBlog', null);
$this->news = $allBlogs->where('chosen', 0)->where('notBlog', 1);
$this->categories = $allCategroy->where('parent_below', null)->where('parent_id', null)->where('parent', null);
$this->categorieNews = $allCategroy->where('is_news', 1)->where('parent_below', null)->where('parent_id', '!=', null)->where('parent', null);
}
public function selectCategory($categoryId, $type = 'posts')
{
$this->selectedCategoryPosts = $categoryId;
$category = Category::find($categoryId);
if (isset($category)) {
$this->selectedRoutePosts = route('CategoryBlog.index', ['slug' => $category->slug]) . "/";
}
}
public function selectCategoryNews($categoryId, $type = 'news')
{
$this->selectedCategoryNews = $categoryId;
$category = Category::find($categoryId);
if (isset($category)) {
$this->selectedRouteNews = route('NewsCategory.show', ['slug' => $category->slug]) . "/";
}
}
public function resetCategory($type = 'posts')
{
$this->selectedRoutePosts = null;
$this->selectedCategoryPosts = null;
}
public function resetCategoryNews($type = 'news')
{
$this->selectedRouteNews = null;
$this->selectedCategoryNews = null;
}
public function getCategoryItems($categoryId = null, $type = 'posts')
{
if ($type === 'posts') {
$query = Blog::where('status', 1)->whereNull('notBlog');
if ($categoryId) {
$query->where(function($q) use ($categoryId) {
$q->where('category_id', $categoryId)
->orWhereJsonContains('category_array', (string)$categoryId);
});
}
return $query->orderByDesc('published_at')
->take(4)
->get();
} else {
$query = Blog::where('status', 1)->where('notBlog', 1);
if ($categoryId) {
$query->where(function($q) use ($categoryId) {
$q->where('category_id', $categoryId)
->orWhereJsonContains('category_array', (string)$categoryId);
});
}
return $query->orderByDesc('published_at')
->take(4)
->get();
}
}
#[Layout('components.layouts.app2')]
public function render()
{
return view('livewire.home2');
}
}

68
app/Livewire/Images.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
namespace App\Livewire;
use App\Models\Blog;
use App\Models\Image;
use Livewire\Component;
use Livewire\Attributes\Layout;
use Illuminate\Support\Facades\Storage;
class Images extends Component
{
public $images = [];
public $imagesblog = [];
public function mount()
{
$blogs = Blog::all();
foreach ($blogs as $blog) {
$this->checkImageMountForBlog($blog->id);
}
$this->images = $this->imagesblog;
}
public function checkImageMountForBlog($blogId)
{
$blog = Blog::find($blogId);
if (!$blog) {
return;
}
$imageName = $blog->image;
$content = $blog->content;
if (empty($content)) {
return;
}
$pattern = '/<img[^>]+src="([^">]+)"/i';
preg_match_all($pattern, $content, $matches);
$extractedImages = $matches[1] ?? [];
$extractedImages = array_map(function ($imageUrl) {
$parts = explode('/images/', $imageUrl);
return end($parts);
}, $extractedImages);
$extractedImages = array_filter($extractedImages, function ($image) {
return Storage::disk('public')->exists($image);
});
if ($imageName) {
if (Storage::disk('public')->exists($imageName)) {
$this->imagesblog[] = $imageName;
}
}
foreach ($extractedImages as $image) {
$this->imagesblog[] = $image;
}
}
#[Layout('components.layouts.panel.master')]
public function render()
{
return view('livewire.images');
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Livewire\Partials;
use Livewire\Component;
use App\Models\UserCounselingRequests;
class Form extends Component
{
public $full_name;
public $phone_number;
public $description;
public $textSuccess = '';
public function counselingRequest()
{
if (is_null($this->full_name) && is_null($this->phone_number) && is_null($this->description)) {
return [
'status' => 'error',
'message' => 'اطلاعات را به صورت کامل تکمیل کنید.',
];
}
$phone = convertPersianToEnglishNumber($this->phone_number);
$phone = ltrim($phone, '0');
$phone = substr($phone, 0, 2) == '98' ? substr($phone, 2) : $phone;
$phone = str_replace('+98', '', $phone);
$phone = '0' . $phone;
UserCounselingRequests::create([
'full_name' => $this->full_name,
'phone_number' => $phone,
'counseling_text' => $this->description,
]);
$this->textSuccess = 'پیام شما با موفقیت دریافت شد.';
return $this->dispatch('ticket_ok');
}
public function render()
{
return view('livewire.partials.form');
}
}

View File

@@ -0,0 +1,191 @@
<?php
namespace App\Livewire\Partials;
use App\Models\Blog;
use App\Models\Category;
use Livewire\Component;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
class Header extends Component
{
public $search = '';
public $showMenu = false;
public $activeTab = 'posts';
public $selectedCategory = null;
public $blogsSearchs = [];
public $expandedCategory = null;
public $categoryBlogs = [];
public $loadedCategories = [];
public $loadingStates = [];
public $dynamicBlogs = [];
public $lastNewsPosts2 = [];
// داده‌های اصلی
public $blogs;
public $categories;
protected $cacheKey = 'header_all_data_v4';
protected $cacheExpiration = 60; // 1 دقیقه
public function mount()
{
$this->loadAllData();
}
protected function loadAllData()
{
$data = Cache::remember($this->cacheKey, $this->cacheExpiration, function () {
return $this->fetchAllData();
});
$this->blogs = $data['blogs'];
$this->categories = $data['categories_full'];
$this->lastNewsPosts2 = $data['lastNewsPosts2'];
}
protected function fetchAllData(): array
{
// فقط 10 پست کافی است
$blogs = Blog::where('status', 1)
->select('id', 'subject', 'slug', 'image', 'published_at', 'category_id', 'notBlog', 'category_array')
->orderByDesc('published_at')
->take(10)
->get();
$categories = Category::where('status', 1)
->with(['children' => fn($q) => $q->orderByDesc('priority')])
->orderByDesc('priority')
->get();
$posts = $blogs->whereNull('notBlog');
$articles = $blogs->where('notBlog', 1);
return [
'blogs' => $blogs,
'lastNewsPosts2' => $posts->take(10),
'categories_full' => $categories,
'categoriesNotBlog' => $categories->whereNotNull('parent_id')->whereNull('parent'),
'categoriesNotBlogM' => $categories->where('is_news', 1)->whereNull('parent_below')->whereNotNull('parent_id'),
];
}
public function loadCategoryData($categoryId)
{
if (isset($this->categoryBlogs[$categoryId])) {
$this->expandedCategory = $categoryId;
return;
}
$this->expandedCategory = $categoryId;
$this->loadingStates[$categoryId] = true;
$this->dynamicBlogs[$categoryId] = [];
if (!in_array($categoryId, $this->loadedCategories)) {
$this->loadedCategories[] = $categoryId;
}
$blogs = Cache::remember("category_blogs_{$categoryId}", 300, function () use ($categoryId) {
return Blog::where('status', 1)
->select('id', 'subject', 'slug', 'image', 'published_at')
->where(function ($q) use ($categoryId) {
$q->where('category_id', $categoryId)
->orWhereJsonContains('category_array', (string)$categoryId);
})
->orderByDesc('published_at')
->take(4)
->get();
});
$this->categoryBlogs[$categoryId] = $blogs;
$this->dynamicBlogs[$categoryId] = $blogs->toArray();
$this->loadingStates[$categoryId] = false;
}
public function getLastNewsPosts($notBlog)
{
$this->activeTab = $notBlog ? 'news' : 'posts';
$this->selectedCategory = null;
$source = $notBlog
? $this->blogs->where('notBlog', 1)
: $this->blogs->whereNull('notBlog');
$this->lastNewsPosts2 = $source->take(10);
}
public function searchBox()
{
if (empty($this->search)) {
$this->showMenu = false;
$this->blogsSearchs = [];
return;
}
$search = str_replace(['', ' '], ' ', $this->search);
$searchVariants = [$search, str_replace(' ', '***', $search)];
$source = $this->activeTab === 'posts'
? $this->blogs->whereNull('notBlog')
: $this->blogs->where('notBlog', 1);
if ($this->selectedCategory) {
$source = $source->filter(fn($b) =>
$b->category_id == $this->selectedCategory ||
in_array($this->selectedCategory, $b->category_array ?? [])
);
}
$this->blogsSearchs = $source->filter(function ($blog) use ($searchVariants) {
$subject = $blog->subject;
$excerpt = $blog->excerpt ?? '';
foreach ($searchVariants as $variant) {
if (str_contains($subject, $variant) || str_contains($excerpt, $variant)) {
return true;
}
}
return false;
})
->sortByDesc(function ($blog) use ($searchVariants) {
foreach ($searchVariants as $i => $variant) {
if (str_contains($blog->subject, $variant)) {
return $i;
}
}
return 10;
})
->take(10)
->values();
$this->showMenu = $this->blogsSearchs->isNotEmpty();
}
public function selectCategory($categoryId = null)
{
$this->selectedCategory = $categoryId;
$this->searchBox();
}
public function resetCategory()
{
$this->selectedCategory = null;
$this->searchBox();
}
public function refreshsearch()
{
$this->reset('blogsSearchs');
$this->searchBox();
}
public function render()
{
return view('livewire.partials.header', [
'rootCategories' => $this->categories->whereNull('parent_id')->whereNull('parent_below')->where('is_news', 0),
'lastNewsPosts' => $this->blogs->whereNull('notBlog')->take(10),
]);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Livewire\Partials;
use Livewire\Component;
use App\Models\Category;
use Livewire\Attributes\Lazy;
class ThreeCol extends Component
{
public $category = [] ;
#[Lazy]
public function render()
{
return view('livewire.partials.three-col');
}
}

13
app/Livewire/Reateost.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class Reateost extends Component
{
public function render()
{
return view('livewire.reateost');
}
}

32
app/Livewire/Search.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
namespace App\Livewire;
use App\Models\Blog;
use App\Models\Post;
use Livewire\Component;
use Livewire\Attributes\Url;
use Livewire\WithPagination;
use Livewire\WithoutUrlPagination;
class Search extends Component
{
use WithPagination, WithoutUrlPagination;
public $search = '';
public $showMenu = false;
public function refreshsearch()
{
$this->resetPage();
}
public function render()
{
$kName = htmlspecialchars_decode($this->search, ENT_QUOTES);
$search = str_replace('', '***', $kName);
$this->showMenu = true;
return view('livewire.search', ['blogsSearchs' => Blog::where('content', 'like', '%' . $search . '%')->paginate(5)]);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Livewire\Tools;
use Livewire\Component;
class Coments extends Component
{
public function render()
{
return view('livewire.tools.coments');
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Livewire\Tools;
use App\Models\Comment;
use Livewire\Attributes\Rule;
use Livewire\Component;
class HomeComments extends Component
{
public Comment $comments;
public Comment $comment;
#[Rule('required')]
public $comment_name;
#[Rule('required')]
public $comment_message;
public $comment_name_reply;
public $comment_message_reply;
public $blog_id;
public $comment_id;
public function mount($comments,$comment,$blog_id)
{
$this->comments = $comments;
$this->comment = $comment;
$this->blog_id = $blog_id;
// dd($this->comment);
}
public function render()
{
return view('livewire.tools.home-comments');
}
public function reply($id,$parent_id)
{
if ($this->comment_message_reply && $this->comment_name_reply){
Comment::create(['name'=>$this->comment_name_reply,'message'=>$this->comment_message_reply,'blog_id'=>$this->blog_id,'ip'=>request()->ip(),'user_agent'=>request()->userAgent(),'parent_id'=>$id,'type'=>2]);
Comment::where('id',$parent_id)->increment('reply');
$this->comment_message_reply=null;
$this->comment_name_reply=null;
}
}
}

19
app/Models/AdCategory.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use App\Models\AdSubcategory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class AdCategory extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = ['name', 'slug'];
public function subcategories()
{
return $this->hasMany(AdSubcategory::class);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use App\Models\AdCategory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class AdSubcategory extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = ['ad_category_id', 'name', 'slug'];
public function category()
{
return $this->belongsTo(AdCategory::class);
}
}

24
app/Models/Address.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
namespace App\Models;
use App\Models\User;
use App\Models\Province;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Address extends Model
{
use HasFactory;
protected $table = "address";
protected $guarded = [];
public function user()
{
return $this->belongsTo(User::class);
}
}

30
app/Models/Ads.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
namespace App\Models;
use App\Models\AdSubcategory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Ads extends Model
{
use HasFactory, SoftDeletes;
protected $table = 'ads';
protected $guarded = [];
protected $casts = [
'pages' => 'array',
'subcategories' => 'array',
'unauthorized' => 'array',
'status' => 'boolean'
];
public function getSubcategoryNamesAttribute()
{
if (empty($this->subcategories)) {
return collect();
}
return AdSubcategory::whereIn('id', $this->subcategories) ->get() ->pluck('name');
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class BlockedWord extends Model
{
use HasFactory;
protected $table = 'blocked_words';
protected $guarded = [];
}

251
app/Models/Blog.php Normal file
View File

@@ -0,0 +1,251 @@
<?php
namespace App\Models;
use App\Models\Image;
use App\Models\Heading;
use App\Models\Question;
use App\Models\CommonWord;
use App\Models\BlogSetObject;
use App\Models\CommonWordBlog;
use App\Models\Blog as ModelBlog;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletes;
class Blog extends Model
{
use SoftDeletes;
protected $table = 'blogs';
protected $fillable = [
'content',
'preview',
'changefreq',
'priority',
'image',
'status',
'subject',
'description',
'reed_time',
'views',
'category_array',
'category_id',
'chosen',
'slug',
'user_id', 'imageCheck', 'headingCheck', 'notBlog', 'content_id', 'published_at', 'grade', 'content_errors'];
protected $casts = [
'category_array' => 'array',
'published_at' => 'datetime',
];
protected $appends = ['computed_published_at'];
protected static function boot()
{
parent::boot();
static::addGlobalScope('filtered', function ($query) {
$query->where(function ($query) {
$query
->whereNotNull('content_id')
->where('blogs.id', function ($subQuery) {
$subQuery->selectRaw('MAX(id)')->from('blogs as blog_edits')->whereColumn('blog_edits.content_id', 'blogs.content_id');
})
->orWhere(function ($query) {
$query->whereNull('content_id')->whereNotIn('blogs.id', function ($subQuery) {
$subQuery->select('content_id')->from('blogs')->whereNotNull('content_id');
});
});
});
});
}
public function getComputedPublishedAtAttribute()
{
if ($this->published_at) {
return $this->published_at;
}
if (!is_null($this->content_id)) {
$blog = DB::table('blogs')->where('id', $this->content_id)->first();
if ($blog->published_at == null) {
$blog->published_at = $blog->created_at;
}
return $blog->published_at ?? '2021-08-02 12:05:01';
}
return null;
}
public function getPublishAtAttribute()
{
if ($this->published_at) {
return $this->published_at;
}
if (!is_null($this->content_id)) {
$blog = DB::table('blogs')->where('id', $this->content_id)->first();
if ($blog->published_at == null) {
$blog->published_at = $blog->created_at;
}
return $blog->published_at ?? '2021-08-02 12:05:01';
}
return null;
}
public function parent()
{
return $this->belongsTo(ModelBlog::class, 'content_id', 'id');
}
public function children()
{
return $this->hasMany(ModelBlog::class, 'content_id', 'id');
}
public function headers()
{
return $this->hasMany(Heading::class);
}
public function headings()
{
return $this->hasMany(Heading::class);
}
public function images()
{
return $this->hasMany(Image::class);
}
public function latestChild()
{
return $this->children()->orderBy('created_at', 'desc')->first();
}
public function editsAsContent()
{
return $this->hasMany(Blog::class, 'content_id', 'id');
}
public function latestVersion()
{
return $this->hasMany(ModelBlog::class, 'content_id', 'id')->orderBy('created_at', 'desc')->limit(1);
}
public function categories()
{
return Category::whereIn('id', $this->category_array)->get();
}
public function commonWords()
{
return $this->belongsToMany(CommonWord::class, 'common_word_blog')
->using(CommonWordBlog::class)
->withPivot('count')
->withTimestamps();
}
public function category()
{
return $this->belongsTo(Category::class);
}
public function opinions()
{
return $this->hasMany(UserOpinion::class, 'blog_id', 'id');
}
public function comments()
{
return $this->hasMany(Comment::class, 'blog_id', 'id');
}
public function user()
{
return $this->belongsTo(User::class);
}
public function getStatusClassAttribute()
{
return $this->status == 0 ? 'bg-orange-500' : 'bg-ahrom';
}
public function getStatusTextAttribute()
{
return $this->status == 0 ? 'پیشنویس' : 'انتشار';
}
public function getStatusImageAttribute()
{
if ($this->imageCheck == 1) {
return 'bg-[#FFA500]';
} elseif ($this->imageCheck == 2) {
return 'bg-green-500';
} else {
return 'bg-slate-500';
}
}
public function getStatusHeadAttribute()
{
if ($this->headingCheck == 1) {
return 'bg-[#FFA500]';
} elseif ($this->headingCheck == 2) {
return 'bg-green-500';
} else {
return 'bg-slate-500';
}
}
public function questions()
{
return $this->hasMany(Question::class);
}
public function getContentAttribute($value)
{
return str_replace('***', '&zwnj;', $value);
}
public function getPreviewAttribute($value)
{
return str_replace('***', '&zwnj;', $value);
}
public function setContentAttribute($value)
{
$this->attributes['content'] = str_replace('&zwnj;', '***', $value);
}
public function setPreviewAttribute($value)
{
$this->attributes['preview'] = str_replace('&zwnj;', '***', $value);
}
public function scopeOrderByPublished($query, $direction = 'desc')
{
return $query->orderBy('computed_published_at', $direction);
}
public function setObjects()
{
return $this->hasMany(BlogSetObject::class, 'blog_id', 'id');
}
public function sectionImages()
{
return $this->hasMany(BlogSectionImage::class);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class BlogSectionImage extends Model
{
use HasFactory, softDeletes;
protected $fillable = [
'blog_id',
'h2_text',
'image_src',
'status',
'reason',
];
public function blog()
{
return $this->belongsTo(Blog::class);
}
public function approve(): void
{
$this->update(['status' => 'approved']);
}
public function reject($reason = null): void
{
$this->update(['status' => 'reject', 'reason' => $reason]);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Models;
use App\Models\Blog;
use App\Models\CategoryObject;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class BlogSetObject extends Model
{
protected $fillable = [
'blog_id',
'category_object_id',
'title',
'content',
'order'
];
public function blog(): BelongsTo
{
return $this->belongsTo(Blog::class);
}
public function categoryObject(): BelongsTo
{
return $this->belongsTo(CategoryObject::class);
}
}

231
app/Models/Category.php Normal file
View File

@@ -0,0 +1,231 @@
<?php
namespace App\Models;
use App\Models\CategoryObject;
use Illuminate\Database\Eloquent\Model;
use App\Models\Category as Modelcategory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Category extends Model
{
use SoftDeletes;
protected $fillable = [
'title',
'slug',
'image_url',
'status',
'is_news',
'parent_id',
'parent_below',
'color',
'priority',
];
protected $casts = [
'is_news' => 'boolean',
'status' => 'boolean'
];
public function getAllDescendantIds(): array
{
$ids = collect([$this->id]);
$children = Category::where('parent_id', $this->id)->get();
foreach ($children as $child) {
$ids = $ids->merge($child->getAllDescendantIds());
}
$subcategories = Category::where('parent_below', $this->id)->get();
foreach ($subcategories as $subcategory) {
$ids = $ids->merge($subcategory->getAllDescendantIds());
}
return $ids->unique()->all();
}
public static function getHierarchicalCategoriesForFilter()
{
$allCategories = [];
$rootCategories = self::whereNull('parent_id')
->whereNull('parent_below')
->with(['children', 'subcategories'])
->orderBy('is_news', 'desc')
->orderBy('title')->get();
foreach ($rootCategories as $item) {
self::addCategoryToHierarchyList($item, 0, $allCategories);
}
return $allCategories;
}
private static function addCategoryToHierarchyList(Category $category, int $level, array &$list)
{
$category->level = $level;
$list[] = $category;
$descendants = $category->children->merge($category->subcategories)->sortBy('title');
foreach ($descendants as $descendant) {
self::addCategoryToHierarchyList($descendant, $level + 1, $list);
}
}
public function blogs()
{
return $this->hasMany(Blog::class);
}
public function mag_news($categoryId = null)
{
$id = $categoryId ?? $this->id;
return Blog::query()
->where('status', 1)
->where('notBlog', 1)
->where('category_array', 'like', '%"' . $id . '"%')
->orderByDesc('published_at')
->get()->take(4);
}
public function mag_blogs($limit = 4)
{
return Blog::query()
->where('status', 1)
->whereNull('notBlog')
->where(function($query) {
$query->where('category_id', $this->id)
->orWhereJsonContains('category_array', (string)$this->id);
})
->orderByDesc('published_at')
->take($limit)
->get();
}
public function hasBlogs()
{
return Blog::where('status', 1)
->whereNull('notBlog')
->where(function($query) {
$query->where('category_id', $this->id)
->orWhereJsonContains('category_array', (string)$this->id);
})
->exists();
}
public function blog_category()
{
$blogs = Blog::where('notBlog', 1)->orderBy('created_at', 'desc') ->get();
return $blogs->filter(function($blog) {
$categoryArray = $blog->category_array ;
return isset($categoryArray[0]) && $categoryArray[0] == $this->id;
});
}
public function child()
{
return $this->hasOne(Modelcategory::class , 'parent_id' , 'id');
}
public function isRoot(): bool
{
return is_null($this->parent_id) && is_null($this->parent_below);
}
public static function getNewsRootCategories()
{
return self::where('is_news', true)
->whereNull('parent_id')
->whereNull('parent_below')
->get();
}
public static function getArticleRootCategories()
{
return self::where('is_news', false)
->whereNull('parent_id')
->whereNull('parent_below')
->get();
}
public function getFullHierarchy()
{
$hierarchy = collect([$this]);
if ($this->parent()->exists()) {
$hierarchy = $this->parent()->first()->getFullHierarchy()->merge($hierarchy);
}
if ($this->mainCategory()->exists()) {
$hierarchy = $this->mainCategory()->first()->getFullHierarchy()->merge($hierarchy);
}
return $hierarchy->unique('id');
}
public function children(): HasMany
{
return $this->hasMany(Category::class, 'parent_id')->orderByDesc('priority');
}
// Recursive relation to load all descendants infinitely
public function childrenRecursive()
{
return $this->children()->with('childrenRecursive');
}
public function subcategories(): HasMany
{
return $this->hasMany(Category::class, 'parent_below')->orderByDesc('priority');
}
public function parent(): BelongsTo
{
return $this->belongsTo(Category::class, 'parent_id');
}
public function fparent(): BelongsTo
{
return $this->belongsTo(Category::class, 'parent_id');
}
public function mainCategory(): BelongsTo
{
return $this->belongsTo(Category::class, 'parent_below');
}
public function getBreadcrumbAttribute(): string
{
$breadcrumbs = [];
if ($this->parent_id) {
$parent = $this->parent ?? Category::find($this->parent_id);
if ($parent) {
$breadcrumbs[] = $parent->breadcrumb;
}
}
if ($this->parent_below) {
$mainCategory = $this->mainCategory ?? Category::find($this->parent_below);
if ($mainCategory) {
$breadcrumbs[] = $mainCategory->breadcrumb;
}
}
$breadcrumbs[] = $this->title;
return implode(' > ', array_unique($breadcrumbs));
}
public function categoryObjects(): HasMany
{
return $this->hasMany(CategoryObject::class);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Models;
use App\Models\Category;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class CategoryObject extends Model
{
protected $fillable = [
'category_id',
'subject'
];
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
}

101
app/Models/Comment.php Normal file
View File

@@ -0,0 +1,101 @@
<?php
namespace App\Models;
use App\Models\Blog;
use App\Models\User;
use App\Models\Comment as Modelself;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletes;
class Comment extends Model
{
use SoftDeletes;
protected $fillable = ['message', 'ip', 'user_agent', 'status', 'name', 'blog_id', 'seen', 'parent_id', 'type', 'likes', 'admin' , 'image_url'];
public function blog()
{
return $this->belongsTo(Blog::class);
}
public function admin()
{
return $this->belongsTo(User::class, 'admin', 'id');
}
protected $appends = [
'sub_comments',
];
public function getSubCommentsAttribute()
{
return $this->other()->get();
}
public function other()
{
return $this->hasMany(Comment::class, 'parent_id', 'id');
}
public function hasPendingReplies()
{
foreach ($this->other as $reply) {
if ($reply->status === 0 || $reply->hasPendingReplies()) {
return true;
}
}
return false;
}
public function scopeParent(Builder $query): void
{
$query->where('type', 0);
}
public function scopeAnswer(Builder $query): void
{
$query->where('type', 1);
}
public function scopeReply(Builder $query): void
{
$query->where('type', 2);
}
public function getTypeCheckAttribute()
{
if ($this->type == 0) {
return 'کامنت';
} else if ($this->type == 1) {
return 'جواب';
} else if ($this->type == 2) {
return 'ریپلای';
}
return 'نامشخص';
}
public function getTypeStatusAttribute()
{
if ($this->status == 0) {
return 'در انتظار بررسی';
} else if ($this->status == 1) {
return 'تایید';
} else if ($this->status == 2) {
return 'رد';
}
return 'نا مشخص';
}
public function getTypeStatuscolorAttribute()
{
if ($this->status == 0) {
return 'text-slate-400';
} else if ($this->status == 1) {
return ' text-green-500';
} else if ($this->status == 2) {
return 'text-red-500';
}
return 'text-blue-400';
}
}

85
app/Models/CommonWord.php Normal file
View File

@@ -0,0 +1,85 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class CommonWord extends Model
{
use HasFactory;
protected $table = 'commonwords';
protected $guarded = [];
const TYPE_SINGLE = 1;
const TYPE_DOUBLE = 2;
const TYPE_TRIPLE = 3;
const TYPE_QUAD = 4;
const STATUS_ACTIVE = 1;
const STATUS_BLOCKED = 0;
protected $appends = ['article_count', 'is_blocked'];
public function blogs()
{
return $this->belongsToMany(Blog::class, 'common_word_blog')
->using(CommonWordBlog::class)
->withPivot(['count', 'is_linked'])
->withTimestamps()
->withoutGlobalScopes();
}
public function blockedWords()
{
return $this->hasOne(BlockedWord::class, 'word', 'title');
}
public function getArticleCountAttribute()
{
return $this->blogs()->count();
}
public function getIsBlockedAttribute()
{
return $this->status == self::STATUS_BLOCKED;
}
public function getLinkedArticlesCountAttribute()
{
return $this->blogs()
->wherePivot('is_linked', true)
->count();
}
public function scopeSingleWords($query)
{
return $query->where('word_type', self::TYPE_SINGLE);
}
public function scopeDoubleWords($query)
{
return $query->where('word_type', self::TYPE_DOUBLE);
}
public function scopeTripleWords($query)
{
return $query->where('word_type', self::TYPE_TRIPLE);
}
public function scopeQuadWords($query)
{
return $query->where('word_type', self::TYPE_QUAD);
}
public function scopeActive($query)
{
return $query->where('status', self::STATUS_ACTIVE);
}
public function scopeBlocked($query)
{
return $query->where('status', self::STATUS_BLOCKED);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CommonWordBlog extends Pivot
{
protected $table = 'common_word_blog';
protected $fillable = [
'common_word_id',
'blog_id',
'count',
'is_linked',
];
public $timestamps = true;
protected $casts = [
'count' => 'integer',
'is_linked' => 'boolean',
];
public function commonWord()
{
return $this->belongsTo(CommonWord::class);
}
public function blog()
{
return $this->belongsTo(Blog::class);
}
public function scopeLinked($query)
{
return $query->where('is_linked', true);
}
public function scopeNotLinked($query)
{
return $query->where('is_linked', false);
}
public function scopeWithHighFrequency($query, $minCount = 5)
{
return $query->where('count', '>=', $minCount);
}
}

18
app/Models/Dictionary.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Dictionary extends Model
{
use HasFactory;
protected $table = "Dictionary";
protected $guarded = [];
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Models;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class FinancialInfo extends Model
{
use HasFactory;
protected $table = 'financial_infos';
protected $fillable = [
'user_id', 'confirm'
];
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Frequently_asked extends Model
{
use HasFactory;
protected $table = "frequently_asked _uestions";
protected $guarded = [];
}

26
app/Models/Heading.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
namespace App\Models;
use App\Models\Blog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Heading extends Model
{
use HasFactory ;
protected $table = "headings";
protected $guarded = [];
protected $casts = [
'content_expert_message' => 'array',
];
public function blog()
{
return $this->belongsTo(Blog::class);
}
}

10
app/Models/History.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class History extends Model
{
protected $fillable=['user_agent','ip','blog_link','opened_at','user_id','blog_id'];
}

24
app/Models/Image.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
namespace App\Models;
use App\Models\Blog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Image extends Model
{
use HasFactory , SoftDeletes;
protected $table = "images";
protected $guarded = [];
public function blog()
{
return $this->belongsTo(Blog::class);
}
}

358
app/Models/IndexPage.php Normal file
View File

@@ -0,0 +1,358 @@
<?php
namespace App\Livewire\Panel;
use DOMXPath;
use DOMDocument;
use App\Models\Blog;
use App\Models\Image;
use App\Models\Heading;
use Livewire\Component;
use App\Models\Category;
use Carbon\Carbon;
use Livewire\Attributes\On;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Url;
use Livewire\WithPagination;
use Livewire\WithoutUrlPagination;
use Illuminate\Database\Eloquent\JsonEncodingException;
class IndexPage extends Component
{
use WithPagination, WithoutUrlPagination;
public $blogs = [];
public $categories;
public $headings;
public $comment_message = [];
public $currentCategory = 'all';
public function checkHeadingMount()
{
$blogs = Blog::orderBy('id', 'Desc')->get();
foreach ($blogs as $blog) {
$existingHeading = Heading::where('blog_id', $blog->id)->first();
if ($existingHeading) {
continue;
}
$htmlContent = $blog->content;
$dom = new DOMDocument();
@$dom->loadHTML(mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8'));
$xpath = new DOMXPath($dom);
$headings = $xpath->query('//h1 | //h2 | //h3 | //h4 | //h5 | //h6');
foreach ($headings as $heading) {
$headingText = $heading->nodeValue;
$tagType = $heading->nodeName;
$nextNode = $heading->nextSibling;
while ($nextNode && !in_array($nextNode->nodeName, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])) {
$nextNode = $nextNode->nextSibling;
}
if(strlen($headingText) > 3){
Heading::create([
'blog_id' => $blog->id,
'content' => $headingText ,
'typeTag' => $tagType,
]);
}
}
}
}
public function approveHeading($headingId)
{
$heading = Heading::find($headingId);
$heading->update(['status' => 1]);
// ...
}
public function rejectHeading($headingId)
{
$heading = Heading::find($headingId);
$heading->update(['status' => 2]);
// ...
}
public function approveHeadingexpert($headingId)
{
$heading = Heading::find($headingId);
$heading->update(['content_expert_status' => 1]);
// ...
}
public function rejectHeadingexpert($headingId)
{
$heading = Heading::find($headingId);
$heading->update(['content_expert_status' => 2]);
// ...
}
public function makeMessage($headingId, $key)
{
$heading = Heading::find($headingId);
if ($heading) {
$textmessage = $this->comment_message[$key] ?? null;
if ($textmessage) {
if (!mb_check_encoding($textmessage, 'UTF-8')) {
$textmessage = utf8_encode($textmessage);
}
$time = Carbon::now();
$headingMessageBefore = $heading->content_expert_message;
if (empty($headingMessageBefore)) {
$headingMessageBefore = [];
} elseif (!is_array($headingMessageBefore)) {
$headingMessageBefore = [$headingMessageBefore];
}
$headingMessageBefore[] = ['message' => $textmessage, 'time' => $time];
$headingMessageBefore = array_map(function ($message) {
if (!mb_check_encoding($message['message'], 'UTF-8')) {
$message['message'] = utf8_encode($message['message']);
}
return $message;
}, $headingMessageBefore);
}
}
}
public function headingStatus( $value, $value2)
{
$blog = Blog::find($value);
if(!is_null($blog)){
$blog->update([
'headingCheck' => $value2 ,
]);
}
}
public function imageStatus($value , $value2)
{
$blog = Blog::find($value);
if(!is_null($blog)){
$blog->update([
'imageCheck' => $value2 ,
]);
}
}
public $imagesblog = [];
public $wModalsOpened = [];
public $loadedBlogs = [];
public function checkImageMountForBlog($blogId, $modalid)
{
if (isset($this->loadedBlogs[$blogId])) {
$this->wModalsOpened[] = $modalid;
$this->dispatch('openthemodal', $modalid);
return;
}
$blog = Blog::find($blogId);
if (!$blog) {
return;
}
$imageName = $blog->image;
$existingImage = Image::where('blog_id', $blogId)
->where('imagePath', $imageName)
->first();
if (is_null($existingImage)) {
Image::create([
'blog_id' => $blogId,
'imagePath' => $imageName,
'status' => 0
]);
}
$content = $blog->content;
if (empty($content)) {
return;
}
$pattern = '/<img[^>]+src="([^">]+)"/i';
preg_match_all($pattern, $content, $matches);
$extractedImages = $matches[1] ?? [];
$extractedImages = array_map(function ($imageUrl) {
$parts = explode('/images/', $imageUrl);
return end($parts);
}, $extractedImages);
$existingImages = Image::where('blog_id', $blogId)->get();
$existingImagePaths = $existingImages->pluck('imagePath')->toArray();
$imagesToDelete = array_diff($existingImagePaths, $extractedImages);
if (!empty($imagesToDelete)) {
Image::where('blog_id', $blogId)
->whereIn('imagePath', $imagesToDelete)
->delete();
}
foreach ($extractedImages as $imagePath) {
$existingImage = Image::where('blog_id', $blogId)
->where('imagePath', $imagePath)
->first();
if (is_null($existingImage)) {
Image::create([
'blog_id' => $blogId,
'imagePath' => $imagePath,
'status' => 0
]);
}
}
$this->loadedBlogs[$blogId] = true;
$this->wModalsOpened[] = $modalid;
$this->imagesblog = $blog->images;
$this->dispatch('openthemodal', $modalid);
}
public function approveImage($imageId)
{
$image = Image::find($imageId);
$image->update(['status' => 1]);
}
public function rejectImage($imageId)
{
$image = Image::find($imageId);
$image->update(['status' => 2]);
}
public function delete($id)
{
$blog = Blog::where("id", $id)->first();
if($blog){
$blog->delete();
}
}
public function status($id , $likey = false)
{
$blog= Blog::find($id);
if($blog->status==1){
$blog->update(["status"=>0]);
}else{
$blog->update(["status"=>1]);
}
}
public function setCategory($category)
{
$this->currentCategory = $category;
$this->resetPage();
}
public function refactor($id)
{
$blog = Blog::withTrashed()->find($id);
if ($blog && $blog->trashed()) {
$blog->restore();
return response()->json(['message' => 'Blog restored successfully!']);
} else {
return response()->json(['message' => 'Blog not found or is not soft deleted'], 404);
}
}
public function mount(){
$this->checkHeadingMount();
}
#[Layout('components.layouts.panel.master')]
public function render()
{
$query = Blog::orderBy('created_at', 'Desc');
if ($this->currentCategory == 'publish') {
$query->where('status', 1);
} elseif ($this->currentCategory == 'draft') {
$query->where('status', 0);
} elseif ($this->currentCategory == 'justtrashedlaravel') {
$query->onlyTrashed();
} elseif ($this->currentCategory !== 'all') {
$query->whereHas('category', function ($q) {
$q->where('id', $this->currentCategory);
});
}
$paginatedBlogs = $query->paginate(10);
$this->categories = Category::all();
$headings = Heading::all();
$blogHeadingsMap = [];
foreach ($paginatedBlogs as $blog) {
if (!isset($blogHeadingsMap[$blog->id])) {
$blogHeadingsMap[$blog->id] = [
'blog' => $blog,
'headings' => [],
'images' => []
];
}
}
foreach ($headings as $head) {
if (isset($blogHeadingsMap[$head->blog_id])) {
$blogHeadingsMap[$head->blog_id]['headings'][] = $head;
}
}
$this->blogs = array_values($blogHeadingsMap);
dd($this->blogs);
return view('livewire.panel.index-page', [
'blogs' => $this->blogs,
'paginatedBlogs' => $paginatedBlogs,
]);
}
}

19
app/Models/Keyword.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Keyword extends Model
{
use HasFactory , SoftDeletes;
protected $table = 'keywords';
protected $fillable=['name', 'status' , 'slug' ,'blogs' ];
protected $casts = [
'blogs' => 'array',
];
}

19
app/Models/NameList.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class NameList extends Model
{
use HasFactory;
protected $table = 'name_lists';
protected $fillable = [
'name'
];
public $timestamps = false;
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class NationalCodeCityName extends Model
{
use HasFactory;
protected $table = 'national_code_city_names';
protected $fillable = [
'code', 'city'
];
}

16
app/Models/Newslist.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Newslist extends Model
{
protected $table = "news_list";
protected $guarded = [];
public $timestamps = false;
}

17
app/Models/Page.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Page extends Model
{
use HasFactory , SoftDeletes;
protected $table = 'pages';
protected $guarded = [];
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class PriceDataHistoryLt extends Model
{
use HasFactory;
protected $table = "price_data_history_lt";
protected $guarded = [];
}

14
app/Models/Question.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Question extends Model
{
use HasFactory;
protected $table = "questions";
protected $guarded = [];
}

76
app/Models/User.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Models\Role;
use App\Models\Address;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'phone_number', 'token', 'invite_code', 'mobile_verified_at', 'national_code',
'issue_place', 'confirm_national_code', 'confirm', 'info_status', 'full_confirm',
'is_real', 'joined_from' , 'first_name' , 'last_name' , 'father_name' ,'birth_day' ,
'full_name' , 'picture'
];
// روابط
public function financialInfo()
{
return $this->hasOne(FinancialInfo::class);
}
public function address()
{
return $this->belongsTo(Address::class);
}
public function role()
{
return $this->belongsTo(Role::class);
}
public function scoreUser()
{
return $this->hasOne(ScoreUser::class);
}
public function scoreTransactions()
{
return $this->hasMany(ScoreTransaction::class);
}
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UserOpinion extends Model
{
protected $table = 'user_opinions';
protected $fillable = ['like','user_agent','ip','blog_id','user_id'];
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Providers;
// use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The model to policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
//
];
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
//
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Broadcast::routes();
require base_path('routes/channels.php');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
/**
* Register any events for your application.
*/
public function boot(): void
{
//
}
/**
* Determine if events and listeners should be automatically discovered.
*/
public function shouldDiscoverEvents(): bool
{
return false;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to your application's "home" route.
*
* Typically, users are redirected here after authentication.
*
* @var string
*/
public const HOME = '/home';
/**
* Define your route model bindings, pattern filters, and other route configuration.
*/
public function boot(): void
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
$this->routes(function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
}

467
app/helper.php Normal file
View File

@@ -0,0 +1,467 @@
<?php
use Carbon\Carbon;
use App\Models\User;
use App\Models\Package;
use App\Models\Setting;
use App\Models\Inventory;
use App\Models\Discountcode;
use App\Models\SignedDocument;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Process;
use Morilog\Jalali\Jalalian;
if (!function_exists('generateRandomToken')) {
function generateRandomToken($length = 64)
{
if ($length % 2 != 0) {
$length++;
}
$bytes = openssl_random_pseudo_bytes($length / 2);
$token = bin2hex($bytes);
return $token;
};
}
if (!function_exists('convertPersianToEnglishNumber')) {
function convertPersianToEnglishNumber($number)
{
$number = str_replace('۰', '0', $number);
$number = str_replace('۱', '1', $number);
$number = str_replace('۲', '2', $number);
$number = str_replace('۳', '3', $number);
$number = str_replace('۴', '4', $number);
$number = str_replace('۵', '5', $number);
$number = str_replace('۶', '6', $number);
$number = str_replace('۷', '7', $number);
$number = str_replace('۸', '8', $number);
$number = str_replace('۹', '9', $number);
return $number;
}
function convertEnglishToPersianNumber($number)
{
$number = str_replace('0', '۰', $number);
$number = str_replace('1', '۱', $number);
$number = str_replace('2', '۲', $number);
$number = str_replace('3', '۳', $number);
$number = str_replace('4', '۴', $number);
$number = str_replace('5', '۵', $number);
$number = str_replace('6', '۶', $number);
$number = str_replace('7', '۷', $number);
$number = str_replace('8', '۸', $number);
$number = str_replace('9', '۹', $number);
return $number;
}
function priceFormat($price)
{
$price = number_format($price, 0, '.', ','); // 1,000,000/00
$price = convertEnglishToPersianNumber($price);
return $price;
}
}
if (!function_exists('generatefilename')) {
function generatefilename($name)
{
$year = Carbon::now()->year;
$month = Carbon::now()->month;
$day = Carbon::now()->day;
$hour = Carbon::now()->hour;
$minute = Carbon::now()->minute;
$second = Carbon::now()->second;
$microsecond = Carbon::now()->microsecond;
return $year . '_' . $month . '_' . $day . '_' . $hour . '_' . $minute . '_' . $second . '_' . $microsecond . '_' . $name;
};
}
if(!function_exists('priceFormat')){
function priceFormat($price)
{
$price = number_format($price, 0, '.', ','); // 1,000,000/00
$price = convertEnglishToPersianNumber($price);
return $price;
}
}
if(!function_exists('last_of_route_name')){
function last_of_route_name($route_name)
{
$route=explode('.',$route_name);
return end($route);
}}
if(!function_exists('image_name')){
function image_name($original_name)
{
return time().str_shuffle(random_int(1000000000000000,9999999999999999).str()->random(16)).'_'.$original_name;
}}
if(!function_exists('runPython')){
function runPython($file_name,$input)
{
// code with laravel process
$process = Process::input($input)->env( ['SYSTEMROOT' => getenv('SYSTEMROOT'),'PATH' => getenv("PATH")])->run('python '.base_path('Python/'.$file_name));
$process->exitCode();
if (!$process->successful()){
return -1;
// $error=$process->errorOutput();
// dd($error);
}
return $process->output();
}}
if(!function_exists('status')){
function status($status)
{
if($status==1){
return '<span class="text-red-500">ناموفق</span>';
}
if($status==2){
return '<span class="text-green-500">موفق</span>';
}
if($status==0){
return '<span style="color: #facc15 !important;">نامشخص</span>';
}
return '';
}}
if(!function_exists('jalaliDate')){
function jalaliDate($date, $format = '%A - %Y/%m/%d',$fa=true)
{
$result = Jalalian::forge($date)->format($format);
if(!$fa){
return $result;
}
return convertEnglishToPersianNumber($result);
}}
if(!function_exists('convertPersianToEnglishNumber')){
function convertPersianToEnglishNumber($number)
{
$number = str_replace('۰', '0', $number);
$number = str_replace('۱', '1', $number);
$number = str_replace('۲', '2', $number);
$number = str_replace('۳', '3', $number);
$number = str_replace('۴', '4', $number);
$number = str_replace('۵', '5', $number);
$number = str_replace('۶', '6', $number);
$number = str_replace('۷', '7', $number);
$number = str_replace('۸', '8', $number);
$number = str_replace('۹', '9', $number);
return $number;
}}
if(!function_exists('convertArabicToEnglishNumber')){
function convertArabicToEnglishNumber($number)
{
$number = str_replace('۰', '0', $number);
$number = str_replace('۱', '1', $number);
$number = str_replace('۲', '2', $number);
$number = str_replace('۳', '3', $number);
$number = str_replace('۴', '4', $number);
$number = str_replace('۵', '5', $number);
$number = str_replace('۶', '6', $number);
$number = str_replace('۷', '7', $number);
$number = str_replace('۸', '8', $number);
$number = str_replace('۹', '9', $number);
return $number;
}}
if(!function_exists('convertEnglishToPersianNumber')){
function convertEnglishToPersianNumber($number)
{
$number = str_replace('0', '۰', $number);
$number = str_replace('1', '۱', $number);
$number = str_replace('2', '۲', $number);
$number = str_replace('3', '۳', $number);
$number = str_replace('4', '۴', $number);
$number = str_replace('5', '۵', $number);
$number = str_replace('6', '۶', $number);
$number = str_replace('7', '۷', $number);
$number = str_replace('8', '۸', $number);
$number = str_replace('9', '۹', $number);
return $number;
}}
if(!function_exists('priceFormat')){
function priceFormat($price)
{
$price = number_format($price, 0, '/', ','); // 1,000,000/00
$price = convertEnglishToPersianNumber($price);
return $price;
}}
if(!function_exists('fa2en')){
function fa2en($str) {
return strtr($str, array('۰'=>'0', '۱'=>'1', '۲'=>'2', '۳'=>'3', '۴'=>'4', '۵'=>'5', '۶'=>'6', '۷'=>'7', '۸'=>'8', '۹'=>'9'));
}}
if(!function_exists('home_comments')){
function home_comments($comments,$comment,$blog_id)
{
$result=null;
foreach ($comments->other as $other_comment) {
$result .= '
<div style="margin-right: 40px" class="mr-10 relative" >
<div class="" >
';
if ($other_comment->status==1) {
$result.='
<div class="">
<div >
<div class=" flex flex-col gap-3 m-3">
<div x-data="{reply_id:0}">
<div class="relative rounded-xl p-5 flex gap-4 ">
<div class="flex ">
<img style="width: 40px; height: 40px" wire:ignore alt="" class="size-10 rounded-full"
src="' . profile($other_comment->type == 1) . '">
</div>
<div class="flex flex-col gap-5">
<div class="flex gap-1">
<span class=" text_class font-bold text-[#E1EAF9]"> '.$other_comment->name.'</span>
<span class=" text_class font-bold text-[#E1EAF9]"> |</span>
<span class=" text_class font-bold text-[#E1EAF9]"> '.how_long($other_comment->created_at).'</span>
</div>
<p class="text-[#B4BBC7]"> ' . $other_comment->message . '</p>
<div class="flex gap-10">
<div class="flex flex-col justify-end">
<button type="button" @click="reply_id=' . $other_comment->id . '">
<div class="flex gap-1 items-center content-center">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="16" height="16"
viewBox="0 0 16.000000 16.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,16.000000) scale(0.100000,-0.100000)"
fill="#E1EAF9" stroke="none">
<path d="M131 123 c-2 -29 -27 -53 -56 -53 -18 0 -23 4 -18 16 8 21 -16 14
-31 -8 -7 -12 -6 -21 3 -32 17 -20 32 -21 25 -1 -5 12 2 15 29 15 42 0 60 19
54 57 -3 21 -4 22 -6 6z"/>
</g>
</svg>
<span class="text-xs text-[#E1EAF9]">پاسخ</span>
</div>
</button>
</div>
<div wire:ignore.self x-data="{like_color:like_color_session(\''.session()->get('comment-'.$other_comment->id).'\')}" class="flex flex-col justify-end">
<button @click="like_color=comment_like_color(like_color)" wire:click="like_comment(' . $other_comment->id . ')" type="button" >
<div class="flex gap-1 items-center content-center">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="16" height="12" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
:fill="like_color" fill="#E1EAF9" stroke="none">
<path d="M1262 4830 c-319 -40 -586 -171 -812 -399 -203 -204 -325 -420 -395
-701 -124 -487 -34 -967 264 -1418 191 -289 438 -554 891 -958 288 -257 1167
-1007 1210 -1032 40 -24 55 -27 140 -27 85 0 100 3 140 27 43 25 924 776 1210
1032 455 406 700 670 891 958 298 451 388 931 264 1418 -70 281 -192 497 -395
701 -202 203 -418 320 -701 380 -142 30 -404 33 -528 5 -346 -75 -611 -248
-853 -556 l-28 -35 -27 35 c-239 302 -500 475 -833 551 -99 23 -327 33 -438
19z m334 -305 c284 -50 529 -214 723 -485 33 -47 74 -103 90 -126 74 -104 228
-104 302 0 16 23 57 79 90 126 265 370 634 544 1036 489 446 -61 794 -373 927
-832 105 -363 59 -744 -132 -1087 -160 -287 -427 -588 -892 -1005 -225 -201
-1171 -1015 -1180 -1015 -10 0 -952 811 -1180 1015 -715 641 -997 1041 -1065
1510 -44 303 19 629 172 886 230 387 678 599 1109 524z"/>
</g>
</svg>
<span :style="`color:${like_color}`" class="text-xs text-[#E1EAF9] ">پسندیدم</span>
</div>
</button>
</div>
</div>
</div>
<div class="absolute top-1/2 left-2 flex gap-1 items-center content-center">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="16" height="12" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#E1EAF9" stroke="none">
<path d="M1262 4830 c-319 -40 -586 -171 -812 -399 -203 -204 -325 -420 -395
-701 -124 -487 -34 -967 264 -1418 191 -289 438 -554 891 -958 288 -257 1167
-1007 1210 -1032 40 -24 55 -27 140 -27 85 0 100 3 140 27 43 25 924 776 1210
1032 455 406 700 670 891 958 298 451 388 931 264 1418 -70 281 -192 497 -395
701 -202 203 -418 320 -701 380 -142 30 -404 33 -528 5 -346 -75 -611 -248
-853 -556 l-28 -35 -27 35 c-239 302 -500 475 -833 551 -99 23 -327 33 -438
19z m334 -305 c284 -50 529 -214 723 -485 33 -47 74 -103 90 -126 74 -104 228
-104 302 0 16 23 57 79 90 126 265 370 634 544 1036 489 446 -61 794 -373 927
-832 105 -363 59 -744 -132 -1087 -160 -287 -427 -588 -892 -1005 -225 -201
-1171 -1015 -1180 -1015 -10 0 -952 811 -1180 1015 -715 641 -997 1041 -1065
1510 -44 303 19 629 172 886 230 387 678 599 1109 524z"/>
</g>
</svg>
<span class="text-[#E1EAF9]">' . $other_comment->likes . '</span>
</div>
</div>
<div x-cloak @click.outside="reply_id=0" x-show="reply_id==' . $other_comment->id . '" class="mt-5">
<form >
<div class="border-2 border-black flex flex-col h-60 p-3 rounded-xl">
<input style="border-color: transparent; box-shadow: none;" x-model="name_reply" wire:model="comment_name_reply" class="bg-transparent border border-black focus-ring focus:outline-none focus:ring-0 my-3 p-3 resize-none ring-0 rounded-2xl text-black "
placeholder="نام شما">
<textarea style="border-color: transparent; box-shadow: none;" x-model="message_reply" wire:model="comment_message_reply"
class="bg-transparent border border-black focus-ring focus:outline-none focus:ring-0 my-3 p-3 resize-none ring-0 rounded-2xl text-black"
placeholder="نظر شما"></textarea>
<div class="flex justify-end gap-3">
<button @click="reply_id=0"
type="button"
class="text-white p-2 px-4 w-max text-sm rounded"> لغو پاسخ
</button>
<button @click="show_notif(name_reply.length>0 && message_reply.length>0),reply_id=0"
wire:click="reply(' . $other_comment->id . ',' . $comment->id . ')"
:disabled="!(name_reply.length>0 && message_reply.length>0)"
class="bg-[#F47A53] p-2 text-white text-sm px-4 w-max rounded-xl"> ارسال نظر
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
';
}
$result.='
</div>';
if ($other_comment->status==1) {
$result.='<hr>';
}
$result.='
<div>
'.home_comments($other_comment,$comment,$blog_id).'
</div>
</div>
';
}
return $result;
}}
if (!function_exists('panel_comments')) {
function panel_comments($comments, $comment, $blog_id) {
$result = '';
foreach ($comments->other as $another_comment) {
$result .= '
<div class="mx-10 relative ">
<div class="before:h-full before:absolute before:right-[-10px] before:top-[0] before:z-0 before:w-[3px] before:bg-gray-500 before:block ">
<div class="p-5 rounded ' . ($another_comment->type == 1 ? 'bg-gray-400' : 'bg-gray-200') . ' flex flex-col gap-3 m-3">
<div>
<h4> اسم : ' . $another_comment->name . '</h4>
<p> پیام : ' . $another_comment->message . '</p>
<p> نوع : ' . $another_comment->type_check . '</p>
'
;
$result .= '
</div>
<div>
<a @click="modalshow2 = true , id = {{ $comment->id }} , $wire.id = {{ $comment->id }} , $wire.blog_id = {{ $comment->blog->id }} " class=" w-[140px] text-center bg-gray-500 text-white rounded-xl px-4 py-1"> تایین وضعیت</a>
<a @click="modalshow = true , id = {{ $comment->id }} , $wire.id = {{ $comment->id }} , $wire.blog_id = {{ $comment->blog->id }} " class=" w-[120px] text-center bg-blue-500 text-white rounded-xl px-4 py-1">کامنت گذاری</a>
';
$result .= '
</div>
</div>
</div>
<div class="ps-3 ">
' . panel_comments($another_comment, $comment, $blog_id) . '
</div>
</div>';
}
return $result;
}
}
if(!function_exists('profile')){
function profile($admin=false)
{
if($admin){
return asset('images/profile/admin.png');
}
$num=random_int(1,7);
return asset('images/profile/'.$num.'.png');
}}
if(!function_exists('how_long')){
function how_long($time)
{
Carbon::setLocale('fa');
$res=Carbon::parse($time)->diffForHumans();
return $res;
}}
if (!function_exists('cleanRouteUrl')) {
function cleanRouteUrl($routeName, $parameters = [], $absolute = true)
{
$url = route($routeName, $parameters, $absolute);
$url = preg_replace('/([^:])\/\//', '$1/', $url);
return $url;
}
}