Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - Combine predefined and action based roles #528

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions app/Livewire/Booth/JoinBoothOwnerModal.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ class JoinBoothOwnerModal extends ModalComponent
*/
public function save()
{
$user = Auth::user();

$this->authorize('becomeBoothOwner', $user->company);
$user->assignRole('booth owner');
$this->authorize('becomeBoothOwner', Auth::user()->company);
Auth::user()->assignRole('booth owner');
Auth::user()->removeRole('pending booth owner');

return redirect(route('dashboard'))
->with('status', 'You successfully became a booth owner.');
Expand Down
45 changes: 33 additions & 12 deletions app/Livewire/Company/AddMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
class AddMember extends Component
{
public Company $company;
public $roles;

#[Validate('required|in:speaker,booth owner,company member')]
public $currentRole;

#[Validate('required|unique:users')]
public string $email;
Expand All @@ -25,35 +29,52 @@ class AddMember extends Component
public function mount($company)
{
$this->company = $company;
$this->roles = [
'speaker' => 'The user can request to give a presentation or become a co-speaker for another presentation
within the company.',
'booth owner' => 'The user can request a booth if one does not already exist and is expected to be present
at the booth during the conference.',
'company member' => 'The user can choose to be a speaker or a booth owner. If they do not take action to
become a speaker or booth owner, they will simply accompany the other members.'
];
}

/**
* Handles the selecting of a new role
*
* @param $role
* @return void
*/
public function selectRole($role)
{
$this->currentRole = $role;
}


/**
* Invite a new team member to the given team.
*/
public function invite(): void
{
$this->validate();
if ($this->currentRole == 'speaker') {
$this->currentRole = 'pending speaker';
} else if ($this->currentRole == 'booth owner') {
$this->currentRole = 'pending booth owner';
}

$invitation = $this->company->invitations()->create([
'email' => $this->email,
'role' => 'company member'
'role' => $this->currentRole
]);

Mail::to($this->email)->send(new CustomCompanyInvitation($invitation));

$this->email = '';
$this->currentRole = '';

$this->company = $this->company->refresh();
}


/**
* Returns all roles and descriptions available
* @return array
*/
public function getRolesProperty() : array
{
return config('roles');
session()->flash('message', 'Post successfully updated.');
}

/**
Expand All @@ -73,7 +94,7 @@ public function cancelInvitation($invitation_id)
* Renders the component
* @return View
*/
public function render() : View
public function render(): View
{
return view('livewire.company.add-member');
}
Expand Down
5 changes: 5 additions & 0 deletions app/Livewire/Company/BoothRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ public function requestBooth()
);

Auth::user()->assignRole('booth owner');

if (Auth::user()->hasRole('pending booth owner')) {
Auth::user()->removeRole('pending booth owner');
}

$this->additionalInformation = '';
$this->requestSent = true;
$this->company->refresh();
Expand Down
2 changes: 1 addition & 1 deletion app/Mail/CustomCompanyInvitation.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class CustomCompanyInvitation extends Mailable
* @param $invitation
* @return void
*/
public function __construct(Invitation $invitation)
public function __construct($invitation)
{
$this->invitation = $invitation;
}
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Company.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public function isHz(): Attribute
public function isGoldSponsor(): Attribute
{
return Attribute::make(
get: fn() => $this->sponsorship ? $this->sponsorship->name === 'gold' && $this->is_sponsorhip_approved : 0
get: fn() => $this->sponsorship ? $this->sponsorship->name === 'gold' && $this->is_sponsorship_approved : 0
);
}

Expand Down
4 changes: 4 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ public function joinPresentation($presentation, string $role = 'participant'): b
'role' => $role
]);

if ($this->hasRole('pending speaker')) {
$this->removeRole('pending speaker');
}

return true;
}

Expand Down
15 changes: 12 additions & 3 deletions app/Policies/CompanyPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public function viewAny(User $user): bool
*/
public function view(User $user, Company $company): bool
{
// Edge case since the speaker doesn't have a role that I can give permission to
if ($user->isMemberOf($company) && $user->presenter_of) {
return true;
}

return ($user->is_crew || $user->isMemberOf($company))
&& $user->can('view company');
}
Expand Down Expand Up @@ -96,6 +101,11 @@ public function approveRequest(User $user, Company $company): bool
*/
public function viewAnyMember(User $user, Company $company): bool
{
// Edge case since the speaker doesn't have a role that I can give permission to
if ($user->isMemberOf($company) && $user->presenter_of && $company->is_approved) {
return true;
}

return ($user->is_crew
|| $user->isMemberOf($company) && $company->is_approved)
&& $user->hasPermissionTo('viewAny company member');
Expand Down Expand Up @@ -205,7 +215,7 @@ public function viewRequests(User $user, Company $company): bool
'view booth request',
'view sponsorship request',
'view company delete request'
]) || $user->hasRole('booth owner');
]) || $user->hasRole(['booth owner', 'pending booth owner']);

