Compare commits
1 commit
master
...
phpstan-re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8200dbbd29 |
257 changed files with 9742 additions and 16226 deletions
14
.env.example
14
.env.example
|
|
@ -30,17 +30,19 @@ MAIL_PASSWORD=null
|
|||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=noreply-sw@ldc.fr
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
MAIL_LIST_SERVICEWEB=digital@ldc.fr
|
||||
MAIL_ADMIN=digital@ldc.fr
|
||||
MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr
|
||||
MAIL_ADMIN=equipe.web@ldc.fr
|
||||
|
||||
# Sentry
|
||||
SENTRY_LARAVEL_DSN=
|
||||
|
||||
# UWIL ADMIN SECURE
|
||||
# - LIST SEPARATED WITH ',' (Required)
|
||||
UWIL_ADMIN_SECURE_CIDR_LIST=""
|
||||
# ADMIN SECURE
|
||||
# - API ENDPOINT (Optional)
|
||||
LDC_WEB_API_ENDPOINT=
|
||||
# - API KEY
|
||||
LDC_WEB_API_KEY=
|
||||
# - LIST SEPARATED WITH ',' (Optional)
|
||||
UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST=
|
||||
LDC_WEB_CIDR_MANUAL_ALLOWED_LIST=
|
||||
|
||||
# GITLAB API
|
||||
GITLAB_URL=
|
||||
|
|
|
|||
18
.gitignore
vendored
18
.gitignore
vendored
|
|
@ -8,6 +8,7 @@
|
|||
/.phpunit.cache
|
||||
/.vscode
|
||||
/node_modules
|
||||
/bootstrap
|
||||
/public/build
|
||||
/public/cache
|
||||
/public/hot
|
||||
|
|
@ -21,8 +22,17 @@ Homestead.json
|
|||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
storage/samlidp/*
|
||||
.npmrc
|
||||
.zshrc
|
||||
.npm/
|
||||
.composer/
|
||||
|
||||
# Ignore public favicon
|
||||
/public/android-chrome-192x192.png
|
||||
/public/android-chrome-512x512.png
|
||||
/public/apple-touch-icon.png
|
||||
/public/browserconfig.xml
|
||||
/public/browserconfig.xml
|
||||
/public/favicon-16x16.png
|
||||
/public/favicon-32x32.png
|
||||
/public/favicon.ico
|
||||
/public/mstile-150x150.png
|
||||
/public/safari-pinned-tab.svg
|
||||
/public/site.webmanifest
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ include:
|
|||
file: 'security/security.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: "build/docker-multistage.yml"
|
||||
file: 'build/build.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'test/test.yml'
|
||||
|
|
|
|||
44
Dockerfile
44
Dockerfile
|
|
@ -1,43 +1,5 @@
|
|||
FROM composer:2.9.2 AS vendor
|
||||
|
||||
ARG GITLAB_USER
|
||||
ARG GITLAB_PASSWORD
|
||||
|
||||
COPY database/ database/
|
||||
|
||||
COPY composer.json composer.json
|
||||
COPY composer.lock composer.lock
|
||||
|
||||
RUN composer config gitlab-token.lab.s-web.fr ${GITLAB_USER} ${GITLAB_PASSWORD}
|
||||
RUN composer install \
|
||||
--ignore-platform-reqs \
|
||||
--no-interaction \
|
||||
--no-plugins \
|
||||
--no-scripts \
|
||||
--no-dev \
|
||||
--prefer-dist
|
||||
|
||||
FROM node:20.18 AS frontend
|
||||
|
||||
ARG GITLAB_PASSWORD
|
||||
|
||||
RUN mkdir -p /app/public/build
|
||||
|
||||
COPY package*.json tsconfig.json vite.config.ts .eslintrc.json .stylelintrc.json /app/
|
||||
COPY resources/ /app/resources/
|
||||
WORKDIR /app
|
||||
RUN npm config set @uwil:registry https://lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/
|
||||
RUN npm config set -- '//lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
|
||||
RUN npm ci --no-audit --no-fund --loglevel=error && npm run prod
|
||||
|
||||
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
|
||||
|
||||
ARG USER=www-data
|
||||
|
||||
COPY --chown=${USER}:${USER} . /app/srcs
|
||||
COPY --from=vendor --chown=${USER}:${USER} /app/vendor/ /app/srcs/vendor/
|
||||
COPY --from=frontend --chown=${USER}:${USER} /app/public/build/ /app/srcs/public/build/
|
||||
|
||||
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/ldcweb-production-8.2:latest
|
||||
COPY --chown=www-data:www-data . /app/srcs
|
||||
USER root
|
||||
RUN chmod -R 755 /app/srcs/storage
|
||||
USER ${USER}
|
||||
USER www-data
|
||||
16
README.md
16
README.md
|
|
@ -1,17 +1,3 @@
|
|||
# UWIL Support
|
||||
|
||||
PROD : support.uwil.fr
|
||||
|
||||
RE7 : support-web.re7-s-web.fr
|
||||
|
||||
## Gitlab Intégration
|
||||
Le token de groupe pour l'intégration est valable 11 mois
|
||||
|
||||
Il faut le renouveler ici : https://lab.s-web.fr/groups/ldc-web/projets/-/settings/access_tokens et le nommer SW Intégration
|
||||
|
||||
Role : Guest
|
||||
Scope : api
|
||||
|
||||
## TODO
|
||||
# TODO
|
||||
|
||||
- App\Models\Message:booted(): investigate why this make errors on prod,
|
||||
|
|
|
|||
4633
_ide_helper.php
4633
_ide_helper.php
File diff suppressed because it is too large
Load diff
|
|
@ -117,7 +117,7 @@ class CreateUser extends Command
|
|||
{
|
||||
while (is_null($this->email)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user email', 'digital@ldc.fr');
|
||||
$tmp = $this->ask('Type the wanted user email', 'equipe.web@ldc.fr');
|
||||
$validator = Validator::make(['email' => $tmp], [
|
||||
'email' => 'required|unique:users,email|email:rfc,dns'
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\ExportTicketsState as JobsExportTicketsState;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class ExportTicketsState extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'tickets:export-state';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Export the state of tickets to a CSV file';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Running the Job, this could take some time.');
|
||||
$job = new JobsExportTicketsState();
|
||||
$job->handle();
|
||||
$this->info('Job completed');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ class TestMail extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send test email to digital@ldc.fr';
|
||||
protected $description = 'Send test email to equipe.web@ldc.fr';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
|
|
@ -29,7 +29,7 @@ class TestMail extends Command
|
|||
public function handle()
|
||||
{
|
||||
Mail::raw(sprintf('UWIL mail-test from %s %s', \config('app.name'), \config('app.url')), function ($msg) {
|
||||
$msg->to('digital@ldc.fr')->subject('Test Email');
|
||||
$msg->to('equipe.web@ldc.fr')->subject('Test Email');
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,334 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use App\Models\GitlabIssues;
|
||||
use App\Models\GitlabLabels;
|
||||
use App\Models\GitlabMilestones;
|
||||
use App\Models\GitlabProjects;
|
||||
use App\Models\Ticket;
|
||||
use Carbon\Carbon;
|
||||
use GrahamCampbell\GitLab\Facades\GitLab;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class UpdateGitlabDatas extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:update-gitlab-datas {--is-cron}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Fetch some Gitlab datas';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$isCron = $this->option('is-cron');
|
||||
|
||||
$groupId = 23;
|
||||
|
||||
$this->updateProjectsByGroup($groupId);
|
||||
|
||||
$this->updateLabelsByGroup($groupId);
|
||||
|
||||
$projects = GitlabProjects::all();
|
||||
|
||||
foreach ($projects as $project) {
|
||||
$this->updateMilestonesByProject($project);
|
||||
$this->updateIssuesByProject($project, $isCron);
|
||||
}
|
||||
|
||||
$this->syncTicketStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* updateProjectsByGroup function
|
||||
*
|
||||
* @param integer $groupId
|
||||
* @return void
|
||||
*/
|
||||
private function updateProjectsByGroup(int $groupId): void
|
||||
{
|
||||
$allProjects = [];
|
||||
$page = 1;
|
||||
do {
|
||||
$projects = GitLab::groups()->projects($groupId, [
|
||||
'order_by' => 'created_at',
|
||||
'sort' => 'asc',
|
||||
'per_page' => 100,
|
||||
'page' => $page,
|
||||
'include_subgroups' => true
|
||||
]);
|
||||
$allProjects = array_merge($allProjects, $projects);
|
||||
$page++;
|
||||
} while (!empty($projects));
|
||||
|
||||
$this->info(sprintf(
|
||||
"Fetched %d projects in group %d.",
|
||||
count($allProjects),
|
||||
$groupId
|
||||
));
|
||||
|
||||
foreach ($allProjects as $project) {
|
||||
GitlabProjects::upsert(
|
||||
[
|
||||
'name' => $project['name'],
|
||||
'url' => $project['web_url'],
|
||||
'is_archived' => $project['archived'],
|
||||
'gitlab_id' => $project['id']
|
||||
],
|
||||
['gitlab_id']
|
||||
);
|
||||
}
|
||||
|
||||
$this->info("Gitlab Projects upsert complete.");
|
||||
}
|
||||
|
||||
/**
|
||||
* updateLabelsByGroup function
|
||||
*
|
||||
* @param integer $groupId
|
||||
* @return void
|
||||
*/
|
||||
private function updateLabelsByGroup(int $groupId): void
|
||||
{
|
||||
$allLabels = [];
|
||||
$page = 1;
|
||||
do {
|
||||
$labels = GitLab::groups()->labels($groupId, [
|
||||
'per_page' => 100,
|
||||
'page' => $page,
|
||||
]);
|
||||
$allLabels = array_merge($allLabels, $labels);
|
||||
$page++;
|
||||
} while (!empty($labels));
|
||||
|
||||
$this->info(sprintf(
|
||||
"Fetched %d labels in group %d.",
|
||||
count($allLabels),
|
||||
$groupId
|
||||
));
|
||||
|
||||
foreach ($allLabels as $project) {
|
||||
GitlabLabels::upsert(
|
||||
[
|
||||
'name' => $project['name'],
|
||||
'gitlab_id' => $project['id']
|
||||
],
|
||||
['gitlab_id']
|
||||
);
|
||||
}
|
||||
|
||||
$this->info("Gitlab labels upsert complete.");
|
||||
}
|
||||
|
||||
/**
|
||||
* updateIssuesByProject function
|
||||
*
|
||||
* @param GitlabProjects $project
|
||||
* @param boolean $isCron
|
||||
* @return void
|
||||
*/
|
||||
private function updateIssuesByProject(GitlabProjects $project, bool $isCron = false): void
|
||||
{
|
||||
$projectId = $project->gitlab_id;
|
||||
$allIssues = [];
|
||||
$page = 1;
|
||||
|
||||
do {
|
||||
$params = [
|
||||
'order_by' => 'created_at',
|
||||
'sort' => 'asc',
|
||||
'per_page' => 100,
|
||||
'page' => $page,
|
||||
'state' => 'all',
|
||||
];
|
||||
if ($isCron) {
|
||||
$params = array_merge($params, ['updated_after' => now()->subDay()]);
|
||||
}
|
||||
$issues = GitLab::projects()->issues($projectId, $params);
|
||||
$allIssues = array_merge($allIssues, $issues);
|
||||
$page++;
|
||||
} while (!empty($issues));
|
||||
|
||||
$this->info(sprintf(
|
||||
"Fetched %d issues in project %d.",
|
||||
count($allIssues),
|
||||
$projectId
|
||||
));
|
||||
|
||||
foreach ($allIssues as $issue) {
|
||||
GitlabIssues::upsert(
|
||||
[
|
||||
'title' => $issue['title'],
|
||||
'url' => $issue['web_url'],
|
||||
'estimate_time' => $issue['time_stats']['time_estimate'] ?? 0,
|
||||
'spent_time' => $issue['time_stats']['total_time_spent'] ?? 0,
|
||||
'is_closed' => $issue['state'] === 'closed',
|
||||
'gitlab_id' => $issue['id'],
|
||||
'gitlab_iid' => $issue['iid'],
|
||||
'milestone_iid' => $issue['milestone']['iid'] ?? null,
|
||||
'gitlab_project_id' => $projectId,
|
||||
'g_created_at' => Carbon::parse($issue['created_at'])->format('Y-m-d'),
|
||||
'g_updated_at' => Carbon::parse($issue['updated_at'])->format('Y-m-d'),
|
||||
'g_closed_at' => !is_null($issue['closed_at'])
|
||||
? Carbon::parse($issue['closed_at'])->format('Y-m-d')
|
||||
: null,
|
||||
'g_due_date' => !is_null($issue['due_date'])
|
||||
? Carbon::parse($issue['due_date'])->format('Y-m-d')
|
||||
: null
|
||||
],
|
||||
['gitlab_id']
|
||||
);
|
||||
|
||||
$issueModel = GitlabIssues::where('gitlab_id', $issue['id'])->firstOrFail();
|
||||
$labelIds = [];
|
||||
|
||||
foreach ($issue['labels'] as $labelName) {
|
||||
$label = Cache::remember("gitlab_label_{$labelName}", 300, function () use ($labelName) {
|
||||
return GitlabLabels::where('name', $labelName)->first();
|
||||
});
|
||||
|
||||
if ($label) {
|
||||
$labelIds[] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
$issueModel->gitlabLabels()->sync($labelIds);
|
||||
}//end foreach
|
||||
|
||||
$this->info("Gitlab issues upsert complete.");
|
||||
}
|
||||
|
||||
/**
|
||||
* updateMilestonesByProject function
|
||||
*
|
||||
* @param GitlabProjects $project
|
||||
* @return void
|
||||
*/
|
||||
private function updateMilestonesByProject(GitlabProjects $project): void
|
||||
{
|
||||
$projectId = $project->gitlab_id;
|
||||
$allMilestones = [];
|
||||
$page = 1;
|
||||
|
||||
do {
|
||||
$milestones = [];
|
||||
|
||||
try {
|
||||
$milestones = GitLab::milestones()->all($projectId, [
|
||||
'per_page' => 100,
|
||||
'page' => $page
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
if ($project->delete()) {
|
||||
Log::warning(sprintf(
|
||||
"Project not found (%s), it has been deleted.",
|
||||
$projectId
|
||||
));
|
||||
} else {
|
||||
Log::warning(sprintf(
|
||||
"Project not found (%s).",
|
||||
$projectId
|
||||
));
|
||||
}
|
||||
} else {
|
||||
Log::error(sprintf(
|
||||
'API Error for project %s, Message: %d',
|
||||
$projectId,
|
||||
$e->getMessage()
|
||||
));
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
$allMilestones = array_merge($allMilestones, $milestones);
|
||||
$page++;
|
||||
} while (!empty($milestones));
|
||||
|
||||
$this->info(sprintf(
|
||||
"Fetched %d milestones in project %d.",
|
||||
count($allMilestones),
|
||||
$projectId
|
||||
));
|
||||
|
||||
foreach ($allMilestones as $milestone) {
|
||||
GitlabMilestones::upsert(
|
||||
[
|
||||
'title' => $milestone['title'],
|
||||
'url' => $milestone['web_url'],
|
||||
'is_closed' => $milestone['state'] === 'closed',
|
||||
'gitlab_id' => $milestone['id'],
|
||||
'gitlab_iid' => $milestone['iid'],
|
||||
'gitlab_project_id' => $projectId,
|
||||
'g_created_at' => Carbon::parse($milestone['created_at'])->format('Y-m-d'),
|
||||
'g_updated_at' => Carbon::parse($milestone['updated_at'])->format('Y-m-d'),
|
||||
'g_start_date' => !is_null($milestone['start_date'])
|
||||
? Carbon::parse($milestone['start_date'])->format('Y-m-d')
|
||||
: null,
|
||||
'g_due_date' => !is_null($milestone['due_date'])
|
||||
? Carbon::parse($milestone['due_date'])->format('Y-m-d')
|
||||
: null
|
||||
],
|
||||
['gitlab_id']
|
||||
);
|
||||
}//end foreach
|
||||
|
||||
$this->info("Gitlab milestones upsert complete.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes ticket statuses based on GitLab issue labels.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function syncTicketStatus(): void
|
||||
{
|
||||
$tickets = Ticket::whereNotNull('gitlab_issue')->whereNot('status', TicketStatusEnum::archived)->get();
|
||||
|
||||
foreach ($tickets as $ticket) {
|
||||
$gitlabIssue = GitlabIssues::where('url', $ticket->gitlab_issue)->with('gitlabLabels')->first();
|
||||
|
||||
$gitlabIssueLabels = $gitlabIssue ? $gitlabIssue->gitlabLabels->pluck('name') : [];
|
||||
|
||||
if ($gitlabIssueLabels) {
|
||||
match (true) {
|
||||
$gitlabIssueLabels->contains('g-wip') => $this->updateTicketStatus($ticket, TicketStatusEnum::inDev),
|
||||
$gitlabIssueLabels->contains('g-production') => $this->updateTicketStatus($ticket, TicketStatusEnum::production),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ticket status only if it has changed.
|
||||
*
|
||||
* @param Ticket $ticket The ticket to update.
|
||||
* @param TicketStatusEnum $status The new status to apply.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function updateTicketStatus(Ticket $ticket, TicketStatusEnum $status): void
|
||||
{
|
||||
if ($ticket->status !== $status && $ticket->status !== TicketStatusEnum::waiting) {
|
||||
$ticket->status = $status;
|
||||
$ticket->saveOrFail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Console;
|
||||
|
||||
use App\Jobs\AutoCloseOldTickets;
|
||||
use App\Jobs\ExportTicketsState;
|
||||
use App\Jobs\WarnBeforeAutoCloseTicket;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
|
@ -25,10 +24,8 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->job(ExportTicketsState::class)->weekly()->fridays()->at('14:00');
|
||||
$schedule->job(AutoCloseOldTickets::class)->dailyAt('08:00');
|
||||
$schedule->job(WarnBeforeAutoCloseTicket::class)->dailyAt('08:05');
|
||||
$schedule->command('app:update-gitlab-datas --is-cron')->hourly()->between('7:00', '19:00');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
final readonly class BrevoWebHookDto
|
||||
{
|
||||
public function __construct(
|
||||
public readonly string $plainTextContent,
|
||||
public readonly ?string $brand
|
||||
) {}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Credit;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum EstimationTimeEnum: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case halfHour = 0.0625;
|
||||
case hour = 0.125;
|
||||
case hourAndHalf = 0.1875;
|
||||
case twoHours = 0.25;
|
||||
case twoHoursAndHalf = 0.3125;
|
||||
case threeHours = 0.375;
|
||||
case threeHoursAndHalf = 0.4375;
|
||||
case fourHours = 0.5;
|
||||
case fourHoursAndHalf = 0.5625;
|
||||
case fiveHours = 0.625;
|
||||
case fiveHoursAndHalf = 0.6875;
|
||||
case sixHours = 0.75;
|
||||
case sixHoursAndHalf = 0.8125;
|
||||
case sevenHours = 0.875;
|
||||
case sevenHoursAndHalf = 0.9375;
|
||||
case eightHours = 1;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::halfHour->name => "Une demi-heure",
|
||||
self::hour->name => "Une heure",
|
||||
self::hourAndHalf->name => "Une heure et demie",
|
||||
self::twoHours->name => "Deux heures",
|
||||
self::twoHoursAndHalf->name => "Deux heures et demie",
|
||||
self::threeHours->name => "Trois heures",
|
||||
self::twoHoursAndHalf->name => "Trois heures et demie",
|
||||
self::fourHours->name => "Quatre heures",
|
||||
self::fourHoursAndHalf->name => "Quatre heures et demie",
|
||||
self::fiveHours->name => "Cinq heures",
|
||||
self::fiveHoursAndHalf->name => "Cinq heures et demie",
|
||||
self::sixHours->name => "Six heures",
|
||||
self::sixHoursAndHalf->name => "Six heures et demie",
|
||||
self::sevenHours->name => "Sept heures",
|
||||
self::sevenHoursAndHalf->name => "Sept heures et demi",
|
||||
self::eightHours->name => "Huit heures",
|
||||
];
|
||||
}
|
||||
|
|
@ -8,12 +8,10 @@ enum InvoiceStatusEnum: int
|
|||
{
|
||||
use BaseEnum;
|
||||
|
||||
case opened = 1;
|
||||
case refused = 2;
|
||||
case canceled = 3;
|
||||
case archived = 4;
|
||||
case awaiting_signature = 5;
|
||||
case awaiting_invoicing = 6;
|
||||
case opened = 1;
|
||||
case refused = 2;
|
||||
case canceled = 3;
|
||||
case archived = 4;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition.
|
||||
|
|
@ -23,7 +21,5 @@ enum InvoiceStatusEnum: int
|
|||
self::refused->name => "Refusé (par le client ou aucune réponse de sa part)",
|
||||
self::canceled->name => "Annulé (supprimé)",
|
||||
self::archived->name => "Archivé (validé et envoyé à la comptabilité)",
|
||||
self::awaiting_signature->name => "En attente de signature",
|
||||
self::awaiting_invoicing->name => "En attente de facturation",
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ enum TaskTypeEnum: int
|
|||
* Custom added prices definition
|
||||
*/
|
||||
private const PRICES = [
|
||||
self::web->name => 600,
|
||||
self::web->name => 500,
|
||||
self::seo->name => 690,
|
||||
// * Linked to packages table
|
||||
self::package->name => 0,
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Tickets;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum TicketFileTypeEnum: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case png = '.png';
|
||||
case jpeg = '.jpeg';
|
||||
case jpg = '.jpg';
|
||||
case pdf = '.pdf';
|
||||
case pptx = '.pptx';
|
||||
case docx = '.docx';
|
||||
case xlsx = '.xlsx';
|
||||
case csv = '.csv';
|
||||
case svg = '.svg';
|
||||
|
||||
/**
|
||||
* Optionnal labels definition
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::png->name => "Fichier png",
|
||||
self::jpeg->name => "Fichier jpeg",
|
||||
self::jpg->name => "Fichier jpg",
|
||||
self::pdf->name => "Fichier pdf",
|
||||
self::pptx->name => "Fichier pptx",
|
||||
self::docx->name => "Fichier docx",
|
||||
self::xlsx->name => "Fichier xlsx",
|
||||
self::csv->name => "Fichier csv",
|
||||
self::svg->name => "Fichier svg",
|
||||
];
|
||||
|
||||
/**
|
||||
* Custom added mimes type definition
|
||||
*/
|
||||
private const MIMETYPE = [
|
||||
self::png->name => 'image/png',
|
||||
self::jpeg->name => 'image/jpeg',
|
||||
self::jpg->name => 'image/jpeg',
|
||||
self::pdf->name => 'application/pdf',
|
||||
self::pptx->name => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
self::docx->name => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
self::xlsx->name => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
self::csv->name => 'text/csv',
|
||||
self::svg->name => 'image/svg+xml',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mimetypes(): string
|
||||
{
|
||||
return self::MIMETYPE[$this->name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enum classes
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function toMimetypes(): array
|
||||
{
|
||||
return self::MIMETYPE;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,25 +14,21 @@ enum TicketStatusEnum: int
|
|||
case waiting = 4;
|
||||
case waitingValidation = 5;
|
||||
case recette = 6;
|
||||
case recetteValidated = 7;
|
||||
case production = 8;
|
||||
case archived = 9;
|
||||
case inDev = 10;
|
||||
case production = 7;
|
||||
case archived = 8;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::new->name => "Nouveau",
|
||||
self::estimateTodo->name => "Étude chef(s) de projet",
|
||||
self::takenInAccount->name => "À planifier",
|
||||
self::estimateTodo->name => "Devis à faire",
|
||||
self::takenInAccount->name => "Pris en compte",
|
||||
self::waiting->name => "En attente de réponse",
|
||||
self::waitingValidation->name => "En attente de validation",
|
||||
self::recette->name => "En recettage",
|
||||
self::recetteValidated->name => "Recettage validé",
|
||||
self::production->name => "En production",
|
||||
self::archived->name => "Archivé",
|
||||
self::inDev->name => "En cours de développement",
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -45,10 +41,8 @@ enum TicketStatusEnum: int
|
|||
self::waiting->name => 'text-white bg-danger',
|
||||
self::waitingValidation->name => 'text-warning bg-danger',
|
||||
self::recette->name => 'text-primary',
|
||||
self::recetteValidated->name => 'text-success',
|
||||
self::production->name => 'text-success',
|
||||
self::archived->name => 'text-secondary',
|
||||
self::inDev->name => 'text-discovery',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,14 +8,12 @@ enum TicketTypeEnum: int
|
|||
{
|
||||
use BaseEnum;
|
||||
|
||||
case bug = 1;
|
||||
case evolution = 2;
|
||||
case br = 3;
|
||||
case newsletter = 4;
|
||||
case qrcode = 5;
|
||||
case advice = 6;
|
||||
case complaints = 7;
|
||||
case mailing = 8;
|
||||
case bug = 0;
|
||||
case evolution = 1;
|
||||
case br = 2;
|
||||
case newsletter = 3;
|
||||
case qrcode = 4;
|
||||
case advice = 5;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition
|
||||
|
|
@ -27,8 +25,6 @@ enum TicketTypeEnum: int
|
|||
self::newsletter->name => "Demande newsletter",
|
||||
self::qrcode->name => "Demande de QR Code",
|
||||
self::advice->name => "Conseil - Accompagnement",
|
||||
self::complaints->name => "Réclamations consommateurs",
|
||||
self::mailing->name => "Demande mail en masse",
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -41,8 +37,6 @@ enum TicketTypeEnum: int
|
|||
self::newsletter->name => "bg-warning",
|
||||
self::qrcode->name => "bg-secondary",
|
||||
self::advice->name => "bg-info",
|
||||
self::complaints->name => "bg-dark",
|
||||
self::mailing->name => "bg-discovery",
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
20
app/Enums/Users/GitlabUsersEnum.php
Normal file
20
app/Enums/Users/GitlabUsersEnum.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Users;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum GitlabUsersEnum: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
// Each user is associated to his ID on gitlab.
|
||||
case olivier = 11;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::olivier->name => "Olivier LEGAT",
|
||||
];
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Domain\Models\ValueObjects\Email;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
|
||||
readonly class BrevoWebhookCallReceived
|
||||
{
|
||||
use Dispatchable;
|
||||
|
||||
public function __construct(
|
||||
public Email $from,
|
||||
public Email $to,
|
||||
public string $htmlRawContent
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('default'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TicketCreated implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public readonly Site $siteReceivingTicket,
|
||||
public readonly Ticket $ticket,
|
||||
public readonly string $byUserName
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('default'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Events\BrevoWebhookCallReceived;
|
||||
use App\Http\Requests\Bo\BrevoWebhookRequest;
|
||||
use Domain\Models\ValueObjects\Email;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use \Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class BrevoWebhookController extends BaseController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly Dispatcher $dispatcher
|
||||
) {}
|
||||
|
||||
public function webhookCallReceived(BrevoWebhookRequest $request): JsonResponse
|
||||
{
|
||||
$fromEmail = $request->getFromAddress();
|
||||
$toEmail = $request->getToAddress();
|
||||
$formContent = $request->getRawHtmlBody();
|
||||
|
||||
if (!$this->isFromLdc($fromEmail)) {
|
||||
$this->logger->warning(
|
||||
'Received a brevo webhook call from a non ldc email.',
|
||||
[
|
||||
'from' => $fromEmail,
|
||||
'to' => $toEmail,
|
||||
'content' => base64_encode($formContent)
|
||||
]
|
||||
);
|
||||
|
||||
return response()->json(
|
||||
['ok' => false],
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
$this->dispatcher->dispatch(
|
||||
new BrevoWebhookCallReceived(
|
||||
from: $fromEmail,
|
||||
to: $toEmail,
|
||||
htmlRawContent: $formContent,
|
||||
)
|
||||
);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
private function isFromLdc(Email $email): bool
|
||||
{
|
||||
return substr(strrchr($email->value, "@"), 1) === 'ldc.fr';
|
||||
}
|
||||
}
|
||||
29
app/Http/Controllers/Bo/DashboardController.php
Normal file
29
app/Http/Controllers/Bo/DashboardController.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Dutyhour;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show Home page
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
/**
|
||||
* Get only duty hours for today or later.
|
||||
*
|
||||
* @var \Illuminate\Database\Eloquent\Builder $dutyhour
|
||||
*/
|
||||
$dutyhourModels = Dutyhour::where('date', '>', now()->modify('-1 day'))
|
||||
->orderBy('date', 'asc')
|
||||
->limit(10)
|
||||
->get();
|
||||
return view('home', compact('dutyhourModels'));
|
||||
}
|
||||
}
|
||||
157
app/Http/Controllers/Bo/DutyhourController.php
Normal file
157
app/Http/Controllers/Bo/DutyhourController.php
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Dutyhours\StoreDutyhourRequest;
|
||||
use App\Http\Requests\Bo\Dutyhours\UpdateDutyhourRequest;
|
||||
use App\Models\Dutyhour;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DutyhourController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $dutyhourModels */
|
||||
$dutyhourModels = Dutyhour::query();
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
if ($search) {
|
||||
$this->searchQuery(
|
||||
$dutyhourModels,
|
||||
$search,
|
||||
null,
|
||||
'date',
|
||||
'person',
|
||||
'place'
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Date, personne, lieu');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($dutyhourModels);
|
||||
|
||||
/** Custom pagination */
|
||||
$dutyhourModels = $this->customPaginate($dutyhourModels, $request->pagination);
|
||||
|
||||
return view('bo.pages.dutyhours.index', compact('dutyhourModels', 'search', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param \App\Models\Dutyhour $dutyhour
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function create(Dutyhour $dutyhour): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.dutyhours.create', [
|
||||
'dutyhourModel' => $dutyhour
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Dutyhours\StoreDutyhourRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreDutyhourRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$dutyhour = new Dutyhour();
|
||||
$dutyhour->fill($request->validated());
|
||||
|
||||
if ($dutyhour->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.dutyhours.edit', $dutyhour)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.dutyhours'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.dutyhours'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Dutyhour $dutyhour
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(Dutyhour $dutyhour): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.dutyhours.edit', [
|
||||
'dutyhourModel' => $dutyhour
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Dutyhours\UpdateDutyhourRequest $request
|
||||
* @param \App\Models\Dutyhour $dutyhour
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateDutyhourRequest $request, Dutyhour $dutyhour): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $dutyhour) {
|
||||
$dutyhour->fill($request->validated());
|
||||
if ($dutyhour->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.dutyhours.edit', $dutyhour)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.dutyhours'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.dutyhours'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Dutyhour $dutyhour
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Dutyhour $dutyhour): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($dutyhour) {
|
||||
if ($dutyhour->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.dutyhours.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.dutyhours'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.dutyhours'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -25,27 +25,12 @@ class InvoiceController extends Controller
|
|||
*/
|
||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
// If no sorting is requested, apply the default orderByDesc.
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $invoiceModels */
|
||||
$invoiceModels = (!request()->query('sort_col') && !request()->query('sort_way'))
|
||||
? Invoice::query()->orderByDesc('created_at')
|
||||
: Invoice::query();
|
||||
|
||||
$status = intval($request->status);
|
||||
|
||||
switch ($status) {
|
||||
case InvoiceStatusEnum::awaiting_signature->value:
|
||||
$invoiceModels->whereNotNull('sent_client_date')->whereNull('signed_date');
|
||||
break;
|
||||
case InvoiceStatusEnum::awaiting_invoicing->value:
|
||||
$invoiceModels->whereNotNull('sent_client_date')->whereNotNull('signed_date')->whereNull('sent_accounting_date');
|
||||
break;
|
||||
default:
|
||||
if ($status !== 0) {
|
||||
$invoiceModels->where('status', $status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$invoiceModels = Invoice::query();
|
||||
$status = intval($request->status);
|
||||
$invoiceModels = $invoiceModels->when($status, function ($query) use ($status) {
|
||||
$query->where('status', $status);
|
||||
});
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
|
|
@ -57,10 +42,9 @@ class InvoiceController extends Controller
|
|||
'firstname',
|
||||
'lastname',
|
||||
'ref',
|
||||
'site_id',
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Nom, Prénom, Référence, Site');
|
||||
$searchFields = trans('Nom, Prénom, Référence');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($invoiceModels);
|
||||
|
|
@ -90,7 +74,7 @@ class InvoiceController extends Controller
|
|||
*/
|
||||
public function create(Invoice $invoice): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$packageModels = Package::where('published', true)->get();
|
||||
$packageModels = Package::get();
|
||||
$taskRowModel = Invoice::getTaskStructure();
|
||||
$siteModels = Site::orderBy('name', 'ASC')->get();
|
||||
$companyModels = Company::get();
|
||||
|
|
@ -197,10 +181,7 @@ class InvoiceController extends Controller
|
|||
return $invoice->generateInvoice()
|
||||
->stream(Str::slug(trans('Devis :appname :date - ref :ref', [
|
||||
'appname' => config('app.name'),
|
||||
'date' =>
|
||||
$invoice->created_at !== $invoice->updated_at ?
|
||||
$invoice->updated_at->isoFormat('YYYY-MM-DD') :
|
||||
$invoice->created_at->isoFormat('YYYY-MM-DD'),
|
||||
'date' => $invoice->created_at->isoFormat('YYYY-MM-DD'),
|
||||
'ref' => $invoice->ref,
|
||||
])) . '.pdf');
|
||||
}
|
||||
|
|
@ -220,7 +201,7 @@ class InvoiceController extends Controller
|
|||
{
|
||||
$model = $request->targetModel;
|
||||
return DB::transaction(function () use ($model) {
|
||||
$models = $model::query()->orderBy('name', 'ASC')->paginate(12);
|
||||
$models = $model::orderBy('name', 'ASC')->paginate(12);
|
||||
return \response()->json($models ?? 500);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,15 +23,6 @@ class PackageController extends Controller
|
|||
/** @var \Illuminate\Database\Eloquent\Builder $packageModels */
|
||||
$packageModels = Package::query();
|
||||
|
||||
$status = $request->status;
|
||||
if ($status === null) {
|
||||
$packageModels->where('published', true);
|
||||
} elseif ($status === '0') {
|
||||
$packageModels->where('published', false);
|
||||
} elseif ($status === '1') {
|
||||
$packageModels->where('published', true);
|
||||
}
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
if ($search) {
|
||||
|
|
@ -51,7 +42,7 @@ class PackageController extends Controller
|
|||
/** Custom pagination */
|
||||
$packageModels = $this->customPaginate($packageModels, $request->pagination);
|
||||
|
||||
return view('bo.pages.packages.index', compact('packageModels', 'search', 'searchFields', 'status'));
|
||||
return view('bo.pages.packages.index', compact('packageModels', 'search', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -162,16 +153,4 @@ class PackageController extends Controller
|
|||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Change model published.
|
||||
*
|
||||
* @param \App\Models\Package $package
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function changePublished(Package $package)
|
||||
{
|
||||
$package->update(['published' => !$package->getOriginal('published')]);
|
||||
return redirect()->back()->with('success', trans(__('crud.messages.publish_status_saved')));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
193
app/Http/Controllers/Bo/ProjectController.php
Normal file
193
app/Http/Controllers/Bo/ProjectController.php
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Projects\StoreProjectRequest;
|
||||
use App\Http\Requests\Bo\Projects\UpdateProjectRequest;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Models\Project;
|
||||
use App\Models\Site;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ProjectController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $projectModels */
|
||||
$projectModels = Project::query();
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
if ($search) {
|
||||
$this->searchQuery(
|
||||
$projectModels,
|
||||
$search,
|
||||
null,
|
||||
'name',
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Nom');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($projectModels);
|
||||
|
||||
/** Custom pagination */
|
||||
$projectModels = $this->customPaginate($projectModels, $request->pagination);
|
||||
|
||||
return view('bo.pages.projects.index', compact('projectModels', 'search', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Crud show view
|
||||
*
|
||||
* @param \App\Models\Project $project
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function show(Project $project)
|
||||
{
|
||||
return view('bo.pages.projects.show', [
|
||||
'projectModel' => $project
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param \App\Models\Project $project
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function create(Project $project): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$siteModels = Site::orderBy('name', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.projects.create', [
|
||||
'projectModel' => $project,
|
||||
'siteModels' => $siteModels
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Projects\StoreProjectRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreProjectRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$project = new Project();
|
||||
$project->fill($request->validated());
|
||||
|
||||
if ($project->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.projects.edit', $project)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_created',
|
||||
['model' => Str::singular(trans('models.classes.projects'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_created',
|
||||
['model' => Str::singular(trans('models.classes.projects'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Project $project
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(Project $project): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$siteModels = Site::orderBy('name', 'ASC')->get();
|
||||
|
||||
return view('bo.pages.projects.edit', [
|
||||
'projectModel' => $project,
|
||||
'siteModels' => $siteModels
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Projects\UpdateProjectRequest $request
|
||||
* @param \App\Models\Project $project
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateProjectRequest $request, Project $project): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $project) {
|
||||
$project->fill($request->validated());
|
||||
if ($project->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.projects.edit', $project)
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_updated',
|
||||
['model' => Str::singular(trans('models.classes.projects'))]
|
||||
));
|
||||
} //end if
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
'crud.messages.cannot_be_updated',
|
||||
['model' => Str::singular(trans('models.classes.projects'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Project $project
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Project $project): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($project) {
|
||||
if ($project->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.projects.index')
|
||||
->with('success', trans(
|
||||
'crud.messages.has_been_deleted',
|
||||
['model' => Str::singular(trans('models.classes.projects'))]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':crud.messages.cannot_be_deleted',
|
||||
['model' => Str::singular(trans('models.classes.projects'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a paginate resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function jsonPaginate(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$model = $request->targetModel;
|
||||
$search = $request->search;
|
||||
$models = $model::where("name", "LIKE", "%{$search}%")->orderBy("name", "ASC");
|
||||
|
||||
return ToolboxHelper::jsonPaginate($this->customPaginate($models, $request->pagination));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ use App\Lib\Helpers\ToolboxHelper;
|
|||
use App\Models\Site;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
|
@ -24,15 +23,15 @@ class SiteController extends Controller
|
|||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = Auth::user();
|
||||
$user = \auth()->user();
|
||||
|
||||
if ($user->isAdmin()) {
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $siteModels */
|
||||
$siteModels = Site::query()->with(['invoices', 'tickets']);
|
||||
$siteModels = Site::query();
|
||||
} else {
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $siteModels */
|
||||
$siteModels = Site::whereHas('users', function (\Illuminate\Database\Eloquent\Builder $query) use ($user) {
|
||||
$query->where('id', $user->id)->with(['invoices', 'tickets']);
|
||||
$query->where('id', $user->id);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,48 +2,41 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Models\User;
|
||||
use App\Models\Ticket;
|
||||
use App\Mail\NewTicket;
|
||||
use App\Models\Message;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\UpdateIssueLabels;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use App\Enums\Tickets\TicketTypeEnum;
|
||||
use App\Enums\Users\GitlabUsersEnum;
|
||||
use App\Events\NotifySubscriptions;
|
||||
use App\Events\TicketStatusChanged;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\LinkTicket;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Enums\Tickets\TicketTypeEnum;
|
||||
use App\Http\Requests\Bo\AssignTicketToUserRequest;
|
||||
use App\Http\Requests\Bo\ChangeTicketStatus;
|
||||
use App\Http\Requests\Bo\CreateMessage;
|
||||
use App\Http\Requests\Bo\SortTickets;
|
||||
use App\Http\Requests\Bo\StoreTicket;
|
||||
use App\Http\Requests\Bo\UpdateMessage;
|
||||
use App\Http\Requests\Bo\UpdateTicket;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use App\Events\TicketCreated;
|
||||
use App\Http\Requests\Bo\CreateMessage;
|
||||
use App\Http\Requests\Bo\UpdateMessage;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Mail\NewTicket;
|
||||
use App\Models\Message;
|
||||
use App\Models\Site;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use GrahamCampbell\GitLab\Facades\GitLab;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\Http\Requests\Bo\ChangeTicketStatus;
|
||||
use App\Http\Requests\Bo\UpdateChangeOrderRequest;
|
||||
use App\Http\Requests\Bo\AssignTicketToUserRequest;
|
||||
use App\Http\Requests\Bo\UpdateTicketPriorityRequest;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
/**
|
||||
* TicketController
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly Dispatcher $dispatcher
|
||||
) {
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->authorizeResource(Ticket::class, 'ticket');
|
||||
}
|
||||
|
|
@ -81,6 +74,7 @@ class TicketController extends Controller
|
|||
}));
|
||||
} //end if
|
||||
|
||||
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
$tickets = Ticket::with(['site', 'labels']);
|
||||
|
|
@ -101,30 +95,15 @@ class TicketController extends Controller
|
|||
TicketStatusEnum::archived
|
||||
);
|
||||
|
||||
if (!$user->isAdmin() && $user->sites->count() === 1) {
|
||||
$request->merge([
|
||||
'pr' => $user->sites->first()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$tickets = $this->filterTickets($tickets, $request);
|
||||
$tickets = $this->searchTicket($tickets, $request);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($tickets);
|
||||
|
||||
/** Custom pagination */
|
||||
$tickets = $this->customPaginate($tickets, $request->pagination);
|
||||
|
||||
$sites = Site::select('id', 'name')->orderBy('name')->get();
|
||||
$status = Arr::sort(TicketStatusEnum::cases(), function (TicketStatusEnum $value) {
|
||||
return $value->label();
|
||||
});
|
||||
$types = Arr::sort(TicketTypeEnum::cases(), function (TicketTypeEnum $value) {
|
||||
return $value->label();
|
||||
});
|
||||
$status = TicketStatusEnum::cases();
|
||||
|
||||
return view('bo.pages.tickets.index', compact('tickets', 'sites', 'status', 'types'));
|
||||
return view('bo.pages.tickets.index', compact('tickets', 'sites', 'status'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -156,11 +135,7 @@ class TicketController extends Controller
|
|||
|
||||
$messages = $ticket->messages()->orderBy('created_at', 'DESC')->get();
|
||||
$isSubscribed = (bool)$ticket->subscriptions()->where('user_id', $user->id)->count();
|
||||
return view('bo.pages.tickets.show', [
|
||||
'ticket' => $ticket,
|
||||
'messages' => $messages,
|
||||
'isSubscribed' => $isSubscribed
|
||||
]);
|
||||
return view('bo.pages.tickets.show', compact('ticket', 'messages', 'isSubscribed'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -203,20 +178,19 @@ class TicketController extends Controller
|
|||
|
||||
$ticket = new Ticket($request->validated());
|
||||
|
||||
/** @var array<\Illuminate\Http\UploadedFile> */
|
||||
$fileTickets = $request->file_tickets ?? [];
|
||||
if (count($fileTickets) > 0) {
|
||||
foreach ($fileTickets as $key => $file) {
|
||||
if ($key === 0) {
|
||||
$ticket->file = FileStorageHelper::storeFile($ticket, $file);
|
||||
} else {
|
||||
$fileNumber = 'file' . $key + 1;
|
||||
$ticket->$fileNumber = FileStorageHelper::storeFile($ticket, $file);
|
||||
}
|
||||
}
|
||||
/** @var \Illuminate\Http\UploadedFile|null */
|
||||
$fileTicket = $request->file_ticket;
|
||||
/** @var \Illuminate\Http\UploadedFile|null */
|
||||
$fileTicket2 = $request->file_ticket2;
|
||||
|
||||
if ($fileTicket) {
|
||||
$ticket->file = FileStorageHelper::storeFile($ticket, $fileTicket);
|
||||
}
|
||||
if ($fileTicket2) {
|
||||
$ticket->file2 = FileStorageHelper::storeFile($ticket, $fileTicket2);
|
||||
}
|
||||
|
||||
$ticket->user()->associate($user);
|
||||
$ticket->user()->associate(auth()->user());
|
||||
$ticket->site()->associate($site);
|
||||
$ticket->saveOrFail();
|
||||
|
||||
|
|
@ -226,11 +200,11 @@ class TicketController extends Controller
|
|||
|
||||
$user->subscriptions()->toggle($ticket->id);
|
||||
|
||||
$this->dispatcher->dispatch(new TicketCreated(
|
||||
siteReceivingTicket: $site,
|
||||
ticket: $ticket,
|
||||
byUserName: $user->name
|
||||
));
|
||||
if (config('mail.MAIL_ADMIN')) {
|
||||
Mail::to(config('mail.MAIL_ADMIN'))->send(new NewTicket($ticket));
|
||||
} else {
|
||||
throw new \ErrorException('Missing MAIL_ADMIN in .env');
|
||||
}
|
||||
|
||||
return redirect()->route('bo.ticket.show', $ticket)
|
||||
->with('success', trans('Ticket enregistré !'));
|
||||
|
|
@ -278,18 +252,18 @@ class TicketController extends Controller
|
|||
/** @var \App\Models\Site */
|
||||
$site = Site::findOrFail($request->site_id);
|
||||
|
||||
/** @var null|array<\Illuminate\Http\UploadedFile> */
|
||||
$fileTickets = $request->file_tickets;
|
||||
if (isset($fileTickets) && count($fileTickets) > 0) {
|
||||
foreach ($fileTickets as $key => $file) {
|
||||
if ($key === 0) {
|
||||
$ticket->file = FileStorageHelper::storeFile($ticket, $file);
|
||||
} else {
|
||||
$fileNumber = 'file' . $key + 1;
|
||||
$ticket->$fileNumber = FileStorageHelper::storeFile($ticket, $file);
|
||||
}
|
||||
}
|
||||
/** @var \Illuminate\Http\UploadedFile|null */
|
||||
$fileTicket = $request->file_ticket;
|
||||
/** @var \Illuminate\Http\UploadedFile|null */
|
||||
$fileTicket2 = $request->file_ticket2;
|
||||
|
||||
if ($fileTicket) {
|
||||
$ticket->file = FileStorageHelper::storeFile($ticket, $fileTicket);
|
||||
}
|
||||
if ($fileTicket2) {
|
||||
$ticket->file2 = FileStorageHelper::storeFile($ticket, $fileTicket2);
|
||||
}
|
||||
|
||||
|
||||
$ticket->labels()->sync($request->labels);
|
||||
|
||||
|
|
@ -316,10 +290,6 @@ class TicketController extends Controller
|
|||
*/
|
||||
public function changeStatus(ChangeTicketStatus $request, Ticket $ticket)
|
||||
{
|
||||
if ($ticket->gitlab_issue) {
|
||||
\dispatch(new UpdateIssueLabels($ticket, $request->status));
|
||||
}
|
||||
|
||||
$ticket->fill($request->validated());
|
||||
$ticket->saveOrFail();
|
||||
|
||||
|
|
@ -339,39 +309,32 @@ class TicketController extends Controller
|
|||
try {
|
||||
return DB::transaction(function () use ($request, $ticket) {
|
||||
/** @var \Illuminate\Http\UploadedFile|null */
|
||||
$filesMessage = $request->file_messages;
|
||||
$message = new Message($request->validated());
|
||||
$fileMessage = $request->file_message;
|
||||
|
||||
$message = new Message($request->validated());
|
||||
$message->user()->associate(auth()->user());
|
||||
$message->ticket()->associate($ticket);
|
||||
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
// Subscribe to ticket.
|
||||
if ($request->subscribe) {
|
||||
$user->subscriptions()->syncWithoutDetaching([$ticket->id]);
|
||||
} else {
|
||||
$user->subscriptions()->detach($ticket->id);
|
||||
}
|
||||
|
||||
// Store files if any.
|
||||
if (isset($filesMessage) and $filesMessage) {
|
||||
foreach ($filesMessage as $key => $singleFile) {
|
||||
if ($key === 0) {
|
||||
$message->file = FileStorageHelper::storeFile($message, $singleFile);
|
||||
$message->saveOrFail();
|
||||
} else {
|
||||
$fileNumber = 'file' . $key + 1;
|
||||
$message->$fileNumber = FileStorageHelper::storeFile($message, $singleFile);
|
||||
$message->saveOrFail();
|
||||
}
|
||||
if ($request->subscribe) {
|
||||
if (!$user->subscriptions()->find($ticket->id)) {
|
||||
$user->subscriptions()->attach($ticket->id);
|
||||
}
|
||||
} elseif ($user->subscriptions()->find($ticket->id)) {
|
||||
$user->subscriptions()->detach($ticket->id);
|
||||
}
|
||||
|
||||
$message->saveOrFail();
|
||||
|
||||
if ($fileMessage) {
|
||||
$message->file = FileStorageHelper::storeFile($message, $fileMessage);
|
||||
$message->saveOrFail();
|
||||
}
|
||||
return back()
|
||||
->with('success', trans('Votre message à été ajouté'));
|
||||
}, 5);
|
||||
});
|
||||
} catch (\ErrorException $e) {
|
||||
report($e);
|
||||
Session::flash('error', trans('Une erreur est survenue'));
|
||||
|
|
@ -507,48 +470,6 @@ class TicketController extends Controller
|
|||
return back()->with('info', trans('Le ticket n\'est plus assigné à personne'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Link two tickets.
|
||||
*
|
||||
* @param LinkTicket $request
|
||||
* @param Ticket $ticket
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function linkTicket(LinkTicket $request, Ticket $ticket)
|
||||
{
|
||||
$linkedTicket = Ticket::findOrFail($request->validated())->first();
|
||||
|
||||
if ($ticket->site_id !== $linkedTicket->site_id) {
|
||||
return back()->with('error', trans('Le ticket que vous avez renseigné ne fait pas partie du même site.'));
|
||||
}
|
||||
|
||||
if (!$ticket->linkedTickets()->where('linked_ticket_id', $linkedTicket->id)->exists()) {
|
||||
$ticket->linkedTickets()->attach($linkedTicket->id);
|
||||
$linkedTicket->linkedTickets()->attach($ticket->id);
|
||||
return back()->with('success', trans('Les tickets ont été liés avec succès.'));
|
||||
}
|
||||
|
||||
return back()->with('error', trans('Les tickets sont déjà liés ensemble.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink two tickets.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @param Ticket $linkedTicket
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function unlinkTicket(Ticket $ticket, Ticket $linkedTicket)
|
||||
{
|
||||
$ticket->linkedTickets()->detach($linkedTicket->id);
|
||||
$linkedTicket->linkedTickets()->detach($ticket->id);
|
||||
|
||||
return back()->with('warning', trans('Le lien entre les tickets à été supprimé.'));
|
||||
}
|
||||
|
||||
// * PRIVATES
|
||||
|
||||
/**
|
||||
|
|
@ -566,10 +487,8 @@ class TicketController extends Controller
|
|||
Session::remove('tickets.ass');
|
||||
Session::remove('tickets.st');
|
||||
Session::remove('tickets.pr');
|
||||
Session::remove('tickets.ty');
|
||||
Session::remove('tickets.sort_col');
|
||||
Session::remove('tickets.sort_way');
|
||||
Session::remove('tickets.or');
|
||||
Session::remove('tickets.search');
|
||||
}
|
||||
if ($request->assr) {
|
||||
|
|
@ -581,43 +500,21 @@ class TicketController extends Controller
|
|||
if ($request->sts) {
|
||||
Session::remove('tickets.st');
|
||||
}
|
||||
if ($request->tys) {
|
||||
Session::remove('tickets.ty');
|
||||
}
|
||||
if ($request->sort_col) {
|
||||
Session::put('tickets.sort_col', $request->sort_col);
|
||||
}
|
||||
if ($request->sort_way) {
|
||||
Session::put('tickets.sort_way', $request->sort_way);
|
||||
}
|
||||
if ($request->ord) {
|
||||
Session::remove('tickets.or');
|
||||
}
|
||||
if ($request->pr) {
|
||||
Session::put('tickets.pr', $request->pr);
|
||||
}
|
||||
if ($request->st) {
|
||||
Session::put('tickets.st', $request->st);
|
||||
}
|
||||
if ($request->ty) {
|
||||
Session::put('tickets.ty', $request->ty);
|
||||
}
|
||||
if ($request->ass) {
|
||||
Session::put('tickets.ass', $request->ass);
|
||||
}
|
||||
if (Session::has('tickets.or')) {
|
||||
Session::remove('tickets.ass');
|
||||
Session::remove('tickets.st');
|
||||
Session::remove('tickets.ty');
|
||||
Session::remove('tickets.sort_col');
|
||||
Session::remove('tickets.sort_way');
|
||||
Session::remove('tickets.search');
|
||||
}
|
||||
|
||||
if ($request->or && Session::has('tickets.pr')) {
|
||||
Session::put('tickets.or', $request->or);
|
||||
}
|
||||
|
||||
Session::save();
|
||||
|
||||
if (Session::has('tickets.pr')) {
|
||||
|
|
@ -634,24 +531,12 @@ class TicketController extends Controller
|
|||
$tickets->where('status', Session::get('tickets.st'));
|
||||
}
|
||||
|
||||
if (Session::has('tickets.ty')) {
|
||||
$tickets->where('type', Session::get('tickets.ty'));
|
||||
}
|
||||
|
||||
if (Session::has('tickets.or')) {
|
||||
$tickets->orderBy('order', 'ASC');
|
||||
}
|
||||
|
||||
if (
|
||||
Session::has('tickets.sort_col') and
|
||||
Session::has('tickets.sort_way') and
|
||||
in_array(Session::get('tickets.sort_col'), [
|
||||
'type',
|
||||
'title',
|
||||
'assigned_to',
|
||||
'date_mep',
|
||||
'created_at',
|
||||
'created_by'
|
||||
'id', 'site_id', 'created_at', 'created_by',
|
||||
'type', 'status', 'assigned_to'
|
||||
])
|
||||
) {
|
||||
$tickets->orderBy(
|
||||
|
|
@ -661,7 +546,6 @@ class TicketController extends Controller
|
|||
} else {
|
||||
$tickets->orderBy('last_activity', 'DESC');
|
||||
}
|
||||
|
||||
return $tickets;
|
||||
}
|
||||
|
||||
|
|
@ -711,7 +595,7 @@ class TicketController extends Controller
|
|||
});
|
||||
} //end foreach
|
||||
} //end if
|
||||
}, 'text', 'title', 'file', 'file2', 'file3', 'file4', 'file5');
|
||||
}, 'text', 'title', 'file', 'file2');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -752,54 +636,33 @@ class TicketController extends Controller
|
|||
*/
|
||||
public function createGitlabIssue(Ticket $ticket)
|
||||
{
|
||||
$userGitlabId = auth()->user()->gitlab_id;
|
||||
$gitlabRepoId = $ticket->site->gitlab_project_id;
|
||||
|
||||
if (GitLab::projects()->show($gitlabRepoId)['archived']) {
|
||||
return back()->with('error', \trans("Ce projet GitLab est archivé et ne peut pas être utilisé."));
|
||||
}
|
||||
|
||||
$description = \sprintf("%s<br>", $ticket->text);
|
||||
$cLabel = match ($ticket->type) {
|
||||
TicketTypeEnum::bug => 'c-bug,g-to-dispatch',
|
||||
TicketTypeEnum::evolution,
|
||||
TicketTypeEnum::mailing => 'c-feature',
|
||||
TicketTypeEnum::newsletter => 'c-feature,g-to-estimate',
|
||||
};
|
||||
|
||||
$assigneeId = match ($ticket->type) {
|
||||
TicketTypeEnum::bug => $userGitlabId,
|
||||
TicketTypeEnum::evolution,
|
||||
TicketTypeEnum::mailing,
|
||||
TicketTypeEnum::newsletter => $ticket->site->projectManager?->gitlab_id
|
||||
$description = \sprintf("%s<br>", $ticket->text);
|
||||
$cLabel = match ($ticket->type) {
|
||||
TicketTypeEnum::bug => 'c-bug',
|
||||
TicketTypeEnum::evolution => 'c-feature',
|
||||
};
|
||||
|
||||
try {
|
||||
foreach ($ticket->getFiles() as $key => $file) {
|
||||
if (!\is_null($file)) {
|
||||
$uploadedFile = GitLab::projects()->uploadFile($gitlabRepoId, $file);
|
||||
$description .= $this->formatGitlabFiles($ticket, $uploadedFile, $key + 1);
|
||||
}
|
||||
if (!\is_null($ticket->file)) {
|
||||
$uploadedFile = GitLab::projects()->uploadFile($gitlabRepoId, $ticket->file);
|
||||
$description .= $this->formatGitlabFiles($ticket, $uploadedFile, 1);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'title' => sprintf(
|
||||
'ts-%s : %s',
|
||||
$ticket->id,
|
||||
$ticket->title
|
||||
),
|
||||
if (!\is_null($ticket->file2)) {
|
||||
$uploadedFile2 = GitLab::projects()->uploadFile($gitlabRepoId, $ticket->file2);
|
||||
$description .= $this->formatGitlabFiles($ticket, $uploadedFile2, 2);
|
||||
}
|
||||
|
||||
$issue = GitLab::issues()->create($gitlabRepoId, [
|
||||
'title' => 'ts-' . $ticket->id,
|
||||
'description' => $description,
|
||||
'labels' => \implode(",", [
|
||||
'c-support',
|
||||
$cLabel
|
||||
]),
|
||||
];
|
||||
|
||||
if ($assigneeId) {
|
||||
$data['assignee_id'] = $assigneeId;
|
||||
}
|
||||
|
||||
$issue = GitLab::issues()->create($gitlabRepoId, $data);
|
||||
'assignee_id' => GitlabUsersEnum::olivier,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
\report($e);
|
||||
return back()->with('error', \trans("Une erreur est survenue"));
|
||||
|
|
@ -827,7 +690,7 @@ class TicketController extends Controller
|
|||
*/
|
||||
private function formatGitlabFiles(Ticket $ticket, array $uploadedFile, int $fileNb)
|
||||
{
|
||||
if (Str::endsWith($ticket->file, ['jpg', 'png', 'jpeg', 'pptx', 'docx', 'xslx', 'csv', 'svg'])) {
|
||||
if (Str::endsWith($ticket->file, ['jpg', 'png', 'jpeg'])) {
|
||||
$file = \sprintf(
|
||||
"",
|
||||
$fileNb,
|
||||
|
|
@ -842,92 +705,4 @@ class TicketController extends Controller
|
|||
}
|
||||
return \sprintf("<br><br> Fichier %d : <br>%s<br>", $fileNb, $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change order.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\UpdateChangeOrderRequest $request
|
||||
* @param mixed ...$params
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \RuntimeException Si le nom du parametre de la route ne correspond pas au params utilisé.
|
||||
*/
|
||||
public function changeOrder(UpdateChangeOrderRequest $request, mixed ...$params): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$paramNames = collect(request()->route()->parameterNames);
|
||||
$className = Str::of($paramNames->get($paramNames->count() - 2))->lower()->studly();
|
||||
$className = "\\App\\Models\\{$className}";
|
||||
$model = Arr::get($params, $paramNames->count() - 2);
|
||||
|
||||
if (!class_exists($className)) {
|
||||
throw new \RuntimeException("The {$className} class doesn't exist.");
|
||||
}
|
||||
|
||||
if (!\is_object($model)) {
|
||||
throw new \RuntimeException("The second last param isn't an object.");
|
||||
}
|
||||
|
||||
if (get_class($model) !== (string)Str::of($className)->replaceStart('\\', '')) {
|
||||
throw new \RuntimeException("The {$className} doesn't match second last binded param.");
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Model|null */
|
||||
$model = $className::query()->where($model->getRouteKeyName(), $model->getRouteKey())->first();
|
||||
|
||||
if (!$model) {
|
||||
return back()->with('error', trans('crud.messages.order_not_changed'));
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($request, $className, $model) {
|
||||
/** @var \Illuminate\Support\Collection $models */
|
||||
$models = $className::query()
|
||||
->orderBy('order', 'ASC')
|
||||
->where('site_id', $model->site_id)
|
||||
->where('status', '!=', TicketStatusEnum::archived)
|
||||
->where('id', '!=', $model->getKey())
|
||||
->where('order', $request->direction ? '<' : '>', $model->order)
|
||||
->get();
|
||||
/** @var \Illuminate\Database\Eloquent\Model|null $tmp */
|
||||
$tmp = $request->direction ? $models->last() : $models->first();
|
||||
|
||||
if (!$tmp) {
|
||||
return back()->with('error', trans('crud.messages.order_not_changed'));
|
||||
}
|
||||
|
||||
$newOrder = $tmp->getOriginal('order');
|
||||
$tmp->update(['order' => $model->getOriginal('order')]);
|
||||
$model->update(['order' => $newOrder]);
|
||||
|
||||
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ticket priority.
|
||||
*
|
||||
* @param UpdateTicketPriorityRequest $request
|
||||
* @param Ticket $ticket
|
||||
* @return void
|
||||
*/
|
||||
public function changePriority(UpdateTicketPriorityRequest $request, Ticket $ticket)
|
||||
{
|
||||
$newPriority = $request->validated('priority');
|
||||
|
||||
return DB::transaction(function () use ($ticket, $newPriority) {
|
||||
// Update all tickets who will be moved with this priority update.
|
||||
$request = Ticket::query()
|
||||
->where('site_id', $ticket->site_id)
|
||||
->whereNot('status', TicketStatusEnum::archived)
|
||||
->whereNot('id', $ticket->id)
|
||||
->whereBetween('order', [min($ticket->order, $newPriority), max($ticket->order, $newPriority)]);
|
||||
$ticket->order < $newPriority ? $request->decrement('order', 1) : $request->increment('order', 1);
|
||||
|
||||
// Update the ticket.
|
||||
$ticket->order = $newPriority;
|
||||
if (!$ticket->saveOrFail()) {
|
||||
return back()->with('error', trans('crud.messages.order_not_changed'));
|
||||
};
|
||||
|
||||
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,15 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Bo\Auth\ForgotPasswordController;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Users\StoreUserRequest;
|
||||
use App\Http\Requests\Bo\Users\UpdateUserRequest;
|
||||
use App\Http\Controllers\Bo\Auth\ForgotPasswordController;
|
||||
use App\Http\Requests\Bo\Users\FavouriteSiteRequest;
|
||||
use App\Models\Site;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
|
|
@ -73,9 +72,8 @@ class UserController extends Controller
|
|||
public function store(StoreUserRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$user = User::query()->onlyTrashed()->where('email', $request->validated('email'))->first() ?? new User();
|
||||
$user = new User();
|
||||
$user->fill($request->safe()->except('sites'));
|
||||
$user->deleted_at = null;
|
||||
|
||||
if ($user->saveOrFail()) {
|
||||
$user->sites()->attach(collect($request->validated('sites'))->pluck('id'));
|
||||
|
|
@ -172,35 +170,9 @@ class UserController extends Controller
|
|||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function settings(): \Illuminate\Contracts\View\View
|
||||
public function passwordReset(): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.users.settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Favourite site submit
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Users\FavouriteSiteRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function favouriteSiteSubmit(FavouriteSiteRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
|
||||
try {
|
||||
$user->favourite_site_id = $request->favourite_site_id;
|
||||
$user->saveOrFail();
|
||||
|
||||
return redirect()->back()->with("success", trans('crud.messages.favourite_site_changed'));
|
||||
} catch (\Exception $e) {
|
||||
\report($e);
|
||||
return redirect()->back()->with('error', trans('crud.messages.favourite_site_not_changed'));
|
||||
} catch (\Throwable $e) {
|
||||
\report($e);
|
||||
return redirect()->back()->with('error', trans('crud.messages.favourite_site_not_changed'));
|
||||
}
|
||||
return view('bo.pages.users.passwordReset');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ use Illuminate\Support\Facades\Cache;
|
|||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
|
|
@ -118,78 +117,26 @@ class Controller extends BaseController
|
|||
* @param array $fields
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
private function searchOnFields(
|
||||
Builder $query,
|
||||
string $search,
|
||||
array $fields
|
||||
): \Illuminate\Database\Eloquent\Builder {
|
||||
private function searchOnFields(Builder $query, string $search, array $fields): Builder
|
||||
{
|
||||
$table = $query->getModel()->getTable();
|
||||
foreach ($fields as $field) {
|
||||
$field = str_replace('?', '\?', $field);
|
||||
if (is_array($field)) {
|
||||
foreach ($fields as $f) {
|
||||
$f = str_replace('?', '\?', $f);
|
||||
if (is_array($f)) {
|
||||
$query->orWhereRaw(
|
||||
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($field)->map(function ($q) use ($table) {
|
||||
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($f)->map(function ($q) use ($table) {
|
||||
return "`$table`.`$q`";
|
||||
})->implode(', \' \', ')),
|
||||
['%' . htmlspecialchars($search) . '%']
|
||||
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
|
||||
);
|
||||
} else {
|
||||
$query->orWhereRaw(
|
||||
"UPPER(`$table`.`$f`) LIKE UPPER(?)",
|
||||
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
|
||||
);
|
||||
return $query;
|
||||
}
|
||||
// Get models woth enum's label.
|
||||
if (is_array($this->getSearchValue($query, $search, $field))) {
|
||||
foreach ($this->getSearchValue($query, $search, $field) as $array) {
|
||||
$query->orWhereRaw(
|
||||
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
|
||||
['%' . htmlspecialchars($array->value) . '%']
|
||||
);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
// Get models with relation's name/label.
|
||||
if (Str::endsWith($field, '_id')) {
|
||||
$query->orWhereHas(Str::remove('_id', $field), function ($queryRelation) use ($field, $search) {
|
||||
if (Schema::hasColumn(Str::remove('_id', $field) . 's', 'name')) {
|
||||
$queryRelation->where('name', 'like', '%' . $search . '%');
|
||||
} elseif (Schema::hasColumn(Str::remove('_id', $field) . 's', 'label')) {
|
||||
$queryRelation->where('label', 'like', '%' . $search . '%');
|
||||
}
|
||||
});
|
||||
return $query;
|
||||
}
|
||||
$query->orWhereRaw(
|
||||
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
|
||||
['%' . htmlspecialchars($this->getSearchValue($query, $search, $field)) . '%']
|
||||
);
|
||||
} //end foreach
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the search value (on string or Enum).
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param string $search
|
||||
* @param string $field
|
||||
* @return string|array
|
||||
*/
|
||||
protected function getSearchValue(Builder $query, string $search, string $field): string|array
|
||||
{
|
||||
$cast = $query->getModel()->getCasts()[$field] ?? null;
|
||||
if (
|
||||
count($query->getModel()->getCasts()) and // Check if the model has casts.
|
||||
$cast and // Check if there is cast about specific field.
|
||||
enum_exists($cast) // Check if the cast is an enum.
|
||||
) {
|
||||
/** @var \App\Traits\Enums $cast */
|
||||
// @phpstan-ignore-next-line
|
||||
$cases = collect($cast::toArray());
|
||||
$enum = $cases->filter(function ($item) use ($search) {
|
||||
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label));
|
||||
});
|
||||
return $enum->toArray();
|
||||
} else {
|
||||
return $search;
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -216,13 +163,17 @@ class Controller extends BaseController
|
|||
Session::remove("$rName.sort_col");
|
||||
Session::remove("$rName.sort_way");
|
||||
}
|
||||
if (
|
||||
request()->sort_col &&
|
||||
request()->sort_way &&
|
||||
Schema::hasColumn($table, request()->sort_col) &&
|
||||
(!isset($ignore) || (isset($ignore) && !in_array(request()->sort_col, $ignore)))
|
||||
) {
|
||||
$query = $query->orderBy("$table." . request()->sort_col, request()->sort_way);
|
||||
if (request()->sort_col and request()->sort_way and Schema::hasColumn($table, request()->sort_col)) {
|
||||
if (
|
||||
!isset($ignore) or
|
||||
(isset($ignore) and !in_array(request()->sort_col, $ignore))
|
||||
) {
|
||||
$query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->sort_way);
|
||||
}
|
||||
} elseif (Schema::hasColumn($table, 'order')) {
|
||||
$query = $query->orderBy('order', 'ASC');
|
||||
Session::put("$rName.sort_col", 'order');
|
||||
Session::put("$rName.sort_way", 'asc');
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ class RedirectIfAuthenticated
|
|||
if (Auth::guard($guard)->check()) {
|
||||
switch ($guard) {
|
||||
case 'backend':
|
||||
if (!$request->routeIs('bo.*') && !$request->routeIs('login')) {
|
||||
continue 2;
|
||||
if (!$request->routeIs('bo.*')) {
|
||||
continue;
|
||||
}
|
||||
return \redirect()->route('bo.dashboard');
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ class VerifyCsrfToken extends Middleware
|
|||
* @var array<int, string>
|
||||
*/
|
||||
protected $except = [
|
||||
'/csp-report',
|
||||
'/brevo-in'
|
||||
'/csp-report'
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class AssignTicketToUserRequest extends FormRequest
|
|||
return [
|
||||
'assign' => [
|
||||
'nullable', 'exists:users,id',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
/** @var \App\Models\User $user */
|
||||
if ($user = User::whereId($value)->first() and !$user->isAdmin()) {
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use Domain\Models\ValueObjects\Email;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
class BrevoWebhookRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getFromAddress(): Email
|
||||
{
|
||||
return new Email($this->string('items.0.From.Address'));
|
||||
}
|
||||
|
||||
public function getToAddress(): Email
|
||||
{
|
||||
return new Email((string) $this->input('items.0.To.0.Address'));
|
||||
}
|
||||
|
||||
public function getRawHtmlBody(): string
|
||||
{
|
||||
return $this->string('items.0.RawHtmlBody');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$expectedFormAddress = Config::string('mail.brevo_webook.expected_from_address');
|
||||
|
||||
return [
|
||||
'items' => ['required', 'array', 'min:1'],
|
||||
'items.0.From.Address' => ['required', 'email:rfc,spoof'],
|
||||
'items.0.To.*.Address' => ['required', 'email:rfc,spoof', "in:{$expectedFormAddress}"],
|
||||
'items.0.RawHtmlBody' => ['required', 'string', 'min:10'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ class ChangeTicketStatus extends FormRequest
|
|||
return [
|
||||
'status' => [
|
||||
'required',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketStatusEnum::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
|
|
|
|||
|
|
@ -37,11 +37,9 @@ class CreateMessage extends FormRequest
|
|||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
$this->merge([
|
||||
'subscribe' => $this->subscribe ? true : false,
|
||||
'type' => $this->is_private ? MessageTypeEnum::private->value : MessageTypeEnum::public->value
|
||||
'type' => $this->is_private ? MessageTypeEnum::private->value : MessageTypeEnum::public->value
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -55,24 +53,13 @@ class CreateMessage extends FormRequest
|
|||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return [
|
||||
'subscribe' => 'required|boolean',
|
||||
'message' => [
|
||||
'subscribe' => 'required|boolean',
|
||||
'message' => 'required|min:' . ($user->isAdmin() ? '5' : '20'),
|
||||
'file_message' => 'sometimes|mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
'type' => [
|
||||
'required',
|
||||
'min:' . ($user->isAdmin() ? '5' : '20'),
|
||||
function ($attribute, $value, $fail) {
|
||||
$forbidden = ['merci de', 'merci de'];
|
||||
foreach ($forbidden as $word) {
|
||||
if (stripos(strtolower($value), $word) !== false) {
|
||||
$fail(
|
||||
"Le champs 'Message' contient la chaine de caractère non autorisée suivante : $word"
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
'file_messages' => 'sometimes|array',
|
||||
'file_messages.*' => 'mimes:pptx,docx,xlsx,csv,txt,jpeg,jpg,png,pdf,svg|max:2048',
|
||||
'type' => ['required', new Enum(MessageTypeEnum::class)]
|
||||
new Enum(MessageTypeEnum::class)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,18 +33,14 @@ class CreateEstimateRequest extends FormRequest
|
|||
$ticket = $this->ticket;
|
||||
return [
|
||||
'amount' => [
|
||||
'required',
|
||||
'numeric',
|
||||
'gt:0',
|
||||
function ($attribute, $value, $fail) {
|
||||
if (fmod((\floatval($value) * 1000), 62.5) !== 0.0) {
|
||||
$fail("$attribute doit être un multiple de 62.5 (soit 0.0625)");
|
||||
'required', 'numeric', 'gt:0', function ($attribute, $value, $fail) {
|
||||
if ((\floatval($value) * 1000) % 125 !== 0) {
|
||||
$fail("$attribute doit être un multiple de 125 (soit 0.125)");
|
||||
}
|
||||
}
|
||||
],
|
||||
'credit_account_id' => [
|
||||
'required',
|
||||
'exists:credit_accounts,id',
|
||||
'required', 'exists:credit_accounts,id',
|
||||
function ($attribute, $value, $fail) use ($ticket) {
|
||||
/** @var \App\Models\Credit\Account|null */
|
||||
$account = Account::whereId($value)->first();
|
||||
|
|
@ -61,11 +57,11 @@ class CreateEstimateRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'amount' => 'Montant',
|
||||
'credit_account_id' => 'Compte à débiter'
|
||||
'credit_account_id' => 'Compte'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class StoreCreditLogRequest extends FormRequest
|
|||
{
|
||||
return [
|
||||
'amount' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'required', 'numeric', 'min:0', 'max:255', function ($attribute, $value, $fail) {
|
||||
if (($value * 10) % 5 !== 0) {
|
||||
$fail("Le Montant de l'opération doit être divisible par 0.5 jour/homme");
|
||||
|
|
|
|||
47
app/Http/Requests/Bo/Dutyhours/StoreDutyhourRequest.php
Normal file
47
app/Http/Requests/Bo/Dutyhours/StoreDutyhourRequest.php
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Dutyhours;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class StoreDutyhourRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Gate::allows('isAdmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'date' => 'required|date|after_or_equal:today',
|
||||
'person' => 'required|string|min:3|max:255',
|
||||
'place' => 'required|string|min:3|max:255',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'date' => trans('Date de la permanence'),
|
||||
'person' => trans('Personne associée à la permanence'),
|
||||
'place' => trans('Lieu de la permanence'),
|
||||
];
|
||||
}
|
||||
}
|
||||
7
app/Http/Requests/Bo/Dutyhours/UpdateDutyhourRequest.php
Normal file
7
app/Http/Requests/Bo/Dutyhours/UpdateDutyhourRequest.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Dutyhours;
|
||||
|
||||
class UpdateDutyhourRequest extends StoreDutyhourRequest
|
||||
{
|
||||
}
|
||||
37
app/Http/Requests/Bo/EraseCellContentRequest.php
Normal file
37
app/Http/Requests/Bo/EraseCellContentRequest.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use App\Enums\Planning\TableRowEnum;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class EraseCellContentRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->check() and $this->ajax();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'id' => 'required|exists:week_plannings,id',
|
||||
'day' => 'required|numeric',
|
||||
'row' => [
|
||||
'required',
|
||||
new Enum(TableRowEnum::class)
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ class StoreInvoiceRequest extends FormRequest
|
|||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'tasks' => request()->tasks ? \collect(json_decode(request()->tasks))
|
||||
'tasks' => request()->tasks ? \collect(json_decode(request()->tasks))
|
||||
->map(function ($task) {
|
||||
return \array_intersect_key((array)$task, Invoice::getTaskStructure());
|
||||
})->toArray() : [],
|
||||
|
|
@ -44,24 +44,24 @@ class StoreInvoiceRequest extends FormRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'firstname' => 'required|string|min:3|max:255',
|
||||
'lastname' => 'required|string|min:3|max:255',
|
||||
'object' => 'required|string|min:3|max:255',
|
||||
'tasks' => 'required|array|min:1',
|
||||
'tasks.*' => 'required|array',
|
||||
'tasks.*.days' => 'required|numeric',
|
||||
'firstname' => 'required|string|min:3|max:255',
|
||||
'lastname' => 'required|string|min:3|max:255',
|
||||
'object' => 'required|string|min:3|max:255',
|
||||
'tasks' => 'required|array|min:1',
|
||||
'tasks.*' => 'required|array',
|
||||
'tasks.*.days' => 'required|numeric',
|
||||
'tasks.*.amount' => 'required|numeric',
|
||||
'tasks.*.desc' => 'required|string|min:10',
|
||||
'tasks.*.type' => [
|
||||
'tasks.*.desc' => 'required|string|min:10',
|
||||
'tasks.*.type' => [
|
||||
'required', new Enum(TaskTypeEnum::class)
|
||||
],
|
||||
'tasks.*.package' => 'required_if:tasks.*.type,' . TaskTypeEnum::package->value .
|
||||
'|nullable|exists:packages,id',
|
||||
'comment' => 'sometimes|nullable|string|min:15',
|
||||
'show_days' => 'required|boolean',
|
||||
'site_id' => 'required|integer|exists:sites,id',
|
||||
'company_id' => 'required|integer|exists:companies,id',
|
||||
'invoiced_to_id' => 'required|integer|exists:companies,id',
|
||||
'comment' => 'sometimes|nullable|string|min:15',
|
||||
'show_days' => 'required|boolean',
|
||||
'site_id' => 'required|integer|exists:sites,id',
|
||||
'company_id' => 'required|integer|exists:companies,id',
|
||||
'invoiced_to_id' => 'required|integer|exists:companies,id',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ class UpdateInvoiceRequest extends StoreInvoiceRequest
|
|||
$rules = array_merge($rules, parent::rules());
|
||||
}
|
||||
$rules = array_merge($rules, [
|
||||
'comment' => 'sometimes|nullable|string|min:15',
|
||||
'sent_client_date' => 'required_with:signed_date,sent_accounting_date|sometimes|nullable|date',
|
||||
'signed_date' => 'required_with:sent_accounting_date|sometimes|nullable|date',
|
||||
'comment' => 'sometimes|nullable|string|min:15',
|
||||
'sent_client_date' => 'required_with:signed_date,sent_accounting_date|sometimes|nullable|date',
|
||||
'signed_date' => 'required_with:sent_accounting_date|sometimes|nullable|date',
|
||||
'sent_accounting_date' => 'sometimes|nullable|date',
|
||||
'status' => [
|
||||
'status' => [
|
||||
'required',
|
||||
new Enum(InvoiceStatusEnum::class),
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
//phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) use ($model) {
|
||||
if (
|
||||
(intval($value) === InvoiceStatusEnum::archived->value) &&
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Labels;
|
||||
|
||||
use App\Rules\Hex;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use LVR\Colour\Hex;
|
||||
|
||||
class StoreLabelRequest extends FormRequest
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class LinkTicket extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
/** @var \App\Models\User|null $user */
|
||||
$user = Auth::user();
|
||||
return Auth::check() && $user->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$ticket = $this->route('ticket');
|
||||
return [
|
||||
'linked_ticket_id' => [
|
||||
'required',
|
||||
'numeric',
|
||||
'exists:tickets,id',
|
||||
'not_in:' . $ticket->id,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -17,18 +17,6 @@ class StorePackageRequest extends FormRequest
|
|||
return Gate::allows('isAdmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'published' => $this->boolean('published'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
|
|
@ -39,7 +27,6 @@ class StorePackageRequest extends FormRequest
|
|||
return [
|
||||
'name' => 'required|string|min:3|max:255',
|
||||
'amount' => 'required|numeric|min:0|regex:/^\d+(\.\d{1,2})?$/',
|
||||
'published' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +40,6 @@ class StorePackageRequest extends FormRequest
|
|||
return [
|
||||
'name' => trans('Nom'),
|
||||
'amount' => trans('Montant (par jour)'),
|
||||
'published' => trans('Publication')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
32
app/Http/Requests/Bo/Projects/StoreProjectRequest.php
Normal file
32
app/Http/Requests/Bo/Projects/StoreProjectRequest.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Projects;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class StoreProjectRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Gate::allows('isAdmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|min:3|max:255|unique:projects,name',
|
||||
'site_id' => 'required|exists:sites,id',
|
||||
];
|
||||
}
|
||||
}
|
||||
18
app/Http/Requests/Bo/Projects/UpdateProjectRequest.php
Normal file
18
app/Http/Requests/Bo/Projects/UpdateProjectRequest.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Projects;
|
||||
|
||||
class UpdateProjectRequest extends StoreProjectRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), [
|
||||
'name' => 'required|string|min:3|max:255|unique:projects,name,' . $this->route('project')->id . ',id',
|
||||
]);
|
||||
}
|
||||
}
|
||||
68
app/Http/Requests/Bo/SetCellContentRequest.php
Normal file
68
app/Http/Requests/Bo/SetCellContentRequest.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use App\Enums\Planning\CellModelEnum;
|
||||
use App\Enums\Planning\CellTypeEnum;
|
||||
use App\Enums\Planning\TableRowEnum;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class SetCellContentRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
$this->merge([
|
||||
'model' => $this->model ?? null,
|
||||
'foreign' => $this->foreign ?? null,
|
||||
'text' => $this->text ?? ''
|
||||
]);
|
||||
return auth()->check() and $this->ajax();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'id' => 'required|exists:week_plannings,id',
|
||||
'day' => 'required|numeric',
|
||||
'row' => [
|
||||
'required',
|
||||
new Enum(TableRowEnum::class)
|
||||
],
|
||||
'type' => [
|
||||
'required',
|
||||
new Enum(CellTypeEnum::class)
|
||||
],
|
||||
'CellModelEnum' => \sprintf(
|
||||
'nullable',
|
||||
new Enum(CellModelEnum::class)
|
||||
),
|
||||
'foreign' => 'required_with:CellModelEnum|nullable|numeric',
|
||||
'text' => 'required|string|min:5|max:90'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'CellModelEnum' => 'Type d\'élément lié',
|
||||
'foreign' => 'Élément lié',
|
||||
'text' => 'Description courte'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -28,8 +28,7 @@ class StoreSiteRequest extends FormRequest
|
|||
'name' => 'required|string|min:3|max:255',
|
||||
'users' => 'nullable|array',
|
||||
'users.*.id' => 'required|exists:users,id',
|
||||
'gitlab_project_id' => 'nullable',
|
||||
'project_manager_id' => 'nullable|exists:users,id',
|
||||
'gitlab_project_id' => 'nullable|unique:sites,gitlab_project_id',
|
||||
'url_re7' => 'nullable|url',
|
||||
'url_prod' => 'nullable|url'
|
||||
];
|
||||
|
|
@ -47,7 +46,6 @@ class StoreSiteRequest extends FormRequest
|
|||
'users' => trans('Utilisateurs associés au site'),
|
||||
'users.*.id' => trans('Élément parmis les Utilisateurs associés au site'),
|
||||
'gitlab_project_id' => trans('ID du dépôt Gitlab'),
|
||||
'project_manager_id' => trans('Chef de projet'),
|
||||
'url_re7' => trans('Url de RECETTE'),
|
||||
'url_prod' => trans('Url de prod')
|
||||
];
|
||||
|
|
|
|||
|
|
@ -4,4 +4,15 @@ namespace App\Http\Requests\Bo\Sites;
|
|||
|
||||
class UpdateSiteRequest extends StoreSiteRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), [
|
||||
'gitlab_project_id' => 'nullable|unique:sites,gitlab_project_id,' . $this->route('site')->id . ',id',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class SortTickets extends FormRequest
|
|||
'sort_way' => 'sometimes|in:asc,desc',
|
||||
'status' => [
|
||||
'sometimes',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketStatusEnum::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class StoreTicket extends FormRequest
|
|||
'site_id' => [
|
||||
'required',
|
||||
'exists:sites,id',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
|
|
@ -76,7 +76,7 @@ class StoreTicket extends FormRequest
|
|||
],
|
||||
'type' => [
|
||||
'required',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketTypeEnum::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
|
|
@ -87,7 +87,7 @@ class StoreTicket extends FormRequest
|
|||
],
|
||||
'status' => [
|
||||
'required',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketStatusEnum::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
|
|
@ -96,29 +96,14 @@ class StoreTicket extends FormRequest
|
|||
}
|
||||
}
|
||||
],
|
||||
'date_mep' => 'nullable|date',
|
||||
'text' => [
|
||||
'required',
|
||||
'string',
|
||||
'min:40',
|
||||
function ($attribute, $value, $fail) {
|
||||
$forbidden = ['merci de', 'merci de'];
|
||||
foreach ($forbidden as $word) {
|
||||
if (stripos(strtolower($value), $word) !== false) {
|
||||
$fail(
|
||||
"Le champs 'Description du ticket' contient la chaine de caractère non autorisée suivante : $word"
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
'title' => 'required|string|between:3,255',
|
||||
'file_tickets' => 'sometimes|array',
|
||||
'file_tickets.*' => 'mimes:pptx,docx,xlsx,csv,txt,jpeg,jpg,png,pdf,svg|max:2048',
|
||||
'is_internal' => 'required|boolean',
|
||||
'labels' => 'sometimes|array',
|
||||
'labels.*' => [
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
'text' => 'required|string|min:40',
|
||||
'title' => 'required|string|between:3,255',
|
||||
'file_ticket' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
'file_ticket2' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
'is_internal' => 'required|boolean',
|
||||
'labels' => 'sometimes|array',
|
||||
'labels.*' => [
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'required', 'exists:labels,id', function ($attribute, $value, $fail) use ($user) {
|
||||
if (!$user->can('assignLabels', Ticket::class)) {
|
||||
$fail(trans('Vous n\'êtes pas autorisé à modifier cette valeur'));
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateChangeOrderRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'direction' => $this->route('direction') === 'up' ? true : false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'direction' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateTicketPriorityRequest extends FormRequest
|
||||
{
|
||||
private \App\Models\Ticket $ticket;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->ticket = $this->route('ticket');
|
||||
$max = Ticket::query()->where('site_id', $this->ticket->site_id)->max('order');
|
||||
|
||||
$this->merge([
|
||||
'priority' => min($this->integer('priority'), $max)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'priority' => [
|
||||
'required',
|
||||
'integer',
|
||||
'min:1',
|
||||
function ($attribute, $value, $fail) {
|
||||
if ($this->ticket && intval($value) === $this->ticket->order) {
|
||||
$fail("La valeur de {$attribute} doit être différente de la valeur actuelle.");
|
||||
}
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Users;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FavouriteSiteRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var \App\Models\User|null $user */
|
||||
$user = Auth::user();
|
||||
|
||||
return [
|
||||
'favourite_site_id' => [
|
||||
'nullable',
|
||||
'exists:sites,id',
|
||||
Rule::in($user->sites->pluck('id')),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -19,18 +19,6 @@ class StoreUserRequest extends FormRequest
|
|||
return Gate::allows('isAdmin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'gitlab_id' => \boolval($this->input('gitlab_id')) ? $this->input('gitlab_id') : null
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
|
|
@ -40,18 +28,13 @@ class StoreUserRequest extends FormRequest
|
|||
{
|
||||
return [
|
||||
'name' => 'required|string|min:3|max:255',
|
||||
'email' => [
|
||||
'email',
|
||||
'required',
|
||||
Rule::unique('users', 'email')->whereNull('deleted_at')
|
||||
],
|
||||
'email' => 'email|required|unique:users,email',
|
||||
'role' => [
|
||||
'required',
|
||||
Rule::in(collect(RoleEnum::cases())->pluck('value')->all()),
|
||||
],
|
||||
'sites' => 'nullable|array',
|
||||
'sites.*.id' => 'required|exists:sites,id',
|
||||
'gitlab_id' => 'nullable|integer|unique:users,gitlab_id'
|
||||
'sites.*.id' => 'required|exists:sites,id'
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +51,6 @@ class StoreUserRequest extends FormRequest
|
|||
'role' => trans('Rôle de l\'utilisateur'),
|
||||
'sites' => trans('Sites associés à l\'utilisateur'),
|
||||
'sites.*.id' => trans('Élément parmis les sites associés à l\'utilisateur'),
|
||||
'gitlab_id' => trans("ID de l'utilisateur Gitlab")
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ class UpdateUserRequest extends StoreUserRequest
|
|||
public function rules()
|
||||
{
|
||||
return array_merge(parent::rules(), [
|
||||
'email' => 'email|required|unique:users,email,' . $this->route('user')->id . ',id',
|
||||
'gitlab_id' => 'nullable|integer|unique:users,gitlab_id,' . $this->route('user')->id . ',id'
|
||||
'email' => 'email|required|unique:users,email,' . $this->route('user')->id . ',id',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Interfaces;
|
||||
|
||||
interface SpsConfigInterface
|
||||
{
|
||||
/**
|
||||
* URL method
|
||||
* Website (SP) url ex: https://le-gaulois-pro.s-web.test
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url(): string;
|
||||
/**
|
||||
* acsBase64 method
|
||||
* Return destination url base64 encoded
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function acsBase64(): string;
|
||||
/**
|
||||
* destination method
|
||||
* Return acs url concatenated with url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function destination(): string;
|
||||
/**
|
||||
* logout method
|
||||
* Return sls url concatenated with url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function logout(): string;
|
||||
/**
|
||||
* certificate method
|
||||
* Return certificate (.pem) file from kebab case of Enum name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function certificate(): string;
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use App\Models\Site;
|
||||
use App\Models\Ticket;
|
||||
use App\Notifications\ExportTicketsStateNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class ExportTicketsState implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* CSV File headers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $header = [
|
||||
"Priorité service",
|
||||
"Site",
|
||||
"Numéro de ticket",
|
||||
"Priorité",
|
||||
"Date de MEP souhaitée",
|
||||
"Type de ticket",
|
||||
"Titre du ticket",
|
||||
"Statut du ticket",
|
||||
"Chef de projet",
|
||||
"Utilisateur assigné",
|
||||
"Date de dernière activité",
|
||||
"Date de création",
|
||||
"Lien vers le ticket",
|
||||
"Lien vers l'issue GitLab"
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
// L'ordre commence à 0 et reprendra à 1 pour chaque site.
|
||||
$order = 0;
|
||||
// Dernier site traité.
|
||||
$lastSiteId = null;
|
||||
// Insertion de la ligne d'en-têtes.
|
||||
$csvlines[] = $this->header;
|
||||
|
||||
// Récupération des tickets.
|
||||
Ticket::query()
|
||||
->whereNotIn(
|
||||
'status',
|
||||
[TicketStatusEnum::archived, TicketStatusEnum::production]
|
||||
)
|
||||
->orderBy(Site::select('name')
|
||||
->whereColumn('sites.id', 'tickets.site_id'))
|
||||
->orderBy('order')->get()->each(function (Ticket $ticket) use (&$csvlines, &$lastSiteId, &$order) {
|
||||
$csvlines[] = [
|
||||
"",
|
||||
$ticket->site->name,
|
||||
$ticket->id,
|
||||
$lastSiteId === $ticket->site_id ? $order + 1 : 1,
|
||||
$ticket->date_mep?->format('d-m-Y') ?? 'No MEP Date',
|
||||
$ticket->type->label(),
|
||||
$ticket->title,
|
||||
$ticket->status->label(),
|
||||
$ticket->projectManager->name ?? 'No PM',
|
||||
$ticket->assignedUser()->name ?? 'No Assigned User',
|
||||
Carbon::create($ticket->getRawOriginal('last_activity'))->format('d-m-Y H:i:s'),
|
||||
$ticket->created_at->format('d-m-Y H:i:s'),
|
||||
route('bo.ticket.show', $ticket->id),
|
||||
$ticket->gitlab_issue ?? 'No GitLab Issue'
|
||||
];
|
||||
|
||||
$order = $lastSiteId === $ticket->site_id ? $order + 1 : 1;
|
||||
$lastSiteId = $ticket->site_id;
|
||||
});
|
||||
|
||||
Notification::route('mail', config('mail.MAIL_ADMIN'))
|
||||
->notify(new ExportTicketsStateNotification($this->array2csv($csvlines, ";")));
|
||||
}
|
||||
|
||||
/**
|
||||
* converts an array to a csv stream
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $delimiter
|
||||
* @param string $enclosure
|
||||
* @param string $escape_char
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function array2csv(
|
||||
array $data,
|
||||
string $delimiter = ',',
|
||||
string $enclosure = '"',
|
||||
string $escape_char = "\\"
|
||||
) {
|
||||
$f = fopen('php://memory', 'r+');
|
||||
|
||||
// UTF-8 BOM.
|
||||
$BOM = "\xEF\xBB\xBF";
|
||||
fwrite($f, $BOM);
|
||||
|
||||
foreach ($data as $item) {
|
||||
fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
|
||||
}
|
||||
rewind($f);
|
||||
return stream_get_contents($f);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use App\Traits\Controllers\HasGitlabIssue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use App\Http\Requests\Bo\ChangeTicketStatus;
|
||||
|
||||
class UpdateIssueLabels implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
use HasGitlabIssue;
|
||||
|
||||
/** @var Ticket */
|
||||
protected $ticket;
|
||||
|
||||
/** @var requestStatus */
|
||||
protected $requestStatus;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param \App\Models\Ticket $ticket
|
||||
* @param string $request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Ticket $ticket, string $requestStatus)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->requestStatus = $requestStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$oldStatus = $this->ticket->status;
|
||||
$requestStatus = (int) $this->requestStatus;
|
||||
$gitlabIssue = $this->getGitlabIssue($this->ticket->site->gitlab_project_id, $this->ticket->gitlab_issue);
|
||||
|
||||
$issueLabels = $gitlabIssue['labels'];
|
||||
|
||||
if ($oldStatus === TicketStatusEnum::waiting && $requestStatus !== TicketStatusEnum::waiting->value) {
|
||||
$issueLabels = array_values(array_diff($issueLabels, ['g-wait']));
|
||||
}
|
||||
|
||||
switch ($requestStatus) {
|
||||
case TicketStatusEnum::takenInAccount->value:
|
||||
$newLabels = ['g-to-dispatch'];
|
||||
$updatedLabels = array_unique(array_merge($issueLabels, $newLabels));
|
||||
|
||||
$updatedIssue = $this->updateGitlabIssueLabels($gitlabIssue['project_id'], $gitlabIssue['iid'], $updatedLabels);
|
||||
break;
|
||||
case TicketStatusEnum::waiting->value:
|
||||
$newLabels = ['g-wait'];
|
||||
$updatedLabels = array_unique(array_merge($issueLabels, $newLabels));
|
||||
|
||||
$updatedIssue = $this->updateGitlabIssueLabels($gitlabIssue['project_id'], $gitlabIssue['iid'], $updatedLabels);
|
||||
break;
|
||||
case TicketStatusEnum::waitingValidation->value:
|
||||
$removeLabels = ['g-to-estimate'];
|
||||
$updatedLabels = array_diff($issueLabels, $removeLabels);
|
||||
|
||||
$updatedIssue = $this->updateGitlabIssueLabels($gitlabIssue['project_id'], $gitlabIssue['iid'], $updatedLabels);
|
||||
break;
|
||||
case TicketStatusEnum::recetteValidated->value:
|
||||
$newLabels = ['g-re7-ok', 'to-prod'];
|
||||
$updatedLabels = array_unique(array_merge($issueLabels, $newLabels));
|
||||
|
||||
$updatedIssue = $this->updateGitlabIssueLabels($gitlabIssue['project_id'], $gitlabIssue['iid'], $updatedLabels);
|
||||
break;
|
||||
case TicketStatusEnum::archived->value:
|
||||
$updatedIssue = $this->closeGitlabIssue($gitlabIssue['project_id'], $gitlabIssue['iid'], $issueLabels);
|
||||
break;
|
||||
default:
|
||||
$updatedIssue = $this->updateGitlabIssueLabels($gitlabIssue['project_id'], $gitlabIssue['iid'], $issueLabels);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -68,18 +68,6 @@ class ToolboxHelper
|
|||
return \preg_match('/(\.png|\.jpg|\.jpeg|\.gif)$/', $url, $m) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check uri points to pdf file
|
||||
*
|
||||
* @param string $url
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isPdfFile(string $url): bool
|
||||
{
|
||||
$m = [];
|
||||
return \preg_match('/(\.pdf)$/', $url, $m) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip scheme (https) on oembed urls
|
||||
* Only embed allowed are for MP4 self hosted videos right now
|
||||
|
|
@ -351,7 +339,7 @@ class ToolboxHelper
|
|||
): Builder {
|
||||
$currentLocale = app()->currentLocale();
|
||||
$locales = collect(config('app.locales'))
|
||||
->mapWithKeys(fn(string $locale) => [$locale => $locale]);
|
||||
->mapWithKeys(fn (string $locale) => [$locale => $locale]);
|
||||
if (!$locales->has($defaultLocale)) {
|
||||
// * Remove default locale.
|
||||
$locales->pull($defaultLocale);
|
||||
|
|
@ -369,7 +357,7 @@ class ToolboxHelper
|
|||
$q->whereRaw("JSON_EXTRACT({$column}, '$.{$currentLocale}') = '{$value}'");
|
||||
}
|
||||
// * Query any other locale
|
||||
$locales->each(fn($locale) => $q->orWhereRaw(
|
||||
$locales->each(fn ($locale) => $q->orWhereRaw(
|
||||
"JSON_EXTRACT({$column}, '$.{$locale}') = '{$value}'"
|
||||
));
|
||||
});
|
||||
|
|
@ -461,10 +449,7 @@ class ToolboxHelper
|
|||
$fileFullPath = self::getUploadedFileFullPath($value, $useStorage);
|
||||
if (
|
||||
!\in_array(self::getUploadedFileMimeType($value, $useStorage), [
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
'image/png',
|
||||
'image/gif'
|
||||
'image/jpeg', 'image/jpg', 'image/png', 'image/gif'
|
||||
])
|
||||
) {
|
||||
$fail(trans(':attribute doit être une image de type \'image/jpeg,image/jpg,image/png,image/gif\'', [
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ class AddStatusMessages
|
|||
$message = new Message();
|
||||
$message->ticket_id = $event->ticket->id;
|
||||
// * Le message system est privé si demandé (eg: Assignation à une personne).
|
||||
$message->type = $event->is_private ? MessageTypeEnum::private : MessageTypeEnum::public;
|
||||
$message->type = $event->is_private ?
|
||||
MessageTypeEnum::public : MessageTypeEnum::private;
|
||||
if ($event->message) {
|
||||
$message->message = $event->message;
|
||||
} elseif ($event->user) {
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\BrevoWebhookCallReceived;
|
||||
use App\Events\TicketCreated;
|
||||
use App\Mail\NewTicket;
|
||||
use App\Repositories\SiteRepository;
|
||||
use App\Services\AutomaticTicketCreator;
|
||||
use Domain\Models\ValueObjects\Email;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
// NOTE: this should be queued in order to be eventually retried or at least keep info data.
|
||||
class CreateTicketAutomatically implements ShouldQueue
|
||||
{
|
||||
private const string SITE_NAME_WHERE_TO_CREATE_TICKET = 'Mailing en masse';
|
||||
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly AutomaticTicketCreator $automaticTicketCreator,
|
||||
private readonly SiteRepository $siteRepository,
|
||||
private readonly Dispatcher $dispatcher
|
||||
) {}
|
||||
|
||||
public function handle(BrevoWebhookCallReceived $event): void
|
||||
{
|
||||
$fromEmail = $event->from;
|
||||
$toEmail = $event->to;
|
||||
$htmlRawContent = $event->htmlRawContent;
|
||||
|
||||
$this->logger->info('Received a ticket creation event from brevo');
|
||||
$this->logger->debug(
|
||||
'Payload for ticket creation form brevo',
|
||||
[
|
||||
'from_email' => $fromEmail->value,
|
||||
'to_email' => $toEmail->value,
|
||||
'html_raw_content' => base64_encode($htmlRawContent)
|
||||
]
|
||||
);
|
||||
|
||||
$siteReceivingTickets = $this->siteRepository->findByName(self::SITE_NAME_WHERE_TO_CREATE_TICKET);
|
||||
|
||||
if ($siteReceivingTickets === null) {
|
||||
throw new \UnexpectedValueException(
|
||||
'No site found with name \'' .
|
||||
self::SITE_NAME_WHERE_TO_CREATE_TICKET . '\''
|
||||
);
|
||||
}
|
||||
|
||||
$projectManager = $siteReceivingTickets->projectManager()->first();
|
||||
|
||||
if ($projectManager === null) {
|
||||
throw new \UnexpectedValueException(
|
||||
'No project manager found for site \'' .
|
||||
self::SITE_NAME_WHERE_TO_CREATE_TICKET . '\''
|
||||
);
|
||||
}
|
||||
|
||||
$ticket = $this->automaticTicketCreator->createTicket(
|
||||
$siteReceivingTickets,
|
||||
$projectManager,
|
||||
$htmlRawContent,
|
||||
);
|
||||
|
||||
$this->dispatcher->dispatch(new TicketCreated(
|
||||
siteReceivingTicket: $siteReceivingTickets,
|
||||
ticket: $ticket,
|
||||
byUserName: $fromEmail->value
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,51 +3,21 @@
|
|||
namespace App\Listeners;
|
||||
|
||||
use App\Events\NotifyAdmin;
|
||||
use App\Events\TicketCreated;
|
||||
use App\Mail\NewTicket;
|
||||
use App\Mail\TicketUpdate;
|
||||
use Domain\Models\ValueObjects\Email;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class SendNotificationMailToAdmin
|
||||
{
|
||||
private readonly Email $mailAdmin;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mailAdmin = new Email(
|
||||
Config::string('mail.MAIL_ADMIN')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param \App\Events\NotifyAdmin $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(NotifyAdmin | TicketCreated $event)
|
||||
public function handle(NotifyAdmin $event)
|
||||
{
|
||||
if ($event instanceof NotifyAdmin) {
|
||||
$ticket = $event->ticket;
|
||||
Mail::to($this->mailAdmin->value)
|
||||
->send(new TicketUpdate($ticket, $event->corpsMaj));
|
||||
}
|
||||
if ($event instanceof TicketCreated) {
|
||||
$ticket = $event->ticket;
|
||||
$siteReceivingTickets = $event->siteReceivingTicket;
|
||||
$userName = $event->byUserName;
|
||||
|
||||
Mail::to($this->mailAdmin->value)
|
||||
->send(new NewTicket(
|
||||
ticketId: $ticket->id,
|
||||
siteName: $siteReceivingTickets->name,
|
||||
ticketTitle: $ticket->title,
|
||||
ticketType: $ticket->type,
|
||||
userName: $userName,
|
||||
ticketDescription: $ticket->text,
|
||||
));
|
||||
}
|
||||
$ticket = $event->ticket;
|
||||
Mail::to(config('mail.MAIL_ADMIN'))
|
||||
->send(new TicketUpdate($ticket, $event->corpsMaj));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,23 +2,29 @@
|
|||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Enums\Tickets\TicketTypeEnum;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class NewTicket extends Mailable implements ShouldQueue
|
||||
class NewTicket extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
private readonly int $ticketId,
|
||||
private readonly string $siteName,
|
||||
private readonly string $ticketTitle,
|
||||
private readonly TicketTypeEnum $ticketType,
|
||||
private readonly string $userName,
|
||||
private readonly string $ticketDescription,
|
||||
) {}
|
||||
/** @var \App\Models\Ticket */
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param \App\Models\Ticket $ticket
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
|
|
@ -27,14 +33,8 @@ class NewTicket extends Mailable implements ShouldQueue
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->subject("[Support] Nouveau ticket n° {$this->ticketId} - {$this->ticketTitle}")
|
||||
->view('emails.new-ticket', [
|
||||
'ticketId' => $this->ticketId,
|
||||
'siteName' => $this->siteName,
|
||||
'ticketTitle' => $this->ticketTitle,
|
||||
'ticketType' => $this->ticketType,
|
||||
'userName' => $this->userName,
|
||||
'ticketDescription' => $this->ticketDescription,
|
||||
]);
|
||||
$ticket = $this->ticket;
|
||||
return $this->subject("[Support] Nouveau ticket n°" . $ticket->id)
|
||||
->view('emails.new-ticket', compact('ticket'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class TicketMention extends Mailable
|
|||
{
|
||||
$ticket = $this->ticket;
|
||||
$corpsMaj = ToolboxHelper::plainToHtml($this->corpsMaj);
|
||||
return $this->subject("[Support] Vous avez été mentionné sur le ticket n°$ticket->id - $ticket->title")
|
||||
->view('emails.ticket-mention', compact('ticket', 'corpsMaj'));
|
||||
return $this->subject("[Support] Vous avez été mentionné sur le ticket n° $ticket->id")
|
||||
->view('emails.ticket-mention', compact('ticket', 'corpsMaj'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class TicketUpdate extends Mailable
|
|||
{
|
||||
$ticket = $this->ticket;
|
||||
$corpsMaj = \html_entity_decode(ToolboxHelper::plainToHtml($this->corpsMaj));
|
||||
return $this->subject("[Support][{$ticket->site->name}] Ticket n°$ticket->id - $ticket->title")
|
||||
->view('emails.ticket-update', compact('ticket', 'corpsMaj'));
|
||||
return $this->subject("[Support][{$ticket->site->name}] Ticket n°$ticket->id")
|
||||
->view('emails.ticket-update', compact('ticket', 'corpsMaj'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id Doit correspondre aux ids marques de la CRM
|
||||
* @property string $name Nom de la marque
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, Account> $accounts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Site> $sites
|
||||
* @mixin \Eloquent
|
||||
* @property string $name
|
||||
*/
|
||||
class Brand extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,14 +7,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read mixed $value
|
||||
* @method static \Database\Factories\CompanyFactory factory($count = null, $state = [])
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Company extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,16 +7,10 @@ use App\Models\Brand;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property AccountTypeEnum $type Enum Credit\AccountTypeEnum
|
||||
* @property string $label Custom account label
|
||||
* @property float $balance Account balance
|
||||
* @property int $brand_id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read Brand $brand
|
||||
* @property-read \App\Models\Credit\CreditLog|null $creditlogs
|
||||
* @mixin \Eloquent
|
||||
* @property string $label
|
||||
* @property AccountTypeEnum $type
|
||||
* @property integer $balance
|
||||
* @property Brand $brand_id
|
||||
*/
|
||||
class Account extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,15 +6,10 @@ use App\Enums\Credit\BalanceOperationEnum;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property BalanceOperationEnum $type Enum Credit\BalanceOperationEnum
|
||||
* @property float $amount Montant de l'opération
|
||||
* @property int $credit_account_id
|
||||
* @property string $created_at
|
||||
* @property-read \App\Models\Credit\Account $account
|
||||
* @property-read \App\Models\Credit\EstimationLog|null $pivot
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit\Estimation> $estimation
|
||||
* @mixin \Eloquent
|
||||
* @property BalanceOperationEnum $type
|
||||
* @property double $amount
|
||||
* @property Account $credit_account_id
|
||||
* @property date $created_at
|
||||
*/
|
||||
class CreditLog extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,22 +9,6 @@ use App\Models\User;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property EstimationStatusEnum $status Enum Credit\EstimationStatusEnum
|
||||
* @property numeric $amount Estimation amount
|
||||
* @property int $ticket_id
|
||||
* @property int $credit_account_id The account to debit.
|
||||
* @property int $estimator_id The person who has done the estimate.
|
||||
* @property int|null $validator_id The person who has validate the estimate.
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\Credit\Account $account
|
||||
* @property-read User|null $estimator
|
||||
* @property-read Ticket|null $ticket
|
||||
* @property-read User|null $validator
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Estimation extends Model
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,14 +4,6 @@ namespace App\Models\Credit;
|
|||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $credit_log_id
|
||||
* @property int $credit_estimation_id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class EstimationLog extends Pivot
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
43
app/Models/Dutyhour.php
Normal file
43
app/Models/Dutyhour.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property date $date
|
||||
* @property string $person
|
||||
* @property string $place
|
||||
*/
|
||||
class Dutyhour extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
/**
|
||||
* The attributes that are fillable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'date',
|
||||
'person',
|
||||
'place'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'date' => 'date'
|
||||
];
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $title Gitlab issue title
|
||||
* @property string $url Gitlab URL
|
||||
* @property int $estimate_time Gitlab issue estimate time in seconds
|
||||
* @property int $spent_time Gitlab issue spent time in seconds
|
||||
* @property int $is_closed Gitlab issue status
|
||||
* @property int $gitlab_id Gitlab issue id
|
||||
* @property int $gitlab_iid Gitlab issue iid in project
|
||||
* @property int|null $milestone_iid Gitlab issue linked milestone iid in project
|
||||
* @property int $gitlab_project_id Gitlab project id
|
||||
* @property string $g_created_at Gitlab issue created at
|
||||
* @property string $g_updated_at Gitlab issue updated at
|
||||
* @property string|null $g_closed_at Gitlab issue closed at
|
||||
* @property string|null $g_due_date Gitlab issue due date
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\GitlabLabels> $gitlabLabels
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class GitlabIssues extends Model
|
||||
{
|
||||
/**
|
||||
* Fillable array model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'url',
|
||||
'estimate_time',
|
||||
'spent_time',
|
||||
'is_closed',
|
||||
'gitlab_id',
|
||||
'gitlab_iid',
|
||||
'milestone_iid',
|
||||
'gitlab_project_id',
|
||||
'g_created_at',
|
||||
'g_updated_at',
|
||||
'g_closed_at',
|
||||
'g_due_date'
|
||||
];
|
||||
|
||||
/**
|
||||
* Gitlab Labels relationship
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function gitlabLabels()
|
||||
{
|
||||
return $this->belongsToMany(GitlabLabels::class, 'gitlab_issues_labels', 'issue_id', 'label_id')
|
||||
->withTimestamps();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name Label name
|
||||
* @property int $gitlab_id Label Gitlab id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\GitlabIssues> $issues
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class GitlabLabels extends Model
|
||||
{
|
||||
/**
|
||||
* Fillable array model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'gitlab_id'
|
||||
];
|
||||
|
||||
/**
|
||||
* Gitlab Issues relationship
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function issues()
|
||||
{
|
||||
return $this->belongsToMany(GitlabIssues::class, 'gitlab_issues_labels', 'label_id', 'issue_id')
|
||||
->withTimestamps();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $title Milestone title
|
||||
* @property string $url Gitlab URL
|
||||
* @property int $is_closed Gitlab milestone status
|
||||
* @property int $gitlab_id Gitlab milestone id
|
||||
* @property int $gitlab_iid Gitlab milestone iid in project
|
||||
* @property int $gitlab_project_id Gitlab project id
|
||||
* @property string $g_created_at Gitlab milestone created at
|
||||
* @property string $g_updated_at Gitlab milestone updated at
|
||||
* @property string|null $g_start_date Gitlab milestone start date
|
||||
* @property string|null $g_due_date Gitlab milestone due date
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class GitlabMilestones extends Model
|
||||
{
|
||||
/**
|
||||
* Fillable array model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'url',
|
||||
'is_closed',
|
||||
'gitlab_id',
|
||||
'gitlab_iid',
|
||||
'gitlab_project_id',
|
||||
'g_created_at',
|
||||
'g_updated_at',
|
||||
'g_start_date',
|
||||
'g_due_date'
|
||||
];
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name Gitlab project name
|
||||
* @property string $url Gitlab URL
|
||||
* @property int $is_archived Gitlab archive status
|
||||
* @property int $gitlab_id Gitlab unique ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class GitlabProjects extends Model
|
||||
{
|
||||
/**
|
||||
* Fillable array model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'url',
|
||||
'is_archived',
|
||||
'gitlab_id'
|
||||
];
|
||||
}
|
||||
|
|
@ -7,13 +7,9 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $title
|
||||
* @property string $message
|
||||
* @property InfoColorsEnum $type Defined by the InfoColorsEnum enum.
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @mixin \Eloquent
|
||||
* @property InfoColorsEnum $type
|
||||
*/
|
||||
class Information extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,42 +10,28 @@ use Illuminate\Support\Carbon;
|
|||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use Mccarlosen\LaravelMpdf\LaravelMpdf;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $ref The invoice reference built as YYYY_MM_INCREMENT_USER. INCREMENT is the N invoice of the month. USER is the first two letters of the user who last edited the invoice. This field has to generated only on create.
|
||||
* @property string $firstname The person to which the invoice is addressed.
|
||||
* @property string $lastname The person to which the invoice is addressed.
|
||||
* @property string $object The invoice object.
|
||||
* @property array<array-key, mixed> $tasks A JSON object, each line has to be contructed using these fields description, days, type Invoices\TaskTypeEnum, amount
|
||||
* @property float $total The total calculated using all tasks
|
||||
* @property float $total_days The total days calculated using all tasks
|
||||
* @property string|null $comment Any comment joined to the invoice
|
||||
* @property int $show_days Show days on the printed invoice
|
||||
* @property Carbon|null $signed_date The date the invoice was signed
|
||||
* @property Carbon|null $sent_client_date The date the invoice was send to the client
|
||||
* @property Carbon|null $sent_accounting_date The date the invoice was send to the client
|
||||
* @property int $site_id
|
||||
* @property int $company_id
|
||||
* @property int $invoiced_to_id
|
||||
* @property InvoiceStatusEnum $status Status of the invoice.
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property Carbon|null $deleted_at
|
||||
* @property-read \App\Models\Company $company
|
||||
* @property-read \App\Models\Company $companyInvoiced
|
||||
* @property-read \App\Models\Site|null $site
|
||||
* @method static \Database\Factories\InvoiceFactory factory($count = null, $state = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice withTrashed(bool $withTrashed = true)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Invoice withoutTrashed()
|
||||
* @mixin \Eloquent
|
||||
* @property string $ref
|
||||
* @property string $firstname
|
||||
* @property string $lastname
|
||||
* @property string $object
|
||||
* @property string $tasks
|
||||
* @property double $total
|
||||
* @property double $total_days
|
||||
* @property string $comment
|
||||
* @property boolean $show_days
|
||||
* @property date $signed_date
|
||||
* @property date $sent_client_date
|
||||
* @property date $sent_accounting_date
|
||||
* @property Site $site_id
|
||||
* @property Company $company_id
|
||||
* @property Company $invoiced_to_id
|
||||
* @property InvoiceStatusEnum $status
|
||||
*/
|
||||
class Invoice extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are fillable.
|
||||
|
|
@ -97,7 +83,7 @@ class Invoice extends Model
|
|||
Carbon::now()->isoFormat('YYYY-MM'),
|
||||
Str::padLeft((Invoice::whereYear('created_at', Carbon::now()->isoFormat('YYYY'))
|
||||
->whereMonth('created_at', Carbon::now()->isoFormat('MM'))
|
||||
->count() + 1) ?: 1, 4, '0'),
|
||||
->count() + 1) ?: 1, 4, '0'),
|
||||
Str::substr(Str::upper(Str::slug(Auth::user()->name)), 0, 1)
|
||||
);
|
||||
$model->total_days = collect($model->tasks)
|
||||
|
|
@ -123,10 +109,6 @@ class Invoice extends Model
|
|||
->reduce(function ($previous, array $task) {
|
||||
return \floatval($task['amount']) + \floatval($previous);
|
||||
});
|
||||
|
||||
if($model->sent_accounting_date && $model->status !== InvoiceStatusEnum::archived->value) {
|
||||
$model->status = InvoiceStatusEnum::archived;
|
||||
}
|
||||
});
|
||||
static::deleting(function () {
|
||||
throw new \Error('Action impossible');
|
||||
|
|
@ -210,30 +192,30 @@ class Invoice extends Model
|
|||
'packages' => $packages,
|
||||
],
|
||||
[
|
||||
'mode' => '',
|
||||
'format' => 'A4',
|
||||
'default_font_size' => '12',
|
||||
'default_font' => 'sans-serif',
|
||||
'margin_left' => 0,
|
||||
'margin_right' => 0,
|
||||
'margin_top' => 0,
|
||||
'margin_bottom' => 0,
|
||||
'margin_header' => 0,
|
||||
'margin_footer' => 0,
|
||||
'orientation' => 'P',
|
||||
'title' => __('Devis Équipe Web :ref', ['ref' => $this->ref]),
|
||||
'author' => 'Equipe Web',
|
||||
'watermark' => '',
|
||||
'show_watermark' => false,
|
||||
'watermark_font' => 'sans-serif',
|
||||
'display_mode' => 'fullpage',
|
||||
'watermark_text_alpha' => 0.1,
|
||||
'custom_font_dir' => '',
|
||||
'mode' => '',
|
||||
'format' => 'A4',
|
||||
'default_font_size' => '12',
|
||||
'default_font' => 'sans-serif',
|
||||
'margin_left' => 0,
|
||||
'margin_right' => 0,
|
||||
'margin_top' => 0,
|
||||
'margin_bottom' => 0,
|
||||
'margin_header' => 0,
|
||||
'margin_footer' => 0,
|
||||
'orientation' => 'P',
|
||||
'title' => __('Devis Équipe Web :ref', ['ref' => $this->ref]),
|
||||
'author' => 'Equipe Web',
|
||||
'watermark' => '',
|
||||
'show_watermark' => false,
|
||||
'watermark_font' => 'sans-serif',
|
||||
'display_mode' => 'fullpage',
|
||||
'watermark_text_alpha' => 0.1,
|
||||
'custom_font_dir' => '',
|
||||
'custom_font_data' => [],
|
||||
'auto_language_detection' => false,
|
||||
'temp_dir' => ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(),
|
||||
'pdfa' => false,
|
||||
'pdfaauto' => false,
|
||||
'auto_language_detection' => false,
|
||||
'temp_dir' => ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(),
|
||||
'pdfa' => false,
|
||||
'pdfaauto' => false,
|
||||
]
|
||||
);
|
||||
return $pdf;
|
||||
|
|
|
|||
|
|
@ -7,14 +7,6 @@ use App\Lib\Helpers\ToolboxHelper;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name Un ou deux mot désignant le label
|
||||
* @property string $color Cast HTML color
|
||||
* @property-read \App\Models\Site|null $site
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Ticket> $tickets
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Label extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
|
|||
|
|
@ -9,20 +9,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @property string $message The message content.
|
||||
* @property \App\Enums\MessageTypeEnum $type The message is not visible for clients.
|
||||
* @property string $file The message joined file path.
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int $ticket_id
|
||||
* @property int|null $user_id
|
||||
* @property string $message
|
||||
* @property MessageTypeEnum $type Message Type defined by an enum.
|
||||
* @property string|null $file
|
||||
* @property string|null $file2 Pièce jointes n°2
|
||||
* @property string|null $file3 Pièce jointes n°3
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\Ticket|null $ticket
|
||||
* @property-read \App\Models\User|null $user
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Message extends Model
|
||||
{
|
||||
|
|
@ -104,9 +96,14 @@ class Message extends Model
|
|||
}
|
||||
// ? Is message author is admin ?
|
||||
if ($messageUser->isAdmin()) {
|
||||
// Url: https://supportweb.ldc.fr/ticket/583/message/create.
|
||||
// SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '583-8' for key 'PRIMARY'
|
||||
// $ticket->subscriptions()->attach($messageUser);
|
||||
// Add subscription.
|
||||
$messageUser->subscriptions()->syncWithoutDetaching([$ticket->id]);
|
||||
\session()->flash('info', trans('Vous avez été inscrit.'));
|
||||
if (!$messageUser->subscriptions()->find($ticket->id)) {
|
||||
$messageUser->subscriptions()->attach($ticket->id);
|
||||
\session()->flash('info', trans('Vous avez été inscrit.'));
|
||||
}
|
||||
}
|
||||
// * Send mail to other subscribed users
|
||||
event(new NotifySubscriptions(
|
||||
|
|
|
|||
|
|
@ -6,12 +6,8 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property float $amount The cost per day
|
||||
* @property bool $published
|
||||
* @method static \Database\Factories\PackageFactory factory($count = null, $state = [])
|
||||
* @mixin \Eloquent
|
||||
* @property double $amount
|
||||
*/
|
||||
class Package extends Model
|
||||
{
|
||||
|
|
@ -32,16 +28,5 @@ class Package extends Model
|
|||
protected $fillable = [
|
||||
'name',
|
||||
'amount',
|
||||
'published'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'published' => 'boolean',
|
||||
];
|
||||
|
||||
}
|
||||
|
|
|
|||
37
app/Models/Project.php
Normal file
37
app/Models/Project.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property Site $site_id
|
||||
*/
|
||||
class Project extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'site_id'
|
||||
];
|
||||
|
||||
// * RELATIONSHIPS.
|
||||
|
||||
/**
|
||||
* BelongsTo Site
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function site()
|
||||
{
|
||||
return $this->belongsTo(Site::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,30 +6,14 @@ use App\Lib\Helpers\ToolboxHelper;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string|null $url_re7
|
||||
* @property string|null $url_prod
|
||||
* @property int|null $gitlab_project_id
|
||||
* @property int|null $brand_id Relation is nullable, since not all site would be affiliate with a brand.
|
||||
* @property int|null $project_manager_id Project manager relationship
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @property-read \App\Models\Brand|null $brand
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \App\Models\User|null $projectManager
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Ticket> $tickets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read mixed $value
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Site onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Site withTrashed(bool $withTrashed = true)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Site withoutTrashed()
|
||||
* @mixin \Eloquent
|
||||
* @property string $name
|
||||
* @property string $url_re7
|
||||
* @property string $url_prod
|
||||
* @property integer $gitlab_project_id
|
||||
* @property Brand $brand_id
|
||||
*/
|
||||
class Site extends Model
|
||||
{
|
||||
|
|
@ -45,8 +29,7 @@ class Site extends Model
|
|||
'name',
|
||||
'url_re7',
|
||||
'url_prod',
|
||||
'gitlab_project_id',
|
||||
'project_manager_id'
|
||||
'gitlab_project_id'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -72,10 +55,6 @@ class Site extends Model
|
|||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::deleted(function ($site) {
|
||||
$site->invoices()->delete();
|
||||
$site->tickets()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
|
@ -103,7 +82,7 @@ class Site extends Model
|
|||
* HasMany Message relation
|
||||
* The users of type client that would have access to this site tickets
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\belongsToMany
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
|
|
@ -120,16 +99,6 @@ class Site extends Model
|
|||
return $this->hasMany(Ticket::class, 'site_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* HasMany Invoices relation
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany(Invoice::class, 'site_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* BelongsTo Brand relation
|
||||
*
|
||||
|
|
@ -141,14 +110,13 @@ class Site extends Model
|
|||
}
|
||||
|
||||
/**
|
||||
* BelongsTo User relation
|
||||
* The project manager of the site
|
||||
* BelongsTo Project relation
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function projectManager(): BelongsTo
|
||||
public function project()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'project_manager_id');
|
||||
return $this->belongsTo(Project::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,11 +4,6 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
/**
|
||||
* @property int $site_id
|
||||
* @property int $user_id
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class SiteUser extends Pivot
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,68 +2,26 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Events\NotifyAdmin;
|
||||
use App\Mail\TicketMention;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\GitlabIssues;
|
||||
use App\Enums\Users\RoleEnum;
|
||||
use App\Models\Credit\Account;
|
||||
use App\Models\Credit\Estimation;
|
||||
use App\Models\Ticket\TicketType;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use App\Enums\Tickets\TicketTypeEnum;
|
||||
use App\Events\NotifyAdmin;
|
||||
use App\Events\NotifySubscriptions;
|
||||
use App\Events\TicketStatusChanged;
|
||||
use App\Jobs\SendTicketMentionMail;
|
||||
use App\Enums\Tickets\TicketTypeEnum;
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use GrahamCampbell\GitLab\Facades\GitLab;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use App\Mail\TicketMention;
|
||||
use App\Models\Credit\Account;
|
||||
use App\Models\Credit\Estimation;
|
||||
use App\Models\Ticket\TicketType;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $created_by
|
||||
* @property int|null $assigned_to La personne a qui est assigné le ticket.
|
||||
* @property int $site_id
|
||||
* @property TicketTypeEnum $type
|
||||
* @property string $title Titre du ticket
|
||||
* @property string $text
|
||||
* @property string|null $file
|
||||
* @property string|null $file2
|
||||
* @property string|null $file3 Pièce jointes n°3
|
||||
* @property string|null $file4 Pièce jointes n°4
|
||||
* @property string|null $file5 Pièce jointes n°5
|
||||
* @property TicketStatusEnum $status
|
||||
* @property int $order Ticket order.
|
||||
* @property bool $is_internal
|
||||
* @property string|null $gitlab_issue URL de l'issue Gitlab
|
||||
* @property \Illuminate\Support\Carbon|null $date_mep Date MEP souhaitée
|
||||
* @property int $last_activity Last activity on the ticket.
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @property-read \App\Models\User|null $assignedUser
|
||||
* @property-read Estimation|null $estimation
|
||||
* @property-read string $full_name
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Label> $labels
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, Ticket> $linkedTickets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Message> $messages
|
||||
* @property-read \App\Models\User|null $projectManager
|
||||
* @property-read \App\Models\Site|null $site
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $subscriptions
|
||||
* @property-read TicketType|null $ticketType
|
||||
* @property-read \App\Models\User|null $user
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Ticket onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Ticket withTrashed(bool $withTrashed = true)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|Ticket withoutTrashed()
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Ticket extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are fillable.
|
||||
|
|
@ -74,8 +32,6 @@ class Ticket extends Model
|
|||
'site_id',
|
||||
'type',
|
||||
'status',
|
||||
'order',
|
||||
'date_mep',
|
||||
'text',
|
||||
'title',
|
||||
'is_internal',
|
||||
|
|
@ -88,10 +44,9 @@ class Ticket extends Model
|
|||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'is_internal' => 'bool',
|
||||
'type' => TicketTypeEnum::class,
|
||||
'status' => TicketStatusEnum::class,
|
||||
'date_mep' => 'date',
|
||||
'is_internal' => 'bool',
|
||||
'type' => TicketTypeEnum::class,
|
||||
'status' => TicketStatusEnum::class,
|
||||
'last_activity' => 'timestamp',
|
||||
];
|
||||
|
||||
|
|
@ -103,7 +58,6 @@ class Ticket extends Model
|
|||
protected static function booted()
|
||||
{
|
||||
static::creating(function (Ticket $ticket) {
|
||||
self::setOrder($ticket);
|
||||
// If bug force the ticket status on new. All the others are estimateTodo.
|
||||
if ($ticket->type->equals(TicketTypeEnum::bug)) {
|
||||
$ticket->status = TicketStatusEnum::new;
|
||||
|
|
@ -112,54 +66,28 @@ class Ticket extends Model
|
|||
}
|
||||
});
|
||||
static::updating(function (Ticket $ticket) {
|
||||
if (
|
||||
!$ticket->original['status'] !== $ticket->status->value && $ticket->original['order'] === $ticket->order
|
||||
) {
|
||||
$user = auth()->user();
|
||||
|
||||
if (!$ticket->original['status'] !== $ticket->status->value) {
|
||||
event(new TicketStatusChanged(
|
||||
$ticket,
|
||||
TicketStatusEnum::make($ticket->original['status']),
|
||||
$user,
|
||||
auth()->user(),
|
||||
null,
|
||||
false
|
||||
));
|
||||
|
||||
$message = $user ? sprintf('<b>%s</b> a modifié le statut en <b>%s</b>', $user->name, $ticket->status->label()) : sprintf('Le statut a été modifié en <b>%s</b>', $ticket->status->label());
|
||||
|
||||
event(new NotifySubscriptions($ticket, $message));
|
||||
event(new NotifyAdmin($ticket, $message));
|
||||
}
|
||||
if ($ticket->status->equals(TicketStatusEnum::archived)) {
|
||||
self::setOrder($ticket, true);
|
||||
event(new NotifySubscriptions($ticket, sprintf(
|
||||
'<b>%s</b> a modifié le statut en <b>%s</b>',
|
||||
auth()->user()->name,
|
||||
$ticket->status->label()
|
||||
)));
|
||||
event(new NotifyAdmin($ticket, sprintf(
|
||||
'<b>%s</b> a modifié le statut en <b>%s</b>',
|
||||
auth()->user()->name,
|
||||
$ticket->status->label()
|
||||
)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param self $model
|
||||
* @param boolean $isArchived
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(self $model, bool $isArchived = false): void
|
||||
{
|
||||
$maxOrder = \intval(self::query()->where('status', '!=', TicketStatusEnum::archived)->max('order'));
|
||||
if ($isArchived) {
|
||||
$request = Ticket::query()
|
||||
->where('site_id', $model->site_id)
|
||||
->whereNot('status', TicketStatusEnum::archived)
|
||||
->whereNot('id', $model->id)
|
||||
->whereBetween('order', [$model->order, $maxOrder]);
|
||||
$request->decrement('order', 1);
|
||||
$model->order = 0;
|
||||
return;
|
||||
}
|
||||
$model->order = $maxOrder + 1;
|
||||
}
|
||||
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -204,17 +132,6 @@ class Ticket extends Model
|
|||
return $this->belongsTo(User::class, 'assigned_to');
|
||||
}
|
||||
|
||||
/**
|
||||
* BelongsTo User relation
|
||||
* The user that is in charge of the site linked to this ticket
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function projectManager()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'project_manager_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* HasMany Message relation
|
||||
*
|
||||
|
|
@ -256,16 +173,6 @@ class Ticket extends Model
|
|||
return $this->belongsTo(TicketType::class, 'type', 'type');
|
||||
}
|
||||
|
||||
/**
|
||||
* BelongsToMany Linked Ticket
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function linkedTickets()
|
||||
{
|
||||
return $this->belongsToMany(Ticket::class, 'linked_tickets', 'ticket_id', 'linked_ticket_id');
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
|
|
@ -368,20 +275,4 @@ class Ticket extends Model
|
|||
Str::limit(\preg_replace('/[[:cntrl:]]+/', '', $ticket->text), 35),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all files columns of the ticket.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFiles(): array
|
||||
{
|
||||
return [
|
||||
$this->file,
|
||||
$this->file2,
|
||||
$this->file3,
|
||||
$this->file4,
|
||||
$this->file5,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,8 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property TicketTypeEnum $type TicketType Enum
|
||||
* @property string $template Le template du type de ticket
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, Ticket> $tickets
|
||||
* @mixin \Eloquent
|
||||
* @property TicketTypeEnum $type
|
||||
* @property string $template
|
||||
*/
|
||||
class TicketType extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,27 +15,12 @@ use Illuminate\Support\Facades\Hash;
|
|||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $email
|
||||
* @property string $password
|
||||
* @property string $remember_token
|
||||
* @property RoleEnum $role
|
||||
* @property string|null $remember_token
|
||||
* @property int|null $gitlab_id ID du user Gitlab
|
||||
* @property int|null $favourite_site_id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @property-read Collection<int, \App\Models\Message> $messages
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read Collection<int, \App\Models\Site> $sites
|
||||
* @property-read Collection<int, \App\Models\Ticket> $subscriptions
|
||||
* @property-read Collection<int, \App\Models\Ticket> $tickets
|
||||
* @method static \Database\Factories\UserFactory factory($count = null, $state = [])
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|User onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|User withTrashed(bool $withTrashed = true)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|User withoutTrashed()
|
||||
* @mixin \Eloquent
|
||||
* @property Collection $sites
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
|
|
@ -60,9 +45,7 @@ class User extends Authenticatable
|
|||
'email',
|
||||
'password',
|
||||
'role',
|
||||
'sites',
|
||||
'gitlab_id',
|
||||
'favourite_site_id'
|
||||
'sites'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -165,8 +148,8 @@ class User extends Authenticatable
|
|||
*/
|
||||
public static function adminUsers(): Collection
|
||||
{
|
||||
return Cache::remember('AdminUsers', 86400, function () {
|
||||
return self::whereIn('role', [RoleEnum::admin, RoleEnum::developper])->orderBy('name')->get();
|
||||
return Cache::rememberForever('AdminUsers', function () {
|
||||
return self::whereIn('role', [RoleEnum::admin, RoleEnum::developper])->get();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ExportTicketsStateNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* The CSV content to be sent.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $csvContent;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param string $csvContent The content of the CSV file to be sent.
|
||||
*/
|
||||
public function __construct(string $csvContent)
|
||||
{
|
||||
$this->csvContent = $csvContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail(): \Illuminate\Notifications\Messages\MailMessage
|
||||
{
|
||||
return (new MailMessage())
|
||||
->subject(trans("Export de l'état des lieux des tickets"))
|
||||
->line(trans("Vous trouverez ci-joint le fichier CSV contenant l'état des tickets."))
|
||||
->attachData(
|
||||
$this->csvContent,
|
||||
sprintf('tickets_state_%s.csv', Carbon::now()->format('Y-m-d_H-i-s')),
|
||||
[
|
||||
'mime' => 'text/csv',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -67,17 +67,6 @@ class TicketPolicy
|
|||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user can link ticket .
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function linkTicket(User $user)
|
||||
{
|
||||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user can change the internal status of a given ticket.
|
||||
*
|
||||
|
|
@ -283,25 +272,8 @@ class TicketPolicy
|
|||
public function createGitlabIssue(User $user, Ticket $ticket)
|
||||
{
|
||||
return $user->role->equals(RoleEnum::developper)
|
||||
&& (
|
||||
$ticket->type->equals(TicketTypeEnum::bug)
|
||||
|| $ticket->type->equals(TicketTypeEnum::evolution)
|
||||
|| $ticket->type->equals(TicketTypeEnum::newsletter)
|
||||
|| $ticket->type->equals(TicketTypeEnum::mailing)
|
||||
)
|
||||
&& ($ticket->type->equals(TicketTypeEnum::bug) || $ticket->type->equals(TicketTypeEnum::evolution))
|
||||
&& !\is_null($ticket->site->gitlab_project_id)
|
||||
&& \is_null($ticket->gitlab_issue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user can changeOrder
|
||||
*
|
||||
* @param User $user
|
||||
* @return boolean
|
||||
* @throws Error The error.
|
||||
*/
|
||||
public function changeOrder(User $user)
|
||||
{
|
||||
return $user->role->equals(RoleEnum::developper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,24 +2,12 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Repositories\EloquentSiteRepository;
|
||||
use App\Repositories\SiteRepository;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Override;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
#[Override]
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton(
|
||||
SiteRepository::class,
|
||||
fn() => new EloquentSiteRepository()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
|
|
@ -36,7 +24,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
return request()->getClientIp();
|
||||
} else {
|
||||
return request()->server('HTTP_X_FORWARDED_FOR') ??
|
||||
request()->getClientIp();
|
||||
request()->getClientIp();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,14 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Events\NotifyAdmin;
|
||||
use App\Events\NotifySubscriptions;
|
||||
use App\Events\NotifyTicketCreator;
|
||||
use App\Events\TicketStatusChanged;
|
||||
use App\Listeners\AddStatusMessages;
|
||||
use App\Listeners\SendNotificationMailToAdmin;
|
||||
use App\Listeners\SendNotificationMailToTicketCreator;
|
||||
use App\Listeners\SendSubscriptionsNotificationsMail;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
|
@ -15,6 +23,10 @@ class EventServiceProvider extends ServiceProvider
|
|||
*/
|
||||
protected $listen = [
|
||||
Registered::class => [SendEmailVerificationNotification::class],
|
||||
TicketStatusChanged::class => [AddStatusMessages::class],
|
||||
NotifySubscriptions::class => [SendSubscriptionsNotificationsMail::class],
|
||||
NotifyTicketCreator::class => [SendNotificationMailToTicketCreator::class],
|
||||
NotifyAdmin::class => [SendNotificationMailToAdmin::class],
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -24,6 +36,6 @@ class EventServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function shouldDiscoverEvents(): bool
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@ use App\Models\Brand;
|
|||
use App\Models\Company;
|
||||
use App\Models\Credit\Account;
|
||||
use App\Models\Credit\CreditLog;
|
||||
use App\Models\Dutyhour;
|
||||
use App\Models\Information;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Label;
|
||||
use App\Models\Package;
|
||||
use App\Models\Project;
|
||||
use App\Models\Site;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Ticket\TicketType;
|
||||
|
|
@ -87,12 +89,15 @@ class RouteServiceProvider extends ServiceProvider
|
|||
});
|
||||
Route::model('brand', Brand::class);
|
||||
Route::model('label', Label::class);
|
||||
Route::model('marker', Marker::class);
|
||||
Route::model('package', Package::class);
|
||||
Route::model('dutyhour', Dutyhour::class);
|
||||
Route::model('information', Information::class);
|
||||
Route::model('company', Company::class);
|
||||
Route::model('invoice', Invoice::class);
|
||||
Route::model('user', User::class);
|
||||
Route::model('site', Site::class);
|
||||
Route::model('project', Project::class);
|
||||
Route::model('ticket_type', TicketType::class);
|
||||
Route::bind('ticket', function ($value) {
|
||||
return Ticket::where('id', $value)->has('site')->firstOrFail();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class TranslationServiceProvider extends ServiceProvider
|
|||
{
|
||||
foreach ($this->collectLocalesStrings() as $locale) {
|
||||
// * Supported locales
|
||||
Cache::remember(sprintf('translations.%s', $locale), 84600, function () use ($locale) {
|
||||
Cache::rememberForever(sprintf('translations.%s', $locale), function () use ($locale) {
|
||||
$translations = [
|
||||
'php' => $this->phpTranslations($locale),
|
||||
'json' => $this->jsonTranslations($locale),
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Site;
|
||||
use Override;
|
||||
|
||||
class EloquentSiteRepository implements SiteRepository
|
||||
{
|
||||
#[Override]
|
||||
public function findByName(string $name): ?Site
|
||||
{
|
||||
return Site::query()
|
||||
->where('name', $name)
|
||||
->first();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Site;
|
||||
|
||||
interface SiteRepository
|
||||
{
|
||||
public function findByName(string $name): ?Site;
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
class Hex implements ValidationRule
|
||||
{
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $forceFull;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $allowAlpha;
|
||||
|
||||
/**
|
||||
* __construct method
|
||||
*
|
||||
* @param boolean $forceFull
|
||||
* @param boolean $allowAlpha
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(bool $forceFull = false, bool $allowAlpha = false)
|
||||
{
|
||||
$this->forceFull = $forceFull;
|
||||
|
||||
$this->allowAlpha = $allowAlpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
* @param \Closure(string):\Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
* @return void
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, \Closure $fail): void
|
||||
{
|
||||
$pattern = '/^#([a-fA-F0-9]{6}';
|
||||
|
||||
if (!$this->forceFull) {
|
||||
$pattern .= '|[a-fA-F0-9]{3}';
|
||||
}
|
||||
|
||||
if ($this->allowAlpha) {
|
||||
$pattern .= '|[a-fA-F0-9]{8}';
|
||||
|
||||
if (!$this->forceFull) {
|
||||
$pattern .= '|[a-fA-F0-9]{4}';
|
||||
}
|
||||
}
|
||||
|
||||
$pattern .= ')$/';
|
||||
|
||||
if (!(bool)preg_match($pattern, $value)) {
|
||||
$fail(trans($this->message()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function message(): string
|
||||
{
|
||||
return 'The hex code is not valid';
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue