set timezone

This commit is contained in:
Benjamin Takats
2022-12-02 16:24:25 +01:00
parent b55ac39215
commit b995c5737c
18 changed files with 286 additions and 34 deletions

View File

@@ -11,5 +11,5 @@ models:
Registration: { event_id: biginteger, participant_id: biginteger, active: 'boolean default:1' } Registration: { event_id: biginteger, participant_id: biginteger, active: 'boolean default:1' }
Team: { user_id: biginteger, name: string, personal_team: boolean } Team: { user_id: biginteger, name: string, personal_team: boolean }
TeamInvitation: { team_id: biginteger, email: string, role: 'string nullable' } TeamInvitation: { team_id: biginteger, email: string, role: 'string nullable' }
User: { name: string, public_key: 'string nullable', email: 'string nullable', email_verified_at: 'datetime nullable', password: 'string nullable', remember_token: 'string:100 nullable', current_team_id: 'biginteger nullable', profile_photo_path: 'string:2048 nullable', is_lecturer: 'boolean default:', two_factor_secret: 'text nullable', two_factor_recovery_codes: 'text nullable', two_factor_confirmed_at: 'datetime nullable' } User: { name: string, public_key: 'string nullable', email: 'string nullable', email_verified_at: 'datetime nullable', password: 'string nullable', remember_token: 'string:100 nullable', current_team_id: 'biginteger nullable', profile_photo_path: 'string:2048 nullable', is_lecturer: 'boolean default:', two_factor_secret: 'text nullable', two_factor_recovery_codes: 'text nullable', two_factor_confirmed_at: 'datetime nullable', timezone: 'string default:Europe/Berlin' }
Venue: { city_id: biginteger, name: string, slug: string, street: string } Venue: { city_id: biginteger, name: string, slug: string, street: string }

View File

@@ -20,11 +20,13 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
public function update($user, array $input) public function update($user, array $input)
{ {
Validator::make($input, [ Validator::make($input, [
'name' => ['required', 'string', 'max:255'], 'name' => ['required', 'string', 'max:255'],
'email' => ['nullable', 'email', 'max:255', Rule::unique('users') 'timezone' => ['required', 'string'],
->ignore($user->id) 'email' => [
'nullable', 'email', 'max:255', Rule::unique('users')
->ignore($user->id)
], ],
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'], 'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
]) ])
->validateWithBag('updateProfileInformation'); ->validateWithBag('updateProfileInformation');
@@ -37,8 +39,9 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
$this->updateVerifiedUser($user, $input); $this->updateVerifiedUser($user, $input);
} else { } else {
$user->forceFill([ $user->forceFill([
'name' => $input['name'], 'name' => $input['name'],
'email' => $input['email'], 'email' => $input['email'],
'timezone' => $input['timezone'],
]) ])
->save(); ->save();
} }
@@ -57,6 +60,7 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
$user->forceFill([ $user->forceFill([
'name' => $input['name'], 'name' => $input['name'],
'email' => $input['email'], 'email' => $input['email'],
'timezone' => $input['timezone'],
'email_verified_at' => null, 'email_verified_at' => null,
]) ])
->save(); ->save();

View File

@@ -3,6 +3,7 @@
namespace App\Http; namespace App\Http;
use App\Http\Middleware\CustomEnsureEmailVerified; use App\Http\Middleware\CustomEnsureEmailVerified;
use App\Http\Middleware\SetTimezoneMiddleware;
use Illuminate\Foundation\Http\Kernel as HttpKernel; use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel class Kernel extends HttpKernel
@@ -34,12 +35,14 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class, \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
SetTimezoneMiddleware::class,
], ],
'api' => [ 'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api', 'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
SetTimezoneMiddleware::class,
], ],
]; ];

View File

@@ -34,9 +34,15 @@ class EventTable extends DataTableComponent
->sortable(), ->sortable(),
Column::make("Kurs", "course.name") Column::make("Kurs", "course.name")
->sortable(), ->sortable(),
Column::make("Erstellt am", "created_at") Column::make("Von", "from")
->format(
fn($value, $row, Column $column) => $value->asDateTime()
)
->sortable(), ->sortable(),
Column::make("Zuletzt geändert", "updated_at") Column::make("Bis", "to")
->format(
fn($value, $row, Column $column) => $value->asDateTime()
)
->sortable(), ->sortable(),
/*Column::make("Teilnehmer") /*Column::make("Teilnehmer")
->label( ->label(

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class SetTimezoneMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
*
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if (
!collect($request->segments())->contains('nova')
&& $request->user()
&& $timezone = $request->user()->timezone
) {
config(['app.timezone' => $timezone]);
}
config(['app.timezone' => 'Europe/Berlin']);
return $next($request);
}
}

View File

@@ -52,12 +52,12 @@ class City extends Resource
Number::make('Latitude') Number::make('Latitude')
->rules('required', 'numeric') ->rules('required', 'numeric')
->step(0.00001) ->step(0.000001)
->help('https://latitude.to/lat/47.72671/lng/10.31688'), ->help('https://latitude.to/lat/47.72671/lng/10.31688'),
Number::make('Longitude') Number::make('Longitude')
->rules('required', 'numeric') ->rules('required', 'numeric')
->step(0.00001) ->step(0.000001)
->help('https://latitude.to/lat/47.72671/lng/10.31688'), ->help('https://latitude.to/lat/47.72671/lng/10.31688'),
BelongsTo::make('Country'), BelongsTo::make('Country'),

View File

@@ -57,11 +57,11 @@ class Event extends Resource
DateTime::make('From') DateTime::make('From')
->rules('required') ->rules('required')
->step(CarbonInterval::minutes(30)), ->step(CarbonInterval::minutes(30))->displayUsing(fn ($value) => $value->asDateTime()),
DateTime::make('To') DateTime::make('To')
->rules('required') ->rules('required')
->step(CarbonInterval::minutes(30)), ->step(CarbonInterval::minutes(30))->displayUsing(fn ($value) => $value->asDateTime()),
BelongsTo::make('Course'), BelongsTo::make('Course'),
BelongsTo::make('Venue') BelongsTo::make('Venue')

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Observers;
use App\Models\Event;
class EventObserver
{
/**
* Handle the Event "created" event.
*
* @param \App\Models\Event $event
*
* @return void
*/
public function created(Event $event)
{
//
}
/**
* Handle the Event "updated" event.
*
* @param \App\Models\Event $event
*
* @return void
*/
public function updated(Event $event)
{
//
}
/**
* Handle the Event "deleted" event.
*
* @param \App\Models\Event $event
*
* @return void
*/
public function deleted(Event $event)
{
//
}
/**
* Handle the Event "restored" event.
*
* @param \App\Models\Event $event
*
* @return void
*/
public function restored(Event $event)
{
//
}
/**
* Handle the Event "force deleted" event.
*
* @param \App\Models\Event $event
*
* @return void
*/
public function forceDeleted(Event $event)
{
//
}
}

View File

