Init
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Spatie\Sitemap\Sitemap;
|
||||||
|
use Spatie\Sitemap\Tags\Url;
|
||||||
|
|
||||||
|
class GenerateSitemap extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'sitemap:generate';
|
||||||
|
|
||||||
|
protected $description = 'Generate the sitemap dynamically using config routes';
|
||||||
|
|
||||||
|
private const PRIORITY = 0.5;
|
||||||
|
|
||||||
|
private const CHANGE_FREQUENCY = 'weekly';
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$sitemap = Sitemap::create();
|
||||||
|
$routes = config('routes.web', []);
|
||||||
|
|
||||||
|
foreach ($routes as $route) {
|
||||||
|
if (isset($route['path'])) {
|
||||||
|
$this->info('Adding '.$route['path'].' to sitemap.');
|
||||||
|
$sitemap->add(Url::create($route['path'])
|
||||||
|
->setPriority($route['priority'] ?? static::PRIORITY)
|
||||||
|
->setLastModificationDate($route['last_modified'] ?? now())
|
||||||
|
->setChangeFrequency($route['frequency'] ?? static::CHANGE_FREQUENCY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sitemap->writeToFile(public_path('sitemap.xml'));
|
||||||
|
$this->info('Sitemap has been successfully generated!');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Contact;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
|
class ContactController extends Controller
|
||||||
|
{
|
||||||
|
private const SUBJECT = 'New Contact us page message';
|
||||||
|
|
||||||
|
public function email(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'name' => 'required',
|
||||||
|
'email' => 'required|email',
|
||||||
|
'message' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->createRecord([
|
||||||
|
'name' => $request->input('name'),
|
||||||
|
'email' => $request->input('email'),
|
||||||
|
'subject' => self::SUBJECT,
|
||||||
|
'message' => $request->input('message'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Mail::raw($this->formatMessage($request), function ($message) use ($request) {
|
||||||
|
$message->to(config('app.email'))->subject(self::SUBJECT.' from '.$request->input('email'));
|
||||||
|
$message->from(config('app.email'), $request->input('name'));
|
||||||
|
});
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', 'Your message has been sent.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function trial(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'name' => 'required',
|
||||||
|
'email' => 'required|email',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->createRecord([
|
||||||
|
'name' => $request->input('name'),
|
||||||
|
'email' => $request->input('email'),
|
||||||
|
'subject' => 'New Trial class request',
|
||||||
|
'message' => 'Contact to book a trial class.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
Mail::raw($this->formatMessage($request), function ($message) use ($request) {
|
||||||
|
$message->to(config('app.email'))->subject('New Trial class request from '.$request->input('email'));
|
||||||
|
$message->from(config('app.email'), $request->input('name'));
|
||||||
|
});
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', "We'll be in touch to book your trial class.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function formatMessage(Request $request): string
|
||||||
|
{
|
||||||
|
return <<<EOF
|
||||||
|
You have received a new contact message.
|
||||||
|
Name: {$request->input('name')}
|
||||||
|
Email: {$request->input('email')}
|
||||||
|
Message: {$request->input('message')}
|
||||||
|
EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createRecord(array $data)
|
||||||
|
{
|
||||||
|
Contact::create([
|
||||||
|
'name' => $data['name'] ?? '?',
|
||||||
|
'email' => $data['email'] ?? '?',
|
||||||
|
'subject' => $data['subject'] ?? '?',
|
||||||
|
'message' => $data['message'] ?? null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
abstract class Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ImagesController extends Controller
|
||||||
|
{
|
||||||
|
public function show(Request $request, string $file)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return response()->file($this->imagePath($file));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subDirectory(Request $request, string $directory, string $file)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return response()->file($this->imagePath("{$directory}/{$file}"));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function imagePath(string $file): string
|
||||||
|
{
|
||||||
|
return resource_path('images/'.$file);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Traits\HasActive;
|
||||||
|
use App\Traits\HasTableName;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Blog extends Model
|
||||||
|
{
|
||||||
|
use HasActive;
|
||||||
|
use HasFactory;
|
||||||
|
use HasTableName;
|
||||||
|
|
||||||
|
public function getRouteKeyName(): string
|
||||||
|
{
|
||||||
|
return 'slug';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'blog.'.$this->slug
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Traits\HasTableName;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Contact extends Model
|
||||||
|
{
|
||||||
|
use HasTableName;
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
#[Scope]
|
||||||
|
protected function unanswered(Builder $builder): void
|
||||||
|
{
|
||||||
|
$builder->where('answered', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Traits\HasActive;
|
||||||
|
use App\Traits\HasTableName;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Faq extends Model
|
||||||
|
{
|
||||||
|
use HasActive;
|
||||||
|
use HasFactory;
|
||||||
|
use HasTableName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
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',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class AppServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register any application services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Laravel\Telescope\IncomingEntry;
|
||||||
|
use Laravel\Telescope\Telescope;
|
||||||
|
use Laravel\Telescope\TelescopeApplicationServiceProvider;
|
||||||
|
|
||||||
|
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register any application services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->hideSensitiveRequestDetails();
|
||||||
|
|
||||||
|
$isLocal = $this->app->environment('local');
|
||||||
|
$recordAll = config('telescope.record_all');
|
||||||
|
|
||||||
|
Telescope::filter(function (IncomingEntry $entry) use ($isLocal, $recordAll) {
|
||||||
|
return $isLocal ||
|
||||||
|
$recordAll ||
|
||||||
|
$entry->isReportableException() ||
|
||||||
|
$entry->isFailedRequest() ||
|
||||||
|
$entry->isFailedJob() ||
|
||||||
|
$entry->isScheduledTask() ||
|
||||||
|
$entry->hasMonitoredTag();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent sensitive request details from being logged by Telescope.
|
||||||
|
*/
|
||||||
|
protected function hideSensitiveRequestDetails(): void
|
||||||
|
{
|
||||||
|
if ($this->app->environment('local')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Telescope::hideRequestParameters(['_token']);
|
||||||
|
|
||||||
|
Telescope::hideRequestHeaders([
|
||||||
|
'cookie',
|
||||||
|
'x-csrf-token',
|
||||||
|
'x-xsrf-token',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the Telescope gate.
|
||||||
|
*
|
||||||
|
* This gate determines who can access Telescope in non-local environments.
|
||||||
|
*/
|
||||||
|
protected function gate(): void
|
||||||
|
{
|
||||||
|
Gate::define('viewTelescope', function ($user = null) {
|
||||||
|
$allowed = explode(',', config('telescope.allowed_ips'));
|
||||||
|
|
||||||
|
return in_array(request()->ip(), $allowed);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
|
trait HasActive
|
||||||
|
{
|
||||||
|
public function scopeActive(Builder $query): Builder
|
||||||
|
{
|
||||||
|
return $query->where('active', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
trait HasTableName
|
||||||
|
{
|
||||||
|
public static function tableName(): string
|
||||||
|
{
|
||||||
|
return (new static)->getTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class Footer 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.footer');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class Header 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.header');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class Meta 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.meta');
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user