Skip to content

Commit

Permalink
Merge pull request #545 from lonnieezell/models
Browse files Browse the repository at this point in the history
Alternate Models
  • Loading branch information
MGatner authored Jul 13, 2022
2 parents c6a603a + f637622 commit 92f8f76
Show file tree
Hide file tree
Showing 11 changed files with 402 additions and 296 deletions.
4 changes: 3 additions & 1 deletion docs/_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## Unreleased

_No unreleased changes yet_
Enhancements:

- Added alternate authorization Models with stronger typing

## 1.1.0

Expand Down
7 changes: 7 additions & 0 deletions docs/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ Entities with your own casts and class methods.
If you extend the Model and supply your own validation rules you can also enforce those on the
`AuthController` by providing a `$registrationRules` property in **app/Config/Validation.php**.

### Alternate Models

Since version `1.2.0` this library includes an alternate version of the authorization models
that use specific Entities as their return types. These models are not yet used by the library
itself for backwards-compatibility, but they are highly recommended for any implementing
projects or model extensions.

## Views

Myth:Auth uses its own views by default, but you may want to update these in order to change
Expand Down
1 change: 1 addition & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ parameters:
- src/Config/Routes.php
- src/Views/*
ignoreErrors:
- '#.+deprecated class Myth\\Auth\\Authorization\\(Group|Permission)Model.+#'
- '#.+Mockery.+#'
- '#Call to an undefined method .+::shouldReceive\(\)#'
- '#Call to an undefined static method Config\\Services::[A-Za-z]+\(\)#'
Expand Down
197 changes: 7 additions & 190 deletions src/Authorization/GroupModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,196 +2,13 @@

namespace Myth\Auth\Authorization;

use CodeIgniter\Model;
use Myth\Auth\Models\GroupModel as BaseModel;

class GroupModel extends Model
/**
* @deprecated 1.2.0 Use Myth\Auth\Models\GroupModel instead
*/
class GroupModel extends BaseModel
{
protected $table = 'auth_groups';
protected $primaryKey = 'id';
protected $returnType = 'object';
protected $allowedFields = [
'name', 'description',
];
protected $useTimestamps = false;
protected $validationRules = [
'name' => 'required|max_length[255]|is_unique[auth_groups.name,name,{name}]',
'description' => 'max_length[255]',
];
protected $validationMessages = [];
protected $skipValidation = false;

//--------------------------------------------------------------------
// Users
//--------------------------------------------------------------------

/**
* Adds a single user to a single group.
*
* @return bool
*/
public function addUserToGroup(int $userId, int $groupId)
{
cache()->delete("{$groupId}_users");
cache()->delete("{$userId}_groups");
cache()->delete("{$userId}_permissions");

$data = [
'user_id' => $userId,
'group_id' => $groupId,
];

return (bool) $this->db->table('auth_groups_users')->insert($data);
}

/**
* Removes a single user from a single group.
*
* @param int|string $groupId
*
* @return bool
*/
public function removeUserFromGroup(int $userId, $groupId)
{
cache()->delete("{$groupId}_users");
cache()->delete("{$userId}_groups");
cache()->delete("{$userId}_permissions");

return $this->db->table('auth_groups_users')
->where([
'user_id' => $userId,
'group_id' => (int) $groupId,
])->delete();
}

/**
* Removes a single user from all groups.
*
* @return bool
*/
public function removeUserFromAllGroups(int $userId)
{
cache()->delete("{$userId}_groups");
cache()->delete("{$userId}_permissions");

return $this->db->table('auth_groups_users')
->where('user_id', $userId)
->delete();
}

/**
* Returns an array of all groups that a user is a member of.
*
* @return array
*/
public function getGroupsForUser(int $userId)
{
if (null === $found = cache("{$userId}_groups")) {
$found = $this->builder()
->select('auth_groups_users.*, auth_groups.name, auth_groups.description')
->join('auth_groups_users', 'auth_groups_users.group_id = auth_groups.id', 'left')
->where('user_id', $userId)
->get()->getResultArray();

cache()->save("{$userId}_groups", $found, 300);
}

return $found;
}

/**
* Returns an array of all users that are members of a group.
*
* @return array
*/
public function getUsersForGroup(int $groupId)
{
if (null === $found = cache("{$groupId}_users")) {
$found = $this->builder()
->select('auth_groups_users.*, users.*')
->join('auth_groups_users', 'auth_groups_users.group_id = auth_groups.id', 'left')
->join('users', 'auth_groups_users.user_id = users.id', 'left')
->where('auth_groups.id', $groupId)
->get()->getResultArray();

cache()->save("{$groupId}_users", $found, 300);
}

return $found;
}

//--------------------------------------------------------------------
// Permissions
//--------------------------------------------------------------------

/**
* Gets all permissions for a group in a way that can be
* easily used to check against:
*
* [
* id => name,
* id => name
* ]
*/
public function getPermissionsForGroup(int $groupId): array
{
$permissionModel = model(PermissionModel::class);
$fromGroup = $permissionModel
->select('auth_permissions.*')
->join('auth_groups_permissions', 'auth_groups_permissions.permission_id = auth_permissions.id', 'inner')
->where('group_id', $groupId)
->findAll();

$found = [];

foreach ($fromGroup as $permission) {
$found[$permission['id']] = $permission;
}

return $found;
}

/**
* Add a single permission to a single group, by IDs.
*
* @return mixed
*/
public function addPermissionToGroup(int $permissionId, int $groupId)
{
$data = [
'permission_id' => $permissionId,
'group_id' => $groupId,
];

return $this->db->table('auth_groups_permissions')->insert($data);
}

//--------------------------------------------------------------------

/**
* Removes a single permission from a single group.
*
* @return mixed
*/
public function removePermissionFromGroup(int $permissionId, int $groupId)
{
return $this->db->table('auth_groups_permissions')
->where([
'permission_id' => $permissionId,
'group_id' => $groupId,
])->delete();
}

//--------------------------------------------------------------------

/**
* Removes a single permission from all groups.
*
* @return mixed
*/
public function removePermissionFromAllGroups(int $permissionId)
{
return $this->db->table('auth_groups_permissions')
->where('permission_id', $permissionId)
->delete();
}
protected $returnType = 'object';
protected string $permissionModel = PermissionModel::class;
}
98 changes: 6 additions & 92 deletions src/Authorization/PermissionModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,98 +2,12 @@

