Initial Commit
This commit is contained in:
55
app/Helpers/CMail.php
Normal file
55
app/Helpers/CMail.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
|
||||
class CMail {
|
||||
|
||||
public static function send($config, $reply = false) {
|
||||
$mail = new PHPMailer(true);
|
||||
|
||||
try {
|
||||
//Server settings
|
||||
$mail->SMTPDebug = 2;
|
||||
$mail->Debugoutput = 'error_log'; //Enable verbose debug output
|
||||
$mail->isSMTP(); //Send using SMTP
|
||||
$mail->Host = config("services.mail.host"); //Set the SMTP server to send through
|
||||
$mail->SMTPAuth = true; //Enable SMTP authentication
|
||||
$mail->Username = config("services.mail.username"); //SMTP username
|
||||
$mail->Password = config("services.mail.password"); //SMTP password
|
||||
$mail->SMTPSecure = config("services.mail.encryption"); //Enable implicit TLS encryption
|
||||
$mail->Port = config("services.mail.port"); //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
|
||||
|
||||
//Recipients
|
||||
$mail->setFrom(isset($config["from_address"]) ? $config["from_address"] : config("services.mail.from_address"), isset($config["from_name"]) ? $config["from_name"] : config("services.mail.from_name"));
|
||||
$mail->addAddress($config["recipient_address"], isset($config["recipient_name"]) ? $config["recipient_name"] : null); //Add a recipient
|
||||
|
||||
if($reply) {
|
||||
$mail->addReplyTo(isset($config['replyToAddress']) ? $config['replyToAddress'] : '', isset($config['replyToName']) ? $config['replyToName'] : '');
|
||||
}
|
||||
//Content
|
||||
$mail->isHTML(true);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->Encoding = 'base64';
|
||||
$mail->Subject = $config["subject"];
|
||||
$mail->Body = $config["body"];
|
||||
|
||||
if(!$mail->send()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
logger()->error('Mail error: ' . $mail->ErrorInfo);
|
||||
logger()->error('Exception: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
338
app/Helpers/common.php
Normal file
338
app/Helpers/common.php
Normal file
@@ -0,0 +1,338 @@
|
||||
<?php
|
||||
|
||||
use App\Models\GeneralSetting;
|
||||
use App\Models\ParentCategory;
|
||||
use App\Models\Category;
|
||||
use App\Models\Slide;
|
||||
use App\Models\Post;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\SiteSocialLink;
|
||||
|
||||
|
||||
/**
|
||||
* Einstellungen
|
||||
* Lädt die allgemeinen Website-Einstellungen aus der Datenbank.
|
||||
*
|
||||
|
||||
* Hinweis:
|
||||
* - Die Funktion gibt aktuell nur dann etwas zurück, wenn Settings existieren.
|
||||
* Andernfalls endet sie ohne Return (entspricht in PHP: null).
|
||||
*
|
||||
* @example
|
||||
* $title = settings()?->site_title; // PHP 8+ Nullsafe Operator
|
||||
* $logo = settings()?->site_logo;
|
||||
*/
|
||||
|
||||
if(!function_exists("settings")) {
|
||||
function settings() {
|
||||
$settings = GeneralSetting::take(1)->first();
|
||||
|
||||
if(!is_null($settings)) { return $settings; }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seiten Social Link
|
||||
* Lädt die Social-Media-Links der Website aus der Datenbank.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Die Funktion gibt nur dann einen Wert zurück, wenn Einträge existieren.
|
||||
* Andernfalls endet sie ohne expliziten Return (entspricht in PHP: null).
|
||||
*
|
||||
* @example
|
||||
* $facebook = site_social_links()?->facebook;
|
||||
* $twitter = site_social_links()?->twitter;
|
||||
*/
|
||||
if(!function_exists('site_social_links')) {
|
||||
function site_social_links() {
|
||||
$links = SiteSocialLink::take(1)->first();
|
||||
if(!is_null($links)) { return $links; }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamisches Navigations Menu
|
||||
* Generiert die HTML-Navigation basierend auf Kategorien mit Beiträgen.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Es werden nur Kategorien berücksichtigt, die mindestens einen Beitrag haben.
|
||||
* - Parent-Kategorien werden als Dropdown dargestellt, sofern Kinder mit Beiträgen existieren.
|
||||
* - Kategorien ohne Parent werden als normale Navigationslinks ausgegeben.
|
||||
*
|
||||
* @return string HTML-Markup der Navigationsliste
|
||||
*
|
||||
* @example
|
||||
* {!! navigations() !!}
|
||||
*/
|
||||
if(!function_exists('navigations')) {
|
||||
function navigations() {
|
||||
$navigations_html = '';
|
||||
|
||||
$pcategories = ParentCategory::whereHas('children', function($q) {
|
||||
$q->whereHas('posts');
|
||||
})->orderBy('name', 'asc')->get();
|
||||
|
||||
$categories = Category::whereHas('posts')->where('parent', 0)->orderBy('name', 'asc')->get();
|
||||
|
||||
if(count($pcategories) > 0) {
|
||||
foreach($pcategories as $item) {
|
||||
$navigations_html.='
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" href="#!" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
'.$item->name.' <i class="ti-angle-down ml-1"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
';
|
||||
|
||||
foreach($item->children as $category) {
|
||||
if($category->posts->count() > 0) {
|
||||
$navigations_html.='<a class="dropdown-item" href="'.route('category_posts', $category->slug).'">'.$category->name.'</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$navigations_html.='
|
||||
</div>
|
||||
</li>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
if(count($categories) > 0) {
|
||||
foreach($categories as $item) {
|
||||
$navigations_html.='
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="'.route('category_posts', $item->slug).'">'.$item->name.'</a>
|
||||
</li>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
return $navigations_html;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DATE FORMAT January 12, 2024
|
||||
* Formatiert ein Datum in ein lesbares, lokalisiertes Format.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Erwartet ein Datum im Format `Y-m-d H:i:s`.
|
||||
* - Die Ausgabe erfolgt im ISO-Format `LL` (z. B. „14. September 2025“).
|
||||
*
|
||||
* @param string $value Datum/Zeit im Format `Y-m-d H:i:s`
|
||||
* @return string Formatiertes Datum
|
||||
*
|
||||
* @example
|
||||
* {{ date_formatter($post->created_at) }}
|
||||
*/
|
||||
if(!function_exists('date_formatter')) {
|
||||
function date_formatter($value) {
|
||||
return Carbon::createFromFormat('Y-m-d H:i:s', $value)->isoFormat('LL');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kürzt Wörter
|
||||
* Kürzt einen Text auf eine bestimmte Anzahl von Wörtern.
|
||||
*
|
||||
* Hinweis:
|
||||
* - HTML-Tags werden vor der Kürzung entfernt.
|
||||
* - Am Ende des Textes wird optional ein Abschlusszeichen angehängt.
|
||||
*
|
||||
* @param string $value Ausgangstext
|
||||
* @param int $words Maximale Anzahl an Wörtern (Standard: 15)
|
||||
* @param string $end Angehängter Text am Ende (Standard: "...")
|
||||
* @return string Gekürzter Text
|
||||
*
|
||||
* @example
|
||||
* {{ words($post->content, 30) }}
|
||||
*/
|
||||
if(!function_exists('words')) {
|
||||
function words($value, $words = 15, $end = '...') {
|
||||
return Str::words(strip_tags($value), $words, $end);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lesezeit
|
||||
* Berechnet die geschätzte Lesezeit eines Textes.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Die Berechnung basiert auf ca. 200 Wörtern pro Minute.
|
||||
* - Die minimale Rückgabe beträgt immer 1 Minute.
|
||||
* - Mehrere Textteile können als Argumente übergeben werden.
|
||||
*
|
||||
* @param string ...$text Ein oder mehrere Textinhalte
|
||||
* @return int Geschätzte Lesezeit in Minuten
|
||||
*
|
||||
* @example
|
||||
* {{ readDuration($post->title, $post->content) }} Min. Lesezeit
|
||||
*/
|
||||
if (!function_exists('readDuration')) {
|
||||
function readDuration(...$text): int
|
||||
{
|
||||
// Alles zu einem String zusammenfügen
|
||||
$content = implode(' ', $text);
|
||||
// HTML-Tags entfernen
|
||||
$content = strip_tags($content);
|
||||
// Wörter zählen (für DE ausreichend gut)
|
||||
$totalWords = str_word_count($content);
|
||||
// Lesegeschwindigkeit (Wörter pro Minute) – nach Bedarf anpassen
|
||||
$wordsPerMinute = 220;
|
||||
// Minuten berechnen und immer aufrunden
|
||||
$minutesToRead = (int) ceil($totalWords / max(1, $wordsPerMinute));
|
||||
// Mindestens 1 Minute zurückgeben
|
||||
return max(1, $minutesToRead);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt letzten Post an
|
||||
* Gibt die neuesten sichtbaren Blogbeiträge zurück.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Es werden nur veröffentlichte Beiträge berücksichtigt (`visibility = 1`).
|
||||
* - Über `$skip` können Einträge übersprungen werden (z. B. für Slider oder Pagination).
|
||||
*
|
||||
* @param int $skip Anzahl der zu überspringenden Beiträge (Standard: 0)
|
||||
* @param int $limit Maximale Anzahl der zurückgegebenen Beiträge (Standard: 5)
|
||||
* @return \Illuminate\Support\Collection Sammlung von Blogbeiträgen
|
||||
*
|
||||
* @example
|
||||
* @foreach(latest_posts(0, 3) as $post)
|
||||
* {{ $post->title }}
|
||||
* @endforeach
|
||||
*/
|
||||
if(!function_exists('latest_posts')) {
|
||||
function latest_posts($skip = 0, $limit = 5) {
|
||||
return Post::skip($skip)->limit($limit)->where('visibility', 1)->orderBy('created_at', 'desc')->get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listing Categories With Number of Posts on Sidebar
|
||||
* Gibt Kategorien für die Sidebar zurück, sortiert nach Beitragsanzahl.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Es werden nur Kategorien mit mindestens einem Beitrag berücksichtigt.
|
||||
* - Die Sortierung erfolgt absteigend nach Anzahl der Beiträge.
|
||||
*
|
||||
* @param int $limit Maximale Anzahl der Kategorien (Standard: 8)
|
||||
* @return \Illuminate\Support\Collection Sammlung von Kategorien
|
||||
*
|
||||
* @example
|
||||
* @foreach(sidebar_categories() as $category)
|
||||
* {{ $category->name }} ({{ $category->posts_count }})
|
||||
* @endforeach
|
||||
*/
|
||||
if(!function_exists('sidebar_categories')) {
|
||||
function sidebar_categories($limit = 8) {
|
||||
return Category::withCount('posts')->having('posts_count', '>', 0)->limit($limit)->orderBy('posts_count', 'desc')->get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FETCH ALL TAGS FROM THE 'POSTS' TABLE
|
||||
* Gibt eine eindeutige Liste aller verwendeten Tags zurück.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Tags werden aus dem `tags`-Feld der Beiträge gelesen (kommasepariert).
|
||||
* - Leere Tag-Felder werden ignoriert.
|
||||
* - Die Rückgabe ist alphabetisch sortiert und eindeutig.
|
||||
*
|
||||
* @param int|null $limit Maximale Anzahl der Tags (optional)
|
||||
* @return array Liste der Tags
|
||||
*
|
||||
* @example
|
||||
* @foreach(getTags() as $tag)
|
||||
* {{ $tag }}
|
||||
* @endforeach
|
||||
*/
|
||||
if (!function_exists('getTags')) {
|
||||
function getTags($limit = null) {
|
||||
$tags = Post::whereNotNull('tags')
|
||||
->where('tags', '!=', '')
|
||||
->pluck('tags');
|
||||
|
||||
$uniqueTags = $tags->flatMap(function ($tagsString) {
|
||||
return explode(',', $tagsString);
|
||||
})
|
||||
->map(fn($tag) => normalizeTag($tag))
|
||||
->filter()
|
||||
->unique()
|
||||
->sort()
|
||||
->values();
|
||||
|
||||
if ($limit) {
|
||||
$uniqueTags = $uniqueTags->take($limit);
|
||||
}
|
||||
|
||||
return $uniqueTags->all();
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeTag(string $tag): string
|
||||
{
|
||||
// urldecode: wandelt %20 und auch + -> Leerzeichen (wichtig!)
|
||||
$tag = urldecode($tag);
|
||||
|
||||
// Whitespace vereinheitlichen
|
||||
$tag = preg_replace('/\s+/u', ' ', trim($tag));
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Listing Sidebar Latest posts
|
||||
* Gibt die neuesten sichtbaren Blogbeiträge für die Sidebar zurück.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Es werden nur veröffentlichte Beiträge berücksichtigt (`visibility = 1`).
|
||||
* - Optional kann ein bestimmter Beitrag ausgeschlossen werden.
|
||||
* - Die Sortierung erfolgt nach Erstellungsdatum (neueste zuerst).
|
||||
*
|
||||
* @param int $limit Maximale Anzahl der Beiträge (Standard: 5)
|
||||
* @param int|null $except ID eines auszuschließenden Beitrags (optional)
|
||||
* @return \Illuminate\Support\Collection Sammlung von Blogbeiträgen
|
||||
*
|
||||
* @example
|
||||
* @foreach(sidebar_latest_posts(5, $post->id) as $item)
|
||||
* {{ $item->title }}
|
||||
* @endforeach
|
||||
*/
|
||||
if(!function_exists('sidebar_latest_posts')) {
|
||||
function sidebar_latest_posts($limit = 5, $except = null) {
|
||||
$posts = Post::limit($limit);
|
||||
if($except) {
|
||||
$posts = $posts->where('id', '!=', $except);
|
||||
}
|
||||
|
||||
return $posts->where('visibility', 1)->orderBy('created_at', 'desc')->get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Home Slider
|
||||
* Gibt aktive Slider-Einträge für den Home-Slider zurück.
|
||||
*
|
||||
* Hinweis:
|
||||
* - Es werden nur Slides mit aktivem Status (`status = 1`) berücksichtigt.
|
||||
* - Die Sortierung erfolgt nach der definierten Reihenfolge (`ordering`).
|
||||
*
|
||||
* @param int $limit Maximale Anzahl der Slides (Standard: 5)
|
||||
* @return \Illuminate\Support\Collection Sammlung von Slides
|
||||
*
|
||||
* @example
|
||||
* @foreach(get_slides() as $slide)
|
||||
* {{ $slide->title }}
|
||||
* @endforeach
|
||||
*/
|
||||
if(!function_exists('get_slides')) {
|
||||
function get_slides($limit = 5) {
|
||||
return Slide::where('status', 1)->limit($limit)->orderBy('ordering', 'asc')->get();
|
||||
}
|
||||
}
|
||||
?>
|
||||
265
app/Http/Controllers/AdminController.php
Normal file
265
app/Http/Controllers/AdminController.php
Normal file
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Models\User;
|
||||
use App\Models\Post;
|
||||
use App\Models\NewsletterSubscriber;
|
||||
use SawaStacks\Utils\Kropify;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use App\Models\GeneralSetting;
|
||||
|
||||
class AdminController extends Controller
|
||||
{
|
||||
/**
|
||||
* Zeigt das Admin-Dashboard an.
|
||||
*
|
||||
* ROUTE: /admin/dashboard
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function adminDashboard(Request $request)
|
||||
{
|
||||
$data = [
|
||||
"pageTitle" => "Dashboard",
|
||||
"tagsCount" => Post::whereNotNull('tags')->where('tags', '!=', '')->pluck('tags')->count(),
|
||||
"postsCount" => Post::count(),
|
||||
"subscribersCount" => NewsletterSubscriber::count(),
|
||||
"latestPosts" => Post::latest()->take(5)->get(),
|
||||
"postsWithoutMetaDescriptionCount" => Post::whereNull('meta_description')->orWhere('meta_description', '')->count(),
|
||||
"postsWithoutMetaKeywordsCount" => Post::whereNull('meta_keywords')->orWhere('meta_keywords', '')->count(),
|
||||
"postsWithoutTagsCount" => Post::whereNull('tags')->orWhere('tags', '')->count(),
|
||||
"postsWithoutMetaDescription" => Post::whereNull('meta_description')->orWhere('meta_description', '')->latest()->take(5)->get(),
|
||||
"postsWithoutMetaKeywords" => Post::whereNull('meta_keywords')->orWhere('meta_keywords', '')->latest()->take(5)->get(),
|
||||
"postsWithoutTags" => Post::whereNull('tags')->orWhere('tags', '')->latest()->take(5)->get(),
|
||||
];
|
||||
|
||||
return view("back.pages.dashboard", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Meldet den Benutzer ab und beendet die Session.
|
||||
*
|
||||
* ROUTE: /logout
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function logoutHandler(Request $request) {
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
if(isset($request->source)) {
|
||||
return redirect()->back();
|
||||
}
|
||||
return redirect()->route("admin.login")->with("success", "Du hast dich ausgeloggt");
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Profilseite des eingeloggten Benutzers an.
|
||||
*
|
||||
* ROUTE: /admin/profile
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function profileView(Request $request) {
|
||||
$data = [
|
||||
"pageTitle" => "Profile"
|
||||
];
|
||||
|
||||
return view("back.pages.profile", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert das Profilbild des eingeloggten Benutzers.
|
||||
*
|
||||
* ROUTE: /admin/profile/picture
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function updateProfilePicture(Request $request) {
|
||||
$user = User::findOrFail(auth()->id());
|
||||
|
||||
if (!$request->hasFile('profilePictureFile')) {
|
||||
return response()->json([
|
||||
'status' => 0,
|
||||
'message' => 'Keine Datei hochgeladen.',
|
||||
]);
|
||||
}
|
||||
|
||||
$file = $request->file('profilePictureFile');
|
||||
|
||||
// Der Zielordner relativ zum public/ Verzeichnis:
|
||||
$path = 'images/users/';
|
||||
|
||||
// Dateiname erzeugen
|
||||
$filename = 'IMG_' . uniqid() . '.png';
|
||||
|
||||
// Altes Bild speichern zum Löschen
|
||||
$oldPicture = $user->getAttributes()['picture'] ?? null;
|
||||
|
||||
// Datei mit Kropify speichern (direkt public_path)
|
||||
$upload = Kropify::getFile($file, $filename)
|
||||
->setPath($path) // relativ zu public/
|
||||
->useMove() // Speichert physisch in public/<path>
|
||||
->save();
|
||||
|
||||
if (!$upload) {
|
||||
return response()->json([
|
||||
'status' => 0,
|
||||
'message' => 'Fehler beim Hochladen des Profilfotos.',
|
||||
]);
|
||||
}
|
||||
|
||||
// Neues Bild wurde erfolgreich gespeichert → altes löschen
|
||||
if ($oldPicture && File::exists(public_path($path . $oldPicture))) {
|
||||
File::delete(public_path($path . $oldPicture));
|
||||
}
|
||||
|
||||
// Im User speichern
|
||||
$user->update([
|
||||
'picture' => $filename,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'status' => 1,
|
||||
'message' => 'Profilfoto erfolgreich hochgeladen.',
|
||||
'image' => $path . $filename, // falls du die URL direkt brauchst
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Seite für allgemeine Einstellungen an.
|
||||
*
|
||||
* ROUTE: /admin/settings/general
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function generalSettings(Request $request) {
|
||||
$data = [
|
||||
'pageTitle' => "Allgemeine Einstellungen"
|
||||
];
|
||||
|
||||
return view("back.pages.general_settings", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert das Website-Logo in den allgemeinen Einstellungen.
|
||||
*
|
||||
* ROUTE: /admin/settings/logo
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function updateLogo(Request $request) {
|
||||
$settings = GeneralSetting::take(1)->first();
|
||||
|
||||
if(!is_null($settings)) {
|
||||
$path = 'images/site/';
|
||||
$old_logo = $settings->site_logo;
|
||||
$file = $request->file("site_logo");
|
||||
$filename = 'logo_'.uniqid().'.png';
|
||||
|
||||
if($request->hasFile('site_logo')) {
|
||||
$upload = $file->move(public_path($path), $filename);
|
||||
|
||||
if($upload) {
|
||||
if($old_logo != null && File::exists(public_path($path.$old_logo))) {
|
||||
File::delete(public_path($path.$old_logo));
|
||||
}
|
||||
|
||||
$settings->update(['site_logo' => $filename]);
|
||||
return response()->json(['status' => 1, 'image_path' => $path.$filename, 'message' => 'Logo wurde erfolgreich geändert']);
|
||||
} else {
|
||||
return response()->json(['status' => 0, 'message' => 'Fehler beim hochladen von Logo']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return response()->json(['status' => 0, 'message' => 'Make sure you updated general Settings form First']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert das Website-Favicon in den allgemeinen Einstellungen.
|
||||
*
|
||||
* ROUTE: /admin/settings/favicon
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function updateFavicon(Request $request) {
|
||||
$settings = GeneralSetting::take(1)->first();
|
||||
|
||||
if(!is_null($settings)) {
|
||||
$path = 'images/site/';
|
||||
$old_favicon = $settings->site_favicon;
|
||||
$file = $request->file("site_favicon");
|
||||
$filename = 'favicon_'.uniqid().'.png';
|
||||
|
||||
if($request->hasFile('site_favicon')) {
|
||||
$upload = $file->move(public_path($path), $filename);
|
||||
|
||||
if($upload) {
|
||||
if($old_favicon != null && File::exists(public_path($path.$old_favicon))) {
|
||||
File::delete(public_path($path.$old_favicon));
|
||||
}
|
||||
|
||||
$settings->update(['site_favicon' => $filename]);
|
||||
return response()->json(['status' => 1, 'image_path' => $path.$filename, 'message' => 'Favicon wurde erfolgreich geändert']);
|
||||
} else {
|
||||
return response()->json(['status' => 0, 'message' => 'Fehler beim hochladen von Favicon']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return response()->json(['status' => 0, 'message' => 'Make sure you updated general Settings form First']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Verwaltungsseite für Kategorien an.
|
||||
*
|
||||
* ROUTE: /admin/categories
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function categoriesPage(Request $request) {
|
||||
$data = [
|
||||
"pageTitle" => "Kategorien verwalten"
|
||||
];
|
||||
|
||||
return view("back.pages.categories_page", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Verwaltungsseite für den Home-Slider an.
|
||||
*
|
||||
* ROUTE: /admin/slider
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function manageSlider(Request $request) {
|
||||
$data = [
|
||||
'pageTitle' => 'Manage Home Slider'
|
||||
];
|
||||
|
||||
return view('back.pages.slider', $data);
|
||||
}
|
||||
|
||||
}
|
||||
253
app/Http/Controllers/AuthController.php
Normal file
253
app/Http/Controllers/AuthController.php
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use App\UserStatus;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Helpers\CMail;
|
||||
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* Zeigt das Login-Formular im Backend an.
|
||||
*
|
||||
* ROUTE: /login
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function loginForm(Request $request) {
|
||||
$data = [
|
||||
"pageTitle" => "Login"
|
||||
];
|
||||
return view("back.pages.auth.login", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt das Formular zum Zurücksetzen des Passworts an.
|
||||
*
|
||||
* ROUTE: /forgot-password
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function forgotForm(Request $request) {
|
||||
$data = [
|
||||
"pageTitle" => "Forgot Password"
|
||||
];
|
||||
return view("back.pages.auth.forgot", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet den Login-Vorgang für Benutzer.
|
||||
*
|
||||
* ROUTE: /login
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function loginHandler(Request $request) {
|
||||
$fieldType = filter_var($request->login_id, FILTER_VALIDATE_EMAIL) ? "email" : "username";
|
||||
|
||||
if($fieldType == "email") {
|
||||
$request->validate([
|
||||
"login_id" => "required|email|exists:users,email",
|
||||
"password"=> "required|min:5"
|
||||
], [
|
||||
"login_id.required" => "Gebe deine Email oder Benutzernamen ein",
|
||||
"login_id.email" => "Ungültige Email Adresse",
|
||||
"login_id.exists" => "Kein Account unter dieser Email gefunden",
|
||||
"password.required" => "Passwort wird benötigt",
|
||||
"password.min" => "Bitte gebe mind. 5 Zeichen ein",
|
||||
]);
|
||||
} else {
|
||||
$request->validate([
|
||||
"login_id" => "required|exists:users,username",
|
||||
"password"=> "required|min:5"
|
||||
], [
|
||||
"login_id.required" => "Gebe deine Email oder Benutzernamen ein",
|
||||
"login_id.exists" => "Kein Account unter dieser Email gefunden",
|
||||
"password.required" => "Passwort wird benötigt",
|
||||
"password.min" => "Bitte gebe mind. 5 Zeichen ein",
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
$creds = array(
|
||||
$fieldType=>$request->login_id,
|
||||
"password" => $request->password
|
||||
);
|
||||
|
||||
if(Auth::attempt($creds)) {
|
||||
// Überprüfen ob Benutzer inactive ist
|
||||
if(auth()->user()->status == UserStatus::Inactive) {
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return redirect()->route("admin.login")->with("fail", "Dein Account ist derzeit Inactive. Bitte kontaktiere den Support unter (support@larablog.dev) für weitere Informationen");
|
||||
}
|
||||
|
||||
if(auth()->user()->status == UserStatus::Pending) {
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return redirect()->route("admin.login")->with("fail", "Dein Account ist derzeit in Bearbeitung. Bitte kontaktiere den Support unter (support@larablog.dev) für weitere Informationen");
|
||||
}
|
||||
|
||||
return redirect()->route("admin.dashboard");
|
||||
} else {
|
||||
return redirect()->route("admin.login")->withInput()->with("fail", "Incorrect Password");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versendet einen Link zum Zurücksetzen des Passworts per E-Mail.
|
||||
*
|
||||
* ROUTE: /forgot-password
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function sendPasswordresetLink(Request $request) {
|
||||
$request->validate([
|
||||
"email" => "required|email|exists:users,email"
|
||||
], [
|
||||
"email.required"=>"Email Adresse wird benötigt",
|
||||
"email.email" => "Ungültige Email Adresse",
|
||||
"email.exists" => "Wir konnte diese Email nicht in unseren System finden",
|
||||
]);
|
||||
|
||||
$user = User::where("email", $request->email)->first();
|
||||
|
||||
$token = base64_encode(Str::random(64));
|
||||
|
||||
$oldToken = DB::table("password_reset_tokens")->where("email", $user->email)->first();
|
||||
|
||||
if($oldToken) {
|
||||
DB::table("password_reset_tokens")->where("email", $request->email)->update([
|
||||
"token" => $token,
|
||||
"created_at" => Carbon::now()
|
||||
]);
|
||||
} else {
|
||||
DB::table("password_reset_tokens")->insert([
|
||||
"email" => $user->email,
|
||||
"token" => $token,
|
||||
"created_at" => Carbon::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
$actionLink = route("admin.reset_password_form", ["token" => $token]);
|
||||
|
||||
$data = array("actionlink" => $actionLink, "user" => $user);
|
||||
$mail_body = view("email-templates.forgot-template", $data)->render();
|
||||
|
||||
$mailConfig = array(
|
||||
"recipient_address" => $user->email,
|
||||
"recipient_name" => $user->name,
|
||||
"subject" => "Reset Passwort",
|
||||
"body" => $mail_body
|
||||
);
|
||||
|
||||
if(CMail::send($mailConfig)) {
|
||||
return redirect()->route("admin.forgot")->with("success", "Wir haben Ihnen einen Link per E-Mail zugesendet");
|
||||
} else {
|
||||
return redirect()->route("admin.forgot")->with("fail", "Leider ist etwas schief gegangen, bitte versuchen Sie es später wieder");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt das Formular zum Zurücksetzen des Passworts an.
|
||||
*
|
||||
* ROUTE: /reset-password/{token}
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string|null $token Passwort-Reset-Token
|
||||
* @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function resetForm(Request $request, $token = null) {
|
||||
$isTokenExists = DB::table("password_reset_tokens")->where("token", $token)->first();
|
||||
|
||||
if(!$isTokenExists) {
|
||||
return redirect()->route("admin.forgot")->with("fail", "Ungültiger Token, fordere einen neuen an");
|
||||
} else {
|
||||
|
||||
$diffMins = Carbon::createFromFormat("Y-m-D H:i:s", $isTokenExists->created_at)->diffInMinutes(Carbon::now());
|
||||
|
||||
if($diffMins > 30) {
|
||||
return redirect()->route("admin.forgot")->with("fail", "Der Reset Link ist leider abgelaufen, fordere einen neuen Link an");
|
||||
}
|
||||
|
||||
$data = [
|
||||
"pageTitle" => "Passwort zurücksetzen",
|
||||
"token" => $token
|
||||
];
|
||||
return view("back.pages.auth.reset", $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet das Zurücksetzen des Passworts.
|
||||
*
|
||||
* ROUTE: /reset-password
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function resetPasswordHandler(Request $request) {
|
||||
$request->validate([
|
||||
"new_password" => "required|min:5|required_with:new_password_confirm|same:new_password_confirm",
|
||||
"new_password_confirm" => "required"
|
||||
], [
|
||||
"new_password.required" => "Neues Passwort wird benötigt",
|
||||
"new_password_confirm.required" => "Neues Passwort wird benötigt",
|
||||
"new_password.same" => "Du musst das neue Passwort bestätigen",
|
||||
"new_password.min" => "Bitte gebe mind. 5 Zeichen ein",
|
||||
]);
|
||||
|
||||
$dbToken = DB::table("password_reset_tokens")->where("token", $request->token)->first();
|
||||
|
||||
$user = User::where("email", $dbToken->email)->first();
|
||||
|
||||
User::where("email", $user->email)->update([
|
||||
"password" => Hash::make($request->new_password)
|
||||
]);
|
||||
|
||||
$data = array(
|
||||
"user" => $user,
|
||||
"new_password" => $request->new_password
|
||||
);
|
||||
|
||||
$mail_body = view("email-templates.password-changes-template", $data)->render();
|
||||
|
||||
$mailConfig = array(
|
||||
"recipient_address" => $user->email,
|
||||
"recipient_name" => $user->name,
|
||||
"subject" => "Passwort geändert",
|
||||
"body" => $mail_body
|
||||
);
|
||||
|
||||
if(CMail::send($mailConfig)) {
|
||||
DB::table("password_reset_tokens")->where([
|
||||
"email" => $dbToken->email,
|
||||
"token" => $dbToken->token,
|
||||
])->delete();
|
||||
return redirect()->route("admin.login")->with("success", "Wir haben Ihr Passwort geändert, Sie können sich nun einloggen");
|
||||
} else {
|
||||
return redirect()->route("admin.reset_password_form", ["token" => $dbToken->token])->with("fail", "Leider ist etwas schief gegangen, bitte versuchen Sie es später wieder");
|
||||
}
|
||||
}
|
||||
}
|
||||
326
app/Http/Controllers/BlogController.php
Normal file
326
app/Http/Controllers/BlogController.php
Normal file
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Artesaos\SEOTools\Facades\SEOTools;
|
||||
use Artesaos\SEOTools\Facades\SEOMeta;
|
||||
use App\Models\Post;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
use App\Helpers\CMail;
|
||||
|
||||
class BlogController extends Controller
|
||||
{
|
||||
/**
|
||||
* Zeigt die Startseite der Website an.
|
||||
*
|
||||
* ROUTE: /
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request) {
|
||||
|
||||
$title = isset(settings()->site_title) ? settings()->site_title : '';
|
||||
$description = isset(settings()->site_meta_description) ? settings()->site_meta_description : '';
|
||||
$imgURL = isset(settings()->site_logo) ? asset('/images/site/'.settings()->site_logo) : '';
|
||||
$keywords = isset(settings()->site_meta_keywords) ? settings()->site_meta_keywords : '';
|
||||
$currentUrl = url()->current();
|
||||
|
||||
/**
|
||||
* META SEO
|
||||
*/
|
||||
SEOTools::setTitle($title, false);
|
||||
SEOTools::setDescription($description);
|
||||
SEOMeta::setKeywords($keywords);
|
||||
|
||||
/**
|
||||
* OPEN GRAPH
|
||||
*/
|
||||
SEOTools::opengraph()->setUrl($currentUrl);
|
||||
SEOTools::opengraph()->addImage($imgURL);
|
||||
SEOTools::opengraph()->addProperty('type', 'articles');
|
||||
|
||||
/**
|
||||
* TWITTER
|
||||
*/
|
||||
SEOTools::twitter()->addImage($imgURL);
|
||||
SEOTools::twitter()->setUrl($currentUrl);
|
||||
SEOTools::twitter()->setSite('@larablog');
|
||||
|
||||
$title = isset(settings()->site_title) ? settings()->site_title : '';
|
||||
$data = [
|
||||
'pageTitle' => $title
|
||||
];
|
||||
|
||||
return view('front.pages.index', $data);
|
||||
}
|
||||
/**
|
||||
* Gibt alle sichtbaren Blogbeiträge einer Kategorie aus.
|
||||
*
|
||||
* ROUTE: /category/{slug}
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string|null $slug Slug der Kategorie
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function categoryPosts(Request $request, $slug = null) {
|
||||
$category = Category::where('slug', $slug)->firstOrFail();
|
||||
|
||||
$posts = Post::where('category', $category->id)->where('visibility',1)->paginate(8);
|
||||
|
||||
$title = 'Posts in der Kategorie: '.$category->name;
|
||||
$description = 'Durchstöbern Sie die neuesten Beiträge in der Kategorie '.$category->name.'. Bleiben Sie mit Artikeln, Einblicken und Anleitungen auf dem Laufenden.';
|
||||
|
||||
/**
|
||||
* SEO
|
||||
*/
|
||||
SEOTools::setTitle($title, false);
|
||||
SEOTools::setDescription($description);
|
||||
SEOTools::opengraph()->setUrl(url()->current());
|
||||
|
||||
$data = [
|
||||
'pageTitle' => $category->name,
|
||||
'posts' => $posts
|
||||
];
|
||||
|
||||
return view('front.pages.category_posts', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle sichtbaren Blogbeiträge eines Autors aus.
|
||||
*
|
||||
* ROUTE: /author/{username}
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string|null $username Benutzername des Autors
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function authorPosts(Request $request, $username = null) {
|
||||
$author = User::where('username', $username)->firstOrFail();
|
||||
$posts = Post::where('author_id', $author->id)->where('visibility',1)->orderBy('created_at', 'asc')->paginate(8);
|
||||
$title = $author->name.' - Blog Posts';
|
||||
$description = 'Entdecke die neuesten Beiträge von .'.$author->name.' zu verschiedenen Themen';
|
||||
|
||||
/**
|
||||
* SEO
|
||||
*/
|
||||
SEOTools::setTitle($title, false);
|
||||
SEOTools::setDescription($description);
|
||||
SEOTools::setCanonical(route('author_posts', ['username' => $author->username]));
|
||||
SEOTools::opengraph()->setUrl(route('author_posts', ['username' => $author->username]));
|
||||
SEOTools::opengraph()->addProperty('type', 'profile');
|
||||
SEOTools::opengraph()->setProfile([
|
||||
'first_name' => $author->name,
|
||||
'username' => $author->username
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'pageTitle' => $author->name,
|
||||
'author' => $author,
|
||||
'posts' => $posts
|
||||
];
|
||||
|
||||
return view('front.pages.author_posts', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle sichtbaren Blogbeiträge zu einem bestimmten Tag aus.
|
||||
*
|
||||
* ROUTE: /tag/{tag}
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string|null $tag Tag-Bezeichnung
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function tagPosts(Request $request, $tag = null) {
|
||||
$posts = Post::where('tags', 'LIKE', "%{$tag}%")->where('visibility', 1)->paginate(8);
|
||||
|
||||
$title = "Beiträge mit dem Tag '{$tag}'";
|
||||
$description = "Entdecke alle Beiträge in unserem Blog, die mit {$tag} getaggt sind.";
|
||||
|
||||
|
||||
/**
|
||||
* SEO
|
||||
*/
|
||||
SEOTools::setTitle($title, false);
|
||||
SEOTools::setDescription($description);
|
||||
SEOTools::setCanonical(url()->current());
|
||||
|
||||
SEOTools::opengraph()->setUrl(url()->current());
|
||||
SEOTools::opengraph()->addProperty('type', 'articles');
|
||||
|
||||
$data = [
|
||||
'pageTitle' => $title,
|
||||
'tag' => $tag,
|
||||
'posts' => $posts,
|
||||
];
|
||||
|
||||
return view('front.pages.tag_posts', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Durchsucht Blogbeiträge anhand eines Suchbegriffs.
|
||||
*
|
||||
* ROUTE: /search
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function searchPosts(Request $request) {
|
||||
|
||||
$query = $request->input('q');
|
||||
|
||||
if($query) {
|
||||
$keywords = explode(' ', $query);
|
||||
$postsQuery = Post::query();
|
||||
|
||||
foreach($keywords as $keyword) {
|
||||
$postsQuery->orWhere('title', 'LIKE', '%'.$keyword.'%')->orWhere('tags', 'LIKE', '%'.$keyword.'%');
|
||||
}
|
||||
$posts = $postsQuery->where('visibility', 1)->orderBy('created_at', 'desc')->paginate(10);
|
||||
|
||||
$title = "Such Ergebnis für {$query}";
|
||||
$description = "Durchsuchen Sie die Suchergebnisse für {$query} auf unserem Blog.";
|
||||
} else {
|
||||
$posts = collect();
|
||||
|
||||
$title = 'Suche';
|
||||
$description = "Suchen Sie auf unserer Website nach Blogbeiträgen.";
|
||||
}
|
||||
|
||||
SEOTools::setTitle($title, false);
|
||||
SEOTools::setDescription($description);
|
||||
|
||||
$data = [
|
||||
'pageTitle' => $title,
|
||||
'query' => $query,
|
||||
'posts' => $posts
|
||||
];
|
||||
|
||||
return view('front.pages.search_posts', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt einen einzelnen Blogbeitrag anhand des Slugs aus.
|
||||
*
|
||||
* ROUTE: /post/{slug}
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string|null $slug Eindeutiger Slug des Beitrags
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function readPost(Request $request, $slug = null) {
|
||||
$post = Post::where('slug', $slug)->firstOrFail();
|
||||
|
||||
$relatedPosts = Post::where('category', $post->category)->where('id', '!=', $post->id)->where('visibility', 1)->take(3)->get();
|
||||
$nextPost = Post::where('id', '>', $post->id)->where('visibility', 1)->orderBy('id', 'asc')->first();
|
||||
$prevPost = Post::where('id', '<', $post->id)->where('visibility', 1)->orderBy('id', 'desc')->first();
|
||||
|
||||
/**
|
||||
* SEO
|
||||
*/
|
||||
$title = $post->title;
|
||||
$description = ($post->meta_description != '') ? $post->meta_description : words($post->content, 35);
|
||||
|
||||
SEOTools::setTitle($title, false);
|
||||
SEOTools::setDescription($description);
|
||||
SEOTools::opengraph()->setUrl(route('read_post', ['slug' => $post->slug]));
|
||||
SEOTools::opengraph()->addProperty('type', 'article');
|
||||
SEOTools::opengraph()->addImage(asset('images/posts/'.$post->featured_image));
|
||||
SEOTools::twitter()->setImage(asset('images/posts/'.$post->featured_image));
|
||||
SEOMeta::addMeta('article:published_time', $post->created_at->toW3CString(), 'property');
|
||||
SEOMeta::addMeta('article:section', $post->category, 'property');
|
||||
|
||||
$data = [
|
||||
'pageTitle' => $title,
|
||||
'post' => $post,
|
||||
'relatedPosts' => $relatedPosts,
|
||||
'nextPost' => $nextPost,
|
||||
'prevPost' => $prevPost
|
||||
];
|
||||
|
||||
return view('front.pages.single_post', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Kontaktseite an.
|
||||
*
|
||||
* ROUTE: /contact
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function contactPage(Request $request) {
|
||||
$title = "Kontaktiere uns";
|
||||
$description = "Sie hassen Formulare? Schreiben Sie uns eine E-Mail.";
|
||||
|
||||
/**
|
||||
* SEO
|
||||
*/
|
||||
SEOTools::setTitle($title, false);
|
||||
SEOTools::setDescription($description);
|
||||
|
||||
return view('front.pages.contact');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet das Kontaktformular und versendet eine E-Mail.
|
||||
*
|
||||
* ROUTE: /contact/send
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function sendEmail(Request $request) {
|
||||
$request->validate([
|
||||
'name' => 'required',
|
||||
'email' => 'required|email',
|
||||
'subject' => 'required',
|
||||
'message' => 'required',
|
||||
], [
|
||||
'name.required' => 'Name wird benötigt',
|
||||
'email.required' => 'Email wird benötigt',
|
||||
'email.email' => 'Bitte gültige Email angeben',
|
||||
'subject.required' => 'Titel wird benötigt',
|
||||
'message.required' => 'Nachricht wird benötigt',
|
||||
]);
|
||||
|
||||
$siteInfo = settings();
|
||||
|
||||
$data = [
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'message' => $request->message,
|
||||
'subject' => $request->subject
|
||||
];
|
||||
|
||||
$mail_body = view('email-templates.contact-message-template', $data);
|
||||
|
||||
$mail_config = [
|
||||
'from_name' => config('services.mail.from_name'),
|
||||
'replyToAddress' => $request->email,
|
||||
'replyToName' => $request->name,
|
||||
'recipient_address' => $siteInfo->site_email,
|
||||
'recipient_name' => $siteInfo->site_title,
|
||||
'subject' => $request->subject,
|
||||
'body' => $mail_body
|
||||
];
|
||||
|
||||
if(CMail::send($mail_config, true)) {
|
||||
return redirect()->back()->with("success", "E-Mail wurde gesendet");
|
||||
} else {
|
||||
return redirect()->back()->with("fail", "Leider ist etwas schief gegangen, bitte versuchen Sie es später wieder");
|
||||
}
|
||||
}
|
||||
}
|
||||
8
app/Http/Controllers/Controller.php
Normal file
8
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
354
app/Http/Controllers/PostController.php
Normal file
354
app/Http/Controllers/PostController.php
Normal file
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\ParentCategory;
|
||||
use App\Models\Category;
|
||||
use App\Models\Post;
|
||||
use Intervention\Image\Laravel\Facades\Image;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
use App\Models\NewsletterSubscriber;
|
||||
use App\Jobs\SendNewsletterJob;
|
||||
|
||||
class PostController extends Controller
|
||||
{
|
||||
/**
|
||||
* Zeigt das Formular zum Erstellen eines neuen Blogbeitrags an.
|
||||
*
|
||||
* ROUTE: /admin/posts/create
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function addPost(Request $request) {
|
||||
$categories_html = '';
|
||||
$pcategories = ParentCategory::whereHas('children')->orderBy('name', 'asc')->get();
|
||||
$categories = Category::where('parent', 0)->orderBy('name', 'asc')->get();
|
||||
|
||||
if(count($pcategories) > 0) {
|
||||
foreach($pcategories as $item) {
|
||||
$categories_html.='<optgroup label="'.$item->name.'">';
|
||||
foreach($item->children as $category) {
|
||||
$categories_html.='<option value="'.$category->id.'">'.$category->name.'</option>';
|
||||
}
|
||||
$categories_html.='</optgroup>';
|
||||
}
|
||||
}
|
||||
|
||||
if(count($categories) > 0) {
|
||||
foreach($categories as $item) {
|
||||
$categories_html.='<option value="'.$item->id.'">'.$item->name.'</option>';
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'pageTitle' => 'Add new Post',
|
||||
'categories_html' => $categories_html
|
||||
];
|
||||
|
||||
return view('back.pages.add_post', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen neuen Blogbeitrag und speichert das Beitragsbild.
|
||||
*
|
||||
* ROUTE: /admin/posts
|
||||
* METHOD: POST
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function createPost(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'title' => 'required|unique:posts,title',
|
||||
'content' => 'required',
|
||||
'category' => 'required|exists:categories,id',
|
||||
'featured_image' => 'required|mimes:png,jpg,jpeg',
|
||||
], [
|
||||
'title.required' => 'Titel wird benötigt',
|
||||
'title.unique' => 'Titel bereits vergeben',
|
||||
'content.required' => 'Content wird benötigt',
|
||||
'category.required' => 'Kategorie wird benötigt',
|
||||
'category.exists' => 'Kategorie existiert nicht',
|
||||
'featured_image.required' => 'Image wird benötigt',
|
||||
'featured_image.mimes' => 'Es sind nur png,jpg,jpeg erlaubt',
|
||||
]);
|
||||
|
||||
if ($request->hasFile('featured_image')) {
|
||||
|
||||
$relativePath = 'images/posts/'; // relativ zu /public
|
||||
$basePath = public_path($relativePath); // absoluter Pfad
|
||||
|
||||
$file = $request->file('featured_image');
|
||||
$filename = $file->getClientOriginalName();
|
||||
$newFilename = time().'_'.$filename;
|
||||
|
||||
// Original speichern
|
||||
if (!File::isDirectory($basePath)) {
|
||||
File::makeDirectory($basePath, 0777, true, true);
|
||||
}
|
||||
|
||||
$upload = $file->move($basePath, $newFilename);
|
||||
|
||||
if ($upload) {
|
||||
$originalPath = $basePath.DIRECTORY_SEPARATOR.$newFilename;
|
||||
$quality = 80;
|
||||
|
||||
// resized-Ordner
|
||||
$resizedDir = $basePath.DIRECTORY_SEPARATOR.'resized'.DIRECTORY_SEPARATOR;
|
||||
if (!File::isDirectory($resizedDir)) {
|
||||
File::makeDirectory($resizedDir, 0777, true, true);
|
||||
}
|
||||
|
||||
// 1) Thumbnail (250x250 aus Original)
|
||||
$thumbPath = $resizedDir.'thumb_'.$newFilename;
|
||||
Image::read($originalPath)
|
||||
->cover(250, 250) // v3-Pendant zu fit(250,250)
|
||||
->save($thumbPath, $quality);
|
||||
|
||||
// 2) Resized (512x320 aus Original)
|
||||
$resizedPath = $resizedDir.'resized_'.$newFilename;
|
||||
Image::read($originalPath)
|
||||
->cover(512, 320) // v3-Pendant zu fit(512,320)
|
||||
->save($resizedPath, $quality);
|
||||
|
||||
// Post speichern
|
||||
$post = new Post();
|
||||
$post->author_id = auth()->id();
|
||||
$post->category = $request->category; // ggf. category_id
|
||||
$post->title = $request->title;
|
||||
$post->content = $request->content;
|
||||
$post->featured_image = $newFilename;
|
||||
$post->tags = $request->tags;
|
||||
$post->meta_keywords = $request->meta_keywords;
|
||||
$post->meta_description = $request->meta_description;
|
||||
$post->visibility = $request->visibility;
|
||||
$post->structured_data = $request->structured_data;
|
||||
|
||||
$saved = $post->save();
|
||||
|
||||
if ($saved) {
|
||||
/**
|
||||
* Send Email to Newsletter Subscribers
|
||||
*/
|
||||
if($request->visibility == 1) {
|
||||
$latestPost = Post::latest()->first();
|
||||
|
||||
if(NewsletterSubscriber::count() > 0) {
|
||||
$subscribers = NewsLetterSubscriber::pluck('email');
|
||||
foreach($subscribers as $subscriber_email) {
|
||||
SendNewsletterJob::dispatch($subscriber_email, $latestPost);
|
||||
}
|
||||
$latestPost->is_notified = true;
|
||||
$latestPost->save();
|
||||
}
|
||||
}
|
||||
return response()->json(['status' => 1, 'message' => 'Post wurde erfolgreich erstellt']);
|
||||
}
|
||||
|
||||
return response()->json(['status' => 0, 'message' => 'Post konnte nicht erstellt werden'], 500);
|
||||
}
|
||||
|
||||
return response()->json(['status' => 0, 'message' => 'Leider gab es ein Problem, versuch es später nochmal'], 500);
|
||||
}
|
||||
|
||||
return response()->json(['status' => 0, 'message' => 'Kein Bild hochgeladen'], 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Übersichtsseite aller Blogbeiträge im Backend an.
|
||||
*
|
||||
* ROUTE: /admin/posts
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function allPosts(Request $request) {
|
||||
$data = [
|
||||
'pageTitle' => 'Posts'
|
||||
];
|
||||
return view('back.pages.posts', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt das Formular zum Bearbeiten eines bestehenden Blogbeitrags an.
|
||||
*
|
||||
* ROUTE: /admin/posts/{id}/edit
|
||||
* METHOD: GET
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int|null $id ID des Blogbeitrags
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function editPost(Request $request, $id = null) {
|
||||
$post = Post::findOrFail($id);
|
||||
|
||||
$categories_html = '';
|
||||
$pcategories = ParentCategory::whereHas('children')->orderBy('name', 'asc')->get();
|
||||
$categories = Category::where('parent', 0)->orderBy('name', 'asc')->get();
|
||||
|
||||
if(count($pcategories) > 0) {
|
||||
foreach($pcategories as $item) {
|
||||
$categories_html.='<optgroup label="'.$item->name.'">';
|
||||
foreach($item->children as $category) {
|
||||
$selected = $category->id == $post->category ? 'selected' : '';
|
||||
$categories_html.='<option value="'.$category->id.'">'.$category->name.'</option>';
|
||||
}
|
||||
$categories_html.='</optgroup>';
|
||||
}
|
||||
}
|
||||
|
||||
if(count($categories) > 0) {
|
||||
foreach($categories as $item) {
|
||||
$selected = $item->id == $post->category ? 'selected' : '';
|
||||
$categories_html.='<option value="'.$item->id.'" '.$selected.'>'.$item->name.'</option>';
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'pageTitle' => 'Post Bearbeiten',
|
||||
'post'=> $post,
|
||||
'categories_html' => $categories_html
|
||||
];
|
||||
|
||||
return view('back.pages.edit_post', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert einen bestehenden Blogbeitrag (inkl. optionalem Beitragsbild).
|
||||
*
|
||||
* ROUTE: /admin/posts/{id}
|
||||
* METHOD: PUT/PATCH
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function updatePost(Request $request)
|
||||
{
|
||||
$post = Post::findOrFail($request->post_id);
|
||||
$featured_image_name = $post->featured_image;
|
||||
|
||||
$request->validate([
|
||||
'title' => 'required|unique:posts,title,' . $post->id,
|
||||
'content' => 'required',
|
||||
'category' => 'required|exists:categories,id',
|
||||
'featured_image' => 'nullable|mimes:png,jpg,jpeg',
|
||||
], [
|
||||
'title.required' => 'Titel wird benötigt',
|
||||
'title.unique' => 'Titel bereits vergeben',
|
||||
'content.required' => 'Content wird benötigt',
|
||||
'category.required' => 'Kategorie wird benötigt',
|
||||
'category.exists' => 'Kategorie existiert nicht',
|
||||
'featured_image.mimes' => 'Es sind nur png,jpg,jpeg erlaubt',
|
||||
]);
|
||||
|
||||
if ($request->hasFile('featured_image')) {
|
||||
$old_featured_image = $post->featured_image;
|
||||
|
||||
// Basis-Pfade
|
||||
$relativePath = 'images/posts/'; // relativ zu /public
|
||||
$basePath = public_path($relativePath); // absoluter Pfad
|
||||
|
||||
$file = $request->file('featured_image');
|
||||
$filename = $file->getClientOriginalName();
|
||||
$newFilename = time() . '_' . $filename;
|
||||
|
||||
// Ordner für Original sicherstellen
|
||||
if (!File::isDirectory($basePath)) {
|
||||
File::makeDirectory($basePath, 0777, true, true);
|
||||
}
|
||||
|
||||
$upload = $file->move($basePath, $newFilename);
|
||||
|
||||
if ($upload) {
|
||||
$originalPath = $basePath . DIRECTORY_SEPARATOR . $newFilename;
|
||||
|
||||
// resized-Ordner sicherstellen
|
||||
$resizedDirRelative = $relativePath . 'resized/';
|
||||
$resizedDir = public_path($resizedDirRelative);
|
||||
|
||||
if (!File::isDirectory($resizedDir)) {
|
||||
File::makeDirectory($resizedDir, 0777, true, true);
|
||||
}
|
||||
|
||||
// Thumbnail (1:1) – v3: read + cover
|
||||
$thumbPath = $resizedDir . DIRECTORY_SEPARATOR . 'thumb_' . $newFilename;
|
||||
Image::read($originalPath)
|
||||
->cover(250, 250)
|
||||
->save($thumbPath);
|
||||
|
||||
// Resized (512x320)
|
||||
$resizedPath = $resizedDir . DIRECTORY_SEPARATOR . 'resized_' . $newFilename;
|
||||
Image::read($originalPath)
|
||||
->cover(512, 320)
|
||||
->save($resizedPath);
|
||||
|
||||
// Alte Bilder löschen
|
||||
if ($old_featured_image) {
|
||||
$oldOriginal = public_path($relativePath . $old_featured_image);
|
||||
$oldResized = public_path($resizedDirRelative . 'resized_' . $old_featured_image);
|
||||
$oldThumb = public_path($resizedDirRelative . 'thumb_' . $old_featured_image);
|
||||
|
||||
if (File::exists($oldOriginal)) {
|
||||
File::delete($oldOriginal);
|
||||
}
|
||||
if (File::exists($oldResized)) {
|
||||
File::delete($oldResized);
|
||||
}
|
||||
if (File::exists($oldThumb)) {
|
||||
File::delete($oldThumb);
|
||||
}
|
||||
}
|
||||
|
||||
$featured_image_name = $newFilename;
|
||||
} else {
|
||||
return response()->json([
|
||||
'status' => 0,
|
||||
'message' => 'Leider gab es ein Fehler beim Hochladen von Image',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$sendEmailToSubscribers = ($post->visibility == 0 && $post->is_notified == 0 && $request->visibility == 1) ? true : false;
|
||||
|
||||
// Post-Daten aktualisieren
|
||||
$post->author_id = auth()->id();
|
||||
$post->category = $request->category;
|
||||
$post->title = $request->title;
|
||||
$post->content = $request->content;
|
||||
$post->featured_image = $featured_image_name;
|
||||
$post->tags = $request->tags;
|
||||
$post->meta_keywords = $request->meta_keywords;
|
||||
$post->meta_description = $request->meta_description;
|
||||
$post->visibility = $request->visibility;
|
||||
$post->structured_data = $request->structured_data;
|
||||
|
||||
$saved = $post->save();
|
||||
|
||||
if ($saved) {
|
||||
/**
|
||||
* Send Mail Newsletter to Subscribers
|
||||
*/
|
||||
if($sendEmailToSubscribers) {
|
||||
$currentPost = Post::findOrFail($request->post_id);
|
||||
if(NewsletterSubscriber::count() > 0) {
|
||||
$subscribers = NewsLetterSubscriber::pluck('email');
|
||||
foreach($subscribers as $subscriber_email) {
|
||||
SendNewsletterJob::dispatch($subscriber_email, $currentPost);
|
||||
}
|
||||
$currentPost->is_notified = true;
|
||||
$currentPost->save();
|
||||
}
|
||||
}
|
||||
return response()->json(['status' => 1, 'message' => 'Post wurde erfolgreich bearbeitet']);
|
||||
}
|
||||
|
||||
return response()->json(['status' => 0, 'message' => 'Fehler beim Bearbeiten von Post']);
|
||||
}
|
||||
|
||||
}
|
||||
47
app/Http/Controllers/SitemapController.php
Normal file
47
app/Http/Controllers/SitemapController.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\Sitemap\Sitemap;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
|
||||
use App\Models\Post;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
|
||||
class SitemapController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$sitemap = Sitemap::create();
|
||||
|
||||
$sitemap->add(
|
||||
Url::create('/')
|
||||
->setPriority(1.0)
|
||||
->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY)
|
||||
);
|
||||
|
||||
$sitemap->add(
|
||||
Url::create('/contact')
|
||||
->setPriority(0.8)
|
||||
->setChangeFrequency(Url::CHANGE_FREQUENCY_MONTHLY)
|
||||
);
|
||||
|
||||
// Nur Posts
|
||||
$posts = Post::where('published', true)->get(); // falls du ein Feld dafür hast
|
||||
foreach ($posts as $post) {
|
||||
$url = route('read_post', $post->slug);
|
||||
|
||||
$sitemap->add(
|
||||
Url::create($url)
|
||||
->setPriority(0.7)
|
||||
->setChangeFrequency(Url::CHANGE_FREQUENCY_WEEKLY)
|
||||
->setLastModificationDate($post->updated_at)
|
||||
);
|
||||
}
|
||||
|
||||
return response($sitemap->render(), 200)
|
||||
->header('Content-Type', 'application/xml');
|
||||
}
|
||||
}
|
||||
23
app/Http/Middleware/OnlySuperAdmin.php
Normal file
23
app/Http/Middleware/OnlySuperAdmin.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OnlySuperAdmin
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if(auth()->user()->type != "superAdmin") {
|
||||
abort(403, "Du bist nicht Berechtigt diese Seite zu sehen!");
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
25
app/Http/Middleware/PreventBackHistory.php
Normal file
25
app/Http/Middleware/PreventBackHistory.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class PreventBackHistory
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$response = $next($request);
|
||||
$response->headers->set('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
|
||||
$response->headers->set('Pragma', 'no-cache');
|
||||
$response->headers->set('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT');
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
48
app/Jobs/SendNewsletterJob.php
Normal file
48
app/Jobs/SendNewsletterJob.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
use App\Helpers\CMail;
|
||||
|
||||
class SendNewsletterJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, Queueable, InteractsWithQueue, SerializesModels;
|
||||
|
||||
public $subscriber_email;
|
||||
public $currentPost;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($subscriber_email, $currentPost)
|
||||
{
|
||||
$this->subscriber_email = $subscriber_email;
|
||||
$this->currentPost = $currentPost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$data = ['post' => $this->currentPost];
|
||||
$mail_body = view('email-templates.newsletter-post-template', $data)->render();
|
||||
|
||||
$mail_config = array(
|
||||
'recipient_address' => $this->subscriber_email,
|
||||
'recipient_name' => '',
|
||||
'subject' => 'Letzer Post Blog',
|
||||
'body' => $mail_body
|
||||
);
|
||||
|
||||
CMail::send($mail_config);
|
||||
}
|
||||
}
|
||||
245
app/Livewire/Admin/Categories.php
Normal file
245
app/Livewire/Admin/Categories.php
Normal file
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\ParentCategory;
|
||||
use App\Models\Category;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class Categories extends Component
|
||||
{
|
||||
|
||||
use WithPagination;
|
||||
|
||||
public $isUpdateParentCategoryMode = false;
|
||||
public $pcategory_id, $pcategory_name;
|
||||
|
||||
public $isUpdateCategoryMode = false;
|
||||
public $category_id, $parent = 0, $category_name;
|
||||
|
||||
public $pcategoriesPerPage = 8;
|
||||
public $categoriesPerPage = 10;
|
||||
|
||||
protected $listeners = [
|
||||
'updateCategoryOrdering',
|
||||
'updateParentCategoryOrdering',
|
||||
'deleteParentCategoryAction',
|
||||
'deleteCategoryAction'
|
||||
];
|
||||
|
||||
public function addParentCategory() {
|
||||
$this->pcategory_id = null;
|
||||
$this->pcategory_name = null;
|
||||
$this->isUpdateParentCategoryMode = false;
|
||||
$this->showParentCategoryModalForm();
|
||||
}
|
||||
|
||||
public function createParentCategory() {
|
||||
$this->validate([
|
||||
'pcategory_name' => 'required|unique:parent_categories,name'
|
||||
], [
|
||||
'pcategory_name.required' => 'Name wird benötigt',
|
||||
'pcategory_name.unique' => 'Name wird bereits verwendet',
|
||||
]);
|
||||
|
||||
$pcategory = new ParentCategory();
|
||||
$pcategory->name = $this->pcategory_name;
|
||||
$saved = $pcategory->save();
|
||||
|
||||
if($saved) {
|
||||
$this->hideParentCategoryModalForm();
|
||||
$this->dispatch("showToastr", ["type" => "success", "message" => "Neue Haupt Kategorie wurde erstellt"]);
|
||||
} else {
|
||||
$this->dispatch("showToastr", ["type" => "error", "message" => "Haupt Kategorie konnte nicht erstellt werden"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function editParentCategory($id) {
|
||||
$pcategory = ParentCategory::findOrFail($id);
|
||||
$this->pcategory_id = $pcategory->id;
|
||||
$this->pcategory_name = $pcategory->name;
|
||||
$this->isUpdateParentCategoryMode = true;
|
||||
$this->showParentCategoryModalForm();
|
||||
}
|
||||
|
||||
public function updateParentCategory() {
|
||||
$pcategory = ParentCategory::findOrFail($this->pcategory_id);
|
||||
|
||||
$this->validate([
|
||||
'pcategory_name' => 'required|unique:parent_categories,name,'.$pcategory->id
|
||||
], [
|
||||
'pcategory_name.required' => 'Name wird benötigt',
|
||||
'pcategory_name.unique' => 'Name bereits vergeben',
|
||||
]);
|
||||
|
||||
$pcategory->name = $this->pcategory_name;
|
||||
$pcategory->slug = null;
|
||||
$updated = $pcategory->save();
|
||||
|
||||
if($updated) {
|
||||
$this->hideParentCategoryModalForm();
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Haupt Kategorie wurde erfolgreich bearbeitet']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Haupt Kategorie konnte nicht bearbeitet werden']);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateParentCategoryOrdering($positions) {
|
||||
foreach($positions as $position) {
|
||||
$index = $position[0];
|
||||
$new_position = $position[1];
|
||||
ParentCategory::where('id', $index)->update([
|
||||
'ordering' => $new_position
|
||||
]);
|
||||
}
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Haupt Kategorie wurde neu sortiert']);
|
||||
}
|
||||
|
||||
public function updateCategoryOrdering($positions) {
|
||||
foreach($positions as $position) {
|
||||
$index = $position[0];
|
||||
$new_position = $position[1];
|
||||
Category::where('id', $index)->update([
|
||||
'ordering' => $new_position
|
||||
]);
|
||||
}
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Kategorie wurde neu sortiert']);
|
||||
}
|
||||
|
||||
public function deleteParentCategory($id) {
|
||||
$this->dispatch('deleteParentCategory', ['id' => $id]);
|
||||
}
|
||||
|
||||
public function deleteParentCategoryAction($id) {
|
||||
$pcategory = ParentCategory::findOrFail($id);
|
||||
|
||||
if($pcategory->children->count() > 0) {
|
||||
foreach($pcategory->children as $category) {
|
||||
Category::where('id', $category->id)->update(['parent' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
$delete = $pcategory->delete();
|
||||
|
||||
if($delete) {
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Haupt Kategorie wurde erfolgreich gelöscht']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim löschen der Haupt Kategorie']);
|
||||
}
|
||||
}
|
||||
|
||||
public function showParentCategoryModalForm() {
|
||||
$this->resetErrorBag();
|
||||
$this->dispatch("showParentCategoryModalForm");
|
||||
}
|
||||
|
||||
public function hideParentCategoryModalForm() {
|
||||
$this->dispatch("hideParentCategoryModalForm");
|
||||
$this->isUpdateParentCategoryMode = false;
|
||||
$this->pcategory_id = $this->pcategory_name = null;
|
||||
}
|
||||
|
||||
public function createCategory() {
|
||||
$this->validate([
|
||||
'category_name' => 'required|unique:categories,name'
|
||||
], [
|
||||
'category_name.required' => 'Kategorie Name wird benötigt',
|
||||
'category_name.unique' => 'Kategorie Name bereits vergeben'
|
||||
]);
|
||||
|
||||
$category = new Category();
|
||||
$category->parent = $this->parent;
|
||||
$category->name = $this->category_name;
|
||||
$saved = $category->save();
|
||||
|
||||
if($saved) {
|
||||
$this->hideCategoryModalForm();
|
||||
$this->dispatch("showToastr", ['type' => 'success', 'message' => 'Kategorie wurde erfolgreich erstellt']);
|
||||
} else {
|
||||
$this->dispatch("showToastr", ['type' => 'error', 'message' => 'Kategorie konnte nicht erstellt werden']);
|
||||
}
|
||||
}
|
||||
|
||||
public function addCategory() {
|
||||
$this->pcategory_id = null;
|
||||
$this->parent = 0;
|
||||
$this->pcategory_name = null;
|
||||
$this->isUpdateCategoryMode = false;
|
||||
$this->showCategoryModalForm();
|
||||
}
|
||||
|
||||
public function showCategoryModalForm() {
|
||||
$this->resetErrorBag();
|
||||
$this->dispatch('showCategoryModalForm');
|
||||
}
|
||||
|
||||
public function hideCategoryModalForm() {
|
||||
$this->dispatch('hideCategoryModalForm');
|
||||
$this->isUpdateCategoryMdoe = false;
|
||||
$this->category_id = $this->category_name = null;
|
||||
$this->parent = 0;
|
||||
}
|
||||
|
||||
public function editCategory($id) {
|
||||
$category = Category::findOrFail($id);
|
||||
$this->category_id = $category->id;
|
||||
$this->parent = $category->parent;
|
||||
$this->category_name = $category->name;
|
||||
$this->isUpdateCategoryMode = true;
|
||||
$this->showCategoryModalForm();
|
||||
}
|
||||
|
||||
public function updateCategory() {
|
||||
$category = Category::findOrFail($this->category_id);
|
||||
$this->validate([
|
||||
'category_name' => 'required|unique:categories,name,'.$category->id
|
||||
], [
|
||||
'category_name.required' => 'Kategorie Name wird benötigt',
|
||||
'category_name.unique' => 'Kategorie Name bereits vergeben',
|
||||
]);
|
||||
|
||||
$category->name = $this->category_name;
|
||||
$category->parent = $this->parent;
|
||||
$category_slug = null;
|
||||
$updated = $category->save();
|
||||
|
||||
if($updated) {
|
||||
$this->hideCategoryModalForm();
|
||||
$this->dispatch("showToastr", ["type" => "success", "message" => "Kategorie wurde erfolgreich bearbeitet"]);
|
||||
} else {
|
||||
$this->dispatch("showToastr", ["type" => "error", "message" => "Kategorie konnte nicht bearbeitet werden"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteCategory($id) {
|
||||
$this->dispatch('deleteCategory', ['id' => $id]);
|
||||
}
|
||||
|
||||
public function deleteCategoryAction($id) {
|
||||
$category = Category::findOrFail($id);
|
||||
|
||||
iF($category->posts->count() > 0 ) {
|
||||
$count = $category->posts->count();
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => "Diese Kategorie hat ($count) Post/s. Kann daher nicht gelöscht werden"]);
|
||||
} else {
|
||||
$delete = $category->delete();
|
||||
|
||||
if($delete) {
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Kategorie wurde erfolgreich gelöscht']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim löschen der Kategorie']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.admin.categories',
|
||||
[
|
||||
'pcategories' => ParentCategory::orderBy('ordering', 'asc')->paginate($this->pcategoriesPerPage, ["*"],'pcat_page'),
|
||||
'categories' => Category::orderBy('ordering', 'asc')->paginate($this->categoriesPerPage,["*"],'cat_page')
|
||||
]);
|
||||
}
|
||||
}
|
||||
146
app/Livewire/Admin/Posts.php
Normal file
146
app/Livewire/Admin/Posts.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\Post;
|
||||
use Livewire\WithPagination;
|
||||
use App\Models\ParentCategory;
|
||||
use App\Models\Category;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class Posts extends Component
|
||||
{
|
||||
|
||||
use WithPagination;
|
||||
|
||||
public $perPage = 10;
|
||||
public $categories_html;
|
||||
|
||||
public $search = null;
|
||||
public $author = null;
|
||||
public $category = null;
|
||||
public $visibility = null;
|
||||
public $sortBy = "desc";
|
||||
public $post_visibility;
|
||||
|
||||
protected $queryString = [
|
||||
'search' => ['except' => ''],
|
||||
'author' => ['except' => ''],
|
||||
'category' => ['except' => ''],
|
||||
'visibility' => ['except' => ''],
|
||||
'shortBy' => ['except' => ''],
|
||||
];
|
||||
|
||||
protected $listeners = [
|
||||
'deletePostAction'
|
||||
];
|
||||
|
||||
public function updatedSearch() {
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function updatedAuthor() {
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function updatedCategory() {
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function updatedVisibility() {
|
||||
$this->resetPage();
|
||||
$this->post_visibility = $this->visibility == 'public' ? 1 : 0;
|
||||
}
|
||||
|
||||
public function mount() {
|
||||
$this->author = auth()->user()->type == "superAdmin" ? auth()->user()->id : '';
|
||||
$this->post_visibility = $this->visibility == 'public' ? 1 : 0;
|
||||
$categories_html = '';
|
||||
|
||||
$pcategories = ParentCategory::whereHas('children', function($q) {
|
||||
$q->whereHas('posts');
|
||||
})->orderBy('name', 'asc')->get();
|
||||
|
||||
$categories = Category::whereHas('posts')->where('parent', 0)->orderBy('name', 'asc')->get();
|
||||
|
||||
if(count($pcategories) > 0) {
|
||||
foreach($pcategories as $item) {
|
||||
$categories_html.='<optgroup label="'.$item->name.'">';
|
||||
foreach($item->children as $category) {
|
||||
if($category->posts->count() > 0) {
|
||||
$categories_html.='<option value="'.$category->id.'">'.$category->name.'</option>';
|
||||
}
|
||||
}
|
||||
$categories_html.='</optgroup>';
|
||||
}
|
||||
}
|
||||
|
||||
if(count($categories) > 0) {
|
||||
foreach($categories as $item) {
|
||||
$categories_html.='<option value="'.$item->id.'">'.$item->name.'</option>';
|
||||
}
|
||||
}
|
||||
|
||||
$this->categories_html = $categories_html;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.admin.posts', [
|
||||
'posts' => auth()->user()->type == "superAdmin" ?
|
||||
Post::search(trim($this->search))
|
||||
->when($this->author, function($query) {
|
||||
$query->where('author_id', $this->author);
|
||||
})->when($this->category, function($query) {
|
||||
$query->where('category', $this->category);
|
||||
})->when($this->visibility, function($query) {
|
||||
$query->where('visibility', $this->post_visibility);
|
||||
})->when($this->sortBy, function($query) {
|
||||
$query->orderBy('id', $this->sortBy);
|
||||
})->paginate($this->perPage)
|
||||
: Post::search(trim($this->search))
|
||||
->when($this->author, function($query) {
|
||||
$query->where('author_id', $this->author);
|
||||
})->when($this->category, function($query) {
|
||||
$query->where('category', $this->category);
|
||||
})->when($this->visibility, function($query) {
|
||||
$query->where('visibility', $this->post_visibility);
|
||||
})->when($this->sortBy, function($query) {
|
||||
$query->orderBy('id', $this->sortBy);
|
||||
})->where('author_id', auth()->id())->paginate($this->perPage),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deletePost($id) {
|
||||
$this->dispatch('deletePost', ['id' => $id]);
|
||||
}
|
||||
|
||||
public function deletePostAction($id) {
|
||||
$post = Post::findOrFail($id);
|
||||
$path = "images/posts/";
|
||||
$resized_path = $path.'resized/';
|
||||
$old_featured_image = $post->featured_image;
|
||||
|
||||
if($old_featured_image != "" && File::exists(public_path($path.$old_featured_image))) {
|
||||
File::delete(public_path($path.$old_featured_image));
|
||||
|
||||
if(File::exists(public_path($resized_path.'resized_'.$old_featured_image))) {
|
||||
File::delete(public_path($resized_path.'resized_'.$old_featured_image));
|
||||
}
|
||||
|
||||
if(File::exists(public_path($resized_path.'thumb_'.$old_featured_image))) {
|
||||
File::delete(public_path($resized_path.'thumb_'.$old_featured_image));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$delete = $post->delete();
|
||||
|
||||
if($delete) {
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Post wurde erfolgreich gelöscht']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Post konnte nicht gelöscht werden']);
|
||||
}
|
||||
}
|
||||
}
|
||||
175
app/Livewire/Admin/Profile.php
Normal file
175
app/Livewire/Admin/Profile.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use App\Helpers\CMail;
|
||||
use App\Models\UserSocialLink;
|
||||
|
||||
class Profile extends Component
|
||||
{
|
||||
|
||||
public $tab = null;
|
||||
public $tabname = "personal_details";
|
||||
protected $queryString = ['tab' => ['keep' => true]];
|
||||
|
||||
public $name, $email, $username, $bio;
|
||||
public $current_password, $new_password, $new_password_confirmation;
|
||||
public $facebook_url, $instagram_url, $youtube_url, $linkedin_url, $twitter_url, $github_url;
|
||||
|
||||
protected $listeners = [
|
||||
'updateProfile' => '$refresh'
|
||||
];
|
||||
|
||||
public function selectTab($tab) {
|
||||
$this->tab = $tab;
|
||||
}
|
||||
|
||||
public function mount() {
|
||||
$this->tab = Request("tab") ? Request("tab") : $this->tabname;
|
||||
|
||||
$user = User::with("social_links")->findOrFail(auth()->id());
|
||||
$this->name = $user->name;
|
||||
$this->email = $user->email;
|
||||
$this->username = $user->username;
|
||||
$this->bio = $user->bio;
|
||||
|
||||
if(!is_null($user->social_links)) {
|
||||
$this->facebook_url = $user->social_links->facebook_url;
|
||||
$this->instagram_url = $user->social_links->instagram_url;
|
||||
$this->youtube_url = $user->social_links->youtube_url;
|
||||
$this->twitter_url = $user->social_links->twitter_url;
|
||||
$this->github_url = $user->social_links->github_url;
|
||||
$this->linkedin_url = $user->social_links->linkedin_url;
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePersonalDetails() {
|
||||
$user = User::findOrFail(auth()->id());
|
||||
|
||||
$this->validate([
|
||||
"name" => "required",
|
||||
"username" => "required|unique:users,username,".$user->id,
|
||||
], [
|
||||
"name.required" => "Name wird benötigt",
|
||||
"username.required" => "Benutzername wird benötigt",
|
||||
"username.unique" => "Benutzername bereits vergeben",
|
||||
]);
|
||||
|
||||
$user->name = $this->name;
|
||||
$user->username = $this->username;
|
||||
$user->bio = $this->bio;
|
||||
$updated = $user->save();
|
||||
|
||||
sleep(0.5);
|
||||
|
||||
if($updated) {
|
||||
$this->dispatch("showToastr", ["type" => "success", "message" => "Deine Profil Informationen wurden bearbeitet"]);
|
||||
$this->dispatch("updateTopUserInfo")->to(TopUserInfo::class);
|
||||
} else {
|
||||
$this->dispatch("showToastr", ["type" => "error", "message" => "Deine Profil Informationen konnten nicht bearbeitet werden"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePassword(Request $request) {
|
||||
$user = User::findOrFail(auth()->id());
|
||||
|
||||
$this->validate([
|
||||
"current_password" => [
|
||||
"required",
|
||||
"min:5",
|
||||
function($attribute, $value, $fail) use ($user) {
|
||||
if(!Hash::check($value, $user->password)) {
|
||||
return $fail(__('Dein Passwort stimmt nicht überein'));
|
||||
}
|
||||
}
|
||||
],
|
||||
"new_password" => "required|min:5|confirmed"
|
||||
], [
|
||||
"current_password.required" => "Das aktuelle Passwort wird benötigt",
|
||||
"current_password.min" => "Gebe mind. 5 Zeichen ein",
|
||||
"new_password.required" => "Das aktuelle Passwort wird benötigt",
|
||||
"new_password.min" => "Gebe mind. 5 Zeichen ein",
|
||||
]);
|
||||
|
||||
$updated = $user->update([
|
||||
"password" => Hash::make($this->new_password)
|
||||
]);
|
||||
|
||||
if($updated) {
|
||||
$data = array(
|
||||
"user" => $user,
|
||||
"new_password" => $this->new_password
|
||||
);
|
||||
|
||||
$mail_body = view("email-templates.password-changes-template", $data)->render();
|
||||
|
||||
$mail_config = array(
|
||||
'recipient_address' => $user->email,
|
||||
'recipient_name' => $user->name,
|
||||
"subject" => "Passwort geändert",
|
||||
"body" => $mail_body
|
||||
);
|
||||
|
||||
CMail::send($mail_config);
|
||||
auth()->logout();
|
||||
Session::flash("info", "Dein Passwort wurde geändert, bitte logge dich neu ein");
|
||||
$this->redirectRoute("admin.login");
|
||||
} else {
|
||||
$this->dispatch("showToastr", ["type" => "error", "message" => "Leider lief etwas schief"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSocialLinks() {
|
||||
$this->validate([
|
||||
'facebook_url' => 'nullable|url',
|
||||
'instagram_url' => 'nullable|url',
|
||||
'youtube_url' => 'nullable|url',
|
||||
'linkedin_url' => 'nullable|url',
|
||||
'twitter_url' => 'nullable|url',
|
||||
'github_url' => 'nullable|url',
|
||||
],[
|
||||
'facebook_url.url' => "Du musst einen gültigen Link angeben",
|
||||
'instagram_url.url' => "Du musst einen gültigen Link angeben",
|
||||
'youtube_url.url' => "Du musst einen gültigen Link angeben",
|
||||
'linkedin_url.url' => "Du musst einen gültigen Link angeben",
|
||||
'twitter_url.url' => "Du musst einen gültigen Link angeben",
|
||||
'github_url.url' => "Du musst einen gültigen Link angeben",
|
||||
]);
|
||||
|
||||
$user = User::findOrFail(auth()->id());
|
||||
|
||||
$data = array(
|
||||
'instagram_url' => $this->instagram_url,
|
||||
'facebook_url' => $this->facebook_url,
|
||||
'youtube_url' => $this->youtube_url,
|
||||
'linkedin_url' => $this->linkedin_url,
|
||||
'twitter_url' => $this->twitter_url,
|
||||
'github_url' => $this->github_url,
|
||||
);
|
||||
|
||||
if(!is_null($user->social_links)) {
|
||||
$query = $user->social_links()->update($data);
|
||||
} else {
|
||||
$data['user_id'] = $user->id;
|
||||
$query = UserSocialLink::insert($data);
|
||||
}
|
||||
|
||||
if($query) {
|
||||
$this->dispatch("showToastr", ["type" => "success", "message"=> "Social Links erfolgreich bearbeitet"]);
|
||||
} else {
|
||||
$this->dispatch("showToastr", ["type" => "error", "message"=> "Fehler beim bearbeiten von Social Links"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.admin.profile', [
|
||||
"user" => User::findOrFail(auth()->id())
|
||||
]);
|
||||
}
|
||||
}
|
||||
122
app/Livewire/Admin/Settings.php
Normal file
122
app/Livewire/Admin/Settings.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\GeneralSetting;
|
||||
use App\Models\SiteSocialLink;
|
||||
|
||||
class Settings extends Component
|
||||
{
|
||||
public $tab = null;
|
||||
public $default_tab = 'general_settings';
|
||||
protected $queryString = ['tab' => ['keep' => true]];
|
||||
|
||||
// Allgemein Settings form Properties
|
||||
public $site_title, $site_email, $site_phone, $site_meta_keywords, $site_meta_description;
|
||||
|
||||
// Seiten Social Links
|
||||
public $facebook_url, $instagram_url, $linkedin_url, $twitter_url;
|
||||
|
||||
public function selectTab($tab) {
|
||||
$this->tab = $tab;
|
||||
}
|
||||
|
||||
public function mount() {
|
||||
$this->tab = Request('tab') ? Request('tab') : $this->default_tab;
|
||||
|
||||
$settings = GeneralSetting::take(1)->first();
|
||||
|
||||
// Site Social Links
|
||||
$site_social_links = SiteSocialLink::take(1)->first();
|
||||
|
||||
if(!is_null($settings)) {
|
||||
$this->site_title = $settings->site_title;
|
||||
$this->site_email = $settings->site_email;
|
||||
$this->site_phone = $settings->site_phone;
|
||||
$this->site_meta_keywords = $settings->site_meta_keywords;
|
||||
$this->site_meta_description = $settings->site_meta_description;
|
||||
}
|
||||
|
||||
if(!is_null($site_social_links)) {
|
||||
$this->facebook_url = $site_social_links->facebook_url;
|
||||
$this->instagram_url = $site_social_links->instagram_url;
|
||||
$this->linkedin_url = $site_social_links->linkedin_url;
|
||||
$this->twitter_url = $site_social_links->twitter_url;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSiteInfo() {
|
||||
$this->validate([
|
||||
'site_title' => 'required',
|
||||
'site_email' => 'required|email'
|
||||
], [
|
||||
'site_title.required' => "Seiten Titel wird benötigt",
|
||||
'site_email.required' => "Seiten Titel wird benötigt",
|
||||
'site_email.email' => "Gebe eine gültige Email an",
|
||||
]);
|
||||
|
||||
// Allgemeine Einstellungen
|
||||
$settings = GeneralSetting::take(1)->first();
|
||||
|
||||
$data = array(
|
||||
'site_title' => $this->site_title,
|
||||
'site_email' => $this->site_email,
|
||||
'site_phone' => $this->site_phone,
|
||||
'site_meta_keywords' => $this->site_meta_keywords,
|
||||
'site_meta_description' => $this->site_meta_description,
|
||||
);
|
||||
|
||||
if(!is_null($settings)) {
|
||||
$query = $settings->update($data);
|
||||
} else {
|
||||
$query = GeneralSetting::insert($data);
|
||||
}
|
||||
|
||||
if($query) {
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Einstellungen wurden gespeichert']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim speichern']);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSiteSocialLinks() {
|
||||
$this->validate([
|
||||
'facebook_url' => 'nullable|url',
|
||||
'instagram_url' => 'nullable|url',
|
||||
'linkedin_url' => 'nullable|url',
|
||||
'twitter_url' => 'nullable|url',
|
||||
], [
|
||||
'facebook_url.url' => 'Bitte gebe eine gültige URL ein',
|
||||
'instagram_url.url' => 'Bitte gebe eine gültige URL ein',
|
||||
'linkedin_url.url' => 'Bitte gebe eine gültige URL ein',
|
||||
'twitter_url.url' => 'Bitte gebe eine gültige URL ein',
|
||||
]);
|
||||
|
||||
$site_social_links = SiteSocialLink::take(1)->first();
|
||||
|
||||
$data = array(
|
||||
'facebook_url' => $this->facebook_url,
|
||||
'instagram_url' => $this->instagram_url,
|
||||
'linkedin_url' => $this->linkedin_url,
|
||||
'twitter_url' => $this->twitter_url,
|
||||
);
|
||||
|
||||
if(!is_null($site_social_links)) {
|
||||
$query = $site_social_links->update($data);
|
||||
} else {
|
||||
$query = SiteSocialLink::create($data);
|
||||
}
|
||||
|
||||
if($query) {
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Social Links wurden gespeichert']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim speichern']);
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.admin.settings');
|
||||
}
|
||||
}
|
||||
190
app/Livewire/Admin/Slides.php
Normal file
190
app/Livewire/Admin/Slides.php
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
use App\Models\Slide;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class Slides extends Component
|
||||
{
|
||||
use WithFileUploads;
|
||||
|
||||
|
||||
public $isUpdateSlideMode = false;
|
||||
public $slide_id, $slide_heading, $slide_link, $slide_image, $slide_status = true;
|
||||
public $selected_slide_image = null;
|
||||
|
||||
protected $listeners = [
|
||||
'updateSlidesOrdering',
|
||||
'deleteSlideAction'
|
||||
];
|
||||
|
||||
public function updatedSlideImage() {
|
||||
if($this->slide_image) {
|
||||
$this->selected_slide_image = $this->slide_image->temporaryUrl();
|
||||
}
|
||||
}
|
||||
|
||||
public function addSlide() {
|
||||
$this->slide_id = null;
|
||||
$this->slide_heading = null;
|
||||
$this->slide_link = null;
|
||||
$this->selected_slide_image = null;
|
||||
$this->slide_status = true;
|
||||
$this->isUpdateSlideMode = false;
|
||||
$this->showSlidemodalForm();
|
||||
}
|
||||
|
||||
public function showSlideModalForm() {
|
||||
$this->resetErrorBag();
|
||||
$this->dispatch('showSlideModalForm');
|
||||
}
|
||||
|
||||
public function hideSlideModalForm() {
|
||||
$this->dispatch('hideSlideModalForm');
|
||||
$this->isUpdateSlideMode = false;
|
||||
$this->slide_id = $this->slide_heading = $this->slide_link = $this->slide_image = null;
|
||||
$this->slide_status = true;
|
||||
}
|
||||
|
||||
public function createSlide() {
|
||||
$this->validate([
|
||||
'slide_heading' => 'required',
|
||||
'slide_link' => 'nullable|url',
|
||||
'slide_image' => 'required'
|
||||
], [
|
||||
'slide_heading.required' => 'Der Text wird benötigt',
|
||||
'slide_link.url' => 'Gebe einen gültigen Link ein',
|
||||
'slide_image.required' => 'Bild wird benötigt',
|
||||
]);
|
||||
|
||||
$path = "slides/";
|
||||
$file = $this->slide_image;
|
||||
$filename = "SLD_".date("YmdHis", time()).'.'.$file->getClientOriginalExtension();
|
||||
|
||||
$upload = $file->storeAs($path, $filename, 'slides_uploads');
|
||||
|
||||
if(!$upload) {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim Hochladen von Image']);
|
||||
} else {
|
||||
$slide = new Slide();
|
||||
$slide->image = $filename;
|
||||
$slide->heading = $this->slide_heading;
|
||||
$slide->link = $this->slide_link;
|
||||
$slide->status = $this->slide_status == true ? 1 : 0;
|
||||
$saved = $slide->save();
|
||||
|
||||
if($saved) {
|
||||
$this->hideSlideModalForm();
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Slider wurde erstellt']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim erstellen von Slider']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function editSlide($id) {
|
||||
$slide = Slide::findOrFail($id);
|
||||
$this->slide_id = $slide->id;
|
||||
$this->slide_heading = $slide->heading;
|
||||
$this->slide_link = $slide->link;
|
||||
$this->slide_status = $slide->status == 1 ? true : false;
|
||||
$this->slide_image = null;
|
||||
$this->selected_slide_image = "/images/slides/".$slide->image;
|
||||
$this->isUpdateSlideMode = true;
|
||||
$this->showSlidemodalForm();
|
||||
}
|
||||
|
||||
|
||||
public function updateSlide() {
|
||||
$slide = Slide::findOrFail($this->slide_id);
|
||||
|
||||
$this->validate([
|
||||
'slide_heading' => 'required',
|
||||
'slide_link' => 'nullable|url',
|
||||
'slide_image' => 'nullable'
|
||||
], [
|
||||
'slide_heading.required' => 'Der Text wird benötigt',
|
||||
'slide_link.url' => 'Gebe einen gültigen Link ein',
|
||||
]);
|
||||
|
||||
$slide_image_name = $slide->image;
|
||||
|
||||
if($this->slide_image) {
|
||||
$path = 'slides/';
|
||||
$file = $this->slide_image;
|
||||
$filename = 'SLD_'.date('YmdHis', time()).'.'.
|
||||
$file->getClientOriginalExtension();
|
||||
|
||||
$upload = $file->storeAs($path, $filename, 'slides_uploads');
|
||||
|
||||
if(!$upload) {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim Hochladen von Image']);
|
||||
} else {
|
||||
$slide_path = 'images/'.$path;
|
||||
$old_slide_image = $slide->image;
|
||||
|
||||
if($old_slide_image != '' && File::exists(public_path($slide_path.$old_slide_image))) {
|
||||
File::delete(public_path($slide_path.$old_slide_image));
|
||||
}
|
||||
|
||||
$slide_image_name = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
$slide->image = $slide_image_name;
|
||||
$slide->heading = $this->slide_heading;
|
||||
$slide->link = $this->slide_link;
|
||||
$slide->status = $this->slide_status == true ? 1 : 0;
|
||||
$saved = $slide->save();
|
||||
|
||||
if($saved) {
|
||||
$this->hideSlideModalForm();
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Slider wurde bearbeitet']);
|
||||
} else {
|
||||
$this->dispatch('showToastr', ['type' => 'error', 'message' => 'Fehler beim bearbeiten von Slider']);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSlidesOrdering($positions) {
|
||||
foreach($positions as $position) {
|
||||
$index = $position[0];
|
||||
$newPosition = $position[1];
|
||||
Slide::where('id', $index)->update([
|
||||
'ordering' => $newPosition
|
||||
]);
|
||||
$this->dispatch("showToastr", ['type' => "success", "message" => "Slides wurden neu angeordnet"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteSlideAction($id) {
|
||||
$slide = Slide::findOrFail($id);
|
||||
$path = "slides/";
|
||||
$slide_path = "images/".$path;
|
||||
$slide_image = $slide->image;
|
||||
|
||||
if($slide_image != '' && File::exists(public_path($slide_path.$slide_image))) {
|
||||
File::delete(public_path($slide_path.$slide_image));
|
||||
}
|
||||
|
||||
$delete = $slide->delete();
|
||||
|
||||
if($delete) {
|
||||
$this->dispatch("showToastr", ['type' => "success", "message" => "Slide wurden gelöscht"]);
|
||||
} else {
|
||||
$this->dispatch("showToastr", ['type' => "error", "message" => "Slide konnte nicht gelöscht werden"]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.admin.slides', [
|
||||
'slides' => Slide::orderBy('ordering', 'asc')->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
21
app/Livewire/Admin/TopUserInfo.php
Normal file
21
app/Livewire/Admin/TopUserInfo.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Admin;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\User;
|
||||
|
||||
class TopUserInfo extends Component
|
||||
{
|
||||
|
||||
protected $listeners = [
|
||||
"updateTopUserInfo" => '$refresh'
|
||||
];
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.admin.top-user-info', [
|
||||
"user" => User::findOrFail(auth()->id())
|
||||
]);
|
||||
}
|
||||
}
|
||||
43
app/Livewire/NewsletterForm.php
Normal file
43
app/Livewire/NewsletterForm.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\NewsletterSubscriber;
|
||||
|
||||
|
||||
class NewsletterForm extends Component
|
||||
{
|
||||
|
||||
public $email = "";
|
||||
|
||||
protected $rules = [
|
||||
'email' => 'required|email|unique:newsletter_subscribers,email'
|
||||
];
|
||||
|
||||
protected function messages() {
|
||||
return [
|
||||
'email.required' => 'Bitte gebe eine Email Adresse ein',
|
||||
'email.email' => 'Bitte gebe eine gültige Email Adresse ein',
|
||||
'email.unique' => 'Email bereits im System eingetragen',
|
||||
];
|
||||
}
|
||||
|
||||
public function updatedEmail() {
|
||||
$this->validateOnly('email');
|
||||
}
|
||||
|
||||
public function subscribe() {
|
||||
$this->validate();
|
||||
|
||||
NewsletterSubscriber::create(['email' => $this->email]);
|
||||
|
||||
$this->email = '';
|
||||
$this->dispatch('showToastr', ['type' => 'success', 'message' => 'Sie haben sich erfolgreich in den Newsletter Abo eingetragen']);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.newsletter-form');
|
||||
}
|
||||
}
|
||||
31
app/Models/Category.php
Normal file
31
app/Models/Category.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Cviebrock\EloquentSluggable\Sluggable;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Sluggable;
|
||||
|
||||
protected $fillable = ["name","slug", "parent", "ordering"];
|
||||
|
||||
public function sluggable(): array {
|
||||
return [
|
||||
"slug" => [
|
||||
'source' => 'name'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function parent_category() {
|
||||
return $this->belongsTo(ParentCategory::class, 'parent', 'id');
|
||||
}
|
||||
|
||||
public function posts() {
|
||||
return $this->hasMany(Post::class, 'category', 'id');
|
||||
}
|
||||
}
|
||||
21
app/Models/GeneralSetting.php
Normal file
21
app/Models/GeneralSetting.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class GeneralSetting extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'site_title',
|
||||
'site_email',
|
||||
'site_phone',
|
||||
'site_meta_keywords',
|
||||
'site_meta_description',
|
||||
'site_logo',
|
||||
'site_favicon',
|
||||
];
|
||||
}
|
||||
13
app/Models/NewsletterSubscriber.php
Normal file
13
app/Models/NewsletterSubscriber.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class NewsletterSubscriber extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['email'];
|
||||
}
|
||||
28
app/Models/ParentCategory.php
Normal file
28
app/Models/ParentCategory.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Cviebrock\EloquentSluggable\Sluggable;
|
||||
|
||||
|
||||
class ParentCategory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Sluggable;
|
||||
|
||||
protected $fillable = ["name", "slug", "ordering"];
|
||||
|
||||
public function sluggable(): array {
|
||||
return [
|
||||
"slug" => [
|
||||
'source' => 'name'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function children() {
|
||||
return $this->hasMany(Category::class, 'parent', 'id');
|
||||
}
|
||||
}
|
||||
51
app/Models/Post.php
Normal file
51
app/Models/Post.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Cviebrock\EloquentSluggable\Sluggable;
|
||||
use App\Models\User;
|
||||
use App\Models\Category;
|
||||
|
||||
class Post extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Sluggable;
|
||||
|
||||
protected $fillable = [
|
||||
'author_id',
|
||||
'category',
|
||||
'title',
|
||||
'slug',
|
||||
'content',
|
||||
'tags',
|
||||
'meta_keywords',
|
||||
'meta_description',
|
||||
'visibility',
|
||||
'is_notified',
|
||||
];
|
||||
|
||||
public function sluggable(): array {
|
||||
return [
|
||||
'slug' => [
|
||||
'source' => 'title'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function author() {
|
||||
return $this->hasOne(User::class, 'id', 'author_id');
|
||||
}
|
||||
|
||||
public function post_category() {
|
||||
return $this->hasOne(Category::class, 'id', 'category');
|
||||
}
|
||||
|
||||
public function scopeSearch($query, $term) {
|
||||
$term = "%$term%";
|
||||
$query->where(function($query) use ($term) {
|
||||
$query->where('title', 'like', $term);
|
||||
});
|
||||
}
|
||||
}
|
||||
19
app/Models/SiteSocialLink.php
Normal file
19
app/Models/SiteSocialLink.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class SiteSocialLink extends Model
|
||||
{
|
||||
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'facebook_url',
|
||||
'instagram_url',
|
||||
'linkedin_url',
|
||||
'twitter_url',
|
||||
];
|
||||
}
|
||||
20
app/Models/Slide.php
Normal file
20
app/Models/Slide.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
|
||||
class Slide extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'image',
|
||||
'heading',
|
||||
'link',
|
||||
'status',
|
||||
'ordering',
|
||||
];
|
||||
}
|
||||
76
app/Models/User.php
Normal file
76
app/Models/User.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use App\UserStatus;
|
||||
use App\UserType;
|
||||
use App\Models\UserSocialLink;
|
||||
use App\Models\Post;
|
||||
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
"username",
|
||||
"picture",
|
||||
"bio",
|
||||
"type",
|
||||
"status"
|
||||
];
|
||||
|
||||
/**
|
||||
* 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',
|
||||
"status" => UserStatus::class,
|
||||
"type" => UserType::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function getPictureAttribute($value) {
|
||||
return $value ? asset("/images/users/".$value) : asset("/images/users/default-avatar.png");
|
||||
}
|
||||
|
||||
public function social_links() {
|
||||
return $this->hasOne(UserSocialLink::class, "id", "user_id");
|
||||
}
|
||||
|
||||
public function getTypeAttribute($value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function posts() {
|
||||
return $this->hasMany(Post::class, 'author_id', 'id');
|
||||
}
|
||||
}
|
||||
19
app/Models/UserSocialLink.php
Normal file
19
app/Models/UserSocialLink.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class UserSocialLink extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'facebook_url',
|
||||
'instagram_url',
|
||||
'youtube_url',
|
||||
'twitter_url',
|
||||
'github_url',
|
||||
'linkedin_url',
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
41
app/Providers/AppServiceProvider.php
Normal file
41
app/Providers/AppServiceProvider.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
use Illuminate\Auth\Middleware\RedirectIfAuthenticated;
|
||||
use Illuminate\Auth\Middleware\Authenticate;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Schema::defaultStringLength(191);
|
||||
|
||||
// Authenticated Benutzer ins Dashboard umleiten
|
||||
RedirectIfAuthenticated::redirectUsing(function() {
|
||||
return route("admin.dashboard");
|
||||
});
|
||||
|
||||
// Nicht Authenticated Benutzer ins Admin Login umleiten
|
||||
Authenticate::redirectUsing(function() {
|
||||
Session::flash("fail", "Sie müssen im Administratorbereich angemeldet sein. Bitte melden Sie sich an, um fortzufahren.");
|
||||
return route("admin.login");
|
||||
});
|
||||
}
|
||||
}
|
||||
11
app/UserStatus.php
Normal file
11
app/UserStatus.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
enum UserStatus: string
|
||||
{
|
||||
case Pending = "pending";
|
||||
case Active ="active";
|
||||
case Inactive = "inactive";
|
||||
case Rejected = "rejected";
|
||||
}
|
||||
9
app/UserType.php
Normal file
9
app/UserType.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
enum UserType: string
|
||||
{
|
||||
case Admin = "admin";
|
||||
case SuperAdmin = "superAdmin";
|
||||
}
|
||||
26
app/View/Components/FormAlerts.php
Normal file
26
app/View/Components/FormAlerts.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class FormAlerts extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*/
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('components.form-alerts');
|
||||
}
|
||||
}
|
||||
26
app/View/Components/SidebarCategories.php
Normal file
26
app/View/Components/SidebarCategories.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class SidebarCategories extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*/
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('components.sidebar-categories');
|
||||
}
|
||||
}
|
||||
26
app/View/Components/SidebarSearch.php
Normal file
26
app/View/Components/SidebarSearch.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class SidebarSearch extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*/
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('components.sidebar-search');
|
||||
}
|
||||
}
|
||||
26
app/View/Components/SidebarTags.php
Normal file
26
app/View/Components/SidebarTags.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class SidebarTags extends Component
|
||||
{
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*/
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('components.sidebar-tags');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user