diff --git a/public/medias/logo/logo.png b/public/medias/logo/logo.png index 5924292..9aca92a 100644 Binary files a/public/medias/logo/logo.png and b/public/medias/logo/logo.png differ diff --git a/src/Controller/IssueController.php b/src/Controller/IssueController.php index ec629c3..7617d72 100644 --- a/src/Controller/IssueController.php +++ b/src/Controller/IssueController.php @@ -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 { diff --git a/src/Form/IssueType.php b/src/Form/IssueType.php index 5244ed8..1f32a42 100644 --- a/src/Form/IssueType.php +++ b/src/Form/IssueType.php @@ -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, + ]) ; } diff --git a/src/Service/RedmineService.php b/src/Service/RedmineService.php index 7fe44b7..e8efcda 100644 --- a/src/Service/RedmineService.php +++ b/src/Service/RedmineService.php @@ -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], ]); diff --git a/templates/base.html.twig b/templates/base.html.twig index 0e51977..15bd239 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -3,8 +3,9 @@ {{appName}}{% block title %}{% endblock %} - - + + + diff --git a/templates/issue/edit.html.twig b/templates/issue/edit.html.twig index d94cd24..0cc16a3 100644 --- a/templates/issue/edit.html.twig +++ b/templates/issue/edit.html.twig @@ -29,6 +29,7 @@
Information
{{ form_row(form.color) }} + {{ form_row(form.assignedTo) }}
diff --git a/templates/issue/view.html.twig b/templates/issue/view.html.twig index 72e7742..e0f2a06 100644 --- a/templates/issue/view.html.twig +++ b/templates/issue/view.html.twig @@ -18,7 +18,8 @@ {% endif %}
- Modifier + Modifier / Affecter + Fermer
diff --git a/templates/project/edit.html.twig b/templates/project/edit.html.twig index 39b4c1c..c055ef6 100644 --- a/templates/project/edit.html.twig +++ b/templates/project/edit.html.twig @@ -4,7 +4,6 @@ {% block body %}

{{title}}

- {{ form_start(form) }} {{ form_widget(form.submit) }}