Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0b29730e7f | ||
|
1cc854ae1f | ||
|
8d408c4704 | ||
|
eaccd5224a | ||
|
0ed83d7bc2 | ||
|
881c89bfc1 | ||
|
79cb5ceb19 | ||
|
c7ce9ac177 | ||
|
b749cdf591 | ||
|
f3a3dcb566 | ||
|
2f4f917032 | ||
|
84ef42382a | ||
|
2d5cb8cdc6 | ||
|
558d49a986 | ||
|
c1802dfb52 | ||
|
17616bad17 | ||
|
6ad2ddeb4a | ||
|
790f595f0f | ||
|
84d20bd23c | ||
|
8e1b00a6c7 | ||
|
c7ae8e0f3f | ||
702a1e7d46 | |||
|
9abc4c4961 | ||
|
065655ca7e | ||
|
1254f7015b | ||
|
b486cad1ad | ||
|
7951b8c84c | ||
|
13756de3a8 | ||
|
e166932809 | ||
|
425630ad44 | ||
|
d2ea5ab548 |
74
Dockerfile
Normal file
74
Dockerfile
Normal file
@ -0,0 +1,74 @@
|
||||
# Use PHP with Apache as the base image
|
||||
FROM php:8.3-apache
|
||||
|
||||
# Timezone
|
||||
ENV TZ="Europe/Prague"
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
RUN printf '[Date]\ndate.timezone="%s"\n', $TZ > /usr/local/etc/php/conf.d/tzone.ini
|
||||
|
||||
# PHP
|
||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||
RUN sed -i "s|memory_limit = 128M|memory_limit = 256M |g" /etc/sysctl.conf
|
||||
RUN sed -i "s|upload_max_filesize = 2M|upload_max_filesize = 100M |g" /etc/sysctl.conf
|
||||
RUN sed -i "s|post_max_size = 8M|post_max_size = 100M |g" /etc/sysctl.conf
|
||||
|
||||
# Install Additional System Dependencies
|
||||
RUN apt-get update && apt-get upgrade -y
|
||||
RUN apt-get install -y \
|
||||
libzip-dev \
|
||||
zip \
|
||||
nodejs \
|
||||
npm \
|
||||
cron \
|
||||
nano \
|
||||
default-mysql-client
|
||||
|
||||
# Clear cache
|
||||
RUN apt-get autoremove
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Enable Apache mod_rewrite for URL rewriting
|
||||
RUN a2enmod rewrite
|
||||
|
||||
# Install PHP extensions
|
||||
RUN docker-php-ext-install pdo_mysql zip
|
||||
|
||||
# Configure Apache DocumentRoot to point to Laravel's public directory
|
||||
# and update Apache configuration files
|
||||
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
|
||||
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
|
||||
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
|
||||
|
||||
# Copy the application code
|
||||
COPY . /var/www/html
|
||||
|
||||
# Install composer
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
# Install project dependencies
|
||||
RUN composer install --quiet --prefer-dist --no-dev -o
|
||||
RUN npm install && npm run build
|
||||
|
||||
# Setup Crone
|
||||
RUN mkdir -p /var/log/cron
|
||||
RUN echo "* * * * * www-data cd /var/www/html && /usr/local/bin/php artisan schedule:run >> /dev/null 2>&1" >> /etc/crontab
|
||||
RUN echo "* * * * * www-data cd /var/www/html && /usr/local/bin/php artisan queue:work --queue=default --stop-when-empty >> /dev/null 2>&1" >> /etc/crontab
|
||||
RUN echo "#" >> /etc/crontab
|
||||
|
||||
# Add a command to base-image entrypont scritp
|
||||
RUN sed -i 's/^exec /printenv > \/etc\/environment\n\nexec /' /usr/local/bin/apache2-foreground
|
||||
RUN sed -i 's/^exec /service cron start\n\nexec /' /usr/local/bin/apache2-foreground
|
||||
|
||||
#Start Container
|
||||
RUN chmod +x /var/www/html/start.sh
|
||||
CMD ["/var/www/html/start.sh"]
|
||||
|
||||
# Set the working directory
|
||||
VOLUME /var/www/html/storage/app/app
|
||||
|
||||
RUN mkdir -p /config
|
||||
VOLUME /config
|
||||
|
||||
# Start Apache
|
||||
WORKDIR /var/www/html/
|
||||
|
79
README.md
79
README.md
@ -1,66 +1,19 @@
|
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||
# Maintenance
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||
</p>
|
||||
#### Docker Build - Powershell (One Line)
|
||||
```powershell
|
||||
$tag = ("0.0.1").Trim(); Remove-Item -Path "./database/database.sqlite" -Force; Remove-Item -Path ".env" -Force; $tag | set-content -path "./public/version.txt" -Force; git reset --hard; git pull origin master; git tag $tag; git push --tags; docker build -t git.steelants.cz/jonatanrek/lar_maintenance:$tag .; docker push git.steelants.cz/jonatanrek/lar_maintenance:$tag; docker build -t git.steelants.cz/jonatanrek/lar_maintenance:latest .; docker push git.steelants.cz/jonatanrek/lar_maintenance:latest
|
||||
```
|
||||
|
||||
## About Laravel
|
||||
#### Docker Build - Bash (One Line)
|
||||
```bash
|
||||
export TAG="0.0.1" && echo "$TAG" > "./public/version.txt" && sudo docker build -t git.steelants.cz/jonatanrek/lar_maintenance:"$TAG" . && sudo docker push git.steelants.cz/jonatanrek/lar_maintenance:"$TAG" && sudo docker build -t git.steelants.cz/jonatanrek/lar_maintenance:latest . && sudo docker push git.steelants.cz/jonatanrek/lar_maintenance:latest
|
||||
```
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||
|
||||
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||
|
||||
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||
|
||||
## Learning Laravel
|
||||
|
||||
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||
|
||||
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
|
||||
|
||||
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||
|
||||
## Laravel Sponsors
|
||||
|
||||
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
|
||||
|
||||
### Premium Partners
|
||||
|
||||
- **[Vehikl](https://vehikl.com/)**
|
||||
- **[Tighten Co.](https://tighten.co)**
|
||||
- **[WebReinvent](https://webreinvent.com/)**
|
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||
- **[64 Robots](https://64robots.com)**
|
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
|
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||
- **[Jump24](https://jump24.co.uk)**
|
||||
- **[Redberry](https://redberry.international/laravel/)**
|
||||
- **[Active Logic](https://activelogic.com)**
|
||||
- **[byte5](https://byte5.de)**
|
||||
- **[OP.GG](https://op.gg)**
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||
|
||||
## License
|
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||
### TODO
|
||||
* Maintenance Relations
|
||||
* Shippable servers in maintenance
|
||||
* Zakazníci
|
||||
* Možnost comentáže pokud skipneš host/task require comment
|
||||
* zodpovědná osoba za maintenance
|
||||
* maintenance doba trvání
|
||||
|
@ -4,8 +4,14 @@ namespace App\Http\Controllers;
|
||||
|
||||
use SteelAnts\LaravelAuth\Traits\Authentication;
|
||||
|
||||
|
||||
class AuthController
|
||||
class AuthController extends Controller
|
||||
{
|
||||
use Authentication;
|
||||
|
||||
protected string $redirectTo = "maintenance.planned";
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth')->only(['logout','root']);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('home');
|
||||
}
|
||||
}
|
@ -2,10 +2,31 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Host;
|
||||
use App\Services\ZabbixService;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class HostController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('hosts.index');
|
||||
}
|
||||
|
||||
public function sync()
|
||||
{
|
||||
$zabbix = new ZabbixService(config('zabbix.url'));
|
||||
$zabbix->connect(config('zabbix.username'), config('zabbix.password'));
|
||||
|
||||
foreach ($zabbix->hosts() as $host) {
|
||||
Host::updateOrCreate([
|
||||
"hostname" => $host['host'],
|
||||
], [
|
||||
"display_name" => $host['name'],
|
||||
"external_id" => $host['hostid'],
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
24
app/Http/Controllers/HostGroupController.php
Normal file
24
app/Http/Controllers/HostGroupController.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Host;
|
||||
use App\Services\ZabbixService;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class HostGroupController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('host_groups.index');
|
||||
}
|
||||
|
||||
public function sync()
|
||||
{
|
||||
$zabbix = new ZabbixService(config('zabbix.url'));
|
||||
$zabbix->connect(config('zabbix.username'), config('zabbix.password'));
|
||||
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
@ -3,6 +3,9 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\MaintenanceHistory;
|
||||
use App\Services\ZabbixService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MaintenanceController extends BaseController
|
||||
{
|
||||
@ -18,8 +21,152 @@ class MaintenanceController extends BaseController
|
||||
|
||||
public function plannedDetail(MaintenanceHistory $maintenance_history)
|
||||
{
|
||||
|
||||
|
||||
if (!empty($maintenance_history->finished_at)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return view('maintenance.planned-detail', [
|
||||
'maintenance_history' => $maintenance_history,
|
||||
'maintenance_history' => $maintenance_history ?? [],
|
||||
]);
|
||||
}
|
||||
|
||||
public function plannedDetailPut(Request $request, MaintenanceHistory $maintenance_history)
|
||||
{
|
||||
|
||||
if (!empty($maintenance_history->finished_at)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return view('maintenance.planned-detail-done', [
|
||||
'maintenance_history' => $maintenance_history,
|
||||
'maintenance_task_status' => $request->input('maintenance_task_status') ?? [],
|
||||
'maintenance_host_skipped' => $request->input('maintenance_host_skipped') ?? [],
|
||||
]);
|
||||
}
|
||||
|
||||
public function plannedDetailFinishPost(Request $request, MaintenanceHistory $maintenance_history)
|
||||
{
|
||||
if (!empty($maintenance_history->finished_at)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
"skippedHostsSummary.*.*" => 'required|string'
|
||||
]);
|
||||
|
||||
// if ($request->has('skippedHostsSummary') || $request->has('skippedHostTasksSummary'))
|
||||
// {
|
||||
// return redirect()->back()->with('error', __('boilerplate::ui.incorect.old.password'));
|
||||
// }
|
||||
|
||||
|
||||
if ($request->has('skippedHostsSummary')) {
|
||||
foreach ($request->input('skippedHostsSummary') as $history_host_id => $summary) {
|
||||
$maintenance_history->historyHosts->find($history_host_id)->update([
|
||||
'summary' => $summary,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->has('skippedHostTasksSummary')) {
|
||||
foreach ($maintenance_history->historyHosts as $history_host) {
|
||||
if (!isset($request->input('skippedHostTasksSummary')[$history_host->id]))
|
||||
continue;
|
||||
|
||||
foreach ($request->input('skippedHostTasksSummary')[$history_host->id] as $history_task_id => $task_summary) {
|
||||
$history_host->historyTasks->find($history_task_id)->update([
|
||||
'summary' => $task_summary,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$maintenance_history->finished_at = Carbon::now();
|
||||
$maintenance_history->save();
|
||||
|
||||
return redirect()->route('maintenance.history.detail', $maintenance_history->id);
|
||||
}
|
||||
|
||||
public function history(Request $request)
|
||||
{
|
||||
return view('maintenance.history');
|
||||
}
|
||||
|
||||
public function historyDetail(Request $request, MaintenanceHistory $maintenance_history)
|
||||
{
|
||||
return view('maintenance.history-detail-done', [
|
||||
'maintenance_history' => $maintenance_history ?? []
|
||||
]);
|
||||
}
|
||||
|
||||
public function start(Request $request, MaintenanceHistory $maintenance_history)
|
||||
{
|
||||
|
||||
$hostsForMaintenance = [];
|
||||
|
||||
foreach ($maintenance_history->historyHosts as $historyHost) {
|
||||
if (empty($historyHost->host->external_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hostsForMaintenance[] = [
|
||||
"hostid" => (int) $historyHost->host->external_id,
|
||||
];
|
||||
}
|
||||
|
||||
$zabbix = new ZabbixService(config('zabbix.url'));
|
||||
$zabbix->connect(config('zabbix.username'), config('zabbix.password'));
|
||||
if (empty($maintenance_history->maintenance->external_id)) {
|
||||
$maintenance_history->maintenance->external_id = $zabbix->maintenancesCreate([
|
||||
"name" => $maintenance_history->maintenance->name . ' - ' . $maintenance_history->start_at->format('Y'),
|
||||
"description" => strip_tags($maintenance_history->maintenance->description),
|
||||
"active_since" => $maintenance_history->start_at->startofyear()->timestamp,
|
||||
"active_till" => $maintenance_history->start_at->endofyear()->timestamp,
|
||||
"tags_evaltype" => 0,
|
||||
"hosts" => $hostsForMaintenance,
|
||||
"timeperiods" => [[
|
||||
"timeperiod_type" => 0,
|
||||
"start_date" => $maintenance_history->start_at->timestamp,
|
||||
"period" => (($maintenance_history->maintenance->duration * 60) * 60),
|
||||
]],
|
||||
])['maintenanceids'][0];
|
||||
$maintenance_history->maintenance->save();
|
||||
} else {
|
||||
$createPeriode = true;
|
||||
$timePeriodes = $zabbix->maintenances([
|
||||
"selectTimeperiods" => "extend",
|
||||
'maintenanceids' => $maintenance_history->maintenance->external_id,
|
||||
])[0]['timeperiods'];
|
||||
|
||||
foreach ($timePeriodes as $periode) {
|
||||
if ((int) $periode['start_date'] === $maintenance_history->start_at->timestamp) {
|
||||
$createPeriode = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($createPeriode) {
|
||||
for ($i = 0; $i < count($timePeriodes); $i++) {
|
||||
unset($timePeriodes[$i]['every']);
|
||||
unset($timePeriodes[$i]['month']);
|
||||
unset($timePeriodes[$i]['dayofweek']);
|
||||
unset($timePeriodes[$i]['day']);
|
||||
unset($timePeriodes[$i]['start_time']);
|
||||
}
|
||||
$timePeriodes[] = [
|
||||
"timeperiod_type" => 0,
|
||||
"start_date" => $maintenance_history->start_at->timestamp,
|
||||
"period" => (($maintenance_history->maintenance->duration * 60) * 60),
|
||||
];
|
||||
|
||||
$zabbix->maintenancesUpdate([
|
||||
"maintenanceid" => $maintenance_history->maintenance->external_id,
|
||||
"timeperiods" => $timePeriodes,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class GenerateMenus
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if ($request->route()->getName() === 'livewire.message') {
|
||||
return $next($request);
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (!auth()->check()) {
|
||||
@ -26,8 +26,8 @@ class GenerateMenus
|
||||
|
||||
Menu::make('main-menu', function ($menu) {
|
||||
$systemRoutes = [
|
||||
'boilerplate::ui.home' => [' fas fa-home', 'home'],
|
||||
'boilerplate::ui.planned' => [' fas fa-home', 'maintenance.planned'],
|
||||
'ui.planned' => [' fas fa-home', 'maintenance.planned'],
|
||||
'ui.history' => [' fas fa-home', 'maintenance.history'],
|
||||
];
|
||||
|
||||
foreach ($systemRoutes as $title => $route_data) {
|
||||
@ -45,8 +45,9 @@ class GenerateMenus
|
||||
Menu::make('settings-menu', function ($menu) {
|
||||
$systemRoutes = [
|
||||
'Host' => [' fas fa-server', 'host'],
|
||||
'Host Groups' => [' fas fa-server', 'host_groups'],
|
||||
'Maintenance' => [' fas fa-calendar', 'maintenance'],
|
||||
'Tasks' => [' fas fa-calendar', 'tasks'],
|
||||
'Tasks' => [' fas fa-list', 'tasks'],
|
||||
];
|
||||
|
||||
foreach ($systemRoutes as $title => $route_data) {
|
||||
|
@ -23,6 +23,7 @@ class UpdateUserRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'email' => ['sometimes', 'string', 'email', 'max:255', 'unique:users'],
|
||||
'password' => ['sometimes', 'nullable', 'string'],
|
||||
'newPassword' => ['sometimes', 'nullable', 'string', 'min:8', 'confirmed'],
|
||||
];
|
||||
}
|
||||
|
@ -5,12 +5,14 @@ namespace App\Jobs;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\MaintenanceHistory;
|
||||
use App\Models\MaintenanceTaskHistory;
|
||||
use Carbon\Carbon;
|
||||
use Cron\CronExpression;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Poliander\Cron\CronExpression as CronCronExpression;
|
||||
|
||||
class ScheduleNextMaintenance implements ShouldQueue
|
||||
{
|
||||
@ -31,16 +33,18 @@ class ScheduleNextMaintenance implements ShouldQueue
|
||||
{
|
||||
$maintenances = Maintenance::all();
|
||||
foreach ($maintenances as $maintenance) {
|
||||
$valid = CronExpression::isValidExpression($maintenance->schedule);
|
||||
if (!$valid) {
|
||||
dd($maintenance->schedule);
|
||||
return;
|
||||
}
|
||||
$cron = new CronCronExpression($maintenance->schedule);
|
||||
$nextRunTime = Carbon::createFromTimestamp($cron->getNext());
|
||||
|
||||
if(MaintenanceHistory::where('hash', md5($maintenance->id . $nextRunTime))->first() !== null){
|
||||
continue;
|
||||
};
|
||||
|
||||
$cron = new CronExpression($maintenance->schedule);
|
||||
$maintenancePlanned = $maintenance->history()->create([
|
||||
'start_at' => $cron->getNextRunDate(null, 2)
|
||||
'start_at' => $nextRunTime,
|
||||
'guestor_id' => $maintenance->guestor_id,
|
||||
]);
|
||||
|
||||
$maintenancePlanned->refresh();
|
||||
|
||||
$hosts = $maintenance->hosts;
|
||||
@ -49,7 +53,7 @@ class ScheduleNextMaintenance implements ShouldQueue
|
||||
'host_id' => $host->id
|
||||
]);
|
||||
|
||||
$tasks = $maintenance->tasks;
|
||||
$tasks = $maintenance->hosts->find($host->id)->tasks;
|
||||
foreach ($tasks as $key => $task) {
|
||||
$maintenancePlannedHost->historyTasks()->create([
|
||||
'maintenance_task_id' => $task->id,
|
||||
@ -58,6 +62,5 @@ class ScheduleNextMaintenance implements ShouldQueue
|
||||
}
|
||||
}
|
||||
}
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace App\Livewire\Host;
|
||||
|
||||
use App\Models\Host;
|
||||
use App\Services\ZabbixService;
|
||||
use SteelAnts\DataTable\Livewire\DataTableComponent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
@ -12,15 +13,20 @@ class DataTable extends DataTableComponent
|
||||
'closeModal' => '$refresh',
|
||||
];
|
||||
|
||||
public bool $searchable = true;
|
||||
public array $searchableColumns = ['display_name', 'hostname'];
|
||||
|
||||
public function query(): Builder
|
||||
{
|
||||
return Host::query();
|
||||
return Host::query()->with(['hostGroups']);
|
||||
}
|
||||
|
||||
public function headers(): array
|
||||
{
|
||||
return [
|
||||
'display_name' => 'display_name',
|
||||
'hostname' => 'hostname',
|
||||
'host_groups' => 'host_groups',
|
||||
];
|
||||
}
|
||||
|
||||
@ -28,6 +34,12 @@ class DataTable extends DataTableComponent
|
||||
Host::find($host_id)->delete();
|
||||
}
|
||||
|
||||
|
||||
public function columnHostGroups(mixed $column): mixed
|
||||
{
|
||||
return implode(", " , $column->pluck('name')->toArray());
|
||||
}
|
||||
|
||||
public function actions($item)
|
||||
{
|
||||
return [
|
||||
|
@ -3,12 +3,16 @@ namespace App\Livewire\Host;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\Host;
|
||||
use App\Models\HostGroup;
|
||||
|
||||
class Form extends Component
|
||||
{
|
||||
public $model;
|
||||
public string $hostname;
|
||||
|
||||
public $host_groups = [];
|
||||
public $host_groups_available = [];
|
||||
|
||||
public $action = 'store';
|
||||
|
||||
protected function rules()
|
||||
@ -19,12 +23,15 @@ class Form extends Component
|
||||
}
|
||||
|
||||
public function mount ($model = null){
|
||||
$this->host_groups_available = HostGroup::pluck('name', 'id')->toArray();
|
||||
|
||||
if (!empty($model)) {
|
||||
$host = Host::find($model);
|
||||
|
||||
$this->model = $model;
|
||||
|
||||
$this->hostname = $host->hostname;
|
||||
$this->host_groups = $host->hostGroups()->pluck('host_groups.id')->toArray();
|
||||
|
||||
$this->action = 'update';
|
||||
}
|
||||
@ -33,7 +40,8 @@ class Form extends Component
|
||||
public function store()
|
||||
{
|
||||
$validatedData = $this->validate();
|
||||
Host::create($validatedData);
|
||||
$host = Host::create($validatedData);
|
||||
$host->hostGroups()->sync($this->host_groups);
|
||||
$this->dispatch('closeModal');
|
||||
}
|
||||
|
||||
@ -43,6 +51,7 @@ class Form extends Component
|
||||
$host = Host::find($this->model);
|
||||
if (!empty($host)) {
|
||||
$host->update($validatedData);
|
||||
$host->hostGroups()->sync($this->host_groups);
|
||||
}
|
||||
$this->dispatch('closeModal');
|
||||
}
|
||||
|
59
app/Livewire/HostGroup/DataTable.php
Normal file
59
app/Livewire/HostGroup/DataTable.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace App\Livewire\HostGroup;
|
||||
|
||||
use App\Models\HostGroup;
|
||||
use SteelAnts\DataTable\Livewire\DataTableComponent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class DataTable extends DataTableComponent
|
||||
{
|
||||
public $listeners = [
|
||||
'hostgroupAdded' => '$refresh',
|
||||
'closeModal' => '$refresh',
|
||||
];
|
||||
|
||||
public function query(): Builder
|
||||
{
|
||||
return HostGroup::query()->with(['hosts:id']);
|
||||
}
|
||||
|
||||
public function headers(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'name',
|
||||
'hosts_count' => 'hosts_count',
|
||||
];
|
||||
}
|
||||
|
||||
public function row($row){
|
||||
$row['hosts_count'] = $row->hosts->count();
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function remove($hostgroup_id){
|
||||
HostGroup::find($hostgroup_id)->delete();
|
||||
}
|
||||
|
||||
public function actions($item)
|
||||
{
|
||||
return [
|
||||
[
|
||||
'type' => "livewire",
|
||||
'action' => "edit",
|
||||
'text' => "edit",
|
||||
'parameters' => $item['id']
|
||||
],
|
||||
[
|
||||
'type' => "livewire",
|
||||
'action' => "remove",
|
||||
'text' => "remove",
|
||||
'parameters' => $item['id']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function edit($host_id)
|
||||
{
|
||||
$this->dispatch('openModal', 'host.form', __('boilerplate::host.edit'), ['model' => $host_id]);
|
||||
}
|
||||
}
|
54
app/Livewire/HostGroup/Form.php
Normal file
54
app/Livewire/HostGroup/Form.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace App\Livewire\HostGroup;
|
||||
|
||||
use Livewire\Component;
|
||||
use App\Models\HostGroup;
|
||||
|
||||
class Form extends Component
|
||||
{
|
||||
public $model;
|
||||
public string $name;
|
||||
|
||||
public $action = 'store';
|
||||
|
||||
protected function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount ($model = null){
|
||||
if (!empty($model)) {
|
||||
$hostGroup = HostGroup::find($model);
|
||||
|
||||
$this->model = $model;
|
||||
|
||||
$this->name = $hostGroup->name;
|
||||
|
||||
$this->action = 'update';
|
||||
}
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
$validatedData = $this->validate();
|
||||
HostGroup::create($validatedData);
|
||||
$this->dispatch('closeModal');
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
$validatedData = $this->validate();
|
||||
$hostGroup = HostGroup::find($this->model);
|
||||
if (!empty($hostGroup)) {
|
||||
$hostGroup->update($validatedData);
|
||||
}
|
||||
$this->dispatch('closeModal');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.host-group.form');
|
||||
}
|
||||
}
|
@ -22,10 +22,20 @@ class DataTable extends DataTableComponent
|
||||
return [
|
||||
'name' => 'name',
|
||||
'description' => 'description',
|
||||
'schedule' => 'schedule',
|
||||
'schedule' => 'schedule/offset',
|
||||
];
|
||||
}
|
||||
|
||||
public function renderColumnSchedule($value, $row)
|
||||
{
|
||||
return e(!empty($value) ? $value : $row['blocking_maintenance_offset']);
|
||||
}
|
||||
|
||||
public function renderColumnDescription($value, $row)
|
||||
{
|
||||
return e(!empty($value) ? mb_strimwidth(strip_tags($value), 0, 50, "...") : "");
|
||||
}
|
||||
|
||||
public function remove($maintenance_id){
|
||||
Maintenance::find($maintenance_id)->delete();
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ use Livewire\Component;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\MaintenanceTask;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Form extends Component
|
||||
{
|
||||
@ -23,19 +25,37 @@ class Form extends Component
|
||||
public $hosts_tasks = [];
|
||||
public $hosts_tasks_available = [];
|
||||
|
||||
public int $guestor_id;
|
||||
public $guestor_available = [];
|
||||
|
||||
public $blocking_maintenance_id = null;
|
||||
public $maintenances_available = [];
|
||||
|
||||
public $blocking_maintenance_offset = null;
|
||||
|
||||
public int $duration = 0;
|
||||
|
||||
protected function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
'guestor_id' => 'required|exists:users,id',
|
||||
'blocking_maintenance_id' => 'exists:maintenances,id|nullable',
|
||||
'blocking_maintenance_offset' => 'nullable',
|
||||
'description' => 'required',
|
||||
'schedule' => 'required',
|
||||
'schedule' => 'nullable',
|
||||
'duration' => 'required|max:24',
|
||||
];
|
||||
}
|
||||
|
||||
public function mount($model = null)
|
||||
public function mount(Request $request, $model = null)
|
||||
{
|
||||
$this->hosts_available = Host::all()->pluck('hostname', 'id')->toArray();
|
||||
$this->hosts_tasks_available = Task::all()->pluck('name', 'id')->toArray();
|
||||
$this->guestor_available = User::all()->pluck('name', 'id')->toArray();
|
||||
$this->maintenances_available = Maintenance::where('id', '!=', $model)->pluck('name', 'id')->toArray();
|
||||
$this->maintenances_available = [null => 'Select blocking maintenance...'] + $this->maintenances_available;
|
||||
|
||||
|
||||
if (!empty($model)) {
|
||||
$maintenance = Maintenance::find($model);
|
||||
@ -45,6 +65,11 @@ class Form extends Component
|
||||
$this->name = $maintenance->name;
|
||||
$this->description = $maintenance->description;
|
||||
$this->schedule = $maintenance->schedule;
|
||||
$this->guestor_id = $maintenance->guestor_id;
|
||||
$this->blocking_maintenance_id = $maintenance->blocking_maintenance_id ?? null;
|
||||
$this->blocking_maintenance_offset = $maintenance->blocking_maintenance_offset ?? null;
|
||||
|
||||
$this->duration = $maintenance->duration ;
|
||||
|
||||
$this->hosts = $maintenance->hosts()->pluck('hosts.id')->toArray();
|
||||
foreach ($maintenance->tasks as $task) {
|
||||
@ -52,6 +77,19 @@ class Form extends Component
|
||||
}
|
||||
|
||||
$this->action = 'update';
|
||||
} else {
|
||||
$this->guestor_id = $request->user()->id;
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedHosts($value)
|
||||
{
|
||||
foreach ($this->hosts_tasks as $host_id => $tasks) {
|
||||
if (in_array($host_id, $this->hosts)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($this->hosts_tasks[$host_id]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,8 +98,16 @@ class Form extends Component
|
||||
$validatedData = $this->validate();
|
||||
$maintenance = Maintenance::create($validatedData);
|
||||
$hosts = Host::whereIn('id', $this->hosts)->get();
|
||||
|
||||
foreach ($hosts as $key => $host) {
|
||||
$maintenance->hosts()->attach($host);
|
||||
$tasks = Task::whereIn('id', $this->hosts_tasks[$host->id])->get();
|
||||
foreach ($tasks as $task) {
|
||||
$maintenance->tasks()->create([
|
||||
'task_id' => $task->id,
|
||||
'host_id' => $host->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$this->dispatch('closeModal');
|
||||
}
|
||||
|
133
app/Livewire/Maintenance/ProgressForm.php
Normal file
133
app/Livewire/Maintenance/ProgressForm.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Maintenance;
|
||||
|
||||
use App\Models\MaintenanceHistory;
|
||||
use App\Models\MaintenanceHostHistory;
|
||||
use App\Models\MaintenanceTaskHistory;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Component;
|
||||
|
||||
class ProgressForm extends Component
|
||||
{
|
||||
public $maintenanceHistory;
|
||||
|
||||
//INPUTS
|
||||
public array $maintenance_task_status;
|
||||
public array $maintenance_task_status_old;
|
||||
public array $maintenance_host_skipped;
|
||||
|
||||
public function mount(int $maintenanceHistory)
|
||||
{
|
||||
$this->maintenanceHistory = self::getMaintenanceHistory($maintenanceHistory, true);
|
||||
if (!empty($this->maintenanceHistory->finished_at)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
foreach ($this->maintenanceHistory->historyHosts as $maintenanceHost) {
|
||||
$this->maintenance_host_skipped[$maintenanceHost->id] = (bool)$maintenanceHost->is_skipped;
|
||||
foreach ($maintenanceHost->historyTasks as $maintenanceTask) {
|
||||
$this->maintenance_task_status[$maintenanceHost->id][$maintenanceTask->id] = (!empty($maintenanceTask->finished_at) ? true : false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedMaintenanceHostSkipped($value)
|
||||
{
|
||||
$skipped = [];
|
||||
$notSkipped = [];
|
||||
|
||||
foreach ($this->maintenance_host_skipped as $host_history_id => $is_skipped) {
|
||||
if ($is_skipped === true) {
|
||||
$skipped[] = $host_history_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
$notSkipped[] = $host_history_id;
|
||||
}
|
||||
|
||||
if (count($skipped) != 0) {
|
||||
MaintenanceHostHistory::whereIn('id', $skipped)->update([
|
||||
'is_skipped' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
if (count($notSkipped) != 0) {
|
||||
MaintenanceHostHistory::whereIn('id', $notSkipped)->update([
|
||||
'is_skipped' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedMaintenanceTaskStatus($value)
|
||||
{
|
||||
foreach ($this->maintenance_task_status as $host_history_id => $tasks) {
|
||||
|
||||
$done = [];
|
||||
$notDone = [];
|
||||
|
||||
foreach ($tasks as $task_history_id => $state) {
|
||||
if (isset($this->maintenance_task_status_old[$host_history_id][$task_history_id]) && $this->maintenance_task_status_old[$host_history_id][$task_history_id] === $state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($state === true) {
|
||||
$done[] = $task_history_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
$notDone[] = $task_history_id;
|
||||
}
|
||||
|
||||
if (count($done) != 0) {
|
||||
MaintenanceTaskHistory::where('maintenance_task_histories.maintenance_host_history_id', $host_history_id)
|
||||
->where('maintenance_task_histories.status', '!=', 2)
|
||||
->whereIn('maintenance_task_histories.id', $done)
|
||||
->update([
|
||||
'maintenance_task_histories.status' => 2,
|
||||
'maintenance_task_histories.finished_at' => Carbon::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
if (count($notDone) != 0) {
|
||||
MaintenanceTaskHistory::where('maintenance_task_histories.maintenance_host_history_id', $host_history_id)
|
||||
->where('maintenance_task_histories.status', '!=', 1)
|
||||
->whereIn('maintenance_task_histories.id', $notDone)
|
||||
->update([
|
||||
'maintenance_task_histories.status' => 1,
|
||||
'maintenance_task_histories.finished_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->maintenance_task_status_old = $this->maintenance_task_status;
|
||||
}
|
||||
|
||||
|
||||
public function render()
|
||||
{
|
||||
$this->maintenanceHistory = self::getMaintenanceHistory($this->maintenanceHistory->id);
|
||||
return view('livewire.maintenance.progress-form');
|
||||
}
|
||||
|
||||
private static function getMaintenanceHistory(int $maintenanceHistoryId, bool $force = false)
|
||||
{
|
||||
if ($force){
|
||||
Cache::forget("maintenance_history_{$maintenanceHistoryId}");
|
||||
}
|
||||
|
||||
return Cache::remember("maintenance_history_{$maintenanceHistoryId}", 60, function () use ($maintenanceHistoryId) {
|
||||
return MaintenanceHistory::with([
|
||||
'maintenance.tasks',
|
||||
'maintenance.hosts',
|
||||
'historyHosts',
|
||||
'historyHosts.host',
|
||||
'historyHosts.historyTasks',
|
||||
'historyHosts.historyTasks.maintenanceTask',
|
||||
'historyHosts.historyTasks.maintenanceTask.task'
|
||||
])->find($maintenanceHistoryId);
|
||||
});
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class DataTable extends DataTableComponent
|
||||
{
|
||||
public string $type = "planned";
|
||||
|
||||
public $listeners = [
|
||||
'maintenanceHistoryAdded' => '$refresh',
|
||||
'closeModal' => '$refresh',
|
||||
@ -15,16 +17,31 @@ class DataTable extends DataTableComponent
|
||||
|
||||
public function query(): Builder
|
||||
{
|
||||
return MaintenanceHistory::query();
|
||||
$query = MaintenanceHistory::query();
|
||||
|
||||
if ($this->type == "planned") {
|
||||
$query->whereNull('finished_at');
|
||||
} elseif ($this->type == "history") {
|
||||
$query->whereNotNull('finished_at');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function headers(): array
|
||||
{
|
||||
return [
|
||||
$headers = [
|
||||
'maintenance.name' => 'maintenance.name',
|
||||
'start_at' => 'start_at',
|
||||
'finished_at' => 'finished_at',
|
||||
];
|
||||
|
||||
if ($this->type == "planned") {
|
||||
$headers['guestor.name'] = 'guestor';
|
||||
} else {
|
||||
$headers['finished_at'] = 'finished_at';
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
public function remove($maintenancehistory_id)
|
||||
@ -34,7 +51,24 @@ class DataTable extends DataTableComponent
|
||||
|
||||
public function renderColumnMaintenanceName($val, $row)
|
||||
{
|
||||
$ret = '<a href="' . route('maintenance.planned.detail', $row['id']) . '">' . e($val) . '</a>';
|
||||
if ($this->type == "planned") {
|
||||
$ret = '<a href="' . route('maintenance.planned.detail', $row['id']) . '">' . e($val) . '</a>';
|
||||
} else {
|
||||
$ret = '<a href="' . route('maintenance.history.detail', $row['id']) . '">' . e($val) . '</a>';
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function actions($item)
|
||||
{
|
||||
return [
|
||||
[
|
||||
'type' => "livewire",
|
||||
'action' => "remove",
|
||||
'text' => "remove",
|
||||
'parameters' => $item['id']
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -24,13 +24,13 @@ class Form extends Component
|
||||
|
||||
public function mount ($model = null){
|
||||
if (!empty($model)) {
|
||||
$maintenance-history = MaintenanceHistory::find($model);
|
||||
$maintenanceHistory = MaintenanceHistory::find($model);
|
||||
|
||||
$this->model = $model;
|
||||
|
||||
$this->maintenance_id = $maintenance-history->maintenance_id;
|
||||
$this->start_at = $maintenance-history->start_at;
|
||||
$this->finished_at = $maintenance-history->finished_at;
|
||||
$this->maintenance_id = $maintenanceHistory->maintenance_id;
|
||||
$this->start_at = $maintenanceHistory->start_at;
|
||||
$this->finished_at = $maintenanceHistory->finished_at;
|
||||
|
||||
$this->action = 'update';
|
||||
}
|
||||
@ -46,9 +46,9 @@ class Form extends Component
|
||||
public function update()
|
||||
{
|
||||
$validatedData = $this->validate();
|
||||
$maintenance-history = MaintenanceHistory::find($this->model);
|
||||
if (!empty($maintenance-history)) {
|
||||
$maintenance-history->update($validatedData);
|
||||
$maintenanceHistory = MaintenanceHistory::find($this->model);
|
||||
if (!empty($maintenanceHistory)) {
|
||||
$maintenanceHistory->update($validatedData);
|
||||
}
|
||||
$this->dispatch('closeModal');
|
||||
}
|
||||
|
14
app/Livewire/MaintenanceProgressForm.php
Normal file
14
app/Livewire/MaintenanceProgressForm.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class MaintenanceProgressForm extends Component
|
||||
{
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.maintenance-progress-form');
|
||||
}
|
||||
}
|
@ -25,6 +25,11 @@ class DataTable extends DataTableComponent
|
||||
];
|
||||
}
|
||||
|
||||
public function renderColumnDescription($value, $row)
|
||||
{
|
||||
return e(!empty($value) ? mb_strimwidth(strip_tags($value), 0, 50, "...") : "");
|
||||
}
|
||||
|
||||
public function remove($task_id){
|
||||
Task::find($task_id)->delete();
|
||||
}
|
||||
|
@ -11,10 +11,17 @@ class Host extends Model
|
||||
|
||||
protected $fillable = [
|
||||
'hostname',
|
||||
'display_name',
|
||||
'external_id',
|
||||
];
|
||||
|
||||
public function tasks()
|
||||
{
|
||||
return $this->hasMany(MaintenanceTask::class,);
|
||||
return $this->hasMany(MaintenanceTask::class);
|
||||
}
|
||||
|
||||
public function hostGroups()
|
||||
{
|
||||
return $this->belongsToMany(HostGroup::class)->using(HostHostGroup::class);
|
||||
}
|
||||
}
|
||||
|
21
app/Models/HostGroup.php
Normal file
21
app/Models/HostGroup.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class HostGroup extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'external_id',
|
||||
];
|
||||
|
||||
public function hosts()
|
||||
{
|
||||
return $this->belongsToMany(Host::class)->using(HostHostGroup::class);
|
||||
}
|
||||
}
|
10
app/Models/HostHostGroup.php
Normal file
10
app/Models/HostHostGroup.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class HostHostGroup extends Pivot
|
||||
{
|
||||
//
|
||||
}
|
@ -13,6 +13,11 @@ class Maintenance extends Model
|
||||
'name',
|
||||
'description',
|
||||
'schedule',
|
||||
'guestor_id',
|
||||
'blocking_maintenance_id',
|
||||
'duration',
|
||||
'blocking_maintenance_offset',
|
||||
'external_id',
|
||||
];
|
||||
|
||||
public function hosts()
|
||||
@ -29,4 +34,9 @@ class Maintenance extends Model
|
||||
{
|
||||
return $this->hasMany(MaintenanceTask::class,);
|
||||
}
|
||||
|
||||
public function guestor()
|
||||
{
|
||||
return $this->BelongsTo(User::class, 'guestor_id');
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Observers\MaintenanceHistoryObserver;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
@ -13,8 +14,19 @@ class MaintenanceHistory extends Model
|
||||
'maintenance_id',
|
||||
'start_at',
|
||||
'finished_at',
|
||||
'guestor_id',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'start_at' => 'datetime',
|
||||
'finished_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
MaintenanceHistory::observe(MaintenanceHistoryObserver::class);
|
||||
}
|
||||
|
||||
public function maintenance()
|
||||
{
|
||||
return $this->BelongsTo(Maintenance::class);
|
||||
@ -24,4 +36,9 @@ class MaintenanceHistory extends Model
|
||||
{
|
||||
return $this->hasMany(MaintenanceHostHistory::class);
|
||||
}
|
||||
|
||||
public function guestor()
|
||||
{
|
||||
return $this->BelongsTo(User::class, 'guestor_id');
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,12 @@ class MaintenanceHostHistory extends Model
|
||||
protected $fillable = [
|
||||
'maintenance_history_id',
|
||||
'host_id',
|
||||
'summary',
|
||||
'is_skipped',
|
||||
];
|
||||
|
||||
protected $cast = [
|
||||
'is_skipped' => 'bool'
|
||||
];
|
||||
|
||||
public function host()
|
||||
|
@ -8,11 +8,12 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class MaintenanceTaskHistory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
|
||||
protected $fillable = [
|
||||
'maintenance_task_id',
|
||||
'maintenance_history_id',
|
||||
'maintenance_host_history_id',
|
||||
'summary',
|
||||
];
|
||||
|
||||
public function maintenance()
|
||||
@ -24,4 +25,5 @@ class MaintenanceTaskHistory extends Model
|
||||
{
|
||||
return $this->belongsTo(MaintenanceTask::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
18
app/Observers/MaintenanceHistoryObserver.php
Normal file
18
app/Observers/MaintenanceHistoryObserver.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\MaintenanceHistory;
|
||||
|
||||
class MaintenanceHistoryObserver
|
||||
{
|
||||
public function creating(MaintenanceHistory $maintenanceHistory): void
|
||||
{
|
||||
$maintenanceHistory->hash = md5($maintenanceHistory->maintenance_id . $maintenanceHistory->start_at);
|
||||
}
|
||||
|
||||
public function updating(MaintenanceHistory $maintenanceHistory): void
|
||||
{
|
||||
$maintenanceHistory->hash = md5($maintenanceHistory->maintenance_id . $maintenanceHistory->start_at);
|
||||
}
|
||||
}
|
112
app/Services/ZabbixService.php
Normal file
112
app/Services/ZabbixService.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class ZabbixService
|
||||
{
|
||||
public string $token = "";
|
||||
public string $url = "";
|
||||
public int $id = 1;
|
||||
|
||||
function __construct($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function connect($username, $password)
|
||||
{
|
||||
$this->token = $this->request([
|
||||
"jsonrpc" => "2.0",
|
||||
"method" => "user.login",
|
||||
"params" => [
|
||||
"username" => $username,
|
||||
"password" => $password,
|
||||
],
|
||||
"id" => $this->id,
|
||||
"auth" => null,
|
||||
]);
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
public function hosts($params = [])
|
||||
{
|
||||
return $this->request([
|
||||
"jsonrpc" => "2.0",
|
||||
"method" => "host.get",
|
||||
"params" => $params,
|
||||
"id" => $this->id,
|
||||
"auth" => $this->token,
|
||||
]);
|
||||
}
|
||||
|
||||
public function hostGroups($params = [])
|
||||
{
|
||||
return $this->request([
|
||||
"jsonrpc" => "2.0",
|
||||
"method" => "hostgroup.get",
|
||||
"params" => $params,
|
||||
"id" => $this->id,
|
||||
"auth" => $this->token,
|
||||
]);
|
||||
}
|
||||
|
||||
public function maintenances($params = [])
|
||||
{
|
||||
return $this->request([
|
||||
"jsonrpc" => "2.0",
|
||||
"method" => "maintenance.get",
|
||||
"params" => $params,
|
||||
"id" => $this->id,
|
||||
"auth" => $this->token,
|
||||
]);
|
||||
}
|
||||
|
||||
public function maintenancesCreate($params = [])
|
||||
{
|
||||
return $this->request([
|
||||
"jsonrpc" => "2.0",
|
||||
"method" => "maintenance.create",
|
||||
"params" => $params,
|
||||
"id" => $this->id,
|
||||
"auth" => $this->token,
|
||||
]);
|
||||
}
|
||||
|
||||
public function maintenancesUpdate( $params = [])
|
||||
{
|
||||
return $this->request([
|
||||
"jsonrpc" => "2.0",
|
||||
"method" => "maintenance.update",
|
||||
"params" => $params,
|
||||
"id" => $this->id,
|
||||
"auth" => $this->token,
|
||||
]);
|
||||
}
|
||||
|
||||
/*Helpers*/
|
||||
|
||||
private function request($body = [])
|
||||
{
|
||||
if (empty($this->token) && $body['auth'] != null) {
|
||||
throw new Exception("you need to connect first", 1);
|
||||
}
|
||||
|
||||
$response = Http::withoutVerifying()->post($this->url . "/api_jsonrpc.php", $body);
|
||||
|
||||
if (!$response->successful()) {
|
||||
throw new Exception("Unable To Request", 1);
|
||||
}
|
||||
|
||||
$responseObject = $response->json();
|
||||
if (isset($responseObject['error'])) {
|
||||
throw new Exception($responseObject['error']['data'], $responseObject['error']['code']);
|
||||
}
|
||||
|
||||
$this->id++;
|
||||
return is_array($responseObject["result"]) ? collect($responseObject["result"]) : $responseObject["result"];
|
||||
}
|
||||
}
|
@ -6,10 +6,10 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"dragonmantank/cron-expression": "^3.3",
|
||||
"laravel/framework": "^11.9",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.9",
|
||||
"poliander/cron": "^3.1",
|
||||
"steelants/laravel-boilerplate": "^1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
|
603
composer.lock
generated
603
composer.lock
generated
File diff suppressed because it is too large
Load Diff
7
config/zabbix.php
Normal file
7
config/zabbix.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'url' => env('ZBX_URL', ''),
|
||||
'username' => env('ZBX_USERNAME', ''),
|
||||
'password' => env('ZBX_PASSWORD', ''),
|
||||
];
|
@ -22,6 +22,7 @@ return new class extends Migration
|
||||
$table->foreignIdFor(MaintenanceHostHistory::class);
|
||||
$table->string('status')->default(1);
|
||||
$table->datetime('finished_at')->nullable();
|
||||
$table->text('summary')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ return new class extends Migration
|
||||
$table->id();
|
||||
$table->foreignIdFor(MaintenanceHistory::class);
|
||||
$table->foreignIdFor(Host::class);
|
||||
$table->text('summary')->nullable();
|
||||
$table->boolean('is_skipped')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('maintenances', function (Blueprint $table) {
|
||||
$table->foreignIdFor(User::class, 'guestor_id');
|
||||
$table->foreignIdFor(Maintenance::class, 'blocking_maintenance_id')->nullable();
|
||||
$table->string('blocking_maintenance_offset')->nullable();
|
||||
$table->integer('duration');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('maintenances', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('maintenance_histories', function (Blueprint $table) {
|
||||
$table->foreignIdFor(User::class, 'guestor_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('maintenance_histories', function (Blueprint $table) {
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('maintenance_histories', function (Blueprint $table) {
|
||||
$table->string('hash');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
}
|
||||
};
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('hosts', function (Blueprint $table) {
|
||||
$table->string('display_name')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
}
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('hosts', function (Blueprint $table) {
|
||||
$table->string('external_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('hosts', function (Blueprint $table) {
|
||||
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('maintenances', function (Blueprint $table) {
|
||||
$table->string('external_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('maintenances', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('maintenance_histories', function (Blueprint $table) {
|
||||
$table->string('external_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('maintenance_histories', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('host_groups', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('external_id')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('host_groups');
|
||||
}
|
||||
};
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use App\Models\HostGroup;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('hosts', function (Blueprint $table) {
|
||||
$table->foreignIdFor(HostGroup::class, 'host_group_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('hosts', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Host;
|
||||
use App\Models\HostGroup;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('host_host_group', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Host::class, 'host_id')->nullable();
|
||||
$table->foreignIdFor(HostGroup::class, 'host_group_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('host_host_group');
|
||||
}
|
||||
};
|
@ -14,7 +14,7 @@ class DatabaseSeeder extends Seeder
|
||||
public function run(): void
|
||||
{
|
||||
// User::factory(10)->create();
|
||||
if (empty(User::where('email', 'test@example.co')->first())){
|
||||
if (empty(User::where('email', 'test@example.com')->first())){
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
|
7
lang/en/ui.php
Normal file
7
lang/en/ui.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'dashboard' => 'Dashboard',
|
||||
'planned' => 'Planned',
|
||||
'history' => 'History',
|
||||
];
|
1
public/version.txt
Normal file
1
public/version.txt
Normal file
@ -0,0 +1 @@
|
||||
0.0.1
|
@ -1,189 +0,0 @@
|
||||
<x-layout-app>
|
||||
<div class="container-xl">
|
||||
<div class="page-header">
|
||||
<h1>Welcolm Back !</h1>
|
||||
<a class="btn btn-primary" href="{{ url('home') }}"><i class="fa fa-plus me-2"></i> Page Action</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-xl">
|
||||
|
||||
<h1>head 1</h1>
|
||||
<h2>head 2</h2>
|
||||
<h3>head 3</h3>
|
||||
<h4>head 4</h4>
|
||||
<h5>head 5</h5>
|
||||
<h6>head 6</h6>
|
||||
|
||||
<div class="my-4">
|
||||
<h4>Tabs</h4>
|
||||
<ul class="nav nav-tabs mb-4">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">Active</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav nav-pills">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">Active</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="my-4 d-flex">
|
||||
<div class="app-nav-profile random-bg-1">
|
||||
PS
|
||||
</div>
|
||||
<div class="app-nav-profile random-bg-2">
|
||||
PS
|
||||
</div>
|
||||
<div class="app-nav-profile random-bg-3">
|
||||
PS
|
||||
</div>
|
||||
<div class="app-nav-profile random-bg-4">
|
||||
PS
|
||||
</div>
|
||||
<div class="app-nav-profile random-bg-5">
|
||||
PS
|
||||
</div>
|
||||
<div class="app-nav-profile random-bg-6">
|
||||
PS
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<h4>Buttons</h4>
|
||||
<button type="button" class="btn btn-primary">Primary</button>
|
||||
<button type="button" class="btn btn-secondary">Secondary</button>
|
||||
<button type="button" class="btn btn-success">Success</button>
|
||||
<button type="button" class="btn btn-danger">Danger</button>
|
||||
<button type="button" class="btn btn-warning">Warning</button>
|
||||
<button type="button" class="btn btn-info">Info</button>
|
||||
<button type="button" class="btn btn-light">Light</button>
|
||||
<button type="button" class="btn btn-dark">Dark</button>
|
||||
<button type="button" class="btn">Button</button>
|
||||
<button type="button" class="btn btn-link">Link</button>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<h4>Badges</h4>
|
||||
<span class="badge text-bg-primary">Primary</span>
|
||||
<span class="badge text-bg-secondary">Secondary</span>
|
||||
<span class="badge text-bg-success">Success</span>
|
||||
<span class="badge text-bg-danger">Danger</span>
|
||||
<span class="badge text-bg-warning">Warning</span>
|
||||
<span class="badge text-bg-info">Info</span>
|
||||
<span class="badge text-bg-light">Light</span>
|
||||
<span class="badge text-bg-dark">Dark</span>
|
||||
<br>
|
||||
<span class="badge rounded-pill text-bg-primary">Primary</span>
|
||||
<span class="badge rounded-pill text-bg-secondary">Secondary</span>
|
||||
<span class="badge rounded-pill text-bg-success">Success</span>
|
||||
<span class="badge rounded-pill text-bg-danger">Danger</span>
|
||||
<span class="badge rounded-pill text-bg-warning">Warning</span>
|
||||
<span class="badge rounded-pill text-bg-info">Info</span>
|
||||
<span class="badge rounded-pill text-bg-light">Light</span>
|
||||
<span class="badge rounded-pill text-bg-dark">Dark</span>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<h4>Breadcrumbs</h4>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item active" aria-current="page">Home</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="#">Home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Library</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="#">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="#">Library</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Data</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<h4>Alerts</h4>
|
||||
<div class="alert alert-primary" role="alert">
|
||||
A simple primary alert—check it out!
|
||||
</div>
|
||||
<div class="alert alert-secondary" role="alert">
|
||||
A simple secondary alert—check it out!
|
||||
</div>
|
||||
<div class="alert alert-success" role="alert">
|
||||
A simple success alert—check it out!
|
||||
</div>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
A simple danger alert—check it out!
|
||||
</div>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
A simple warning alert—check it out!
|
||||
</div>
|
||||
<div class="alert alert-info" role="alert">
|
||||
A simple info alert—check it out!
|
||||
</div>
|
||||
<div class="alert alert-light" role="alert">
|
||||
A simple light alert—check it out!
|
||||
</div>
|
||||
<div class="alert alert-dark" role="alert">
|
||||
A simple dark alert—check it out!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<h4>Pagination</h4>
|
||||
<nav aria-label="...">
|
||||
<ul class="pagination">
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link">Previous</a>
|
||||
</li>
|
||||
<li class="page-item"><a class="page-link" href="#">1</a></li>
|
||||
<li class="page-item active" aria-current="page">
|
||||
<a class="page-link" href="#">2</a>
|
||||
</li>
|
||||
<li class="page-item"><a class="page-link" href="#">3</a></li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<h4>Colors</h4>
|
||||
<div class="text-bg-primary p-3">Primary with contrasting color</div>
|
||||
<div class="text-bg-secondary p-3">Secondary with contrasting color</div>
|
||||
<div class="text-bg-success p-3">Success with contrasting color</div>
|
||||
<div class="text-bg-danger p-3">Danger with contrasting color</div>
|
||||
<div class="text-bg-warning p-3">Warning with contrasting color</div>
|
||||
<div class="text-bg-info p-3">Info with contrasting color</div>
|
||||
<div class="text-bg-light p-3">Light with contrasting color</div>
|
||||
<div class="text-bg-dark p-3">Dark with contrasting color</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout-app>
|
20
resources/views/host_groups/index.blade.php
Normal file
20
resources/views/host_groups/index.blade.php
Normal file
@ -0,0 +1,20 @@
|
||||
<x-layout-app>
|
||||
<div class="container-xl">
|
||||
<div class="page-header">
|
||||
<h1>{{ __('boilerplate::host_groups.title') }}</h1>
|
||||
|
||||
<div>
|
||||
<a class="btn btn-primary" href="{{ route('host.sync') }}">
|
||||
<i class="me-2 fas fa-sync-alt"></i><span>{{ __('boilerplate::ui.sync') }}</span>
|
||||
</a>
|
||||
|
||||
<button class="btn btn-primary"
|
||||
onclick="Livewire.dispatch('openModal', {livewireComponents: 'host_group.form', title: '{{ __('boilerplate::host_group.create') }}'})">
|
||||
<i class="me-2 fas fa-plus"></i><span>{{ __('boilerplate::ui.add') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('host_group.data-table', [], key('data-table'))
|
||||
</div>
|
||||
</x-layout-app>
|
@ -3,9 +3,16 @@
|
||||
<div class="page-header">
|
||||
<h1>{{ __('boilerplate::hosts.title') }}</h1>
|
||||
|
||||
<button class="btn btn-primary" onclick="Livewire.dispatch('openModal', {livewireComponents: 'host.form', title: '{{ __('boilerplate::host.create') }}'})">
|
||||
<i class="me-2 fas fa-plus"></i><span>{{ __('boilerplate::ui.add') }}</span>
|
||||
</button>
|
||||
<div>
|
||||
<a class="btn btn-primary" href="{{ route('host.sync') }}">
|
||||
<i class="me-2 fas fa-sync-alt"></i><span>{{ __('boilerplate::ui.sync') }}</span>
|
||||
</a>
|
||||
|
||||
<button class="btn btn-primary"
|
||||
onclick="Livewire.dispatch('openModal', {livewireComponents: 'host.form', title: '{{ __('boilerplate::host.create') }}'})">
|
||||
<i class="me-2 fas fa-plus"></i><span>{{ __('boilerplate::ui.add') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('host.data-table', [], key('data-table'))
|
||||
|
6
resources/views/livewire/host-group/form.blade.php
Normal file
6
resources/views/livewire/host-group/form.blade.php
Normal file
@ -0,0 +1,6 @@
|
||||
<div>
|
||||
<x-form::form wire:submit.prevent="{{$action}}">
|
||||
<x-form::input group-class="mb-3" type="text" wire:model="name" id="name" label="name"/>
|
||||
<x-form::button class="btn-primary" type="submit">Create</x-form::button>
|
||||
</x-form::form>
|
||||
</div>
|
@ -1,6 +1,7 @@
|
||||
<div>
|
||||
<x-form::form wire:submit.prevent="{{$action}}">
|
||||
<x-form::input group-class="mb-3" type="text" wire:model="hostname" id="hostname" label="hostname"/>
|
||||
<x-form::select group-class="mb-3" wire:model.live="host_groups" label="Select groups for Host" :options="$host_groups_available" placeholder="Select value..." multiple />
|
||||
<x-form::button class="btn-primary" type="submit">Create</x-form::button>
|
||||
</x-form::form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,15 +1,23 @@
|
||||
<div>
|
||||
<x-form::form wire:submit.prevent="{{ $action }}">
|
||||
<x-form::input group-class="mb-3" type="text" wire:model="name" id="name" label="name" />
|
||||
<x-form::select group-class="mb-3" wire:model="guestor_id" label="Responsible User" :options="$guestor_available" placeholder="Select guestor..." />
|
||||
<x-form::select group-class="mb-3" wire:model.live="blocking_maintenance_id" label="Blocking Maintenance" :options="$maintenances_available" placeholder="Select blocking maintenance..." />
|
||||
<x-form::quill group-class="mb-3" type="text" wire:model="description" id="description" label="description" />
|
||||
|
||||
@if(empty($blocking_maintenance_id))
|
||||
<x-form::input group-class="mb-3" type="text" wire:model="schedule" id="schedule" label="schedule" />
|
||||
<x-form::select group-class="mb-3" wire:model.live="hosts" label="Livewire Select" :options="$hosts_available" placeholder="Select value..." multiple />
|
||||
|
||||
@else
|
||||
<x-form::input group-class="mb-3" type="text" wire:model="blocking_maintenance_offset" id="blocking_maintenance_offset" label="blocking_maintenance_offset" help="you can use foloving shortcodes (w - weeks, m - months, d - days)" />
|
||||
@endif
|
||||
|
||||
<x-form::input group-class="mb-3" type="text" wire:model="duration" id="duration" label="duration" help="in hours (60 minutes) maximum 24h" />
|
||||
<x-form::select group-class="mb-3" wire:model.live="hosts" label="Hosts in Maintenance" :options="$hosts_available" placeholder="Select value..." multiple />
|
||||
|
||||
@foreach($hosts as $key => $host_id)
|
||||
<x-form::select group-class="mb-3" wire:model="hosts_tasks.{{ $host_id }}" label="Select Tasks for Host {{ $hosts_available[$host_id] }}" :options="$hosts_tasks_available" placeholder="Select value..." multiple />
|
||||
<x-form::select group-class="mb-3" wire:key="{{ $host_id }}" wire:model="hosts_tasks.{{ $host_id }}" label="Select Tasks for Host {{ $hosts_available[$host_id] }}" :options="$hosts_tasks_available" placeholder="Select value..." multiple />
|
||||
@endforeach
|
||||
|
||||
|
||||
<x-form::button class="btn-primary" type="submit">Create</x-form::button>
|
||||
@dump($hosts_tasks)
|
||||
</x-form::form>
|
||||
</div>
|
||||
</div>
|
22
resources/views/livewire/maintenance/progress-form.blade.php
Normal file
22
resources/views/livewire/maintenance/progress-form.blade.php
Normal file
@ -0,0 +1,22 @@
|
||||
<div>
|
||||
@foreach ($maintenanceHistory->historyHosts as $historyHost)
|
||||
<div class="mb-3">
|
||||
<div class="position-relative">
|
||||
<div class="btn-toggle btn py-3 bg-primary w-100 text-start" style="--bs-bg-opacity: .2;" data-bs-toggle="collapse" data-bs-target="#collapse{{ $historyHost->id }}">
|
||||
<b>{{ $historyHost->host->hostname }}</b>
|
||||
</div>
|
||||
<div class="position-absolute top-50 end-0 translate-middle-y px-3 py-2">
|
||||
<x-form::checkbox groupClass="ms-auto" wire:key="{{ $historyHost->id . 'skip' }}" wire:model.live.debounce.250ms="maintenance_host_skipped.{{ $historyHost->id }}" name="maintenance_host_skipped[{{ $historyHost->id }}]" id="maintenance_host_skipped-{{ $historyHost->id }}" label="{{ __('Skip') }}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse" id="collapse{{ $historyHost->id }}" wire:ignore.self>
|
||||
<div class="card card-body mt-2">
|
||||
@foreach ($historyHost->historyTasks as $historyTask)
|
||||
<x-form::checkbox wire:key="{{ $historyHost->id . $historyTask->id }}" wire:model.live.debounce.250ms="maintenance_task_status.{{ $historyHost->id }}.{{ $historyTask->id }}" name="maintenance_task_status[{{ $historyHost->id }}][{{ $historyTask->id }}]" id="maintenance_task_status-{{ $historyHost->id }}-{{ $historyTask->id }}" label="{{ $historyTask->maintenanceTask->task->name }}" />
|
||||
<p>{!! $historyTask->maintenanceTask->task->description !!}</p>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
37
resources/views/maintenance/history-detail-done.blade.php
Normal file
37
resources/views/maintenance/history-detail-done.blade.php
Normal file
@ -0,0 +1,37 @@
|
||||
<x-layout-app>
|
||||
<div class="container-xl">
|
||||
<div class="page-header">
|
||||
<h1>{{ $maintenance_history->maintenance->name }}</h1>
|
||||
</div>
|
||||
<p>{!! $maintenance_history->maintenance->description !!}</p>
|
||||
@foreach ($maintenance_history->historyHosts as $historyHost)
|
||||
<h2>
|
||||
@if (empty($historyHost->summary))
|
||||
<i class="fas fa-check text-success"></i>
|
||||
@else
|
||||
<i class="fas fa-times text-danger"></i>
|
||||
@endif{{ $historyHost->host->hostname }}
|
||||
</h2>
|
||||
@if (!empty($historyHost->summary))
|
||||
<b>{{ __('Oduvodnění') }}</b>
|
||||
<p>{!! $historyHost->summary !!}</p>
|
||||
@endif
|
||||
@foreach ($historyHost->historyTasks as $historyTask)
|
||||
<h3>
|
||||
@if (empty($historyTask->summary))
|
||||
<i class="fas fa-check text-success"></i>
|
||||
@else
|
||||
<i class="fas fa-times text-danger"></i>
|
||||
@endif
|
||||
{{ $historyTask->maintenanceTask->task->name }}
|
||||
</h3>
|
||||
@if (!empty($historyTask->summary))
|
||||
<b>{{ __('Oduvodnění') }}</b>
|
||||
<p>{!! $historyTask->summary !!}</p>
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
<hr>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-layout-app>
|
9
resources/views/maintenance/history.blade.php
Normal file
9
resources/views/maintenance/history.blade.php
Normal file
@ -0,0 +1,9 @@
|
||||
<x-layout-app>
|
||||
<div class="container-xl">
|
||||
<div class="page-header">
|
||||
<h1>{{ __('History') }}</h1>
|
||||
</div>
|
||||
|
||||
@livewire('maintenance-history.data-table', ['type' => 'history'], key('data-table'))
|
||||
</div>
|
||||
</x-layout-app>
|
24
resources/views/maintenance/planned-detail-done.blade.php
Normal file
24
resources/views/maintenance/planned-detail-done.blade.php
Normal file
@ -0,0 +1,24 @@
|
||||
<x-layout-app>
|
||||
<div class="container-xl">
|
||||
<div class="page-header">
|
||||
<h1>{{ __('Planned Maintenance') }}</h1>
|
||||
</div>
|
||||
<p>{!! $maintenance_history->maintenance->description !!}</p>
|
||||
<x-form::form action="{{ route('maintenance.planned.finished', ['maintenance_history' => $maintenance_history->id]) }}" method="POST">
|
||||
@foreach ($maintenance_history->historyHosts as $historyHost)
|
||||
@if (in_array($historyHost->id, array_keys($maintenance_host_skipped)))
|
||||
<x-form::quill required label="{{ __('Reason for Skipping Host: ') . $historyHost->host->hostname}}" id="skipped-host-{{ $historyHost->id }}-summary" name="skippedHostsSummary[{{ $historyHost->id }}]" help="{{ __('Describe why did you skipped the host') }}" />
|
||||
@else
|
||||
@foreach ($historyHost->historyTasks as $historyTask)
|
||||
@if (!isset($maintenance_task_status[$historyHost->id][$historyTask->id]))
|
||||
<x-form::quill required label="{{ __('Reason for Skipping Task: ') . $historyTask->maintenanceTask->name}}" id="skipped-host-{{ $historyHost->id }}-task-{{ $historyTask->id }}-summary" name="skippedHostTasksSummary[{{ $historyHost->id }}][{{ $historyTask->id }}]" help="{{ __('Describe why did you not finished the task') }}" />
|
||||
@else
|
||||
<x-form::checkbox onclick="return false" checked="{{ isset($maintenance_task_status[$historyHost->id][$historyTask->id]) ? 'checked' : '' }}" label="{{ $historyTask->maintenanceTask->task->name }}" name="test-{{ $historyHost->id }}-{{ $historyTask->id }}" />
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endforeach
|
||||
<x-form::button class="btn-primary" type="submit">{{ __('Ukončit Maintenance') }}</x-form::button>
|
||||
</x-form::form>
|
||||
</div>
|
||||
</x-layout-app>
|
@ -2,25 +2,14 @@
|
||||
<div class="container-xl">
|
||||
<div class="page-header">
|
||||
<h1>{{ __('Planned Maintenance') }}</h1>
|
||||
<a class="btn btn-primary" href="{{ route('maintenance.start', ['maintenance_history' => $maintenance_history->id]) }}" disabled>
|
||||
<i class="me-2 fas fa-play"></i><span>{{ __('Zahájit') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<p>{!! $maintenance_history->maintenance->description !!}</p>
|
||||
<x-form::form action="save" method="PUT">
|
||||
@foreach ($maintenance_history->historyHosts as $historyHost)
|
||||
<div class="mb-3">
|
||||
<div class="btn-toggle btn py-3 w-100 bg-primary text-start" style="--bs-bg-opacity: .2;" data-bs-toggle="collapse" data-bs-target="#collapse{{ $historyHost->id }}">
|
||||
<b>{{ $historyHost->host->hostname }}</b>
|
||||
</div>
|
||||
<div class="collapse" id="collapse{{ $historyHost->id }}">
|
||||
<div class="card card-body mt-2">
|
||||
@foreach ($historyHost->historyTasks as $historyTasks)
|
||||
<x-form::checkbox wire:model="test" label="{{$historyTasks->maintenanceTask->task->name}}" />
|
||||
<p>{!! $historyTasks->maintenanceTask->task->description !!}</p>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
<x-form::button class="btn-primary" type="submit">{{ __('Ukončit')}}</x-form::button>
|
||||
<x-form::form action="{{ route('maintenance.planned.detail.put', ['maintenance_history' => $maintenance_history->id]) }}" method="PUT">
|
||||
@livewire('maintenance.progress-form', ['maintenanceHistory' => $maintenance_history->id], key('progress-form'))
|
||||
<x-form::button class="btn-primary" type="submit">{{ __('Pokračovat') }}</x-form::button>
|
||||
</x-form::form>
|
||||
</div>
|
||||
</x-layout-app>
|
||||
</x-layout-app>
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,18 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::auth();
|
||||
Route::get('/', function () {
|
||||
return view('welcome');
|
||||
if (Auth::check()){
|
||||
return redirect()->route('maintenance.planned');
|
||||
}
|
||||
return redirect()->route('login');
|
||||
});
|
||||
|
||||
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
|
||||
Route::get('/maintenance/planned', [App\Http\Controllers\MaintenanceController::class, 'planned'])->name('maintenance.planned');
|
||||
Route::get('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetail'])->name('maintenance.planned.detail');
|
||||
Route::put('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetailPut'])->name('maintenance.planned.detail.put');
|
||||
Route::get('/maintenance/planned/{maintenance_history}/start', [App\Http\Controllers\MaintenanceController::class, 'start'])->name('maintenance.start');
|
||||
Route::post('/maintenance/planned/{maintenance_history}/finished', [App\Http\Controllers\MaintenanceController::class, 'plannedDetailFinishPost'])->name('maintenance.planned.finished');
|
||||
Route::get('/maintenance/history/', [App\Http\Controllers\MaintenanceController::class, 'history'])->name('maintenance.history');
|
||||
Route::get('/maintenance/history/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'historyDetail'])->name('maintenance.history.detail');
|
||||
|
||||
|
||||
Route::get('/host', [App\Http\Controllers\HostController::class, 'index'])->name('host');
|
||||
Route::get('/host/sync', [App\Http\Controllers\HostController::class, 'sync'])->name('host.sync');
|
||||
Route::get('/host_groups', [App\Http\Controllers\HostGroupController::class, 'index'])->name('host_groups');
|
||||
|
||||
Route::get('/maintenance', [App\Http\Controllers\MaintenanceController::class, 'index'])->name('maintenance');
|
||||
Route::get('/tasks', [App\Http\Controllers\TaskController::class, 'index'])->name('tasks');
|
||||
|
||||
|
55
start.sh
Normal file
55
start.sh
Normal file
@ -0,0 +1,55 @@
|
||||
# Install project dependencies
|
||||
init=false
|
||||
if ! test -f /config/.env; then
|
||||
# Create Env File
|
||||
cp .env.example .env
|
||||
php artisan key:generate
|
||||
|
||||
cp .env /config/.env
|
||||
|
||||
init=true
|
||||
echo "Initialization"
|
||||
else
|
||||
cp /config/.env .env
|
||||
fi
|
||||
|
||||
if [ $(grep -ic "DB_CONNECTION=sqlite" /var/www/html/.env) -gt 0 ] || [ "${DEPLOY_ENV}" == "sqlite"]; then
|
||||
if ! test -f "/var/www/html/database/database.sqlite" ; then
|
||||
echo " DB Initialization"
|
||||
init=true
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Migrate Database
|
||||
php artisan migrate --force --no-interaction
|
||||
|
||||
# Link storage and create default user
|
||||
if [ "$init" = true ]; then
|
||||
echo "Initialization of Laravel"
|
||||
|
||||
# Install project build dependencies
|
||||
composer install --quiet --prefer-dist-o
|
||||
|
||||
php artisan db:seed --force --class=DatabaseSeeder
|
||||
php artisan storage:link
|
||||
|
||||
#clear build dependencies and install production dependencies
|
||||
rm -rf vendor/*
|
||||
composer install --quiet --prefer-dist --no-dev -o
|
||||
fi
|
||||
|
||||
# Clear Cashes
|
||||
php artisan cache:clear
|
||||
php artisan config:clear
|
||||
php artisan route:clear
|
||||
php artisan view:clear
|
||||
|
||||
# fix permissions
|
||||
chown -R www-data:www-data /var/www/html
|
||||
find /var/www/html -type f -not -name "*.sh" -exec chmod 664 {} +
|
||||
find /var/www/html -type d -exec chmod 775 {} +
|
||||
|
||||
# Start Apache
|
||||
apache2-foreground
|
||||
|
3
storage/app/.gitignore
vendored
3
storage/app/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
*
|
||||
!public/
|
||||
!.gitignore
|
2
storage/app/public/.gitignore
vendored
2
storage/app/public/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
BIN
storage/app/public/images/logo.png
Normal file
BIN
storage/app/public/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
Loading…
x
Reference in New Issue
Block a user