namespace Myth\Auth\Authorization;

use CodeIgniter\Database\BaseResult;
use CodeIgniter\Database\Query;
use CodeIgniter\Model;
use Myth\Auth\Models\PermissionModel as BaseModel;

class PermissionModel extends Model
/**
* @deprecated 1.2.0 Use Myth\Auth\Models\PermissionModel instead
*/
class PermissionModel extends BaseModel
{
protected $table = 'auth_permissions';
protected $allowedFields = [
'name', 'description',
];
protected $useTimestamps = false;
protected $validationRules = [
'name' => 'required|max_length[255]|is_unique[auth_permissions.name,name,{name}]',
'description' => 'max_length[255]',
];

/**
* Checks to see if a user, or one of their groups,
* has a specific permission.
*/
public function doesUserHavePermission(int $userId, int $permissionId): bool
{
return array_key_exists($permissionId, $this->getPermissionsForUser($userId));
}

/**
* Adds a single permission to a single user.
*
* @return BaseResult|false|Query
*/
public function addPermissionToUser(int $permissionId, int $userId)
{
cache()->delete("{$userId}_permissions");

return $this->db->table('auth_users_permissions')->insert([
'user_id' => $userId,
'permission_id' => $permissionId,
]);
}

/**
* Removes a permission from a user.
*
* @return mixed
*/
public function removePermissionFromUser(int $permissionId, int $userId)
{
$this->db->table('auth_users_permissions')->where([
'user_id' => $userId,
'permission_id' => $permissionId,
])->delete();

cache()->delete("{$userId}_permissions");
}

/**
* Gets all permissions for a user in a way that can be
* easily used to check against:
*
* [
* id => name,
* id => name
* ]
*/
public function getPermissionsForUser(int $userId): array
{
if (null === $found = cache("{$userId}_permissions")) {
$fromUser = $this->db->table('auth_users_permissions')
->select('id, auth_permissions.name')
->join('auth_permissions', 'auth_permissions.id = permission_id', 'inner')
->where('user_id', $userId)
->get()
->getResultObject();
$fromGroup = $this->db->table('auth_groups_users')
->select('auth_permissions.id, auth_permissions.name')
->join('auth_groups_permissions', 'auth_groups_permissions.group_id = auth_groups_users.group_id', 'inner')
->join('auth_permissions', 'auth_permissions.id = auth_groups_permissions.permission_id', 'inner')
->where('user_id', $userId)
->get()
->getResultObject();

$combined = array_merge($fromUser, $fromGroup);

$found = [];

foreach ($combined as $row) {
$found[$row->id] = strtolower($row->name);
}

cache()->save("{$userId}_permissions", $found, 300);
}

return $found;
}
protected $returnType = 'array';
}
18 changes: 18 additions & 0 deletions src/Entities/Group.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Myth\Auth\Entities;

use CodeIgniter\Entity\Entity;

/**
* Group Entity
*
* As of version 1.2 this class is used by the new GroupModel
* to allow using a strongly-typed return. Any logic in this
* class should not be relied on within this library.
*
* @since 1.2.0
*/
class Group extends Entity
{
}
18 changes: 18 additions & 0 deletions src/Entities/Permission.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Myth\Auth\Entities;

use CodeIgniter\Entity\Entity;

/**
* Permission Entity
*
* As of version 1.2 this class is used by the new PermissionModel
* to allow using a strongly-typed return. Any logic in this
* class should not be relied on within this library.
*
* @since 1.2.0
*/
class Permission extends Entity
{
}
Loading

0 comments on commit 92f8f76

Please sign in to comment.