From df19e43112d4a192117a1f05f1ef057423991b1b Mon Sep 17 00:00:00 2001 From: James Collins Date: Fri, 27 Sep 2024 11:24:47 +1000 Subject: [PATCH] update includes --- app/Http/Controllers/WorkshopController.php | 272 +++++++++ app/Models/Workshop.php | 52 ++ config/flare.php | 80 +++ config/ignition.php | 277 ++++++++++ config/tinker.php | 50 ++ .../vendor/clamav-validator/en/validation.php | 5 + resources/views/admin/workshop/edit.blade.php | 172 ++++++ .../views/admin/workshop/index.blade.php | 55 ++ .../views/components/panel-workshop.blade.php | 45 ++ resources/views/errors/401.blade.php | 5 + resources/views/errors/402.blade.php | 5 + resources/views/errors/419.blade.php | 5 + resources/views/errors/429.blade.php | 5 + resources/views/errors/500.blade.php | 5 + resources/views/errors/layout.blade.php | 53 ++ resources/views/errors/minimal.blade.php | 34 ++ .../vendor/notifications/email.blade.php | 58 ++ resources/views/workshop/index.blade.php | 33 ++ resources/views/workshop/show.blade.php | 69 +++ sail | 518 ++++++++++++++++++ 20 files changed, 1798 insertions(+) create mode 100644 app/Http/Controllers/WorkshopController.php create mode 100644 app/Models/Workshop.php create mode 100644 config/flare.php create mode 100644 config/ignition.php create mode 100644 config/tinker.php create mode 100644 lang/vendor/clamav-validator/en/validation.php create mode 100644 resources/views/admin/workshop/edit.blade.php create mode 100644 resources/views/admin/workshop/index.blade.php create mode 100644 resources/views/components/panel-workshop.blade.php create mode 100644 resources/views/errors/401.blade.php create mode 100644 resources/views/errors/402.blade.php create mode 100644 resources/views/errors/419.blade.php create mode 100644 resources/views/errors/429.blade.php create mode 100644 resources/views/errors/500.blade.php create mode 100644 resources/views/errors/layout.blade.php create mode 100644 resources/views/errors/minimal.blade.php create mode 100644 resources/views/vendor/notifications/email.blade.php create mode 100644 resources/views/workshop/index.blade.php create mode 100644 resources/views/workshop/show.blade.php create mode 100644 sail diff --git a/app/Http/Controllers/WorkshopController.php b/app/Http/Controllers/WorkshopController.php new file mode 100644 index 0000000..b5cd125 --- /dev/null +++ b/app/Http/Controllers/WorkshopController.php @@ -0,0 +1,272 @@ +get('search', ''); + + $query = Workshop::query(); + + if(!auth()->user()?->admin) { + $query = $query->where('status', '!=', 'draft'); + } + + if($request->has('search') && $request->search !== '') { + $homeView = false; + $query = $query->where(function ($query) use ($request) { + $query->where('title', 'like', '%' . $request->search . '%') + ->orWhere('content', 'like', '%' . $request->search . '%'); + }); + } + + if($request->has('location') && $request->location !== '') { + $homeView = false; + $query = $query->whereHas('location', function ($query) use ($request) { + $query->where('name', 'like', '%' . $request->location . '%'); + }); + } + + if($request->has('date') && $request->date !== '') { + $homeView = false; + $dates = explode('-', $request->date); + $dates = array_map('trim', $dates); + $dates = array_map(function($date) { + $date = trim($date); + + if(preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { + return $date; + } + if(preg_match('/^(\d{2})-(\d{2})-(\d{2})$/', $date, $matches)) { + return '20' . $matches[1] . '-' . $matches[2] . '-' . $matches[3]; + } + if(preg_match('/^\d{4}-\d{2}$/', $date)) { + return $date . '-01'; + } + if(preg_match('/^\d{4}$/', $date)) { + return $date . '-01-01'; + } + if(preg_match('/^(\d{2})\/(\d{2})\/(\d{2})$/', $date, $matches)) { + return '20' . $matches[3] . '-' . $matches[2] . '-' . $matches[1]; + } + if(preg_match('/^(\d{2})\/(\d{2})\/(\d{4})$/', $date, $matches)) { + return $matches[3] . '-' . $matches[2] . '-' . $matches[1]; + } + + return ''; + }, $dates); + + if(count($dates) == 2) { + // If there are two dates, filter between starts_at and ends_at + $query = $query->whereDate('starts_at', '>=', $dates[0]) + ->whereDate('ends_at', '<=', $dates[1]); + } else { + // If there is one date, filter starts_at that date or newer + $query = $query->whereDate('starts_at', '>=', $dates[0]); + } + } + + if($homeView) { + $query = $query->where('starts_at', '>=', Carbon::now()->subDays(8)) + ->orderBy('starts_at', 'asc'); + } else { + $query = $query->orderBy('starts_at', 'asc'); + } + + $workshops = $query->paginate(12); + return view('workshop.index', [ + 'workshops' => $workshops, + 'search' => $search, + ]); + } + + /** + * Display a listing of the resource. + */ + public function past_index(Request $request) + { + return view('workshop.index', [ + 'workshops' => [], +// 'search' => $search, + ]); + } + + /** + * Display a listing of the resource. + */ + public function admin_index(Request $request) + { + $query = Workshop::query(); + + if($request->has('search')) { + $query->where('title', 'like', '%' . $request->search . '%'); + $query->orWhere('content', 'like', '%' . $request->search . '%'); + } + + $workshops = $query->orderBy('starts_at', 'desc')->paginate(12)->onEachSide(1); + + return view('admin.workshop.index', [ + 'workshops' => $workshops + ]); + } + + /** + * Show the form for creating a new resource. + */ + public function admin_create() + { + return view('admin.workshop.edit'); + } + + /** + * Store a newly created resource in storage. + */ + public function admin_store(Request $request) + { + $request->validate([ + 'title' => 'required', + 'content' => 'required', + 'starts_at' => 'required', + 'ends_at' => 'required|after:starts_at', + 'publish_at' => 'required', + 'closes_at' => 'required', + 'status' => 'required', + 'hero_media_name' => 'required|exists:media,name', + 'registration_data' => 'required_unless:registration,none', + ], [ + 'title.required' => __('validation.custom_messages.title_required'), + 'content.required' => __('validation.custom_messages.content_required'), + 'starts_at.required' => __('validation.custom_messages.starts_at_required'), + 'ends_at.required' => __('validation.custom_messages.ends_at_required'), + 'ends_at.after' => __('validation.custom_messages.ends_at_after'), + 'publish_at.required' => __('validation.custom_messages.publish_at_required'), + 'closes_at.required' => __('validation.custom_messages.closes_at_required'), + 'status.required' => __('validation.custom_messages.status_required'), + 'hero_media_name.required' => __('validation.custom_messages.hero_media_name_required'), + 'hero_media_name.exists' => __('validation.custom_messages.hero_media_name_exists'), + 'registration_data.required_unless' => __('validation.custom_messages.registration_data_required_unless'), + ]); + + $workshopData = $request->all(); + $workshopData['user_id'] = auth()->user()->id; + + if($workshopData['status'] === 'open' && Carbon::parse($workshopData['starts_at'])->lt(Carbon::now())) { + $workshopData['status'] = 'closed'; + } + + $workshop = Workshop::create($workshopData); + $workshop->updateFiles($request->input('files')); + + session()->flash('message', 'Workshop has been created'); + session()->flash('message-title', 'Workshop created'); + session()->flash('message-type', 'success'); + return redirect()->route('admin.workshop.index'); + } + + /** + * Display the specified resource. + */ + public function show(Workshop $workshop) + { + if(!auth()->user()?->admin && $workshop->status == 'draft') { + abort(404); + } + + return view('workshop.show', ['workshop' => $workshop]); + } + + /** + * Show the form for editing the specified resource. + */ + public function admin_edit(Workshop $workshop) + { + return view('admin.workshop.edit', ['workshop' => $workshop]); + } + + /** + * Update the specified resource in storage. + */ + public function admin_update(Request $request, Workshop $workshop) + { + $request->validate([ + 'title' => 'required', + 'content' => 'required', + 'starts_at' => 'required', + 'ends_at' => 'required|after:starts_at', + 'publish_at' => 'required', + 'closes_at' => 'required', + 'status' => 'required', + 'hero_media_name' => 'required|exists:media,name', + 'registration_data' => 'required_unless:registration,none', + ], [ + 'title.required' => __('validation.custom_messages.title_required'), + 'content.required' => __('validation.custom_messages.content_required'), + 'starts_at.required' => __('validation.custom_messages.starts_at_required'), + 'ends_at.required' => __('validation.custom_messages.ends_at_required'), + 'ends_at.after' => __('validation.custom_messages.ends_at_after'), + 'publish_at.required' => __('validation.custom_messages.publish_at_required'), + 'closes_at.required' => __('validation.custom_messages.closes_at_required'), + 'status.required' => __('validation.custom_messages.status_required'), + 'hero_media_name.required' => __('validation.custom_messages.hero_media_name_required'), + 'hero_media_name.exists' => __('validation.custom_messages.hero_media_name_exists'), + 'registration_data.required_unless' => __('validation.custom_messages.registration_data_required_unless'), + ]); + + $workshopData = $request->all(); + if($workshopData['status'] === 'open' && Carbon::parse($workshopData['starts_at'])->lt(Carbon::now())) { + $workshopData['status'] = 'closed'; + } + + $workshop->update($workshopData); + $workshop->updateFiles($request->input('files')); + + session()->flash('message', 'Workshop has been updated'); + session()->flash('message-title', 'Workshop updated'); + session()->flash('message-type', 'success'); + return redirect()->route('admin.workshop.index'); + } + + /** + * Remove the specified resource from storage. + */ + public function admin_destroy(Workshop $workshop) + { + $workshop->delete(); + session()->flash('message', 'Workshop has been deleted'); + session()->flash('message-title', 'Workshop deleted'); + session()->flash('message-type', 'danger'); + + return redirect()->route('admin.workshop.index'); + } + + /** + * Duplicate the specified resource. + */ + public function admin_duplicate(Workshop $workshop) + { + $newWorkshop = $workshop->replicate(); + $newWorkshop->title = $newWorkshop->title . ' (copy)'; + $newWorkshop->status = 'draft'; + $newWorkshop->save(); + + foreach($workshop->files as $file) { + $newWorkshop->files()->attach($file->name); + } + + session()->flash('message', 'Workshop has been duplicated'); + session()->flash('message-title', 'Workshop duplicated'); + session()->flash('message-type', 'success'); + + return redirect()->route('admin.workshop.edit', $newWorkshop); + } +} diff --git a/app/Models/Workshop.php b/app/Models/Workshop.php new file mode 100644 index 0000000..a289d9b --- /dev/null +++ b/app/Models/Workshop.php @@ -0,0 +1,52 @@ + 'datetime', + 'ends_at' => 'datetime', + 'publish_at' => 'datetime', + 'closes_at' => 'datetime', + ]; + + public function author() + { + return $this->belongsTo(User::class, 'user_id'); + } + + public function hero() + { + return $this->belongsTo(Media::class, 'hero_media_name'); + } + + public function location() + { + return $this->belongsTo(Location::class, 'location_id'); + } +} diff --git a/config/flare.php b/config/flare.php new file mode 100644 index 0000000..a4896f3 --- /dev/null +++ b/config/flare.php @@ -0,0 +1,80 @@ + env('FLARE_KEY'), + + /* + |-------------------------------------------------------------------------- + | Middleware + |-------------------------------------------------------------------------- + | + | These middleware will modify the contents of the report sent to Flare. + | + */ + + 'flare_middleware' => [ + RemoveRequestIp::class, + AddGitInformation::class, + AddNotifierName::class, + AddEnvironmentInformation::class, + AddExceptionInformation::class, + AddDumps::class, + AddLogs::class => [ + 'maximum_number_of_collected_logs' => 200, + ], + AddQueries::class => [ + 'maximum_number_of_collected_queries' => 200, + 'report_query_bindings' => true, + ], + AddJobs::class => [ + 'max_chained_job_reporting_depth' => 5, + ], + CensorRequestBodyFields::class => [ + 'censor_fields' => [ + 'password', + 'password_confirmation', + ], + ], + CensorRequestHeaders::class => [ + 'headers' => [ + 'API-KEY', + ] + ] + ], + + /* + |-------------------------------------------------------------------------- + | Reporting log statements + |-------------------------------------------------------------------------- + | + | If this setting is `false` log statements won't be sent as events to Flare, + | no matter which error level you specified in the Flare log channel. + | + */ + + 'send_logs_as_events' => true, +]; diff --git a/config/ignition.php b/config/ignition.php new file mode 100644 index 0000000..3edd721 --- /dev/null +++ b/config/ignition.php @@ -0,0 +1,277 @@ + env('IGNITION_EDITOR', 'phpstorm'), + + /* + |-------------------------------------------------------------------------- + | Theme + |-------------------------------------------------------------------------- + | + | Here you may specify which theme Ignition should use. + | + | Supported: "light", "dark", "auto" + | + */ + + 'theme' => env('IGNITION_THEME', 'auto'), + + /* + |-------------------------------------------------------------------------- + | Sharing + |-------------------------------------------------------------------------- + | + | You can share local errors with colleagues or others around the world. + | Sharing is completely free and doesn't require an account on Flare. + | + | If necessary, you can completely disable sharing below. + | + */ + + 'enable_share_button' => env('IGNITION_SHARING_ENABLED', true), + + /* + |-------------------------------------------------------------------------- + | Register Ignition commands + |-------------------------------------------------------------------------- + | + | Ignition comes with an additional make command that lets you create + | new solution classes more easily. To keep your default Laravel + | installation clean, this command is not registered by default. + | + | You can enable the command registration below. + | + */ + + 'register_commands' => env('REGISTER_IGNITION_COMMANDS', false), + + /* + |-------------------------------------------------------------------------- + | Solution Providers + |-------------------------------------------------------------------------- + | + | You may specify a list of solution providers (as fully qualified class + | names) that shouldn't be loaded. Ignition will ignore these classes + | and possible solutions provided by them will never be displayed. + | + */ + + 'solution_providers' => [ + // from spatie/ignition + BadMethodCallSolutionProvider::class, + MergeConflictSolutionProvider::class, + UndefinedPropertySolutionProvider::class, + + // from spatie/laravel-ignition + IncorrectValetDbCredentialsSolutionProvider::class, + MissingAppKeySolutionProvider::class, + DefaultDbNameSolutionProvider::class, + TableNotFoundSolutionProvider::class, + MissingImportSolutionProvider::class, + InvalidRouteActionSolutionProvider::class, + ViewNotFoundSolutionProvider::class, + RunningLaravelDuskInProductionProvider::class, + MissingColumnSolutionProvider::class, + UnknownValidationSolutionProvider::class, + MissingMixManifestSolutionProvider::class, + MissingViteManifestSolutionProvider::class, + MissingLivewireComponentSolutionProvider::class, + UndefinedViewVariableSolutionProvider::class, + GenericLaravelExceptionSolutionProvider::class, + OpenAiSolutionProvider::class, + ], + + /* + |-------------------------------------------------------------------------- + | Ignored Solution Providers + |-------------------------------------------------------------------------- + | + | You may specify a list of solution providers (as fully qualified class + | names) that shouldn't be loaded. Ignition will ignore these classes + | and possible solutions provided by them will never be displayed. + | + */ + + 'ignored_solution_providers' => [ + + ], + + /* + |-------------------------------------------------------------------------- + | Runnable Solutions + |-------------------------------------------------------------------------- + | + | Some solutions that Ignition displays are runnable and can perform + | various tasks. By default, runnable solutions are only enabled when your + | app has debug mode enabled and the environment is `local` or + | `development`. + | + | Using the `IGNITION_ENABLE_RUNNABLE_SOLUTIONS` environment variable, you + | can override this behaviour and enable or disable runnable solutions + | regardless of the application's environment. + | + | Default: env('IGNITION_ENABLE_RUNNABLE_SOLUTIONS') + | + */ + + 'enable_runnable_solutions' => env('IGNITION_ENABLE_RUNNABLE_SOLUTIONS'), + + /* + |-------------------------------------------------------------------------- + | Remote Path Mapping + |-------------------------------------------------------------------------- + | + | If you are using a remote dev server, like Laravel Homestead, Docker, or + | even a remote VPS, it will be necessary to specify your path mapping. + | + | Leaving one, or both of these, empty or null will not trigger the remote + | URL changes and Ignition will treat your editor links as local files. + | + | "remote_sites_path" is an absolute base path for your sites or projects + | in Homestead, Vagrant, Docker, or another remote development server. + | + | Example value: "/home/vagrant/Code" + | + | "local_sites_path" is an absolute base path for your sites or projects + | on your local computer where your IDE or code editor is running on. + | + | Example values: "/Users//Code", "C:\Users\\Documents\Code" + | + */ + + 'remote_sites_path' => env('IGNITION_REMOTE_SITES_PATH', base_path()), + 'local_sites_path' => env('IGNITION_LOCAL_SITES_PATH', ''), + + /* + |-------------------------------------------------------------------------- + | Housekeeping Endpoint Prefix + |-------------------------------------------------------------------------- + | + | Ignition registers a couple of routes when it is enabled. Below you may + | specify a route prefix that will be used to host all internal links. + | + */ + + 'housekeeping_endpoint_prefix' => '_ignition', + + /* + |-------------------------------------------------------------------------- + | Settings File + |-------------------------------------------------------------------------- + | + | Ignition allows you to save your settings to a specific global file. + | + | If no path is specified, a file with settings will be saved to the user's + | home directory. The directory depends on the OS and its settings but it's + | typically `~/.ignition.json`. In this case, the settings will be applied + | to all of your projects where Ignition is used and the path is not + | specified. + | + | However, if you want to store your settings on a project basis, or you + | want to keep them in another directory, you can specify a path where + | the settings file will be saved. The path should be an existing directory + | with correct write access. + | For example, create a new `ignition` folder in the storage directory and + | use `storage_path('ignition')` as the `settings_file_path`. + | + | Default value: '' (empty string) + */ + + 'settings_file_path' => '', + + /* + |-------------------------------------------------------------------------- + | Recorders + |-------------------------------------------------------------------------- + | + | Ignition registers a couple of recorders when it is enabled. Below you may + | specify a recorders will be used to record specific events. + | + */ + + 'recorders' => [ + DumpRecorder::class, + JobRecorder::class, + LogRecorder::class, + QueryRecorder::class, + ], + + /* + * When a key is set, we'll send your exceptions to Open AI to generate a solution + */ + 'open_ai_key' => env('IGNITION_OPEN_AI_KEY'), + + /* + |-------------------------------------------------------------------------- + | Include arguments + |-------------------------------------------------------------------------- + | + | Ignition show you stack traces of exceptions with the arguments that were + | passed to each method. This feature can be disabled here. + | + */ + + 'with_stack_frame_arguments' => true, + + /* + |-------------------------------------------------------------------------- + | Argument reducers + |-------------------------------------------------------------------------- + | + | Ignition show you stack traces of exceptions with the arguments that were + | passed to each method. To make these variables more readable, you can + | specify a list of classes here which summarize the variables. + | + */ + 'argument_reducers' => [ + \Spatie\Backtrace\Arguments\Reducers\BaseTypeArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\ArrayArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\StdClassArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\EnumArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\ClosureArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\DateTimeArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\DateTimeZoneArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\SymphonyRequestArgumentReducer::class, + \Spatie\LaravelIgnition\ArgumentReducers\ModelArgumentReducer::class, + \Spatie\LaravelIgnition\ArgumentReducers\CollectionArgumentReducer::class, + \Spatie\Backtrace\Arguments\Reducers\StringableArgumentReducer::class, + ], +]; diff --git a/config/tinker.php b/config/tinker.php new file mode 100644 index 0000000..c187942 --- /dev/null +++ b/config/tinker.php @@ -0,0 +1,50 @@ + [ + // App\Console\Commands\ExampleCommand::class, + ], + + /* + |-------------------------------------------------------------------------- + | Auto Aliased Classes + |-------------------------------------------------------------------------- + | + | Tinker will not automatically alias classes in your vendor namespaces + | but you may explicitly allow a subset of classes to get aliased by + | adding the names of each of those classes to the following list. + | + */ + + 'alias' => [ + // + ], + + /* + |-------------------------------------------------------------------------- + | Classes That Should Not Be Aliased + |-------------------------------------------------------------------------- + | + | Typically, Tinker automatically aliases classes as you require them in + | Tinker. However, you may wish to never alias certain classes, which + | you may accomplish by listing the classes in the following array. + | + */ + + 'dont_alias' => [ + 'App\Nova', + ], + +]; diff --git a/lang/vendor/clamav-validator/en/validation.php b/lang/vendor/clamav-validator/en/validation.php new file mode 100644 index 0000000..c6e62c5 --- /dev/null +++ b/lang/vendor/clamav-validator/en/validation.php @@ -0,0 +1,5 @@ + ':attribute contains virus.', +]; diff --git a/resources/views/admin/workshop/edit.blade.php b/resources/views/admin/workshop/edit.blade.php new file mode 100644 index 0000000..054b5e0 --- /dev/null +++ b/resources/views/admin/workshop/edit.blade.php @@ -0,0 +1,172 @@ +@php + $workshopContent = isset($workshop) ? $workshop->content : ''; +@endphp + + {{ isset($workshop) ? 'Edit' : 'Create' }} Workshop + + +
+ @isset($workshop) + @method('PUT') + @endisset + @csrf +
+ +
+
+ +
+
+
+ + + + +
+
+ + + @foreach(\App\Models\Location::orderByRaw("name = 'Online' DESC, name ASC")->get() as $location) + + @endforeach + + +
+
+
+
+ +
+
+ +
+
+
+
+ + + + + + + + + +
+
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + + + + + +
+
+ + + + + + + + + + +
+
+
+ +
+
+ +
+
+ @isset($workshop) + Delete + @endisset + {{ isset($workshop) ? 'Save' : 'Create' }} +
+
+
+
+ + diff --git a/resources/views/admin/workshop/index.blade.php b/resources/views/admin/workshop/index.blade.php new file mode 100644 index 0000000..23ce11f --- /dev/null +++ b/resources/views/admin/workshop/index.blade.php @@ -0,0 +1,55 @@ + + Workshops + + +
+
+ Create +
+
+ +
+
+ + @if($workshops->isEmpty()) + + @else + + + Title + Status + Location + Starts + Action + + + @foreach ($workshops as $workshop) + + + {{ $workshop->hero->title }} +
+
{{ $workshop->title }}
+
{{ $workshop->location->name }} ({{ ucwords($workshop->status) }})
+
{{ \Carbon\Carbon::parse($workshop->starts_at)->format('j/m/Y g:i a') }}
+
+ + {{ ucwords($workshop->status) }} + {{ $workshop->location->name }} + {{ \Carbon\Carbon::parse($workshop->starts_at)->format('M j Y, g:i a') }} + +
+ + + +
+ + + @endforeach +
+
+ + {{ $workshops->appends(request()->query())->links() }} + @endif + +
+
diff --git a/resources/views/components/panel-workshop.blade.php b/resources/views/components/panel-workshop.blade.php new file mode 100644 index 0000000..dffe2b7 --- /dev/null +++ b/resources/views/components/panel-workshop.blade.php @@ -0,0 +1,45 @@ +@props(['workshop']) + +@php + $statusClass = $workshop->status; + $statusTitle = $workshop->status; + + if($workshop->status === 'scheduled') { + $statusClass = 'soon'; + $statusTitle = 'Open soon'; + } +@endphp + + +
+
{{ $workshop->starts_at->format('j') }}
+
{{ $workshop->starts_at->format('M') }}
+
+
{{ $statusTitle }}
+ {{ $workshop->title }} +
+

{{ $workshop->title }}

+
+
+ +
{{ $workshop->starts_at->format('j/m/Y @ g:i a') }} +
+
+
+ +
{{ $workshop->location->name }} +
+ @if($workshop->ages) +
+
+ +
{{ isset($workshop->ages) && $workshop->ages !== '' ? 'Ages ' . $workshop->ages : 'All ages' }} +
+ @endif +
+
+ +
{{ isset($workshop->price) && $workshop->price !== '' && $workshop->price !== '0' ? $workshop->price : 'Free' }} +
+
+
diff --git a/resources/views/errors/401.blade.php b/resources/views/errors/401.blade.php new file mode 100644 index 0000000..5c586db --- /dev/null +++ b/resources/views/errors/401.blade.php @@ -0,0 +1,5 @@ +@extends('errors::minimal') + +@section('title', __('Unauthorized')) +@section('code', '401') +@section('message', __('Unauthorized')) diff --git a/resources/views/errors/402.blade.php b/resources/views/errors/402.blade.php new file mode 100644 index 0000000..3bc23ef --- /dev/null +++ b/resources/views/errors/402.blade.php @@ -0,0 +1,5 @@ +@extends('errors::minimal') + +@section('title', __('Payment Required')) +@section('code', '402') +@section('message', __('Payment Required')) diff --git a/resources/views/errors/419.blade.php b/resources/views/errors/419.blade.php new file mode 100644 index 0000000..c09216e --- /dev/null +++ b/resources/views/errors/419.blade.php @@ -0,0 +1,5 @@ +@extends('errors::minimal') + +@section('title', __('Page Expired')) +@section('code', '419') +@section('message', __('Page Expired')) diff --git a/resources/views/errors/429.blade.php b/resources/views/errors/429.blade.php new file mode 100644 index 0000000..f01b07b --- /dev/null +++ b/resources/views/errors/429.blade.php @@ -0,0 +1,5 @@ +@extends('errors::minimal') + +@section('title', __('Too Many Requests')) +@section('code', '429') +@section('message', __('Too Many Requests')) diff --git a/resources/views/errors/500.blade.php b/resources/views/errors/500.blade.php new file mode 100644 index 0000000..d9e95d9 --- /dev/null +++ b/resources/views/errors/500.blade.php @@ -0,0 +1,5 @@ +@extends('errors::minimal') + +@section('title', __('Server Error')) +@section('code', '500') +@section('message', __('Server Error')) diff --git a/resources/views/errors/layout.blade.php b/resources/views/errors/layout.blade.php new file mode 100644 index 0000000..019c2cd --- /dev/null +++ b/resources/views/errors/layout.blade.php @@ -0,0 +1,53 @@ + + + + + + + @yield('title') + + + + + +
+
+
+ @yield('message') +
+
+
+ + diff --git a/resources/views/errors/minimal.blade.php b/resources/views/errors/minimal.blade.php new file mode 100644 index 0000000..db69f25 --- /dev/null +++ b/resources/views/errors/minimal.blade.php @@ -0,0 +1,34 @@ + + + + + + + @yield('title') + + + + + + +
+
+
+
+ @yield('code') +
+ +
+ @yield('message') +
+
+
+
+ + diff --git a/resources/views/vendor/notifications/email.blade.php b/resources/views/vendor/notifications/email.blade.php new file mode 100644 index 0000000..678e259 --- /dev/null +++ b/resources/views/vendor/notifications/email.blade.php @@ -0,0 +1,58 @@ + +{{-- Greeting --}} +@if (! empty($greeting)) +# {{ $greeting }} +@else +@if ($level === 'error') +# @lang('Whoops!') +@else +# @lang('Hello!') +@endif +@endif + +{{-- Intro Lines --}} +@foreach ($introLines as $line) +{{ $line }} + +@endforeach + +{{-- Action Button --}} +@isset($actionText) + $level, + default => 'primary', + }; +?> + +{{ $actionText }} + +@endisset + +{{-- Outro Lines --}} +@foreach ($outroLines as $line) +{{ $line }} + +@endforeach + +{{-- Salutation --}} +@if (! empty($salutation)) +{{ $salutation }} +@else +@lang('Regards'),
+{{ config('app.name') }} +@endif + +{{-- Subcopy --}} +@isset($actionText) + +@lang( + "If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\n". + 'into your web browser:', + [ + 'actionText' => $actionText, + ] +) [{{ $displayableActionUrl }}]({{ $actionUrl }}) + +@endisset +
diff --git a/resources/views/workshop/index.blade.php b/resources/views/workshop/index.blade.php new file mode 100644 index 0000000..31c971f --- /dev/null +++ b/resources/views/workshop/index.blade.php @@ -0,0 +1,33 @@ + + Workshops + +
+ + + + + @if($workshops->isEmpty()) + + + + @else + + @foreach ($workshops as $workshop) + + @endforeach + + + {{ $workshops->appends(request()->query())->links() }} + + @endif +
+
diff --git a/resources/views/workshop/show.blade.php b/resources/views/workshop/show.blade.php new file mode 100644 index 0000000..d32a472 --- /dev/null +++ b/resources/views/workshop/show.blade.php @@ -0,0 +1,69 @@ + + + +
+
+

{!! $workshop->title !!}

+
{!! $workshop->content !!}
+ +
+
+ @if($workshop->status === 'closed') +
Registration for this event has closed.
+ @elseif($workshop->status === 'full') +
This workshop is currently full.
+ @elseif($workshop->status === 'private') +
This is a private event. Please contact the organiser for details.
+ @if($workshop->registration === 'link') + Register for Event + @elseif($workshop->registration === 'message') +
{{ $workshop->registration_data }}
+ @endif + @elseif($workshop->status === 'scheduled') +
Registration for this workshop will open soon.
+ @elseif($workshop->status === 'cancelled') +
This workshop has been cancelled.
+ @elseif($workshop->registration === 'none') +
Registration not required for this event. Arrive early to avoid disappointment as seating maybe limited.
+ @elseif($workshop->registration === 'link') + Register for Event + @elseif($workshop->registration === 'email') +
Registration for this event by emailing {{ $workshop->registration_data }}.
+ @elseif($workshop->registration === 'message') +
{{ $workshop->registration_data }}
+ @endif + @if(auth()->user()?->admin) + Edit Workshop + @endif +

Date/Time

+

{!! implode('
', \App\Helpers::createTimeDurationStr($workshop->starts_at, $workshop->ends_at)) !!}

+

Location

+ +

{{ isset($workshop->ages) && $workshop->ages !== '' ? 'Ages ' . $workshop->ages : 'All ages' }}

+ @if(\App\Helpers::isUnderAge($workshop->ages)) +

Parental supervision may be required for children 8 years of age and under.

+ @endif +

{{ isset($workshop->price) && $workshop->price !== '' && $workshop->price !== '0' ? $workshop->price : 'Free' }}

+{{-- @if(isset($workshop->price) && $workshop->price !== '' && $workshop->price !== '0' && strtolower($workshop->price) !== 'free')--}} +{{--

Payment by cash or EFTPOS accepted. Please ensure correct change.

--}} +{{-- @endif--}} +
+
+
+
diff --git a/sail b/sail new file mode 100644 index 0000000..8a9d1fb --- /dev/null +++ b/sail @@ -0,0 +1,518 @@ +#!/usr/bin/env bash + +UNAMEOUT="$(uname -s)" + +# Verify operating system is supported... +case "${UNAMEOUT}" in + Linux*) MACHINE=linux;; + Darwin*) MACHINE=mac;; + *) MACHINE="UNKNOWN" +esac + +if [ "$MACHINE" == "UNKNOWN" ]; then + echo "Unsupported operating system [$(uname -s)]. Laravel Sail supports macOS, Linux, and Windows (WSL2)." >&2 + + exit 1 +fi + +# Determine if stdout is a terminal... +if test -t 1; then + # Determine if colors are supported... + ncolors=$(tput colors) + + if test -n "$ncolors" && test "$ncolors" -ge 8; then + BOLD="$(tput bold)" + YELLOW="$(tput setaf 3)" + GREEN="$(tput setaf 2)" + NC="$(tput sgr0)" + fi +fi + +# Function that prints the available commands... +function display_help { + echo "Laravel Sail" + echo + echo "${YELLOW}Usage:${NC}" >&2 + echo " sail COMMAND [options] [arguments]" + echo + echo "Unknown commands are passed to the docker-compose binary." + echo + echo "${YELLOW}docker-compose Commands:${NC}" + echo " ${GREEN}sail up${NC} Start the application" + echo " ${GREEN}sail up -d${NC} Start the application in the background" + echo " ${GREEN}sail stop${NC} Stop the application" + echo " ${GREEN}sail restart${NC} Restart the application" + echo " ${GREEN}sail ps${NC} Display the status of all containers" + echo + echo "${YELLOW}Artisan Commands:${NC}" + echo " ${GREEN}sail artisan ...${NC} Run an Artisan command" + echo " ${GREEN}sail artisan queue:work${NC}" + echo + echo "${YELLOW}PHP Commands:${NC}" + echo " ${GREEN}sail php ...${NC} Run a snippet of PHP code" + echo " ${GREEN}sail php -v${NC}" + echo + echo "${YELLOW}Composer Commands:${NC}" + echo " ${GREEN}sail composer ...${NC} Run a Composer command" + echo " ${GREEN}sail composer require laravel/sanctum${NC}" + echo + echo "${YELLOW}Node Commands:${NC}" + echo " ${GREEN}sail node ...${NC} Run a Node command" + echo " ${GREEN}sail node --version${NC}" + echo + echo "${YELLOW}NPM Commands:${NC}" + echo " ${GREEN}sail npm ...${NC} Run a npm command" + echo " ${GREEN}sail npx${NC} Run a npx command" + echo " ${GREEN}sail npm run prod${NC}" + echo + echo "${YELLOW}Yarn Commands:${NC}" + echo " ${GREEN}sail yarn ...${NC} Run a Yarn command" + echo " ${GREEN}sail yarn run prod${NC}" + echo + echo "${YELLOW}Database Commands:${NC}" + echo " ${GREEN}sail mysql${NC} Start a MySQL CLI session within the 'mysql' container" + echo " ${GREEN}sail mariadb${NC} Start a MySQL CLI session within the 'mariadb' container" + echo " ${GREEN}sail psql${NC} Start a PostgreSQL CLI session within the 'pgsql' container" + echo " ${GREEN}sail redis${NC} Start a Redis CLI session within the 'redis' container" + echo + echo "${YELLOW}Debugging:${NC}" + echo " ${GREEN}sail debug ...${NC} Run an Artisan command in debug mode" + echo " ${GREEN}sail debug queue:work${NC}" + echo + echo "${YELLOW}Running Tests:${NC}" + echo " ${GREEN}sail test${NC} Run the PHPUnit tests via the Artisan test command" + echo " ${GREEN}sail phpunit ...${NC} Run PHPUnit" + echo " ${GREEN}sail pest ...${NC} Run Pest" + echo " ${GREEN}sail pint ...${NC} Run Pint" + echo " ${GREEN}sail dusk${NC} Run the Dusk tests (Requires the laravel/dusk package)" + echo " ${GREEN}sail dusk:fails${NC} Re-run previously failed Dusk tests (Requires the laravel/dusk package)" + echo + echo "${YELLOW}Container CLI:${NC}" + echo " ${GREEN}sail shell${NC} Start a shell session within the application container" + echo " ${GREEN}sail bash${NC} Alias for 'sail shell'" + echo " ${GREEN}sail root-shell${NC} Start a root shell session within the application container" + echo " ${GREEN}sail root-bash${NC} Alias for 'sail root-shell'" + echo " ${GREEN}sail tinker${NC} Start a new Laravel Tinker session" + echo + echo "${YELLOW}Sharing:${NC}" + echo " ${GREEN}sail share${NC} Share the application publicly via a temporary URL" + echo " ${GREEN}sail open${NC} Open the site in your browser" + echo + echo "${YELLOW}Binaries:${NC}" + echo " ${GREEN}sail bin ...${NC} Run Composer binary scripts from the vendor/bin directory" + echo + echo "${YELLOW}Customization:${NC}" + echo " ${GREEN}sail artisan sail:publish${NC} Publish the Sail configuration files" + echo " ${GREEN}sail build --no-cache${NC} Rebuild all of the Sail containers" + + exit 1 +} + +# Proxy the "help" command... +if [ $# -gt 0 ]; then + if [ "$1" == "help" ] || [ "$1" == "-h" ] || [ "$1" == "-help" ] || [ "$1" == "--help" ]; then + display_help + fi +else + display_help +fi + +# Source the ".env" file so Laravel's environment variables are available... +if [ ! -z "$APP_ENV" ] && [ -f ./.env.$APP_ENV ]; then + source ./.env.$APP_ENV; +elif [ -f ./.env ]; then + source ./.env; +fi + +# Define environment variables... +export APP_PORT=${APP_PORT:-80} +export APP_SERVICE=${APP_SERVICE:-"laravel.test"} +export DB_PORT=${DB_PORT:-3306} +export WWWUSER=${WWWUSER:-$UID} +export WWWGROUP=${WWWGROUP:-$(id -g)} + +export SAIL_FILES=${SAIL_FILES:-""} +export SAIL_SHARE_DASHBOARD=${SAIL_SHARE_DASHBOARD:-4040} +export SAIL_SHARE_SERVER_HOST=${SAIL_SHARE_SERVER_HOST:-"laravel-sail.site"} +export SAIL_SHARE_SERVER_PORT=${SAIL_SHARE_SERVER_PORT:-8080} +export SAIL_SHARE_SUBDOMAIN=${SAIL_SHARE_SUBDOMAIN:-""} +export SAIL_SHARE_DOMAIN=${SAIL_SHARE_DOMAIN:-"$SAIL_SHARE_SERVER_HOST"} +export SAIL_SHARE_SERVER=${SAIL_SHARE_SERVER:-""} + +# Function that outputs Sail is not running... +function sail_is_not_running { + echo "${BOLD}Sail is not running.${NC}" >&2 + echo "" >&2 + echo "${BOLD}You may Sail using the following commands:${NC} './vendor/bin/sail up' or './vendor/bin/sail up -d'" >&2 + + exit 1 +} + +# Define Docker Compose command prefix... +docker compose &> /dev/null +if [ $? == 0 ]; then + DOCKER_COMPOSE=(docker compose) +else + DOCKER_COMPOSE=(docker-compose) +fi + +if [ -n "$SAIL_FILES" ]; then + # Convert SAIL_FILES to an array... + IFS=':' read -ra SAIL_FILES <<< "$SAIL_FILES" + + for FILE in "${SAIL_FILES[@]}"; do + if [ -f "$FILE" ]; then + DOCKER_COMPOSE+=(-f "$FILE") + else + echo "${BOLD}Unable to find Docker Compose file: '${FILE}'${NC}" >&2 + + exit 1 + fi + done +fi + +EXEC="yes" + +if [ -z "$SAIL_SKIP_CHECKS" ]; then + # Ensure that Docker is running... + if ! docker info > /dev/null 2>&1; then + echo "${BOLD}Docker is not running.${NC}" >&2 + + exit 1 + fi + + # Determine if Sail is currently up... + if "${DOCKER_COMPOSE[@]}" ps "$APP_SERVICE" 2>&1 | grep 'Exit\|exited'; then + echo "${BOLD}Shutting down old Sail processes...${NC}" >&2 + + "${DOCKER_COMPOSE[@]}" down > /dev/null 2>&1 + + EXEC="no" + elif [ -z "$("${DOCKER_COMPOSE[@]}" ps -q)" ]; then + EXEC="no" + fi +fi + +ARGS=() + +# Proxy PHP commands to the "php" binary on the application container... +if [ "$1" == "php" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" "php" "$@") + else + sail_is_not_running + fi + +# Proxy vendor binary commands on the application container... +elif [ "$1" == "bin" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" ./vendor/bin/"$@") + else + sail_is_not_running + fi + +# Proxy docker-compose commands to the docker-compose binary on the application container... +elif [ "$1" == "docker-compose" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" "${DOCKER_COMPOSE[@]}") + else + sail_is_not_running + fi + +# Proxy Composer commands to the "composer" binary on the application container... +elif [ "$1" == "composer" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" "composer" "$@") + else + sail_is_not_running + fi + +# Proxy Artisan commands to the "artisan" binary on the application container... +elif [ "$1" == "artisan" ] || [ "$1" == "art" ] || [ "$1" == "a" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" php artisan "$@") + else + sail_is_not_running + fi + +# Proxy the "debug" command to the "php artisan" binary on the application container with xdebug enabled... +elif [ "$1" == "debug" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail -e XDEBUG_SESSION=1) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" php artisan "$@") + else + sail_is_not_running + fi + +# Proxy the "test" command to the "php artisan test" Artisan command... +elif [ "$1" == "test" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" php artisan test "$@") + else + sail_is_not_running + fi + +# Proxy the "phpunit" command to "php vendor/bin/phpunit"... +elif [ "$1" == "phpunit" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" php vendor/bin/phpunit "$@") + else + sail_is_not_running + fi + +# Proxy the "pest" command to "php vendor/bin/pest"... +elif [ "$1" == "pest" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" php vendor/bin/pest "$@") + else + sail_is_not_running + fi + +# Proxy the "pint" command to "php vendor/bin/pint"... +elif [ "$1" == "pint" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" php vendor/bin/pint "$@") + else + sail_is_not_running + fi + +# Proxy the "dusk" command to the "php artisan dusk" Artisan command... +elif [ "$1" == "dusk" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=(-e "APP_URL=http://${APP_SERVICE}") + ARGS+=(-e "DUSK_DRIVER_URL=http://selenium:4444/wd/hub") + ARGS+=("$APP_SERVICE" php artisan dusk "$@") + else + sail_is_not_running + fi + +# Proxy the "dusk:fails" command to the "php artisan dusk:fails" Artisan command... +elif [ "$1" == "dusk:fails" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=(-e "APP_URL=http://${APP_SERVICE}") + ARGS+=(-e "DUSK_DRIVER_URL=http://selenium:4444/wd/hub") + ARGS+=("$APP_SERVICE" php artisan dusk:fails "$@") + else + sail_is_not_running + fi + +# Initiate a Laravel Tinker session within the application container... +elif [ "$1" == "tinker" ] ; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" php artisan tinker) + else + sail_is_not_running + fi + +# Proxy Node commands to the "node" binary on the application container... +elif [ "$1" == "node" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" node "$@") + else + sail_is_not_running + fi + +# Proxy NPM commands to the "npm" binary on the application container... +elif [ "$1" == "npm" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" npm "$@") + else + sail_is_not_running + fi + +# Proxy NPX commands to the "npx" binary on the application container... +elif [ "$1" == "npx" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" npx "$@") + else + sail_is_not_running + fi + +# Proxy YARN commands to the "yarn" binary on the application container... +elif [ "$1" == "yarn" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" yarn "$@") + else + sail_is_not_running + fi + +# Initiate a MySQL CLI terminal session within the "mysql" container... +elif [ "$1" == "mysql" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=(mysql bash -c) + ARGS+=("MYSQL_PWD=\${MYSQL_PASSWORD} mysql -u \${MYSQL_USER} \${MYSQL_DATABASE}") + else + sail_is_not_running + fi + +# Initiate a MySQL CLI terminal session within the "mariadb" container... +elif [ "$1" == "mariadb" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=(mariadb bash -c) + ARGS+=("MYSQL_PWD=\${MYSQL_PASSWORD} mysql -u \${MYSQL_USER} \${MYSQL_DATABASE}") + else + sail_is_not_running + fi + +# Initiate a PostgreSQL CLI terminal session within the "pgsql" container... +elif [ "$1" == "psql" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=(pgsql bash -c) + ARGS+=("PGPASSWORD=\${PGPASSWORD} psql -U \${POSTGRES_USER} \${POSTGRES_DB}") + else + sail_is_not_running + fi + +# Initiate a Bash shell within the application container... +elif [ "$1" == "shell" ] || [ "$1" == "bash" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec -u sail) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" bash "$@") + else + sail_is_not_running + fi + +# Initiate a root user Bash shell within the application container... +elif [ "$1" == "root-shell" ] || [ "$1" == "root-bash" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=("$APP_SERVICE" bash "$@") + else + sail_is_not_running + fi + +# Initiate a Redis CLI terminal session within the "redis" container... +elif [ "$1" == "redis" ] ; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + ARGS+=(exec) + [ ! -t 0 ] && ARGS+=(-T) + ARGS+=(redis redis-cli) + else + sail_is_not_running + fi + +# Share the site... +elif [ "$1" == "share" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + docker run --init --rm -p "$SAIL_SHARE_DASHBOARD":4040 -t beyondcodegmbh/expose-server:latest share http://host.docker.internal:"$APP_PORT" \ + --server-host="$SAIL_SHARE_SERVER_HOST" \ + --server-port="$SAIL_SHARE_SERVER_PORT" \ + --auth="$SAIL_SHARE_TOKEN" \ + --server="$SAIL_SHARE_SERVER" \ + --subdomain="$SAIL_SHARE_SUBDOMAIN" \ + --domain="$SAIL_SHARE_DOMAIN" \ + "$@" + + exit + else + sail_is_not_running + fi + +# Open the site... +elif [ "$1" == "open" ]; then + shift 1 + + if [ "$EXEC" == "yes" ]; then + open $APP_URL + + exit + else + sail_is_not_running + fi + +# Pass unknown commands to the "docker-compose" binary... +else + ARGS+=("$@") +fi + +# Run Docker Compose with the defined arguments... +"${DOCKER_COMPOSE[@]}" "${ARGS[@]}"