@@ -2,6 +2,8 @@
namespace App\Providers; namespace App\Providers;
use App\Support\Carbon;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Support\Stringable; use Illuminate\Support\Stringable;
@@ -10,22 +12,22 @@ class AppServiceProvider extends ServiceProvider
{ {
/** /**
* Register any application services. * Register any application services.
*
* @return void * @return void
*/ */
public function register() public function register()
{ {
// Date::use(
Carbon::class
);
} }
/** /**
* Bootstrap any application services. * Bootstrap any application services.
*
* @return void * @return void
*/ */
public function boot() public function boot()
{ {
Stringable::macro('initials', function(){ Stringable::macro('initials', function () {
$words = preg_split("/\s+/", $this); $words = preg_split("/\s+/", $this);
$initials = ""; $initials = "";
@@ -35,7 +37,7 @@ class AppServiceProvider extends ServiceProvider
return new static($initials); return new static($initials);
}); });
Str::macro('initials', function(string $string){ Str::macro('initials', function (string $string) {
return (string) (new Stringable($string))->initials(); return (string) (new Stringable($string))->initials();
}); });
} }

View File

@@ -2,6 +2,7 @@
namespace App\Providers; namespace App\Providers;
use App\Observers\EventObserver;
use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification; use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
@@ -27,7 +28,7 @@ class EventServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
// \App\Models\Event::observe(EventObserver::class);
} }
/** /**

View File

@@ -82,6 +82,10 @@ class NovaServiceProvider extends NovaApplicationServiceProvider
// return MIT license and date // return MIT license and date
return sprintf("%s %s - %s", date('Y'), config('app.name'), __('MIT License')); return sprintf("%s %s - %s", date('Y'), config('app.name'), __('MIT License'));
}); });
Nova::userTimezone(function (Request $request) {
return $request->user()->timezone;
});
} }
/** /**

32
app/Support/Carbon.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
namespace App\Support;
use Carbon\CarbonImmutable;
class Carbon extends CarbonImmutable
{
public function asDate(): string
{
$dt = $this->timezone(config('app.timezone'))->locale('de');
return str($dt->day)->padLeft(2, '0').'. '.$dt->monthName.' '.$dt->year;
}
public function asTime(): string
{
return $this->timezone(config('app.timezone'))->locale('de')
->format('H:i');
}
public function asDateTime(): string
{
$dt = $this->timezone(config('app.timezone'))->locale('de');
return sprintf("%s. %s %s %s (%s)",
str($dt->day)->padLeft(2, '0'),
$dt->monthName,
$dt->year,
$dt->format('H:i'),
$dt->timezone
);
}
}

View File

@@ -14,6 +14,7 @@
"ezadr/lnurl-php": "^1.0", "ezadr/lnurl-php": "^1.0",
"guzzlehttp/guzzle": "^7.2", "guzzlehttp/guzzle": "^7.2",
"itsmejoshua/novaspatiepermissions": "^1.0", "itsmejoshua/novaspatiepermissions": "^1.0",
"jackiedo/timezonelist": "^5.1",
"laravel/framework": "^9.19", "laravel/framework": "^9.19",
"laravel/jetstream": "^2.12", "laravel/jetstream": "^2.12",
"laravel/nova": "~4.0", "laravel/nova": "~4.0",

84
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "3b14fa82c7df08a15f0e0584c572402b", "content-hash": "ff5b859d3c6ae9f19b73878a2e055f42",
"packages": [ "packages": [
{ {
"name": "akuechler/laravel-geoly", "name": "akuechler/laravel-geoly",
@@ -2004,6 +2004,66 @@
}, },
"time": "2022-05-16T01:34:26+00:00" "time": "2022-05-16T01:34:26+00:00"
}, },
{
"name": "jackiedo/timezonelist",
"version": "5.1.3",
"source": {
"type": "git",
"url": "https://github.com/JackieDo/Timezone-List.git",
"reference": "f1c64d0159b4401a78c7ab536505175238c38837"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JackieDo/Timezone-List/zipball/f1c64d0159b4401a78c7ab536505175238c38837",
"reference": "f1c64d0159b4401a78c7ab536505175238c38837",
"shasum": ""
},
"require": {
"illuminate/support": ">=5.0",
"php": ">=5.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
},
"laravel": {
"aliases": {
"Timezonelist": "Jackiedo\\Timezonelist\\Facades\\Timezonelist"
},
"providers": [
"Jackiedo\\Timezonelist\\TimezonelistServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Jackiedo\\Timezonelist\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jackie Do",
"email": "anhvudo@gmail.com"
}
],
"description": "A small package use to create a timezone list box in Laravel",
"keywords": [
"laravel",
"timezone",
"timezonelist",
"timezones"
],
"support": {
"issues": "https://github.com/JackieDo/Timezone-List/issues",
"source": "https://github.com/JackieDo/Timezone-List/tree/5.1.3"
},
"time": "2022-03-17T15:10:43+00:00"
},
{ {
"name": "jaybizzle/crawler-detect", "name": "jaybizzle/crawler-detect",
"version": "v1.2.112", "version": "v1.2.112",
@@ -3656,16 +3716,16 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "2.63.0", "version": "2.64.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "ad35dd71a6a212b98e4b87e97389b6fa85f0e347" "reference": "889546413c97de2d05063b8cb7b193c2531ea211"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/ad35dd71a6a212b98e4b87e97389b6fa85f0e347", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/889546413c97de2d05063b8cb7b193c2531ea211",
"reference": "ad35dd71a6a212b98e4b87e97389b6fa85f0e347", "reference": "889546413c97de2d05063b8cb7b193c2531ea211",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3676,7 +3736,7 @@
"symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0"
}, },
"require-dev": { "require-dev": {
"doctrine/dbal": "^2.0 || ^3.0", "doctrine/dbal": "^2.0 || ^3.1.4",
"doctrine/orm": "^2.7", "doctrine/orm": "^2.7",
"friendsofphp/php-cs-fixer": "^3.0", "friendsofphp/php-cs-fixer": "^3.0",
"kylekatarnls/multi-tester": "^2.0", "kylekatarnls/multi-tester": "^2.0",
@@ -3754,7 +3814,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-10-30T18:34:28+00:00" "time": "2022-11-26T17:36:00+00:00"
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
@@ -10996,16 +11056,16 @@
}, },
{ {
"name": "laravel-lang/lang", "name": "laravel-lang/lang",
"version": "12.5.4", "version": "12.5.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Laravel-Lang/lang.git", "url": "https://github.com/Laravel-Lang/lang.git",
"reference": "94ae1763dd0750ed97034c20949e481ccf13baac" "reference": "6d4f8ccd4694530f0c4c424eded37d5b1308c062"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/94ae1763dd0750ed97034c20949e481ccf13baac", "url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/6d4f8ccd4694530f0c4c424eded37d5b1308c062",
"reference": "94ae1763dd0750ed97034c20949e481ccf13baac", "reference": "6d4f8ccd4694530f0c4c424eded37d5b1308c062",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11067,7 +11127,7 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2022-11-27T15:40:48+00:00" "time": "2022-12-01T13:15:55+00:00"
}, },
{ {
"name": "laravel-lang/publisher", "name": "laravel-lang/publisher",

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('timezone')
->default('Europe/Berlin');
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
//
});
}
};

View File

@@ -107,9 +107,9 @@ class DatabaseSeeder extends Seeder
Event::create([ Event::create([
'course_id' => 1, 'course_id' => 1,
'venue_id' => 1, 'venue_id' => 1,
'from' => now()->addDays(10), 'from' => now()->startOfDay(),
'to' => now() 'to' => now()
->addDays(10) ->startOfDay()
->addHour(), ->addHour(),
]); ]);
Registration::create([ Registration::create([

View File

@@ -84,6 +84,12 @@
@endif @endif
@endif @endif
</div> </div>
<div class="col-span-6 sm:col-span-4">
<x-jet-label for="timezone" value="{{ __('Timezone') }}"/>
<x-select :clearable="false" wire:model.defer="state.timezone" id="timezone"
:options="collect(Timezonelist::toArray(false))->collapse()->keys()"/>
</div>
</x-slot> </x-slot>
<x-slot name="actions"> <x-slot name="actions">

View File

@@ -12,7 +12,11 @@ Route::get('/auth/ln', \App\Http\Livewire\Auth\LNUrlAuth::class)
->middleware('guest'); ->middleware('guest');
Route::get('/{country:code}/suche/stadt', \App\Http\Livewire\Frontend\SearchCity::class) Route::get('/{country:code}/suche/stadt', \App\Http\Livewire\Frontend\SearchCity::class)
->name('search.city'); ->name('search.city')
->where(
'country',
'(.*)'
);
Route::get('/{country:code}/suche/dozent', \App\Http\Livewire\Frontend\SearchLecturer::class) Route::get('/{country:code}/suche/dozent', \App\Http\Livewire\Frontend\SearchLecturer::class)
->name('search.lecturer'); ->name('search.lecturer');