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] Add Community relation to Pools #11070

Merged
merged 32 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7eaa37b
migration to add community field
vd1992 Jul 24, 2024
726cf26
factory and seeding pool->community
vd1992 Jul 24, 2024
06e3f39
fix issues
vd1992 Jul 24, 2024
d85848c
community-pool relations
vd1992 Jul 24, 2024
345697f
pool-community schema
vd1992 Jul 24, 2024
0fdcf85
remove TODOs
vd1992 Jul 24, 2024
49e6cbb
add community to mutation
vd1992 Jul 24, 2024
4b05ad1
add community to pool creation policy
vd1992 Jul 24, 2024
2c100cd
create policy refactor
vd1992 Jul 24, 2024
b880f31
create policy testing updated
vd1992 Jul 24, 2024
8e8f2f9
duplicate pool, policy and policy testing
vd1992 Jul 24, 2024
d8e8e0c
testCreatePool()
vd1992 Jul 25, 2024
639cbd0
test tweak
vd1992 Jul 25, 2024
666e641
test command
vd1992 Jul 25, 2024
519f4d8
add messages
vd1992 Jul 25, 2024
550c7f7
add community, make it work, copy adjustments
vd1992 Jul 25, 2024
ec40bfc
add roles to RequireAuth
vd1992 Jul 25, 2024
e32abd3
intl-check and add department to fr
vd1992 Jul 25, 2024
524e913
Merge branch 'main' into 10364-pool-community-relation
vd1992 Jul 25, 2024
1ec524c
add community to createPool and getCommunities
vd1992 Jul 25, 2024
b48754a
add communities
vd1992 Jul 25, 2024
109b0b4
update tests
vd1992 Jul 25, 2024
7601eaf
Update api/app/Policies/PoolPolicy.php
vd1992 Jul 26, 2024
66cbcfb
use with instead
vd1992 Jul 26, 2024
29ce5bc
communityTeam change
vd1992 Jul 26, 2024
4d33d4f
filter candidates by community
vd1992 Jul 26, 2024
ba3b734
update tests
vd1992 Jul 26, 2024
21b4e76
condense scope changes
vd1992 Jul 29, 2024
cd57066
test draft filtering
vd1992 Jul 29, 2024
7f1879b
Merge branch 'main' into 10364-pool-community-relation
vd1992 Jul 29, 2024
fc5eb8d
translations
vd1992 Jul 29, 2024
dc4e9b3
suggested change
vd1992 Jul 29, 2024
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
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ lint-php:

queue-work:
docker-compose exec webserver sh -c "runuser -u www-data -- php /home/site/wwwroot/api/artisan queue:work"

test:
$(DOCKER_API) "php artisan test"
5 changes: 5 additions & 0 deletions api/app/Models/Community.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public function team(): MorphOne
return $this->morphOne(Team::class, 'teamable');
}

public function pools(): HasMany
{
return $this->hasMany(Pool::class);
}

public function roleAssignments(): HasManyThrough
{
// I think this only works because we use UUIDs
Expand Down
21 changes: 13 additions & 8 deletions api/app/Models/Pool.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,19 @@ public function team(): MorphOne
return $this->morphOne(Team::class, 'teamable');
}

/**
* Get the department that owns the pool.
*/
public function department(): BelongsTo
{
return $this->belongsTo(Department::class);
}

public function community(): BelongsTo
{
return $this->belongsTo(Community::class);
}

public function roleAssignments(): HasManyThrough
{
// I think this only works because we use UUIDs
Expand Down Expand Up @@ -662,12 +675,4 @@ public static function getSelectableColumns()
{
return self::$selectableColumns;
}

/**
* Get the department that owns the pool.
*/
public function department(): BelongsTo
{
return $this->belongsTo(Department::class);
}
}
19 changes: 11 additions & 8 deletions api/app/Models/PoolCandidate.php
Original file line number Diff line number Diff line change
Expand Up @@ -776,14 +776,17 @@ public function scopeAuthorizedToView(Builder $query)
return $user->isAbleTo('view-team-submittedApplication', $team);
})->pluck('id');

