favicon + affectation + close
This commit is contained in:
Binary file not shown.
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 736 KiB |
@ -68,6 +68,20 @@ class IssueController extends AbstractController
|
||||
$form = $this->createForm(IssueType::class, $issue, ['mode' => 'update']);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$assignedTo = $form->get('assignedTo')->getData();
|
||||
try {
|
||||
$payload = [
|
||||
'assigned_to_id' => $assignedTo,
|
||||
];
|
||||
|
||||
$user = $this->getUser();
|
||||
if ($user instanceof \App\Entity\User) {
|
||||
$apikey = $user->getApikey();
|
||||
$this->redmineService->updateIssue($id, $payload, $apikey);
|
||||
}
|
||||
} catch (\RuntimeException $e) {
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('app_project_view', ['id' => $issue->getProject()->getId()]);
|
||||
@ -84,6 +98,41 @@ class IssueController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/user/issue/close/{id}', name: 'app_issue_close')]
|
||||
public function closeIssue(int $id, Request $request, IssueRepository $issueRepository, EntityManagerInterface $em): Response
|
||||
{
|
||||
$issue = $issueRepository->find($id);
|
||||
if (!$issue) {
|
||||
throw new NotFoundHttpException('La ressource demandée est introuvable.');
|
||||
}
|
||||
if (!$issue->getProject()->getUsers()->contains($this->getUser())) {
|
||||
throw new AccessDeniedException('Vous n\'avez pas accès à cette ressource.');
|
||||
}
|
||||
|
||||
$closedStatus = null;
|
||||
foreach (array_reverse($issue->getRedmine()['allowed_statuses']) as $status) {
|
||||
if ($status['is_closed']) {
|
||||
$closedStatus = $status['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$payload = [
|
||||
'status_id' => $closedStatus,
|
||||
];
|
||||
|
||||
$user = $this->getUser();
|
||||
if ($user instanceof \App\Entity\User) {
|
||||
$apikey = $user->getApikey();
|
||||
$this->redmineService->updateIssue($id, $payload, $apikey);
|
||||
}
|
||||
} catch (\RuntimeException $e) {
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('app_project_view', ['id' => $issue->getProject()->getId()]);
|
||||
}
|
||||
|
||||
#[Route('/user/issue/order/{id}', name: 'app_issue_order', methods: ['POST'])]
|
||||
public function orderIssue(int $id, Request $request, IssueRepository $issueRepository, EntityManagerInterface $em): JsonResponse
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ namespace App\Form;
|
||||
use App\Entity\Issue;
|
||||
use App\Form\Type\SelbgType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
@ -13,6 +14,17 @@ class IssueType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$issue = $options['data']; // ton entité courante
|
||||
$project = $issue->getProject();
|
||||
|
||||
// Récupérer les assignables
|
||||
$choices = [];
|
||||
if ($project && isset($project->getRedmine()['issue_users'])) {
|
||||
foreach ($project->getRedmine()['issue_users'] as $user) {
|
||||
$choices[$user['name']] = $user['id'];
|
||||
}
|
||||
}
|
||||
|
||||
$builder
|
||||
->add('submit', SubmitType::class, [
|
||||
'label' => 'Valider',
|
||||
@ -20,6 +32,15 @@ class IssueType extends AbstractType
|
||||
])
|
||||
|
||||
->add('color', SelbgType::class)
|
||||
|
||||
->add('assignedTo', ChoiceType::class, [
|
||||
'choices' => $choices,
|
||||
'required' => false,
|
||||
'placeholder' => 'Aucun intervenant',
|
||||
'label' => 'Affecté à',
|
||||
'mapped' => false,
|
||||
'data' => $issue->getRedmine()['assigned_to']['id'] ?? null,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ class RedmineService
|
||||
|
||||
$data['project']['issue_statuses'] = $this->getIssueStatuses($apiKey);
|
||||
$data['project']['issue_priorities'] = $this->getIssuePriorities($apiKey);
|
||||
$data['project']['issue_users'] = $this->getIssueUsers($id, $apiKey);
|
||||
|
||||
$data['project']['versions'] = $this->getProjectVersions($id, $apiKey);
|
||||
if (empty($data['project']['versions']) && array_key_exists('parent', $data['project'])) {
|
||||
@ -140,6 +141,37 @@ class RedmineService
|
||||
}
|
||||
}
|
||||
|
||||
public function getIssueUsers(int $id, string $apiKey): array
|
||||
{
|
||||
try {
|
||||
$response = $this->client->request('GET', $this->baseUrl.'/projects/'.$id.'/memberships.json', [
|
||||
'headers' => [
|
||||
'X-Redmine-API-Key' => $apiKey,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
|
||||
}
|
||||
|
||||
$data = $response->toArray();
|
||||
if (!$data['memberships']) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$users = [];
|
||||
foreach ($data['memberships'] as $membership) {
|
||||
if (array_key_exists('user', $membership)) {
|
||||
array_push($users, $membership['user']);
|
||||
}
|
||||
}
|
||||
|
||||
return $users;
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function getProjectVersions(int $id, string $apiKey): array
|
||||
{
|
||||
try {
|
||||
@ -237,15 +269,6 @@ class RedmineService
|
||||
}
|
||||
$issue->setRowsprint($sprintPosition);
|
||||
|
||||
// Calcul position issue = plus géré via redmine
|
||||
/*
|
||||
if (isset($rissue['sprint'])) {
|
||||
$issue->setRowissue($rissue['sprint']['position'] ?? 1000000);
|
||||
} else {
|
||||
$issue->setRowissue(1000000);
|
||||
}
|
||||
*/
|
||||
|
||||
$this->em->persist($issue);
|
||||
$project->setUpdateIssuesAt(new \DateTime());
|
||||
|
||||
@ -376,6 +399,7 @@ class RedmineService
|
||||
'headers' => [
|
||||
'X-Redmine-API-Key' => $apiKey,
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
'json' => ['issue' => $data],
|
||||
]);
|
||||
|
@ -3,8 +3,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{appName}}{% block title %}{% endblock %}</title>
|
||||
<link rel="icon" href="">
|
||||
|
||||
|
||||
<link rel="icon" type="image/png" href="{{asset("medias/logo/logo.png")}}">
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('lib/bootstrap/css/bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/bootswatch/bootswatch.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('lib/fontawesome/css/all.min.css') }}">
|
||||
|
@ -29,6 +29,7 @@
|
||||
<div class="card-header">Information</div>
|
||||
<div class="card-body">
|
||||
{{ form_row(form.color) }}
|
||||
{{ form_row(form.assignedTo) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,7 +18,8 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<a href="{{path("app_issue_update",{id:issue.id})}}">Modifier</a>
|
||||
<a class="btn btn-sm btn-success" href="{{path("app_issue_update",{id:issue.id})}}">Modifier / Affecter</a>
|
||||
<a class="btn btn-sm btn-danger ms-auto" href="{{path("app_issue_close",{id:issue.id})}}" onclick="return confirm('Confirmez-vous la fermeture de cette issue ?')">Fermer</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
{% block body %}
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form.submit) }}
|
||||
|
Reference in New Issue
Block a user