New permissions code (#9986)

* Initial permissions

* initial tests

* updates

* finish tests, other tweaks

* update legacy permissions checks
remove global :D

* missed facade extend

* Update eloquent permissions to use the new facade and drop joins

* method descriptions

* more docs

* fix style
This commit is contained in:
Tony Murray
2019-03-19 08:14:01 -05:00
committed by GitHub
parent bafc195ae3
commit 00a1185980
11 changed files with 543 additions and 126 deletions

244
LibreNMS/Permissions.php Normal file
View File

@@ -0,0 +1,244 @@
<?php
/**
* Permissions.php
*
* Class to check the direct permissions on devices, ports, and bills for normal users (not global read only and admin)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2019 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS;
use App\Models\Bill;
use App\Models\Device;
use App\Models\Port;
use App\Models\User;
use Auth;
use DB;
class Permissions
{
private $devicePermissions;
private $portPermissions;
private $billPermissions;
/**
* Check if a device can be accessed by user (non-global read/admin)
* If no user is given, use the logged in user
*
* @param Device|int $device
* @param User|int $user
* @return boolean
*/
public function canAccessDevice($device, $user = null)
{
return $this->getDevicePermissions()
->where('user_id', $this->getUserId($user))
->where('device_id', $this->getDeviceId($device))
->isNotEmpty();
}
/**
* Check if a access can be accessed by user (non-global read/admin)
* If no user is given, use the logged in user
*
* @param Port|int $port
* @param User|int $user
* @return boolean
*/
public function canAccessPort($port, $user = null)
{
return $this->getPortPermissions()
->where('user_id', $this->getUserId($user))
->where('port_id', $this->getPortId($port))
->isNotEmpty();
}
/**
* Check if a bill can be accessed by user (non-global read/admin)
* If no user is given, use the logged in user
*
* @param Bill|int $bill
* @param User|int $user
* @return boolean
*/
public function canAccessBill($bill, $user = null)
{
return $this->getBillPermissions()
->where('user_id', $this->getUserId($user))
->where('bill_id', $this->getBillId($bill))
->isNotEmpty();
}
/**
* Get the user_id of users that have been granted access to device
*
* @param Device|int $device
* @return \Illuminate\Support\Collection
*/
public function usersForDevice($device)
{
return $this->getDevicePermissions()
->where('device_id', $this->getDeviceId($device))
->pluck('user_id');
}
/**
* Get the user_id of users that have been granted access to port
*
* @param Port|int $port
* @return \Illuminate\Support\Collection
*/
public function usersForPort($port)
{
return $this->getPortPermissions()
->where('port_id', $this->getPortId($port))
->pluck('user_id');
}
/**
* Get the user_id of users that have been granted access to bill
*
* @param Bill|int $bill
* @return \Illuminate\Support\Collection
*/
public function usersForBill($bill)
{
return $this->getBillPermissions()
->where('bill_id', $this->getBillId($bill))
->pluck('user_id');
}
/**
* Get a list of device_id of all devices the user can access
*
* @param User|int $user
* @return \Illuminate\Support\Collection
*/
public function devicesForUser($user = null)
{
return $this->getDevicePermissions()
->where('user_id', $this->getUserId($user))
->pluck('device_id');
}
/**
* Get a list of port_id of all ports the user can access
*
* @param User|int $user
* @return \Illuminate\Support\Collection
*/
public function portsForUser($user = null)
{
return $this->getPortPermissions()
->where('user_id', $this->getUserId($user))
->pluck('port_id');
}
/**
* Get a list of bill_id of all bills the user can access
*
* @param User|int $user
* @return \Illuminate\Support\Collection
*/
public function billsForUser($user = null)
{
return $this->getBillPermissions()
->where('user_id', $this->getUserId($user))
->pluck('bill_id');
}
/**
* Get the cached data for device permissions. Use helpers instead.
*
* @return \Illuminate\Support\Collection
*/
public function getDevicePermissions()
{
if (is_null($this->devicePermissions)) {
$this->devicePermissions = DB::table('devices_perms')->get();
}
return $this->devicePermissions;
}
/**
* Get the cached data for port permissions. Use helpers instead.
*
* @return \Illuminate\Support\Collection
*/
public function getPortPermissions()
{
if (is_null($this->portPermissions)) {
$this->portPermissions = DB::table('ports_perms')->get();
}
return $this->portPermissions;
}
/**
* Get the cached data for bill permissions. Use helpers instead.
*
* @return \Illuminate\Support\Collection
*/
public function getBillPermissions()
{
if (is_null($this->billPermissions)) {
$this->billPermissions = DB::table('bill_ports')->get();
}
return $this->billPermissions;
}
/**
* @param $user
* @return int|null
*/
private function getUserId($user)
{
return $user instanceof User ? $user->user_id : (is_int($user) ? $user : Auth::id());
}
/**
* @param $device
* @return int
*/
private function getDeviceId($device)
{
return $device instanceof Device ? $device->device_id : (is_int($device) ? $device : 0);
}
/**
* @param $port
* @return int
*/
private function getPortId($port)
{
return $port instanceof Port ? $port->port_id : (is_int($port) ? $port : 0);
}
/**
* @param $bill
* @return int
*/
private function getBillId($bill)
{
return $bill instanceof Bill ? $bill->bill_id : (is_int($bill) ? $bill : 0);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Permissions.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2019 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Permissions extends Facade
{
protected static function getFacadeAccessor()
{
return 'permissions';
}
}

View File

@@ -26,7 +26,7 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Builder; use Illuminate\Database\Eloquent\Builder;
abstract class BaseModel extends Model abstract class BaseModel extends Model
{ {
@@ -69,8 +69,7 @@ abstract class BaseModel extends Model
$table = $this->getTable(); $table = $this->getTable();
} }
return $query->join('devices_perms', 'devices_perms.device_id', "$table.device_id") return $query->whereIn("$table.device_id", \Permissions::devicesForUser($user));
->where('devices_perms.user_id', $user->user_id);
} }
/** /**
@@ -91,11 +90,9 @@ abstract class BaseModel extends Model
$table = $this->getTable(); $table = $this->getTable();
} }
return $query->join('ports_perms', 'ports_perms.port_id', "$table.port_id") return $query->where(function ($query) use ($table, $user) {
->join('devices_perms', 'devices_perms.device_id', "$table.device_id") return $query->whereIn("$table.port_id", \Permissions::portsForUser($user))
->where(function ($query) use ($user) { ->orWhereIn("$table.device_id", \Permissions::devicesForUser($user));
$query->where('ports_perms.user_id', $user->user_id) });
->orWhere('devices_perms.user_id', $user->user_id);
});
} }
} }

View File

@@ -25,8 +25,6 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
class DeviceRelatedModel extends BaseModel class DeviceRelatedModel extends BaseModel
{ {
// ---- Query Scopes ---- // ---- Query Scopes ----

View File

@@ -7,12 +7,28 @@ use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Permissions;
use LibreNMS\Util\IP; use LibreNMS\Util\IP;
use LibreNMS\Util\Validate; use LibreNMS\Util\Validate;
use Validator; use Validator;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->registerFacades();
$this->registerGeocoder();
$this->app->singleton('permissions', function ($app) {
return new Permissions();
});
}
/** /**
* Bootstrap any application services. * Bootstrap any application services.
* *
@@ -28,17 +44,6 @@ class AppServiceProvider extends ServiceProvider
$this->configureMorphAliases(); $this->configureMorphAliases();
} }
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->registerFacades();
$this->registerGeocoder();
}
private function bootCustomBladeDirectives() private function bootCustomBladeDirectives()
{ {
Blade::if('config', function ($key) { Blade::if('config', function ($key) {

View File

@@ -237,7 +237,7 @@ return [
'Toastr' => Kamaln7\Toastr\Facades\Toastr::class, 'Toastr' => Kamaln7\Toastr\Facades\Toastr::class,
// LibreNMS // LibreNMS
// 'LibreConfig' => \LibreNMS\Config::class, 'Permissions' => \App\Facades\Permissions::class,
], ],
]; ];

View File

@@ -40,6 +40,12 @@ $factory->state(App\Models\User::class, 'read', function ($faker) {
]; ];
}); });
$factory->define(\App\Models\Bill::class, function (Faker\Generator $faker) {
return [
'bill_name' => $faker->text
];
});
$factory->define(\App\Models\Device::class, function (Faker\Generator $faker) { $factory->define(\App\Models\Device::class, function (Faker\Generator $faker) {
return [ return [
'hostname' => $faker->domainWord.'.'.$faker->domainName, 'hostname' => $faker->domainWord.'.'.$faker->domainName,

View File

@@ -18,8 +18,6 @@ use LibreNMS\Config;
function authToken(\Slim\Route $route) function authToken(\Slim\Route $route)
{ {
global $permissions;
if (Auth::check()) { if (Auth::check()) {
$user = Auth::user(); $user = Auth::user();
@@ -29,7 +27,6 @@ function authToken(\Slim\Route $route)
'user_id' => $user->user_id, 'user_id' => $user->user_id,
'userlevel' => $user->level 'userlevel' => $user->level
]; ];
$permissions = permissions_cache($user->user_id);
return; return;
} }

View File

@@ -292,105 +292,48 @@ function print_graph_popup($graph_array)
echo generate_graph_popup($graph_array); echo generate_graph_popup($graph_array);
}//end print_graph_popup() }//end print_graph_popup()
function permissions_cache($user_id)
{
$permissions = array();
foreach (dbFetchRows("SELECT * FROM devices_perms WHERE user_id = '" . $user_id . "'") as $device) {
$permissions['device'][$device['device_id']] = 1;
}
foreach (dbFetchRows("SELECT * FROM ports_perms WHERE user_id = '" . $user_id . "'") as $port) {
$permissions['port'][$port['port_id']] = 1;
}
foreach (dbFetchRows("SELECT * FROM bill_perms WHERE user_id = '" . $user_id . "'") as $bill) {
$permissions['bill'][$bill['bill_id']] = 1;
}
return $permissions;
}//end permissions_cache()
function bill_permitted($bill_id) function bill_permitted($bill_id)
{ {
global $permissions;
if (LegacyAuth::user()->hasGlobalRead()) { if (LegacyAuth::user()->hasGlobalRead()) {
$allowed = true; return true;
} elseif ($permissions['bill'][$bill_id]) {
$allowed = true;
} else {
$allowed = false;
} }
return $allowed; return \Permissions::canAccessBill($bill_id, LegacyAuth::id());
}//end bill_permitted() }
function port_permitted($port_id, $device_id = null) function port_permitted($port_id, $device_id = null)
{ {
global $permissions;
if (!is_numeric($device_id)) { if (!is_numeric($device_id)) {
$device_id = get_device_id_by_port_id($port_id); $device_id = get_device_id_by_port_id($port_id);
} }
if (LegacyAuth::user()->hasGlobalRead()) { if (device_permitted($device_id)) {
$allowed = true; return true;
} elseif (device_permitted($device_id)) {
$allowed = true;
} elseif ($permissions['port'][$port_id]) {
$allowed = true;
} else {
$allowed = false;
} }
return $allowed; return \Permissions::canAccessPort($port_id, LegacyAuth::id());
}//end port_permitted() }
function application_permitted($app_id, $device_id = null) function application_permitted($app_id, $device_id = null)
{ {
global $permissions; if (!is_numeric($app_id)) {
return false;
if (is_numeric($app_id)) {
if (!$device_id) {
$device_id = get_device_id_by_app_id($app_id);
}
if (LegacyAuth::user()->hasGlobalRead()) {
$allowed = true;
} elseif (device_permitted($device_id)) {
$allowed = true;
} elseif ($permissions['application'][$app_id]) {
$allowed = true;
} else {
$allowed = false;
}
} else {
$allowed = false;
} }
return $allowed; if (!$device_id) {
}//end application_permitted() $device_id = get_device_id_by_app_id($app_id);
}
return device_permitted($device_id);
}
function device_permitted($device_id) function device_permitted($device_id)
{ {
global $permissions;
if (LegacyAuth::user()->hasGlobalRead()) { if (LegacyAuth::user()->hasGlobalRead()) {
$allowed = true; return true;
} elseif ($permissions['device'][$device_id]) {
$allowed = true;
} else {
$allowed = false;
} }
return \Permissions::canAccessDevice($device_id, LegacyAuth::id());
return $allowed; }
}//end device_permitted()
function print_graph_tag($args) function print_graph_tag($args)
{ {

View File

@@ -30,7 +30,7 @@
use LibreNMS\Authentication\LegacyAuth; use LibreNMS\Authentication\LegacyAuth;
use LibreNMS\Config; use LibreNMS\Config;
global $config, $permissions, $vars, $console_color; global $config, $vars, $console_color;
error_reporting(E_ERROR|E_PARSE|E_CORE_ERROR|E_COMPILE_ERROR); error_reporting(E_ERROR|E_PARSE|E_CORE_ERROR|E_COMPILE_ERROR);
ini_set('display_errors', 1); ini_set('display_errors', 1);
@@ -153,28 +153,3 @@ if (module_selected('web', $init_modules)) {
} }
$console_color = new Console_Color2(); $console_color = new Console_Color2();
if (module_selected('auth', $init_modules) ||
(
module_selected('graphs', $init_modules) &&
isset($config['allow_unauth_graphs']) &&
$config['allow_unauth_graphs'] != true
)
) {
// populate the permissions cache TODO: remove?
$permissions = [];
$user_id = LegacyAuth::id();
foreach (dbFetchColumn('SELECT device_id FROM devices_perms WHERE user_id=?', [$user_id]) as $device_id) {
$permissions['device'][$device_id] = 1;
}
foreach (dbFetchColumn('SELECT port_id FROM ports_perms WHERE user_id=?', [$user_id]) as $port_id) {
$permissions['port'][$port_id] = 1;
}
foreach (dbFetchColumn('SELECT bill_id FROM bill_perms WHERE user_id=?', [$user_id]) as $bill_id) {
$permissions['bill'][$bill_id] = 1;
}
unset($user_id, $device_id, $port_id, $bill_id);
}

View File

@@ -0,0 +1,216 @@
<?php
/**
* PermissionsTest.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2019 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Tests\Unit;
use App\Models\Bill;
use App\Models\Device;
use App\Models\Port;
use App\Models\User;
use LibreNMS\Tests\LaravelTestCase;
use Mockery\Mock;
class PermissionsTest extends LaravelTestCase
{
public function testUserCanAccessDevice()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getDevicePermissions')->andReturn(collect([
(object)['user_id' => 43, 'device_id' => 54],
(object)['user_id' => 43, 'device_id' => 32],
(object)['user_id' => 14, 'device_id' => 54],
]));
$device = factory(Device::class)->make(['device_id' => 54]);
$user = factory(User::class)->make(['user_id' => 43]);
$this->assertTrue($perms->canAccessDevice($device, 43));
$this->assertTrue($perms->canAccessDevice($device, $user));
$this->assertTrue($perms->canAccessDevice(54, $user));
$this->assertTrue($perms->canAccessDevice(54, 43));
$this->assertTrue($perms->canAccessDevice(54, 43));
$this->assertFalse($perms->canAccessDevice(54, 23));
$this->assertFalse($perms->canAccessDevice(23, 43));
$this->assertFalse($perms->canAccessDevice(54));
\Auth::shouldReceive('id')->once()->andReturn(43);
$this->assertTrue($perms->canAccessDevice(54));
\Auth::shouldReceive('id')->once()->andReturn(23);
$this->assertFalse($perms->canAccessDevice(54));
}
public function testDevicesForUser()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getDevicePermissions')->andReturn(collect([
(object)['user_id' => 3, 'device_id' => 7],
(object)['user_id' => 3, 'device_id' => 2],
(object)['user_id' => 4, 'device_id' => 5],
]));
$this->assertEquals(collect([7,2]), $perms->devicesForUser(3));
$user = factory(User::class)->make(['user_id' => 3]);
$this->assertEquals(collect([7,2]), $perms->devicesForUser($user));
$this->assertEmpty($perms->devicesForUser(9));
$this->assertEquals(collect(), $perms->devicesForUser());
\Auth::shouldReceive('id')->once()->andReturn(4);
$this->assertEquals(collect([5]), $perms->devicesForUser());
}
public function testUsersForDevice()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getDevicePermissions')->andReturn(collect([
(object)['user_id' => 3, 'device_id' => 7],
(object)['user_id' => 3, 'device_id' => 2],
(object)['user_id' => 4, 'device_id' => 5],
(object)['user_id' => 6, 'device_id' => 5],
]));
$this->assertEquals(collect([4, 6]), $perms->usersForDevice(5));
$this->assertEquals(collect([3]), $perms->usersForDevice(factory(Device::class)->make(['device_id' => 7])));
$this->assertEquals(collect(), $perms->usersForDevice(6));
$this->assertEmpty($perms->usersForDevice(9));
}
public function testUserCanAccessPort()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getPortPermissions')->andReturn(collect([
(object)['user_id' => 43, 'port_id' => 54],
(object)['user_id' => 43, 'port_id' => 32],
(object)['user_id' => 14, 'port_id' => 54],
]));
$port = factory(Port::class)->make(['port_id' => 54]);
$user = factory(User::class)->make(['user_id' => 43]);
$this->assertTrue($perms->canAccessPort($port, 43));
$this->assertTrue($perms->canAccessPort($port, $user));
$this->assertTrue($perms->canAccessPort(54, $user));
$this->assertTrue($perms->canAccessPort(54, 43));
$this->assertTrue($perms->canAccessPort(54, 43));
$this->assertFalse($perms->canAccessPort(54, 23));
$this->assertFalse($perms->canAccessPort(23, 43));
$this->assertFalse($perms->canAccessPort(54));
\Auth::shouldReceive('id')->once()->andReturn(43);
$this->assertTrue($perms->canAccessPort(54));
\Auth::shouldReceive('id')->once()->andReturn(23);
$this->assertFalse($perms->canAccessPort(54));
}
public function testPortsForUser()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getPortPermissions')->andReturn(collect([
(object)['user_id' => 3, 'port_id' => 7],
(object)['user_id' => 3, 'port_id' => 2],
(object)['user_id' => 4, 'port_id' => 5],
]));
$this->assertEquals(collect([7,2]), $perms->portsForUser(3));
$user = factory(User::class)->make(['user_id' => 3]);
$this->assertEquals(collect([7,2]), $perms->portsForUser($user));
$this->assertEmpty($perms->portsForUser(9));
$this->assertEquals(collect(), $perms->portsForUser());
\Auth::shouldReceive('id')->once()->andReturn(4);
$this->assertEquals(collect([5]), $perms->portsForUser());
}
public function testUsersForPort()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getPortPermissions')->andReturn(collect([
(object)['user_id' => 3, 'port_id' => 7],
(object)['user_id' => 3, 'port_id' => 2],
(object)['user_id' => 4, 'port_id' => 5],
(object)['user_id' => 6, 'port_id' => 5],
]));
$this->assertEquals(collect([4, 6]), $perms->usersForPort(5));
$this->assertEquals(collect([3]), $perms->usersForPort(factory(Port::class)->make(['port_id' => 7])));
$this->assertEquals(collect(), $perms->usersForPort(6));
$this->assertEmpty($perms->usersForPort(9));
}
public function testUserCanAccessBill()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getBillPermissions')->andReturn(collect([
(object)['user_id' => 43, 'bill_id' => 54],
(object)['user_id' => 43, 'bill_id' => 32],
(object)['user_id' => 14, 'bill_id' => 54],
]));
$bill = factory(Bill::class)->make(['bill_id' => 54]);
$user = factory(User::class)->make(['user_id' => 43]);
$this->assertTrue($perms->canAccessBill($bill, 43));
$this->assertTrue($perms->canAccessBill($bill, $user));
$this->assertTrue($perms->canAccessBill(54, $user));
$this->assertTrue($perms->canAccessBill(54, 43));
$this->assertTrue($perms->canAccessBill(54, 43));
$this->assertFalse($perms->canAccessBill(54, 23));
$this->assertFalse($perms->canAccessBill(23, 43));
$this->assertFalse($perms->canAccessBill(54));
\Auth::shouldReceive('id')->once()->andReturn(43);
$this->assertTrue($perms->canAccessBill(54));
\Auth::shouldReceive('id')->once()->andReturn(23);
$this->assertFalse($perms->canAccessBill(54));
}
public function testBillsForUser()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getBillPermissions')->andReturn(collect([
(object)['user_id' => 3, 'bill_id' => 7],
(object)['user_id' => 3, 'bill_id' => 2],
(object)['user_id' => 4, 'bill_id' => 5],
]));
$this->assertEquals(collect([7,2]), $perms->billsForUser(3));
$user = factory(User::class)->make(['user_id' => 3]);
$this->assertEquals(collect([7,2]), $perms->billsForUser($user));
$this->assertEmpty($perms->billsForUser(9));
$this->assertEquals(collect(), $perms->billsForUser());
\Auth::shouldReceive('id')->once()->andReturn(4);
$this->assertEquals(collect([5]), $perms->billsForUser());
}
public function testUsersForBill()
{
$perms = \Mockery::mock(\LibreNMS\Permissions::class)->makePartial();
$perms->shouldReceive('getBillPermissions')->andReturn(collect([
(object)['user_id' => 3, 'bill_id' => 7],
(object)['user_id' => 3, 'bill_id' => 2],
(object)['user_id' => 4, 'bill_id' => 5],
(object)['user_id' => 6, 'bill_id' => 5],
]));
$this->assertEquals(collect([4, 6]), $perms->usersForBill(5));
$this->assertEquals(collect([3]), $perms->usersForBill(factory(Bill::class)->make(['bill_id' => 7])));
$this->assertEquals(collect(), $perms->usersForBill(6));
$this->assertEmpty($perms->usersForBill(9));
}
}