$query->orWhereHas('pool', function (Builder $query) use ($teamIds) {
return $query
->where('submitted_at', '<=', Carbon::now()->toDateTimeString())
->where(function (Builder $query) use ($teamIds) {
$query->orWhereHas('legacyTeam', function (Builder $query) use ($teamIds) {
return $query->whereIn('id', $teamIds);
})->orWhereHas('team', function (Builder $query) use ($teamIds) {
return $query->whereIn('id', $teamIds);
$query->orWhere(function (Builder $query) use ($teamIds) {
$query->where('submitted_at', '<=', Carbon::now()->toDateTimeString())
->whereHas('pool', function (Builder $query) use ($teamIds) {
return $query->where(function (Builder $query) use ($teamIds) {
$query->orWhereHas('legacyTeam', function (Builder $query) use ($teamIds) {
return $query->whereIn('id', $teamIds);
})->orWhereHas('team', function (Builder $query) use ($teamIds) {
return $query->whereIn('id', $teamIds);
})->orWhereHas('community.team', function (Builder $query) use ($teamIds) {
return $query->whereIn('id', $teamIds);
});
});
});
});
Expand Down
45 changes: 27 additions & 18 deletions api/app/Policies/PoolPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Policies;

use App\Enums\PoolStatus;
use App\Models\Community;
use App\Models\Pool;
use App\Models\Team;
use App\Models\User;
Expand Down Expand Up @@ -75,40 +76,48 @@ public function viewAnyPublished(?User $user)
*/
public function create(User $user, $request)
{
if (array_key_exists('team_id', $request)) {
$team_id = $request['team_id'];

// Get the team to check against
$team = Team::find($team_id);
$teamId = isset($request['team_id']) ? $request['team_id'] : null;
$communityId = isset($request['community_id']) ? $request['community_id'] : null;

// Confirm the user can create pools for the team
if (! is_null($team)) {
if ($user->isAbleTo('create-team-draftPool', $team)) {
return true;
}
} else {
return Response::deny('Cannot find a team matching team_id.');
}
} else {
Response::deny('Pool must be associated with a team when it is created.');
if (is_null($teamId) || is_null($communityId)) {
return false;
}

if ($user->isAbleTo('create-any-pool')) {
return true; // return early, permission does not exist at the moment
}
vd1992 marked this conversation as resolved.
Show resolved Hide resolved

return Response::deny('Cannot create a pool for that team.');
$team = Team::findOrFail($teamId);
$community = Community::with('team')->findOrFail($communityId);

if ($user->isAbleTo('create-team-draftPool', $team)) {
// user is a legacy pool operator
return true;
}

if (! is_null($community->team) && $user->isAbleTo('create-team-draftPool', $community->team)) {
// user is a community recruiter or community admin
return true;
}

return false; // fallback to fail
}

/**
* Determine whether the user can create pools.
* Determine whether the user can duplicate pools.
*
* @return \Illuminate\Auth\Access\Response|bool
*/
public function duplicate(User $user, $request)
{
$existing = Pool::findOrFail($request['id']);
$existing = Pool::with(['team', 'community.team'])->findOrFail($request['id']);

// Confirm the user can create pools for the team
$teamPermission = ! is_null($existing->team) && $user->isAbleTo('create-team-draftPool', $existing->team);
$legacyTeamPermission = ! is_null($existing->legacyTeam) && $user->isAbleTo('create-team-draftPool', $existing->legacyTeam);
if ($teamPermission || $legacyTeamPermission) {
$communityPermission = ! is_null($existing->community->team) && $user->isAbleTo('create-team-draftPool', $existing->community->team);
if ($teamPermission || $legacyTeamPermission || $communityPermission) {
return true;
} else {
return Response::deny('Cannot duplicate a pool for that team.');
Expand Down
11 changes: 5 additions & 6 deletions api/app/Policies/UserPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,19 +181,18 @@ protected function teamAbleToCheck(User $actor, string $roleId, string $teamId)
}

$role = Role::findOrFail($roleId);
$team = Team::findOrFail($teamId);
$team = Team::with(['teamable.community.team'])->findOrFail($teamId);

switch ($role->name) {
case 'pool_operator':
return $actor->isAbleTo('assign-any-teamRole');
case 'process_operator':
// Community roles have the update-team-processOperatorMembership permission, and it should give them the ability to assign processOperator roles to pools in their community.
// TODO: uncomment this in issue #10364
// $pool = $team->teamable; // If we're adding a processOperator to a team, that team should represent a pool. Need validation?
// $community = $pool->community;
$communityTeam = $team->teamable?->community?->team;

return $actor->isAbleTo('update-any-processOperatorMembership')
|| $actor->isAbleTo('update-team-processOperatorMembership', $team);
// || $actor->isAbleTo('update-team-processOperatorMembership', $community->team)
|| $actor->isAbleTo('update-team-processOperatorMembership', $team)
|| (isset($communityTeam) && $actor->isAbleTo('update-team-processOperatorMembership', $communityTeam));
case 'community_recruiter':
return $actor->isAbleTo('update-any-communityRecruiterMembership') || $actor->isAbleTo('update-team-communityRecruiterMembership', $team);
case 'community_admin':
Expand Down
10 changes: 10 additions & 0 deletions api/database/factories/PoolFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use App\Enums\SkillLevel;
use App\Models\AssessmentStep;
use App\Models\Classification;
use App\Models\Community;
use App\Models\Department;
use App\Models\GeneralQuestion;
use App\Models\Pool;
Expand Down Expand Up @@ -71,13 +72,22 @@ public function definition()
$departmentId = Department::factory()->create()->id;
}

$communityId = Community::inRandomOrder()
->limit(1)
->pluck('id')
->first();
if (is_null($communityId)) {
$communityId = Community::factory()->create()->id;
}

// this is essentially the draft state
return [
'name' => ['en' => $name, 'fr' => $name],
'user_id' => $adminUserId,
'team_id' => $teamId,
'classification_id' => $classification->id,
'department_id' => $departmentId,
'community_id' => $communityId,
];
}

Expand Down
59 changes: 59 additions & 0 deletions api/database/migrations/2024_07_24_163356_add_pool_community.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

use App\Models\Community;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// create new community_id column
Schema::table('pools', function (Blueprint $table) {
$table->uuid('community_id')->nullable();
$table->foreign('community_id')->references('id')->on('communities');
});

$communitiesExist = count(Community::all()) != 0;
if ($communitiesExist) { // do not run on migrate:fresh
$communityATIP = Community::where('key', 'atip')->sole()->id;
$communityDigitalCommunity = Community::where('key', 'digital')->sole()->id;

// fill new community_id column based on stream
DB::statement(
<<<'SQL'
UPDATE pools
SET community_id =
case stream
when :atipStream then :atipCommunity::uuid
else :digitalCommunity::uuid
end
SQL, [
'atipStream' => 'ACCESS_INFORMATION_PRIVACY',
'atipCommunity' => $communityATIP,
'digitalCommunity' => $communityDigitalCommunity,
]
);
}

// now that it's filled, make non-nullable
Schema::table('pools', function (Blueprint $table) {
$table->uuid('community_id')->nullable(false)->change(); // TODO, double-check when upgrading to Laravel 11
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('pools', function (Blueprint $table) {
$table->dropColumn('community_id');
});
}
};
12 changes: 12 additions & 0 deletions api/database/seeders/PoolTestSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Enums\PoolStream;
use App\Enums\PublishingGroup;
use App\Models\Classification;
use App\Models\Community;
use App\Models\Pool;
use App\Models\Team;
use App\Models\User;
Expand All @@ -26,6 +27,8 @@ public function run()
$adminUserId = User::select('id')->where('email', '[email protected]')->sole()->id;
$processOperatorUser = User::select('id')->where('email', '[email protected]')->first();
$dcmTeamId = Team::select('id')->where('name', 'digital-community-management')->sole()->id;
$digitalCommunityId = Community::select('id')->where('key', 'digital')->sole()->id;
$atipCommunityId = Community::select('id')->where('key', 'atip')->sole()->id;

// CMO Digital
$createdPool = Pool::factory()
Expand All @@ -40,6 +43,7 @@ public function run()
],
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => config('constants.past_date'),
'closing_date' => config('constants.far_future_date'),
'publishing_group' => PublishingGroup::IT_JOBS->name,
Expand Down Expand Up @@ -67,6 +71,7 @@ public function run()
],
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => config('constants.past_date'),
'closing_date' => config('constants.far_future_date'),
'publishing_group' => PublishingGroup::IAP->name,
Expand All @@ -88,6 +93,7 @@ public function run()
'classification_id' => Classification::select('id')->where('group', 'ilike', 'IT')->where('level', 1)->sole()->id,
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => null,
'closing_date' => config('constants.far_future_date'),
'publishing_group' => PublishingGroup::IT_JOBS->name,
Expand All @@ -110,6 +116,7 @@ public function run()
'classification_id' => Classification::select('id')->where('group', 'ilike', 'IT')->where('level', 2)->sole()->id,
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => null,
'closing_date' => config('constants.far_future_date'),
'publishing_group' => PublishingGroup::IT_JOBS->name,
Expand All @@ -134,6 +141,7 @@ public function run()
'classification_id' => Classification::select('id')->where('group', 'ilike', 'IT')->where('level', 3)->sole()->id,
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => config('constants.past_date'),
'closing_date' => config('constants.far_future_date'),
'publishing_group' => PublishingGroup::IT_JOBS_ONGOING->name,
Expand All @@ -157,6 +165,7 @@ public function run()
'classification_id' => Classification::select('id')->where('group', 'ilike', 'IT')->where('level', 4)->sole()->id,
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => config('constants.past_date'),
'closing_date' => now()->addMonths(6),
'publishing_group' => PublishingGroup::IT_JOBS->name,
Expand All @@ -181,6 +190,7 @@ public function run()
'classification_id' => Classification::select('id')->where('group', 'ilike', 'IT')->where('level', 5)->sole()->id,
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => config('constants.past_date'),
'closing_date' => config('constants.past_date'),
'publishing_group' => PublishingGroup::IT_JOBS->name,
Expand All @@ -206,6 +216,7 @@ public function run()
'stream' => PoolStream::EXECUTIVE_GROUP->name,
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $digitalCommunityId,
'published_at' => config('constants.past_date'),
'closing_date' => config('constants.past_date'),
'publishing_group' => PublishingGroup::EXECUTIVE_JOBS->name,
Expand All @@ -227,6 +238,7 @@ public function run()
'stream' => PoolStream::ACCESS_INFORMATION_PRIVACY->name,
'user_id' => $adminUserId,
'team_id' => $dcmTeamId,
'community_id' => $atipCommunityId,
'published_at' => config('constants.past_date'),
'closing_date' => now()->addMonths(6),
'publishing_group' => PublishingGroup::OTHER->name,
Expand Down
8 changes: 7 additions & 1 deletion api/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ type Pool implements HasRoleAssignments {
id: ID!
owner: UserPublicProfile @belongsTo(relation: "user")
team: Team @belongsTo(relation: "legacyTeam") @canModel(ability: "viewAny")
community: Community @belongsTo(relation: "community")
name: LocalizedString
classification: Classification @belongsTo
operationalRequirements: [LocalizedOperationalRequirement]
Expand Down Expand Up @@ -409,7 +410,8 @@ type PoolCandidate {
@canRoot(ability: "viewAssessment")
assessmentStatus: AssessmentResultStatus
@rename(attribute: "computed_assessment_status")
finalDecision: LocalizedFinalDecision @rename(attribute: "computed_final_decision")
finalDecision: LocalizedFinalDecision
@rename(attribute: "computed_final_decision")
finalDecisionAt: DateTime
@rename(attribute: "final_decision_at")
@canRoot(ability: "viewStatus")
Expand Down Expand Up @@ -475,6 +477,9 @@ type Community implements HasRoleAssignments {
@hasManyThrough
@canRoot(ability: "viewTeamMembers")
teamIdForRoleAssignment: ID
pools: [Pool]
@hasMany(scopes: ["authorizedToView"])
@canResolved(ability: "view")
}

type Team implements HasRoleAssignments {
Expand Down Expand Up @@ -2057,6 +2062,7 @@ type Mutation {
createPool(
userId: ID! @rename(attribute: "user_id")
teamId: ID! @rename(attribute: "team_id")
communityId: ID! @rename(attribute: "community_id")
pool: CreatePoolInput! @spread
): Pool @create @guard @canModel(ability: "create", injectArgs: true)
duplicatePool(
Expand Down
Loading
Loading