return $isCrewOrCompanyMember && $hasRequiredPermissions;
}
Expand All @@ -220,7 +230,7 @@ public function requestBooth(User $user, Company $company): bool
{
return $user->isMemberOf($company)
&& !$company->booth
&& ($user->isDefaultCompanyMember() || $user->hasRole('company representative', 'web'))
&& ($user->isDefaultCompanyMember() || $user->hasRole(['company representative', 'pending booth owner']))
&& $user->hasPermissionTo('create booth request');
}

Expand Down Expand Up @@ -248,7 +258,6 @@ public function becomeBoothOwner(User $user, Company $company): bool
{
return $user->isMemberOf($company)
&& $company->booth
&& ($user->isDefaultCompanyMember() || $user->hasRole('company representative', 'web'))
&& $user->hasPermissionTo('create booth request');
}
}
11 changes: 6 additions & 5 deletions app/Policies/PresentationPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public function view(User $user, Presentation $presentation): bool
}

if ($presentation->company) {
// View if the company member hasn't decided their role
if ($user->isMemberOf($presentation->company) && $user->isDefaultCompanyMember) {
if ($user->isMemberOf($presentation->company)
&& ($user->isDefaultCompanyMember || $user->hasRole(['pending speaker', 'company representative']))) {
return true;
}
}
Expand Down Expand Up @@ -121,8 +121,8 @@ public function request(User $user): bool
// When the user is associated to a company, allow only if the user's
// company has presentations left
if ($user->company) {
// When the user is not default company member and also not company rep, they should be denied
if (!$user->isDefaultCompanyMember && !$user->hasRole('company representative')) {
// When the user is company representative, speaker or pending speaker
if (!$user->hasRole(['company representative', 'pending speaker', 'speaker'])) {
return false;
}

Expand Down Expand Up @@ -225,6 +225,7 @@ public function joinAsCospeaker(User $user, Presentation $presentation): bool
return $user->company
&& $presentation->company
&& $presentation->company->id == $user->company->id
&& $user->isDefaultCompanyMember;
&& !$user->presenter_of
&& ($user->isDefaultCompanyMember || $user->hasAnyRole(['pending speaker', 'company representative']));
}
}
33 changes: 33 additions & 0 deletions app/View/Components/Dashboards/Blocks/BoothOwnerInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace App\View\Components\Dashboards\Blocks;

use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\Component;

class BoothOwnerInfo extends Component
{
public $boothButtons = [];

/**
* Create a new component instance.
*/
public function __construct()
{
if (!Auth::user()->company->booth) {
$this->boothButtons['Request a booth'] = 'company.requests';
} else {
$this->boothButtons['Join the others at the booth'] = null;
}
}

/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.dashboards.blocks.booth-owner-info');
}
}
39 changes: 39 additions & 0 deletions app/View/Components/Dashboards/Blocks/SpeakerInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace App\View\Components\Dashboards\Blocks;

use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\Component;

class SpeakerInfo extends Component
{
public $speakerButtons = [];

/**
* Create a new component instance.
*/
public function __construct()
{
$company = Auth::user()->company;

if ($company->hasPresentationsLeft) {
$this->speakerButtons['Request a presentation'] = 'presentations.create';
}
if ($company->presentations) {
foreach ($company->presentations as $presentation) {
$this->speakerButtons["Join '{$presentation->name}' as a co-speaker"] =
['presentations.show', $presentation];
}
}
}

/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.dashboards.blocks.speaker-info');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@php use \Illuminate\Support\Facades\Auth @endphp

<div>
<dl class="pt-11 pb-5 px-6">
<div
class="py-5 px-4 rounded-lg overflow-hidden relative bg-partner-100 dark:bg-partner-900 shadow-md dark:shadow-md">
<dt>
<div class="p-3 rounded-md absolute bg-partner-500">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="white"
aria-hidden="true" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"/>
</svg>
</div>
</dt>
<div class="ml-16 font-semibold text-md text-gray-700 dark:text-gray-100 overflow-hidden text-ellipsis">
<p>You are part of the people joining {{Auth::user()->company->name}} for the "We are in IT together"
conference!<br>
When the company representative invited you, they specified that you would be part of the booth owners of
the company.
</p>
<div class="pt-8 grid grid-cols-1">
<div class="w-full">
To become a booth owner you must do the following:
</div>
@foreach($boothButtons as $label => $route)
<div class="pt-2">
@if($route)
<a href="{{ route($route) }}"
class="flex w-full items-center bg-partner-500 hover:bg-partner-700 dark:bg-partner-600 dark:hover:bg-gray-900 text-gray-200 dark:text-white font-semibold justify-center py-2 px-4 w-3/4 rounded-lg transition duration-300 ease-in-out">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor"
class="w-6 h-6 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
<span>{{ $label }}</span>
</a>
@else
<button
class="flex w-full items-center bg-partner-500 hover:bg-partner-700 dark:bg-partner-600 dark:hover:bg-gray-900 text-gray-200 dark:text-white font-semibold justify-center py-2 px-4 w-3/4 rounded-lg transition duration-300 ease-in-out"
onclick="Livewire.dispatch('openModal', { component: 'booth.join-booth-owner-modal' })">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor"
class="w-6 h-6 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
<span>{{ $label }}</span>
</button>
@endif
</div>
@endforeach
</div>
</div>
</div>
</dl>
</div>
Loading
Loading