From 6f329a7595892e4cd9e0258e1083b8dae8095b4e Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Thu, 28 Sep 2023 09:49:29 -0500 Subject: [PATCH] Fix alerting find owner contacts on old SQL server versions (#15355) * Fix alerting find owner contacts on old SQL server versions Older SQL server versions had a bug where they didn't accept parenthesis around the first query of a union statement. It was difficult to remove these parenthesis, so use whereHas instead. * Fix style --- LibreNMS/Alert/AlertUtil.php | 32 ++++++++++---------------------- app/Models/User.php | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/LibreNMS/Alert/AlertUtil.php b/LibreNMS/Alert/AlertUtil.php index 1fa4d1b12a..ed65e9bcc6 100644 --- a/LibreNMS/Alert/AlertUtil.php +++ b/LibreNMS/Alert/AlertUtil.php @@ -28,8 +28,8 @@ namespace LibreNMS\Alert; use App\Models\Device; use App\Models\User; use DeviceCache; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Arr; -use Illuminate\Support\Facades\DB; use LibreNMS\Config; use PHPMailer\PHPMailer\PHPMailer; @@ -168,28 +168,16 @@ class AlertUtil public static function findContactsOwners(array $results): array { - return User::whereNot('email', '')->whereIn('user_id', function (\Illuminate\Database\Query\Builder $query) use ($results) { - $tables = [ - 'bill_id' => 'bill_perms', - 'port_id' => 'ports_perms', - 'device_id' => 'devices_perms', - ]; - - $first = true; - foreach ($tables as $column => $table) { - $ids = array_filter(Arr::pluck($results, $column)); // find IDs for this type - - if (! empty($ids)) { - if ($first) { - $query->select('user_id')->from($table)->whereIn($column, $ids); - $first = false; - } else { - $query->union(DB::table($table)->select('user_id')->whereIn($column, $ids)); - } - } + return User::whereNot('email', '')->where(function (Builder $query) use ($results) { + if ($device_ids = array_filter(Arr::pluck($results, 'device_id'))) { + $query->orWhereHas('devicesOwned', fn ($q) => $q->whereIn('devices_perms.device_id', $device_ids)); + } + if ($port_ids = array_filter(Arr::pluck($results, 'port_id'))) { + $query->orWhereHas('portsOwned', fn ($q) => $q->whereIn('ports_perms.port_id', $port_ids)); + } + if ($bill_ids = array_filter(Arr::pluck($results, 'bill_id'))) { + $query->orWhereHas('bills', fn ($q) => $q->whereIn('bill_perms.bill_id', $bill_ids)); } - - return $query; })->pluck('realname', 'email')->all(); } diff --git a/app/Models/User.php b/app/Models/User.php index 4643969ea9..cb7123d580 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -228,6 +228,11 @@ class User extends Authenticatable return $this->hasMany(\App\Models\ApiToken::class, 'user_id', 'user_id'); } + public function bills(): BelongsToMany + { + return $this->belongsToMany(\App\Models\Bill::class, 'bill_perms', 'user_id', 'bill_id'); + } + public function devices() { // pseudo relation @@ -236,6 +241,11 @@ class User extends Authenticatable }); } + public function devicesOwned(): BelongsToMany + { + return $this->belongsToMany(\App\Models\Device::class, 'devices_perms', 'user_id', 'device_id'); + } + public function deviceGroups(): BelongsToMany { return $this->belongsToMany(\App\Models\DeviceGroup::class, 'devices_group_perms', 'user_id', 'device_group_id'); @@ -247,10 +257,15 @@ class User extends Authenticatable return Port::query(); } else { //FIXME we should return all ports for a device if the user has been given access to the whole device. - return $this->belongsToMany(\App\Models\Port::class, 'ports_perms', 'user_id', 'port_id'); + return $this->portsOwned(); } } + public function portsOwned(): BelongsToMany + { + return $this->belongsToMany(\App\Models\Port::class, 'ports_perms', 'user_id', 'port_id'); + } + public function dashboards(): HasMany { return $this->hasMany(\App\Models\Dashboard::class, 'user_id');