Skip to content

Commit

Permalink
pkp#10571 Convert queries to eloquent
Browse files Browse the repository at this point in the history
  • Loading branch information
taslangraham committed Nov 9, 2024
1 parent 0ce0834 commit 6d77552
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 57 deletions.
6 changes: 3 additions & 3 deletions api/v1/emailTemplates/PKPEmailTemplateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,8 @@ public function add(Request $illuminateRequest): JsonResponse
$emailTemplate = Repo::emailTemplate()->newDataObject($params);
Repo::emailTemplate()->add($emailTemplate);

if($params['userGroupIds']) {
Repo::emailTemplate()->updateTemplateAccessGroups($emailTemplate, $params['userGroupIds'], $requestContext->getId());
}
Repo::emailTemplate()->setEmailTemplateAccess($emailTemplate, $requestContext->getId(), $params['userGroupIds'], $params['isUnrestricted']);

$emailTemplate = Repo::emailTemplate()->getByKey($emailTemplate->getData('contextId'), $emailTemplate->getData('key'));

return response()->json(Repo::emailTemplate()->getSchemaMap()->map($emailTemplate), Response::HTTP_OK);
Expand Down Expand Up @@ -258,6 +257,7 @@ public function edit(Request $illuminateRequest): JsonResponse
}

Repo::emailTemplate()->edit($emailTemplate, $params, $requestContext->getId());
Repo::emailTemplate()->setEmailTemplateAccess($emailTemplate, $requestContext->getId(), $params['userGroupIds'], $params['isUnrestricted']);

$emailTemplate = Repo::emailTemplate()->getByKey(
// context ID is null if edited for the first time
Expand Down
34 changes: 34 additions & 0 deletions classes/emailTemplate/EmailTemplateAccessGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace PKP\emailTemplate;

use Eloquence\Behaviours\HasCamelCasing;
use Eloquence\Database\Model;
use Illuminate\Contracts\Database\Eloquent\Builder;

class EmailTemplateAccessGroup extends Model
{
use HasCamelCasing;
public $timestamps = false;
protected $primaryKey = 'email_template_user_group_access_id';
protected $table = 'email_template_user_group_access';
protected $fillable = ['userGroupId', 'contextId','emailKey'];


public function scopeWithEmailKey(Builder $query, ?array $keys): Builder
{
return $query->when(!empty($keys), function ($query) use ($keys) {
return $query->whereIn('email_key', $keys);
});
}

public function scopeWithContextId(Builder $query, int $contextId): Builder
{
return $query->where('context_id', $contextId);
}

public function scopeWithGroupIds(Builder $query, array $ids): Builder
{
return $query->whereIn('user_group_id', $ids);
}
}
150 changes: 104 additions & 46 deletions classes/emailTemplate/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

use APP\emailTemplate\DAO;
use APP\facades\Repo;
use Illuminate\Support\Collection;
use Illuminate\Support\Enumerable;
use Illuminate\Support\Facades\DB;
use PKP\context\Context;
use PKP\core\PKPRequest;
use PKP\plugins\Hook;
Expand Down Expand Up @@ -173,22 +173,16 @@ public function add(EmailTemplate $emailTemplate): string
/** @copydoc DAO::update() */
public function edit(EmailTemplate $emailTemplate, array $params, $contextId)
{
$userGroupIds = $params['userGroupIds'];
unset($params['userGroupIds']);
$newEmailTemplate = clone $emailTemplate;
$newEmailTemplate->setAllData(array_merge($newEmailTemplate->_data, $params));



Hook::call('EmailTemplate::edit', [$newEmailTemplate, $emailTemplate, $params]);

if ($newEmailTemplate->getId()) {
$this->dao->update($newEmailTemplate);
} else {
$this->dao->insert($newEmailTemplate);
}

$this->updateTemplateAccessGroups($emailTemplate, $userGroupIds, $contextId);
}

/** @copydoc DAO::delete() */
Expand Down Expand Up @@ -234,35 +228,56 @@ public function restoreDefaults($contextId): array
}


public function getGroupsAssignedToTemplate(string $key, int $contextId): array
/***
* Gets the IDs of the user groups assigned to an email template
*/
public function getUserGroupsIdsAssignedToTemplate(string $templateKey, int $contextId): array
{
return EmailTemplateAccessGroup::withEmailKey([$templateKey])
->withContextId($contextId)
->whereNot('user_group_id', null)
->get()
->pluck('userGroupId')
->all();
}

