NeedMeetupMiddleware added

This commit is contained in:
Benjamin Takats
2023-01-17 18:59:10 +01:00
parent 3a32d1ebe5
commit 8e0d23a296
26 changed files with 524 additions and 36 deletions

View File

@@ -3,6 +3,7 @@
namespace App\Http;
use App\Http\Middleware\CustomEnsureEmailVerified;
use App\Http\Middleware\NeedMeetupMiddleware;
use App\Http\Middleware\SetTimezoneForNovaMiddleware;
use App\Http\Middleware\SetTimezoneMiddleware;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
@@ -84,5 +85,6 @@ class Kernel extends HttpKernel
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => CustomEnsureEmailVerified::class,
'needMeetup' => NeedMeetupMiddleware::class,
];
}

View File

@@ -0,0 +1,85 @@
<?php
namespace App\Http\Livewire\Profile;
use App\Models\Meetup;
use Livewire\Component;
use WireUi\Traits\Actions;
class Meetups extends Component
{
use Actions;
public $search = '';
public $meetups;
public $myMeetups = [];
public $myMeetupNames = [];
public $hasMeetups = false;
public function rules()
{
return [
'search' => 'string',
];
}
public function mount()
{
$this->meetups = Meetup::query()
->where('name', 'ilike', '%'.$this->search.'%')
->orderBy('name')
->limit(10)
->get();
$this->myMeetups = auth()
->user()
->meetups()
->pluck('meetup_id')
->toArray();
$this->myMeetupNames = auth()
->user()
->meetups()
->pluck('meetups.name', 'meetups.id')
->toArray();
if (count($this->myMeetups) > 0) {
$this->hasMeetups = true;
}
}
public function updatedSearch($value)
{
$this->meetups = Meetup::query()
->where('name', 'ilike', '%'.$value.'%')
->orderBy('name')
->limit(10)
->get();
}
public function render()
{
return view('livewire.profile.meetups');
}
public function signUpForMeetup($id)
{
$user = auth()->user();
$user->meetups()
->toggle($id);
$this->myMeetups = auth()
->user()
->meetups()
->pluck('meetup_id')
->toArray();
if (count($this->myMeetups) > 0) {
$this->hasMeetups = true;
} else {
$this->hasMeetups = false;
}
$this->myMeetupNames = auth()
->user()
->meetups()
->pluck('meetups.name', 'meetups.id')
->toArray();
$this->notification()
->success(__('Saved.'));
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cookie;
class NeedMeetupMiddleware
{
/**
* 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 ($request->user()) {
$request->user()->load('meetups');
if ($request->user()->meetups->count() < 1) {
return redirect()->route('profile.meetups')->with('redirectToThis', $request->route()?->getName());
}
}
return $next($request);
}
}

View File

@@ -61,6 +61,11 @@ class User extends Authenticatable implements MustVerifyEmail, CanComment
return $this->hasMany(OrangePill::class);
}
public function meetups()
{
return $this->belongsToMany(Meetup::class);
}
public function reputations()
{
return $this->morphMany('QCod\Gamify\Reputation', 'subject');

View File

@@ -37,6 +37,10 @@ class Meetup extends Resource
public static function afterCreate(NovaRequest $request, Model $model)
{
auth()
->user()
->meetups()
->attach($model);
\App\Models\User::find(1)
->notify(new ModelCreatedNotification($model, str($request->getRequestUri())
->after('/nova-api/')

View File

@@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\DateTime;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;
@@ -47,6 +48,18 @@ class MeetupEvent extends Resource
->toString()));
}
public static function relatableMeetups(NovaRequest $request, $query, Field $field)
{
if ($field instanceof BelongsTo) {
$query->whereIn('meetups.id', $request->user()
->meetups()
->pluck('id')
->toArray());
}
return $query;
}
public function subtitle()
{
return __('Created by: :name', ['name' => $this->createdBy->name]);
@@ -79,14 +92,16 @@ class MeetupEvent extends Resource
->rules('required', 'string'),
BelongsTo::make('Meetup')
->searchable()->withSubtitles(),
->searchable()
->withSubtitles(),
BelongsTo::make(__('Created By'), 'createdBy', User::class)
->canSee(function ($request) {
return $request->user()
->hasRole('super-admin');
})
->searchable()->withSubtitles(),
->searchable()
->withSubtitles(),
];
}

View File

@@ -53,7 +53,7 @@ class MeetupEventPolicy extends BasePolicy
*/
public function update(User $user, MeetupEvent $meetupEvent)
{
return $meetupEvent->created_by === $user->id || $user->can((new \ReflectionClass($this))->getShortName().'.'.__FUNCTION__);
return $user->meetups->contains($meetupEvent->meetup) || $user->can((new \ReflectionClass($this))->getShortName().'.'.__FUNCTION__);
}
/**
@@ -65,7 +65,7 @@ class MeetupEventPolicy extends BasePolicy
*/
public function delete(User $user, MeetupEvent $meetupEvent)
{
return false;
return false && $meetupEvent->created_by === $user->id;
}
/**

View File

@@ -57,7 +57,7 @@ class MeetupPolicy extends BasePolicy
*/
public function update(User $user, Meetup $meetup)
{
return true || $meetup->created_by === $user->id || $user->can((new \ReflectionClass($this))->getShortName().'.'.__FUNCTION__);
return $user->meetups->contains($meetup) || $user->can((new \ReflectionClass($this))->getShortName().'.'.__FUNCTION__);
}
/**
@@ -70,7 +70,7 @@ class MeetupPolicy extends BasePolicy
*/
public function delete(User $user, Meetup $meetup)
{
return false;
return $meetup->created_by === $user->id;
}
/**

View File

@@ -109,7 +109,8 @@ return [
DispatchServingNovaEvent::class,
BootTools::class,
\Itsmejoshua\Novaspatiepermissions\ForgetCachedPermissions::class,
'verified'
'verified',
'needMeetup',
],
'api_middleware' => [

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateMeetupUserTable extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::disableForeignKeyConstraints();
Schema::create('meetup_user', function (Blueprint $table) {
$table->foreignId('meetup_id')
->constrained()
->cascadeOnDelete()
->cascadeOnUpdate();
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete()
->cascadeOnUpdate();
$table->boolean('is_leader')
->default(false);
});
Schema::enableForeignKeyConstraints();
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::dropIfExists('meetup_user');
}
}

View File

@@ -27,7 +27,6 @@ use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Str;
use JoeDixon\Translation\Console\Commands\SynchroniseMissingTranslationKeys;
use JoeDixon\Translation\Console\Commands\SynchroniseTranslationsCommand;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
@@ -378,8 +377,8 @@ Deshalb werden Sie von mir in diesem Kurs leicht verständlich an das Thema hera
Artisan::call(SyncOpenBooks::class);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig Kempten',
'link' => 'https://t.me/EinundzwanzigKempten',
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
MeetupEvent::create([
@@ -404,6 +403,60 @@ Deshalb werden Sie von mir in diesem Kurs leicht verständlich an das Thema hera
'link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 2,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 3,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
Meetup::create([
'city_id' => 1,
'name' => 'Einundzwanzig ' . str()->random(5),
'telegram_link' => 'https://t.me/EinundzwanzigKempten',
'created_by' => 1,
]);
BitcoinEvent::create([
'venue_id' => 4,
'from' => Carbon::parse('2023-09-12')

View File

@@ -1,4 +0,0 @@
models:
Item:
name: string:unique
link: string

View File

@@ -644,5 +644,18 @@
"points": "Punkte",
"Submit new book case": "Bücherschrank einreichen",
"Share url copied!": "Link kopiert!",
"Share link": "Link zum Teilen"
"Share link": "Link zum Teilen",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "Suche dir eine oder mehrere Meetup-Gruppen aus, um Zugriff auf diese Gruppen im Backend zu erhalten.",
"choice": "Auswahl",
"By id": "nach ID",
"Twitter": "",
"New City": "Neue Stadt",
"My meetups": "Meine Meetups",
"please limit your search here": "bitte begrenze deine Suche hier",
"Deselect": "Abwählen",
"Your current Meetup groups": "Deine aktuellen Meetup-Gruppen",
"Thanks, continue here": "Danke, weiter geht es hier"
}

View File

@@ -640,5 +640,15 @@
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": ""
"Share link": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"choice": "",
"By id": "",
"Twitter": "",
"New City": "",
"My meetups": "",
"please limit your search here": "",
"Deselect": "",
"Your current Meetup groups": "",
"Thanks, continue here": ""
}

View File

@@ -634,5 +634,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -634,5 +634,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -634,5 +634,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -634,5 +634,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -634,5 +634,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -634,5 +634,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -634,5 +634,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -608,5 +608,17 @@
"You get a point when you log in.": "",
"points": "",
"All courses of :name": "",
"Here you can see all events of :name.": ""
"Here you can see all events of :name.": "",
"By id": "",
"Telegram-Link": "",
"Website": "",
"Twitter Username": "",
"Share url copied!": "",
"Share link": "",
"Twitter": "",
"Submit new book case": "",
"choice": "",
"Select one or more meetup groups so that you can get access to these groups in the backend.": "",
"New City": "",
"My meetups": ""
}

View File

@@ -11,6 +11,7 @@
"Remove sort option": "Entferne Sortierauswahl",
"Search": "Suche",
"Select All": "Alle auswählen",
"Select": "Auswählen",
"Showing": "Anzeigen",
"Deselect All": "Alle abwählen",
"You are currently selecting all": "Es sind schon alle ausgewählt",

View File

@@ -0,0 +1,109 @@
<div class="flex flex-col">
<section class="">
<div class="px-10 pt-6 mx-auto max-w-7xl">
<div class="w-full mx-auto text-left md:text-center">
<h1 class="mb-6 text-5xl font-extrabold leading-none max-w-5xl mx-auto tracking-normal text-gray-900 sm:text-6xl md:text-6xl lg:text-7xl md:tracking-tight">
<span
class="w-full text-transparent bg-clip-text bg-gradient-to-r from-amber-400 via-amber-500 to-amber-500 lg:inline">{{ __('Meetup') }}</span>
<br class="lg:block hidden"> {{ __('choice') }}
</h1>
<p class="px-0 mb-6 text-lg text-gray-200 md:text-xl lg:px-24">
{{ __('Select one or more meetup groups so that you can get access to these groups in the backend.') }}
</p>
</div>
</div>
</section>
<section x-data="{ open: @entangle('hasMeetups') }"
x-show="open"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
>
<div class="px-10 pt-6 mx-auto max-w-7xl">
<div class="w-full mx-auto text-left md:text-center">
<p class="px-0 mb-6 text-lg text-gray-200 md:text-xl lg:px-24">
<x-button href="/" primary lg>
{{ __('Thanks, continue here') }}
</x-button>
</p>
</div>
</div>
</section>
<div class="grid grid-cols-2">
<div class="">
<div class="px-10 pt-6 mx-auto max-w-7xl">
<div class="bg-21gray p-6 rounded">
<div>
<x-input wire:model="search" placeholder="{{ __('Search') }}"
hint="{{ __('please limit your search here') }}"/>
</div>
<div class="mt-6 flow-root">
<ul role="list" class="-my-5 divide-y divide-gray-200">
@foreach($meetups as $meetup)
@php
$activeClass = in_array($meetup->id, $myMeetups, true) ? 'font-bold text-amber-500' : 'text-gray-200';
@endphp
<li class="py-4" wire:key="meetup_id_{{ $meetup->id }}">
<div class="flex items-center space-x-4">
<div class="flex-shrink-0">
<img class="h-12 w-12 rounded object-cover"
src="{{ $meetup->getFirstMediaUrl('logo') }}"
alt="{{ $meetup->name }}">
</div>
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-medium {{ $activeClass }}">{{ $meetup->name }}</p>
<p class="truncate text-sm {{ $activeClass }}">{{ $meetup->city->name }}</p>
</div>
<div>
@if(in_array($meetup->id, $myMeetups, true))
<x-button
primary
wire:click="signUpForMeetup({{ $meetup->id }})"
>
<i class="fa-thin fa-xmark"></i>
{{ __('Deselect') }}
</x-button>
@else
<x-button
black
wire:click="signUpForMeetup({{ $meetup->id }})"
>
<i class="fa-thin fa-check"></i>
{{ __('Select') }}
</x-button>
@endif
</div>
</div>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<div class="p-4">
<p class="px-0 mb-6 text-lg text-gray-200 md:text-xl">
{{ __('Your current Meetup groups') }}
</p>
<div class="grid grid-cols-4 gap-2">
@foreach($myMeetupNames as $id => $myMeetupName)
<x-badge class="cursor-pointer" wire:click="signUpForMeetup({{ $id }})" lg outline white
label="{{ $myMeetupName }}"/>
@endforeach
</div>
</div>
</div>
</div>

View File

@@ -83,6 +83,14 @@
{{ __('My profile') }}
</x-button>
</div>
<div>
<x-button xs amber href="{{ route('profile.meetups') }}"
:active="request()->routeIs('profile.meetups')">
<i class="fa fa-thin fa-users"></i>
{{ __('My meetups') }}
</x-button>
</div>
</div>
</div>

View File

@@ -3,9 +3,16 @@
use Illuminate\Support\Facades\Route;
use Laravel\Socialite\Facades\Socialite;
Route::get('/', \App\Http\Livewire\Frontend\Welcome::class)
Route::middleware([
'needMeetup',
])
->get('/', \App\Http\Livewire\Frontend\Welcome::class)
->name('welcome');
Route::middleware([])
->get('/my-meetups', \App\Http\Livewire\Profile\Meetups::class)
->name('profile.meetups');
Route::get('/auth/ln', \App\Http\Livewire\Auth\LNUrlAuth::class)
->name('auth.ln')
->middleware('guest');
@@ -42,7 +49,9 @@ Route::get('/auth/twitter/callback', function () {
/*
* School
* */
Route::middleware([])
Route::middleware([
'needMeetup',
])
->as('school.')
->prefix('/{country:code}/school')
->group(function () {
@@ -68,7 +77,9 @@ Route::middleware([])
/*
* Library
* */
Route::middleware([])
Route::middleware([
'needMeetup',
])
->as('library.')
->prefix('/{country:code}/library')
->group(function () {
@@ -82,7 +93,9 @@ Route::middleware([])
/*
* Books
* */
Route::middleware([])
Route::middleware([
'needMeetup',
])
->as('bookCases.')
->prefix('/{country:code}/book-cases')
->group(function () {
@@ -102,7 +115,9 @@ Route::middleware([])
/*
* Events
* */
Route::middleware([])
Route::middleware([
'needMeetup',
])
->as('bitcoinEvent.')
->prefix('/{country:code}/event')
->group(function () {
@@ -116,7 +131,9 @@ Route::middleware([])
/*
* Meetups
* */
Route::middleware([])
Route::middleware([
'needMeetup',
])
->as('meetup.')
->prefix('/{country:code}/meetup')
->group(function () {
@@ -138,7 +155,8 @@ Route::middleware([])
Route::middleware([
'auth:sanctum',
config('jetstream.auth_session'),
'verified'
'verified',
'needMeetup',
])
->group(function () {
Route::get('/dashboard', function () {