Issues (2963)

app/Http/Controllers/ServiceTemplateController.php (3 issues)

1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Models\Device;
6
use App\Models\DeviceGroup;
7
use App\Models\Service;
8
use App\Models\ServiceTemplate;
9
use Illuminate\Http\Request;
10
use Illuminate\Validation\Rule;
11
use LibreNMS\Alerting\QueryBuilderFilter;
12
use LibreNMS\Services;
13
use Toastr;
14
15
class ServiceTemplateController extends Controller
16
{
17
    public function __construct()
18
    {
19
        $this->authorizeResource(ServiceTemplate::class, 'template');
20
    }
21
22
    /**
23
     * Display a listing of the resource.
24
     *
25
     * @return \Illuminate\Http\Response|\Illuminate\View\View
26
     */
27
    public function index()
28
    {
29
        //$this->authorize('manage', ServiceTemplate::class);
30
31
        return view(
32
            'service-template.index', [
33
                'service_templates' => ServiceTemplate::orderBy('name')->withCount('devices')->withCount('groups')->get(),
34
                'groups' => DeviceGroup::orderBy('name')->has('serviceTemplates')->get(),
35
                'devices' => Device::orderBy('hostname')->has('serviceTemplates')->get(),
36
            ]
37
        );
38
    }
39
40
    /**
41
     * Show the form for creating a new resource.
42
     *
43
     * @return \Illuminate\Http\Response|\Illuminate\View\View
44
     */
45
    public function create()
46
    {
47
        return view(
48
            'service-template.create', [
49
                'template' => new ServiceTemplate(),
50
                'service_templates' => ServiceTemplate::orderBy('name')->get(),
51
                'services' => Services::list(),
52
                'filters' => json_encode(new QueryBuilderFilter('group')),
53
            ]
54
        );
55
    }
56
57
    /**
58
     * Store a newly created resource in storage.
59
     *
60
     * @param  \Illuminate\Http\Request  $request
61
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
62
     */
63
    public function store(Request $request)
64
    {
65
        $this->validate(
66
            $request, [
67
                'name' => 'required|string|unique:service_templates',
68
                'groups' => 'array',
69
                'groups.*' => 'integer',
70
                'devices' => 'array',
71
                'devices.*' => 'integer',
72
                'check' => 'string',
73
                'type' => 'required|in:dynamic,static',
74
                'rules' => 'json|required_if:type,dynamic',
75
                'param' => 'nullable|string',
76
                'ip' => 'nullable|string',
77
                'desc' => 'nullable|string',
78
                'changed' => 'integer',
79
                'disabled' => 'integer',
80
                'ignore' => 'integer',
81
            ]
82
        );
83
84
        $template = ServiceTemplate::make(
85
            $request->only(
86
                [
87
                    'name',
88
                    'check',
89
                    'type',
90
                    'rules',
91
                    'param',
92
                    'ip',
93
                    'desc',
94
                    'changed',
95
                    'disabled',
96
                    'ignore',
97
                ]
98
            )
99
        );
100
        $template->rules = json_decode($request->rules);
101
        $template->save();
102
103
        if ($request->type == 'static') {
104
            $template->devices()->sync($request->devices);
105
        }
106
107
        $template->groups()->sync($request->groups);
108
        Toastr::success(__('Service Template :name created', ['name' => $template->name]));
109
110
        return redirect()->route('services.templates.index');
111
    }
112
113
    /**
114
     * Display the specified resource.
115
     *
116
     * @param  \App\Models\ServiceTemplate  $template
117
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
118
     */
119
    public function show(ServiceTemplate $template)
120
    {
121
        return redirect(url('/services/templates/' . $template->id));
122
    }
123
124
    /**
125
     * Show the form for editing the specified resource.
126
     *
127
     * @param  \App\Models\ServiceTemplate  $template
128
     * @return \Illuminate\Http\Response|\Illuminate\View\View
129
     */
130
    public function edit(ServiceTemplate $template)
131
    {
132
        return view(
133
            'service-template.edit', [
134
                'template' => $template,
135
                'filters' => json_encode(new QueryBuilderFilter('group')),
136
                'services' => Services::list(),
137
            ]
138
            //
139
        );
140
    }
141
142
    /**
143
     * Update the specified resource in storage.
144
     *
145
     * @param  \Illuminate\Http\Request  $request
146
     * @param  \App\Models\ServiceTemplate  $template
147
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
148
     */
149
    public function update(Request $request, ServiceTemplate $template)
150
    {
151
        $this->validate(
152
            $request, [
153
                'name' => [
154
                    'required',
155
                    'string',
156
                    Rule::unique('service_templates')->where(
157
                        function ($query) use ($template) {
158
                            $query->where('id', '!=', $template->id);
159
                        }
160
                    ),
161
                ],
162
                'type' => 'required|in:dynamic,static',
163
                'rules' => 'json|required_if:type,dynamic',
164
                'devices' => 'array',
165
                'devices.*' => 'integer',
166
                'groups' => 'array',
167
                'groups.*' => 'integer',
168
                'check' => 'string',
169
                'param' => 'nullable|string',
170
                'ip' => 'nullable|string',
171
                'desc' => 'nullable|string',
172
                'changed' => 'integer',
173
                'disabled' => 'integer',
174
                'ignore' => 'integer',
175
            ]
176
        );
177
178
        $template->fill(
179
            $request->only(
180
                [
181
                    'name',
182
                    'check',
183
                    'type',
184
                    'rules',
185
                    'param',
186
                    'ip',
187
                    'desc',
188
                    'changed',
189
                    'ignore',
190
                    'disabled',
191
                ]
192
            )
193
        );
194
195
        $devices_updated = false;
196
        if ($template->type == 'static') {
197
            // sync device_ids from input
198
            $updated = $template->devices()->sync($request->get('devices', []));
199
            // check for attached/detached/updated
200
            $devices_updated = array_sum(array_map(function ($device_ids) {
201
                return count($device_ids);
202
            }, $updated)) > 0;
203
        } elseif ($template->type == 'dynamic') {
204
            $template->rules = json_decode($request->rules);
205
        } elseif ($template->type == 'groups') {
206
            // sync device_group_ids from input
207
            $updated = $template->groups()->sync($request->get('groups', []));
208
            // check for attached/detached/updated
209
            $device_groups_updated = array_sum(array_map(function ($device_group_ids) {
210
                return count($device_group_ids);
211
            }, $updated)) > 0;
212
        }
213
214
        if ($template->isDirty() || $devices_updated || isset($device_groups_updated)) {
215
            try {
216
                if ($template->save() || $devices_updated || isset($device_groups_updated)) {
217
                    Toastr::success(__('Service Template :name updated', ['name' => $template->name]));
218
                } else {
219
                    Toastr::error(__('Failed to save'));
220
221
                    return redirect()->back()->withInput();
222
                }
223
            } catch (\Illuminate\Database\QueryException $e) {
224
                return redirect()->back()->withInput()->withErrors([
225
                    'rules' => __('Rules resulted in invalid query: ') . $e->getMessage(),
0 ignored issues
show
Are you sure __('Rules resulted in invalid query: ') of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

225
                    'rules' => /** @scrutinizer ignore-type */ __('Rules resulted in invalid query: ') . $e->getMessage(),
Loading history...
226
                ]);
227
            }
228
        } else {
229
            Toastr::info(__('No changes made'));
230
        }
231
232
        return redirect()->route('services.templates.index');
233
    }
234
235
    /**
236
     * Apply specified Service Template to Device Groups.
237
     *
238
     * @param  \App\Models\ServiceTemplate  $template
239
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
240
     */
241
    public function applyDeviceGroups(ServiceTemplate $template)
242
    {
243
        foreach (DeviceGroup::inServiceTemplate($template->id)->get() as $device_group) {
244
            foreach (Device::inDeviceGroup($device_group->id)->get() as $device) {
245
                $device->services()->updateOrCreate(
246
                    [
247
                        'service_template_id' => $template->id,
248
                    ],
249
                    [
250
                        'service_name' => $template->name,
251
                        'service_type' => $template->check,
252
                        'service_template_id' => $template->id,
253
                        'service_param' => $template->param,
254
                        'service_ip' => $template->ip,
255
                        'service_desc' => $template->desc,
256
                        'service_disabled' => $template->disabled,
257
                        'service_ignore' => $template->ignore,
258
                    ]
259
                );
260
            }
261
        }
262
        $msg = __('Services for Template :name have been updated', ['name' => $template->name]);
263
264
        return response($msg, 200);
265
    }
266
267
    /**
268
     * Apply specified Service Template to Devices.
269
     *
270
     * @param  \App\Models\ServiceTemplate  $template
271
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
272
     */
273
    public function applyDevices(ServiceTemplate $template)
274
    {
275
        foreach (Device::inServiceTemplate($template->id)->get() as $device) {
276
            $device->services()->updateOrCreate(
277
                [
278
                    'service_template_id' => $template->id,
279
                ],
280
                [
281
                    'service_name' => $template->name,
282
                    'service_type' => $template->check,
283
                    'service_template_id' => $template->id,
284
                    'service_param' => $template->param,
285
                    'service_ip' => $template->ip,
286
                    'service_desc' => $template->desc,
287
                    'service_disabled' => $template->disabled,
288
                    'service_ignore' => $template->ignore,
289
                ]
290
            );
291
        }
292
        $msg = __('Services for Template :name have been updated', ['name' => $template->name]);
293
294
        return response($msg, 200);
295
    }
296
297
    /**
298
     * Apply all Service Templates.
299
     *
300
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
301
     */
302
    public function applyAll()
303
    {
304
        foreach (ServiceTemplate::all() as $template) {
305
            $this->apply($template);
306
        }
307
        $msg = __('All Service Templates have been applied');
308
309
        return response($msg, 200);
310
    }
311
312
    /**
313
     * Apply specified Service Template.
314
     *
315
     * @param  \App\Models\ServiceTemplate  $template
316
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
317
     */
318
    public function apply(ServiceTemplate $template)
319
    {
320
        ServiceTemplateController::applyDevices($template);
0 ignored issues
show
Bug Best Practice introduced by
The method App\Http\Controllers\Ser...troller::applyDevices() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

320
        ServiceTemplateController::/** @scrutinizer ignore-call */ 
321
                                   applyDevices($template);
Loading history...
321
        ServiceTemplateController::applyDeviceGroups($template);
0 ignored issues
show
Bug Best Practice introduced by
The method App\Http\Controllers\Ser...er::applyDeviceGroups() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

321
        ServiceTemplateController::/** @scrutinizer ignore-call */ 
322
                                   applyDeviceGroups($template);
Loading history...
322
323
        // remove any remaining services no longer in the correct device group
324
        foreach (Device::notInServiceTemplate($template->id)->notInDeviceGroup($template->groups)->get() as $device) {
325
            Service::where('device_id', $device->device_id)->where('service_template_id', $template->id)->delete();
326
        }
327
        $msg = __('All Service Templates have been applied');
328
329
        return response($msg, 200);
330
    }
331
332
    /**
333
     * Remove specified Service Template.
334
     *
335
     * @param  \App\Models\ServiceTemplate  $template
336
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
337
     */
338
    public function remove(ServiceTemplate $template)
339
    {
340
        Service::where('service_template_id', $template->id)->delete();
341
342
        $msg = __('All Service Templates have been applied');
343
344
        return response($msg, 200);
345
    }
346
347
    /**
348
     * Destroy the specified resource from storage.
349
     *
350
     * @param  \App\Models\ServiceTemplate  $template
351
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\View\View
352
     */
353
    public function destroy(ServiceTemplate $template)
354
    {
355
        Service::where('service_template_id', $template->id)->delete();
356
        $template->delete();
357
358
        $msg = __('Service Template :name deleted, Services removed', ['name' => $template->name]);
359
360
        return response($msg, 200);
361
    }
362
}
363