/***
* Checks if an Email Template is unrestricted
*/
public function isTemplateUnrestricted(string $templateKey, int $contextId): bool
{
// FIXME - can this be replaced with eloquent?
return DB::table('email_template_role_access')
->where('email_key', $key)
->where('context_id', $contextId)
->pluck('user_group_id')
->toArray();
return !!EmailTemplateAccessGroup::withEmailKey([$templateKey])
->withContextId($contextId)
->where('user_group_id', null)
->first();
}


/**
* Checks if an email template is accessible to a user. A template is accessible if it is assigned to a user group that the user belongs to or if the template is unrestricted
*/
public function isTemplateAccessibleToUser(User $user, EmailTemplate $template, int $contextId): bool
{
if ($user->hasRole([Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_MANAGER,], $contextId)) {
return true;
}

$userUserGroups = Repo::userGroup()->userUserGroups($user->getId(), $contextId)->all();
$templateUserGroups = $this->getGroupsAssignedToTemplate($template->getData('key'), $contextId);
$userHasAccess = false;
$templateUserGroups = $this->getUserGroupsIdsAssignedToTemplate($template->getData('key'), $contextId);

// Null entry indicates that template is unrestricted
if(in_array(null, $templateUserGroups)) {
return true;
}


foreach ($userUserGroups as $userGroup) {
if (in_array($userGroup->getId(), $templateUserGroups) || $template->getData('isUnrestricted')) {
$userHasAccess = true;
break;
if (in_array($userGroup->getId(), $templateUserGroups)) {
return true;
}
}

return $userHasAccess;
return false;
}

/**
Expand All @@ -271,9 +286,9 @@ public function isTemplateAccessibleToUser(User $user, EmailTemplate $template,
* @param Enumerable $templates List of EmailTemplate objects to filter.
* @param User $user The user whose access level is used for filtering.
*
* @return \Illuminate\Support\Collection Filtered list of EmailTemplate objects accessible to the user.
* @return Collection Filtered list of EmailTemplate objects accessible to the user.
*/
public function filterTemplatesByUserAccess(Enumerable $templates, User $user, int $contextId): \Illuminate\Support\Collection
public function filterTemplatesByUserAccess(Enumerable $templates, User $user, int $contextId): Collection
{
$filteredTemplates = collect();

Expand All @@ -286,36 +301,79 @@ public function filterTemplatesByUserAccess(Enumerable $templates, User $user, i
return $filteredTemplates;
}

/**
* Pass empty array to delete all existing user groups for a template
/***
* Internal method used to assign user group IDs to an email template
*/
public function updateTemplateAccessGroups(EmailTemplate $emailTemplate, array $newUserGroupIds, int $contextId): void
private function _updateTemplateAccessGroups(EmailTemplate $emailTemplate, array $newUserGroupIds, int $contextId): void
{
$isUnrestricted = in_array(null, $newUserGroupIds);
// remove any null values
// Delete old entries for user groups IDs not found in new list of user group IDs
DB::table('email_template_role_access')
->where('email_key', $emailTemplate->getData('key'))
->where('context_id', $contextId)
->whereNotIn('user_group_id', $newUserGroupIds)
->delete();
EmailTemplateAccessGroup::withEmailKey([$emailTemplate->getData('key')])
->withContextId($contextId)
->whereNotIn('user_group_id', $newUserGroupIds)->delete();

foreach ($newUserGroupIds as $id) {
DB::table('email_template_role_access')
->updateOrInsert(
[ // The where conditions (keys that should match)
'email_key' => $emailTemplate->getData('key'),
'user_group_id' => $id,
'context_id' => $contextId
],
[ // The data to insert or update (values to set)
'email_key' => $emailTemplate->getData('key'),
'user_group_id' => $id,
'context_id' => $contextId,
]
);
EmailTemplateAccessGroup::updateOrCreate(
[
// The where conditions (keys that should match)
'email_key' => $emailTemplate->getData('key'),
'user_group_id' => $id,
'context_id' => $contextId,
],
[
// The data to insert or update (values to set)
'emailKey' => $emailTemplate->getData('key'),
'userGroupId' => $id,
'contextId' => $contextId,
]
);
}
}

/**
* Pass empty array in $userGroupIds to delete all existing user groups for a template
*/
public function setEmailTemplateAccess(EmailTemplate $emailTemplate, int $contextId, ?array $userGroupIds, ?bool $isUnrestricted): void
{
if($userGroupIds !== null) {
$this->_updateTemplateAccessGroups($emailTemplate, $userGroupIds, $contextId);
}

if($isUnrestricted !== null) {
$this->markTemplateAsUnrestricted($emailTemplate, $isUnrestricted, $contextId);
}
}


/**
* Mark an email template as unrestricted or not.
* An unrestricted email template is available to all user groups associated with the Roles linked to the mailable that the template belongs to.
* Mailable roles are stored in the $fromRoleIds property of a mailable
*/
private function markTemplateAsUnrestricted(EmailTemplate $emailTemplate, bool $isUnrestricted, int $contextId): void
{
// Unrestricted emails are represented by an entry with a `null` value for the user group ID
if ($isUnrestricted) {
EmailTemplateAccessGroup::updateOrCreate(
[
// The where conditions (keys that should match)
'email_key' => $emailTemplate->getData('key'),
'user_group_id' => null,
'context_id' => $contextId,
],
[
// The data to insert or update (values to set)
'emailKey' => $emailTemplate->getData('key'),
'userGroupId' => null,
'contextId' => $contextId,
]
);

} else {
// Remove entry with a `null` value for the user group ID to reflect that it is no longer unrestricted
EmailTemplateAccessGroup::withEmailKey([$emailTemplate->getData('key')])
->withContextId($contextId)
->withGroupIds([null])
->delete();
}
}

}
11 changes: 7 additions & 4 deletions classes/emailTemplate/maps/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,16 @@ protected function mapByProperties(array $props, EmailTemplate $item, string $ma
$output = [];

$mailableClass = $mailableClass ?? Repo::mailable()->getMailableByEmailTemplate($item);

$assignedUserGroupsIds = [];
// some mailable are not found during some operations such as performing a search for templates. So ensure mailable exist before using
if($mailableClass) {
if ($mailableClass) {
$isUserGroupsAssignable = Repo::mailable()->isGroupsAssignableToTemplates($mailableClass);

$assignedUserGroupsIds = Repo::emailTemplate()->getUserGroupsIdsAssignedToTemplate($item->getData('key'), Application::get()->getRequest()->getContext()->getId());
if (!$isUserGroupsAssignable) {
$output['assignedUserGroupIds'] = [];
} else {
// Get the current user groups assigned to the template
$output['assignedUserGroupIds'] = Repo::emailTemplate()->getGroupsAssignedToTemplate($item->getData('key'), Application::get()->getRequest()->getContext()->getId());
$output['assignedUserGroupIds'] = $assignedUserGroupsIds;
}
}

Expand All @@ -108,6 +108,9 @@ protected function mapByProperties(array $props, EmailTemplate $item, string $ma
'emailTemplates/' . $item->getData('key')
);
break;
case 'isUnrestricted':
$output['isUnrestricted'] = Repo::emailTemplate()->isTemplateUnrestricted($item->getData('key'), Application::get()->getRequest()->getContext()->getId());
break;
default:
$output[$prop] = $item->getData($prop);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ class I10403_EmailTemplateRoleAccess extends Migration
public function up(): void
{

Schema::create('email_template_role_access', function (Blueprint $table) {
$table->bigInteger('email_template_role_access_id')->autoIncrement();
Schema::create('email_template_user_group_access', function (Blueprint $table) {
$table->bigInteger('email_template_user_group_access_id')->autoIncrement();
$table->string('email_key', 255);
$table->bigInteger('context_id');
$table->bigInteger('user_group_id');
$table->bigInteger('user_group_id')->nullable();

$table->foreign('context_id')->references('journal_id')->on('journals')->onDelete('cascade');
$table->foreign('user_group_id')->references('user_group_id')->on('user_groups')->onDelete('cascade');
Expand All @@ -30,6 +30,6 @@ public function up(): void
*/
public function down(): void
{
Schema::drop('email_template_role_access');
Schema::drop('email_template_user_group_access');
}
}

0 comments on commit 6d77552

Please sign in to comment.