From 3a0a4514b5ded777846681fbf74da7dd0d183abc Mon Sep 17 00:00:00 2001 From: Mathieu Perrin Date: Wed, 3 Apr 2024 11:49:42 +0200 Subject: [PATCH 1/2] 171: races to activities - migrate visual and services - add migration helper page --- app/pages/dev/dev_page.php | 6 + .../{race_edit.php => activity_edit.php} | 59 ++++-- app/pages/events/activity_view.php | 83 ++++++++ ...b_race.php => entry_list_tab_activity.php} | 10 +- .../events/entry_list/entry_list_tabs.php | 18 +- app/pages/events/event_delete.php | 2 +- app/pages/events/event_edit.php | 9 +- app/pages/events/event_register.php | 90 +++++---- app/pages/events/event_view.php | 188 ++++++++++-------- app/services/ActivityService.php | 16 ++ app/services/EventService.php | 10 +- app/services/RaceService.php | 16 -- .../css/{race_edit.css => activity_edit.css} | 0 assets/css/event_view.css | 12 +- database/models/events.db.php | 6 +- database/race_to_activity.php | 72 +++++++ routes.php | 8 +- 17 files changed, 413 insertions(+), 192 deletions(-) rename app/pages/events/{race_edit.php => activity_edit.php} (62%) create mode 100644 app/pages/events/activity_view.php rename app/pages/events/entry_list/{entry_list_tab_race.php => entry_list_tab_activity.php} (84%) create mode 100644 app/services/ActivityService.php delete mode 100644 app/services/RaceService.php rename assets/css/{race_edit.css => activity_edit.css} (100%) create mode 100644 database/race_to_activity.php diff --git a/app/pages/dev/dev_page.php b/app/pages/dev/dev_page.php index f0d8e1f7..c38b31b4 100644 --- a/app/pages/dev/dev_page.php +++ b/app/pages/dev/dev_page.php @@ -29,4 +29,10 @@ function DevButton($href, $label) + +Migrations + \ No newline at end of file diff --git a/app/pages/events/race_edit.php b/app/pages/events/activity_edit.php similarity index 62% rename from app/pages/events/race_edit.php rename to app/pages/events/activity_edit.php index 5f4ad37d..0bdaff81 100644 --- a/app/pages/events/race_edit.php +++ b/app/pages/events/activity_edit.php @@ -4,51 +4,59 @@ restrict_access(Access::$ADD_EVENTS); $event_id = get_route_param("event_id"); -$race_id = get_route_param("race_id", false); +$activity_id = get_route_param("activity_id", false); $event = em()->find(Event::class, $event_id); if (!$event) { return "this event does not exist"; } -if ($race_id) { - $race = em()->find(Race::class, $race_id); +if ($activity_id) { + $activity = em()->find(Activity::class, $activity_id); $form_values = [ - "name" => $race->name, - "date" => date_format($race->date, "Y-m-d"), - "place" => $race->place + //TODO + "name" => $activity->name, + "date" => date_format($activity->date, "Y-m-d"), + "location_label" => $activity->location_label, + "location_url" => $activity->location_url ]; - foreach ($race->categories as $index => $category) { + foreach ($activity->categories as $index => $category) { $form_values["category_{$index}_name"] = $category->name; $form_values["category_{$index}_toggle"] = $category->removed ? 0 : 1; } } else { - $race = new Race(); + $activity = new Activity(); } +$type_array = ["RACE" => "Course", "TRAINING" => "Entraînement", "OTHER" => "Autre"]; + $v = new Validator($form_values ?? ["date" => $event->start_date->format("Y-m-d")]); -$name = $v->text("name")->label("Nom de la course")->placeholder()->required(); +$name = $v->text("name")->label("Nom de l'activité")->placeholder()->required(); +$type = $v->select("type")->options($type_array)->label("Type d'activité"); $date = $v->date("date") ->label("Date") ->min($event->start_date->format("Y-m-d"), "Doit être après la date de début de l'événement") ->max($event->end_date->format("Y-m-d"), "Doit être avant la date de fin de l'événement") ->required(); -$place = $v->text("place")->label("Lieu")->required(); +$location_label = $v->text("location_label")->label("Nom du Lieu")->required(); +$location_url = $v->url("location_url")->label("URL du lieu"); +$description = $v->textarea("description")->label("Description de l'activité"); $category_rows = []; -foreach ($race->categories as $index => $category) { +foreach ($activity->categories as $index => $category) { $category_rows[$index]['name'] = $v->text("category_{$index}_name")->required(); $category_rows[$index]['toggle'] = $v->switch("category_{$index}_toggle")->set_labels(" ", "Supprimer"); } if ($v->valid()) { - $race->set($name->value, date_create($date->value), $place->value, $event); - foreach ($race->categories as $index => $category) { + $activity->set($name->value, date_create($date->value), $event, $location_label->value, $location_url->value, $description->value); + $activity->type = ActivityType::from($type->value); + foreach ($activity->categories as $index => $category) { $category->name = $category_rows[$index]['name']->value; $category->removed = !$category_rows[$index]['toggle']->value ?? 0; // TODO change this later if we want to deal with soft delete if ($category->removed /* && !count($category->entries)*/) { em()->remove($category); - $race->categories->removeElement($category); + $activity->categories->removeElement($category); } } $new_categories = $_POST["new_categories"] ?? []; @@ -56,16 +64,16 @@ if ($category_name) { $category = new Category(); $category->name = $category_name; - $category->race = $race; - $race->categories[] = $category; + $category->activity = $activity; + $activity->categories[] = $category; } } - em()->persist($race); + em()->persist($activity); em()->flush(); redirect("/evenements/$event->id"); } -page($race_id ? "{$race->name} : Modifier" : "Ajouter une course")->css("race_edit.css"); +page($activity_id ? "{$activity->name} : Modifier" : "Ajouter une activité")->css("activity_edit.css"); ?>
render_validation() ?> render() ?> +
+ render() ?> +
render() ?>
- render() ?> + render() ?> +
+
+ render() ?>
+ render() ?>

Catégories

@@ -93,8 +108,8 @@ Ajouter
- categories)): - foreach ($race->categories as $index => $category): + categories)): + foreach ($activity->categories as $index => $category): $entry_count = count($category->entries); ?>
diff --git a/app/pages/events/activity_view.php b/app/pages/events/activity_view.php new file mode 100644 index 00000000..d0fc9589 --- /dev/null +++ b/app/pages/events/activity_view.php @@ -0,0 +1,83 @@ +find(Activity::class, get_route_param("activity_id")); + +if ($activity->type == ActivityType::RACE) { + $icon = "fa fa-stopwatch"; +} elseif ($activity->type == ActivityType::TRAINING) { + $icon = "fa fa-dumbbell"; +} else { + $icon = "fa fa-bowl-food"; +} + +page($activity->name)->css("event_view.css"); +?> + + + +
+
+ type == ActivityType::RACE) { + $type = "Course"; + } elseif ($activity->type == ActivityType::TRAINING) { + $type = "Entrainement"; + } else { + $type = "Autre"; + } ?> + +

+ Type : + + +

+
+
+ + + date) ?> + +
+
+
+ event->open): ?> +
+ entries[0] ?? null; ?> +
    + present): ?> + +
  • Inscrit
  • + + + +
  • + +
  • +
    + +
+ category): ?> +
    +
  • + category?->name ?> +
  • +
+ +
+ comment): ?> +
+ Remarque : + comment ?> +
+ + description): ?> +
Description
+

+ description ?> +

+ + \ No newline at end of file diff --git a/app/pages/events/entry_list/entry_list_tab_race.php b/app/pages/events/entry_list/entry_list_tab_activity.php similarity index 84% rename from app/pages/events/entry_list/entry_list_tab_race.php rename to app/pages/events/entry_list/entry_list_tab_activity.php index 953252f8..55fac161 100644 --- a/app/pages/events/entry_list/entry_list_tab_race.php +++ b/app/pages/events/entry_list/entry_list_tab_activity.php @@ -1,9 +1,9 @@ - -

Pas d'inscrits sur cette course

+ +

Pas d'inscrits sur cette activité

@@ -19,7 +19,7 @@ + foreach ($activityEntries as $entry): ?> present): $totalEntries++ ?> user->id) ?>> diff --git a/app/pages/events/entry_list/entry_list_tabs.php b/app/pages/events/entry_list/entry_list_tabs.php index 9ce3c6ee..a25a9eb3 100644 --- a/app/pages/events/entry_list/entry_list_tabs.php +++ b/app/pages/events/entry_list/entry_list_tabs.php @@ -2,23 +2,23 @@ include_once __DIR__ . "/TotalRow.php"; $eventId = Component::prop("event_id") ?? get_route_param("event_id") ?? throw new Exception("no event selected"); -$selectedRaceId = Component::prop("race_id") ?? get_query_param("race_id", false) ?? null; -$races = EventService::getRaceIdList($eventId); +$selectedActivityId = Component::prop("activity_id") ?? get_query_param("activity_id", false) ?? null; +$activities = EventService::getActivityIdList($eventId); $getProps = fn($isSelected) => 'role="tab" aria-controls="tab-content" ' . ($isSelected ? 'aria-selected="true" class="contrast" autofocus' : 'class="secondary outline" aria-selected="false"'); ?>
- - - + +
- $selectedRaceId]) + $selectedActivityId]) : Component::render(__DIR__ . "/entry_list_tab_event.php", ["event_id" => $eventId]) ?> \ No newline at end of file diff --git a/app/pages/events/event_delete.php b/app/pages/events/event_delete.php index f423c29d..37669165 100644 --- a/app/pages/events/event_delete.php +++ b/app/pages/events/event_delete.php @@ -26,7 +26,7 @@ Courses: - races) ?> + activities) ?> diff --git a/app/pages/events/event_edit.php b/app/pages/events/event_edit.php index 05aed713..b07c7bf8 100644 --- a/app/pages/events/event_edit.php +++ b/app/pages/events/event_edit.php @@ -15,7 +15,7 @@ "end_date" => date_format($event->end_date, "Y-m-d"), "limit_date" => date_format($event->deadline, "Y-m-d"), "bulletin_url" => $event->bulletin_url, - + "description" => $event->description ]; } else { $event = new Event(); @@ -31,9 +31,11 @@ ->label("Deadline")->required() ->max($start_date->value ? date_create($start_date->value)->sub(new DateInterval("PT23H59M59S"))->format("Y-m-d") : "", "Doit être avant le jour de départ"); $bulletin_url = $v->url("bulletin_url")->label("Lien vers le bulletin")->placeholder(); +$description = $v->textarea("description")->label("Description"); if (!empty($_POST) && $v->valid()) { $event->set($event_name->value, $start_date->value, $end_date->value, $limit_date->value, $bulletin_url->value ?? ""); + $event->description = $description->value; em()->persist($event); em()->flush(); redirect("/evenements/$event->id"); @@ -63,9 +65,8 @@
render() ?>
-
- render() ?> -
+ render() ?> + render() ?>
\ No newline at end of file diff --git a/app/pages/events/event_register.php b/app/pages/events/event_register.php index c93ec678..9b8d2f40 100644 --- a/app/pages/events/event_register.php +++ b/app/pages/events/event_register.php @@ -21,12 +21,12 @@ ]; } -foreach ($event->races as $index => $race) { - $race_entry = $race->entries[0] ?? null; - if ($race_entry) { - $form_values["race_{$index}_entry"] = $race_entry->present; - $form_values["race_{$index}_comment"] = $race_entry->comment; - $form_values["race_{$index}_category"] = $race_entry->category->id ?? ""; +foreach ($event->activities as $index => $activity) { + $activity_entry = $activity->entries[0] ?? null; + if ($activity_entry) { + $form_values["activity_{$index}_entry"] = $activity_entry->present; + $form_values["activity_{$index}_comment"] = $activity_entry->comment; + $form_values["activity_{$index}_category"] = $activity_entry->category->id ?? ""; } } @@ -37,13 +37,13 @@ $accomodation = $v->switch("event_accomodation")->label("Hébergement"); $event_comment = $v->textarea("event_comment")->label("Remarques"); $event_comment_noentry = $v->textarea("event_comment_noentry")->label("Remarque"); -$race_rows = []; -foreach ($event->races as $index => $race) { - $race_rows[$index]["entry"] = $v->switch("race_{$index}_entry")->set_labels("Je cours", "Je ne cours pas"); - $race_rows[$index]["comment"] = $v->textarea("race_{$index}_comment")->label("Remarque"); - if (count($race->categories)) { - $race_rows[$index]["category"] = $v->select("race_{$index}_category")->label("Catégorie") - ->options(Category::toSelectOptions($race->categories)); +$activity_rows = []; +foreach ($event->activities as $index => $activity) { + $activity_rows[$index]["entry"] = $v->switch("activity_{$index}_entry")->set_labels("Je cours", "Je ne cours pas"); + $activity_rows[$index]["comment"] = $v->textarea("activity_{$index}_comment")->label("Remarque"); + if (count($activity->categories)) { + $activity_rows[$index]["category"] = $v->select("activity_{$index}_category")->label("Catégorie") + ->options(Category::toSelectOptions($activity->categories)); } } @@ -60,27 +60,27 @@ ); em()->persist($event_entry); - foreach ($event->races as $index => $race) { - // Map race categories with ids - $race_category_map = []; - foreach ($race->categories as $category) { - $race_category_map[$category->id] = $category; + foreach ($event->activities as $index => $activity) { + // Map activity categories with ids + $activity_category_map = []; + foreach ($activity->categories as $category) { + $activity_category_map[$category->id] = $category; } - $race_entry = $race->entries[0] ?? new RaceEntry(); - $race_form = $race_rows[$index]; - $race_present = $event_present->value && $race_form["entry"]->value; - if ($race_present) { - $race_entry->set( + $activity_entry = $activity->entries[0] ?? new ActivityEntry(); + $activity_form = $activity_rows[$index]; + $activity_present = $event_present->value && $activity_form["entry"]->value; + if ($activity_present) { + $activity_entry->set( $user, - $race, - $race_present, - $race_present ? $race_form["comment"]->value : "", + $activity, + $activity_present, + $activity_present ? $activity_form["comment"]->value : "", ); - $race_entry->category = $race_present ? $race_category_map[$race_form["category"]->value] : null; - em()->persist($race_entry); + $activity_entry->category = $activity_present ? $activity_category_map[$activity_form["category"]->value] : null; + em()->persist($activity_entry); } else { - em()->remove($race_entry); + em()->remove($activity_entry); } } em()->flush(); @@ -145,21 +145,25 @@ function getToggleClass($selector, $initialState) render() ?> - races)): ?> + activities)): ?>

Courses :

- races as $index => $race): - $race_form = $race_rows[$index]; - $toggle_class = getToggleClass("raceToggle$index", $race_form['entry']->value); ?> + activities as $index => $activity): + $activity_form = $activity_rows[$index]; + $toggle_class = getToggleClass("activityToggle$index", $activity_form['entry']->value); ?> - - - @@ -167,16 +171,16 @@ function getToggleClass($selector, $initialState)
- attributes(["onchange" => "toggleDisplay(this,'.raceToggle$index')"])->render() ?> + attributes(["onchange" => "toggleDisplay(this,'.activityToggle$index')"])->render() ?>
- categories)): ?> + categories)): ?>
- render() ?> + render() ?>
- render() ?> + render() ?>
diff --git a/app/pages/events/event_view.php b/app/pages/events/event_view.php index b40fddb3..9972a6aa 100644 --- a/app/pages/events/event_view.php +++ b/app/pages/events/event_view.php @@ -75,25 +75,6 @@ - -
- - open): ?> - present): ?> - - Je participe - - - - - - - - Pas encore publié - - -
- bulletin_url): ?>

@@ -109,81 +90,127 @@ - - present): ?> -

-

- transport, "Transport avec le club") ?> -

+ open): ?> +

+ +

+ open): ?> + + present): ?> + + Inscrit + + + Je ne participe pas + + + + + Pas encore inscrit + + + + Pas encore publié + +
+ +

+ present): ?> +
+

+ transport, "Transport avec le club") ?> +

+

+ accomodation, "Hébergement avec le club") ?> +

+
+ + comment): ?> + Remarque :

- accomodation, "Hébergement avec le club") ?> + comment ?>

-
+ - - comment): ?> -
- comment ?> -
- - - races)): ?> -

Courses : - - - -

- - races as $race): - $race_entry = $race->entries[0] ?? null; ?> + activities)): ?> +

Activités

+ + activities as $activity): + if ($activity->type == ActivityType::RACE) { + $icon = "fa-stopwatch"; + $title = "Course"; + } elseif ($activity->type == ActivityType::TRAINING) { + $icon = "fa-dumbbell"; + $title = "Entrainement"; + } else { + $icon = "fa-bowl-food"; + $title = "Autre"; + } + $activity_entry = $activity->entries[0] ?? null; ?>
- present) . " " . $race->name ?> + > + present) . " " ?> + + name ?> + -
-
+
+
    +
  • + date) ?> +
  • +
+ location_label): ?> -
-
+ +
+

+ + + Détails + + + + Modifier + +

+
+
    - present): ?> + present): ?>
  • Je participe
  • - +
  • - category): ?> -
  • - category?->name ?> -
  • -
+ category): ?> +
    +
  • + category?->name ?> +
  • +
+
-
- comment): ?> -
- Remarque : - comment ?> -
-
- - - - Modifier - - + comment): ?> +
+ Remarque : + comment ?> +
+ +
@@ -191,10 +218,15 @@

- - Ajouter une course + + Ajouter une activité

+ description): ?> +

Description

+ description ?> + + \ No newline at end of file diff --git a/app/services/ActivityService.php b/app/services/ActivityService.php new file mode 100644 index 00000000..3708d85b --- /dev/null +++ b/app/services/ActivityService.php @@ -0,0 +1,16 @@ +createQueryBuilder() + ->select("a") + ->from(ActivityEntry::class, "a") + ->leftJoin("a.user", "u") + ->where("a.activity = :activityId") + ->setParameters(['activityId' => $activityId]) + ->getQuery() + ->getResult(); + } +} \ No newline at end of file diff --git a/app/services/EventService.php b/app/services/EventService.php index 30e96704..6c793218 100644 --- a/app/services/EventService.php +++ b/app/services/EventService.php @@ -1,12 +1,12 @@ createQueryBuilder() - ->select("NEW RaceInfoDto(r.id, r.name)") - ->from(Race::class, "r") + ->select("NEW ActivityInfoDto(r.id, r.name)") + ->from(Activity::class, "r") ->where("r.event = :eid") ->setParameter("eid", $eventId) ->getQuery()->getResult(); @@ -40,7 +40,7 @@ function __construct(public int $id, public string $name, public bool $open) } } -class RaceInfoDto +class ActivityInfoDto { function __construct(public int $id, public string $name) { diff --git a/app/services/RaceService.php b/app/services/RaceService.php deleted file mode 100644 index d1e0eabd..00000000 --- a/app/services/RaceService.php +++ /dev/null @@ -1,16 +0,0 @@ -createQueryBuilder() - ->select("r") - ->from(RaceEntry::class, "r") - ->leftJoin("r.user", "u") - ->where("r.race = :raceId") - ->setParameters(['raceId' => $raceId]) - ->getQuery() - ->getResult(); - } -} \ No newline at end of file diff --git a/assets/css/race_edit.css b/assets/css/activity_edit.css similarity index 100% rename from assets/css/race_edit.css rename to assets/css/activity_edit.css diff --git a/assets/css/event_view.css b/assets/css/event_view.css index 5966eded..3a54b173 100644 --- a/assets/css/event_view.css +++ b/assets/css/event_view.css @@ -20,17 +20,17 @@ header > .row > .col-sm-6 { table td { border-bottom: none; } - table .race-name { + table .activity-name { grid-area: name; padding-bottom: 0; } - table .race-date { + table .activity-date { grid-area: date; } - table .race-place { + table .activity-place { grid-area: place; } - table .race-entry { + table .activity-entry { grid-area: icon; align-self: center; } @@ -59,3 +59,7 @@ textarea { details summary:focus:not([role="button"]) { color: var(--accordion-close-summary-color); } + +ul { + margin-bottom: 0.5rem; +} diff --git a/database/models/events.db.php b/database/models/events.db.php index 123ee408..c1af0e10 100644 --- a/database/models/events.db.php +++ b/database/models/events.db.php @@ -135,7 +135,7 @@ static function getWithGraphData($event_id, $user_id = null): Event|null $qb->select('e', 'ee', 'r', 're', 'c') ->from(Event::class, 'e') ->leftJoin('e.entries', 'ee', Join::WITH, 'ee.user = :uid') - ->leftJoin('e.races', 'r') + ->leftJoin('e.activities', 'r') ->leftJoin('r.entries', 're', Join::WITH, 're.user = :uid') ->leftJoin('re.category', 'c') ->where('e.id = :eid') @@ -157,7 +157,7 @@ static function getAllEntries($event_id): array ->from(EventEntry::class, 'e') ->join('e.event', 'ev') ->leftJoin('e.user', 'u') - ->leftJoin('u.race_entries', 're', JOIN::WITH, 're.user = e.user and re.race MEMBER OF ev.races', 're.race') + ->leftJoin('u.activity_entries', 're', JOIN::WITH, 're.user = e.user and re.activity MEMBER OF ev.activities', 're.activity') ->where('e.event = :eid') ->setParameters(['eid' => $event_id]) ->getQuery()->getResult(); @@ -270,7 +270,7 @@ static function fromEventList(array $events) $event['end_date'], $event['deadline'], $event['open'], - isset ($event['present']) ? $event['present'] : null + isset($event['present']) ? $event['present'] : null ); } return $result; diff --git a/database/race_to_activity.php b/database/race_to_activity.php new file mode 100644 index 00000000..9e500d67 --- /dev/null +++ b/database/race_to_activity.php @@ -0,0 +1,72 @@ +createQuery("SELECT r FROM Race r JOIN Event e JOIN RaceEntry re JOIN Category c")->getResult(); +$activities = em()->getRepository(Activity::class)->findAll(); + +$v_up = new Validator(action: "migrate_activities_up"); + +$v_down = new Validator(action: "migrate_activities_down"); + +$logger->debug("races", $races); +$logger->debug("activities", $activities); + +if ($v_up->valid()) { + + #migrate race + foreach ($races as $race) { + $newActivity = new Activity(); + $newActivity->name = $race->name; + $newActivity->date = $race->date; + $newActivity->location_label = $race->place; + $newActivity->location_url = ''; + $newActivity->description = ''; + $newActivity->type = ActivityType::RACE; + $newActivity->event = $race->event; + em()->persist($newActivity); + + #create activity entries corresponding to the race entries, and connect them to the new activity + foreach ($race->entries as $entry) { + $newEntry = new ActivityEntry(); + $newEntry->user = $entry->user; + $newEntry->activity = $newActivity; + $newEntry->category = $entry->category; + $newEntry->present = $entry->present; + $newEntry->comment = $entry->comment; + em()->persist($newEntry); + } + } + em()->flush(); +} + +if ($v_down->valid()) { + foreach ($activities as $activity) { + em()->remove($activity); + } + em()->flush(); +} + +page("Migration")->disableNav(); +?> +valid()): + $count = count($races); + echo "Migration de $count courses vers les activités ✅"; +elseif ($v_down->valid()): + $count = count($activities); + echo "Suppression de $count activités 💥"; +else: ?> + + render_validation() ?> +

Up

+

Sûr de vouloir migrer ? +

+ + + + render_validation() ?> +

Down

+

Sûr de vouloir revenir en arrière ? +

+ + + \ No newline at end of file diff --git a/routes.php b/routes.php index d59e2cdd..6630fbc4 100644 --- a/routes.php +++ b/routes.php @@ -26,6 +26,7 @@ // --- migration --- Router::add('/dev/migrate', '../database/migrate_db'); + Router::add('/dev/migrate_activities', '../database/race_to_activity'); // ---experiments Router::add('/dev/toast', 'pages/dev/test_toast'); @@ -37,8 +38,6 @@ Router::add('/evenements/passes', 'pages/events/event_list/past_events'); Router::add('/evenements/nouveau', 'pages/events/event_edit'); Router::add('/evenements/$event_id/modifier', 'pages/events/event_edit'); -Router::add('/evenements/$event_id/ajouter-course', 'pages/events/race_edit'); -Router::add('/evenements/$event_id/course/$race_id', 'pages/events/race_edit'); Router::add('/evenements/$event_id', 'pages/events/event_view'); Router::add('/evenements/$event_id/inscription', 'pages/events/event_register'); Router::add('/evenements/$event_id/publier', 'pages/events/event_publish'); @@ -49,6 +48,11 @@ Router::add('/evenements/$event_id/participants/tabs', 'pages/events/entry_list/entry_list_tabs'); // Router::add('/download', 'uploads/download_file'); +// Activities +Router::add('/evenements/$event_id/activite/$activity_id/modifier', 'pages/events/activity_edit'); +Router::add('/evenements/$event_id/ajouter-activite', 'pages/events/activity_edit'); +Router::add('/evenements/$event_id/activite/$activity_id', 'pages/events/activity_view'); + // Settings Router::add('/mon-profil', 'pages/settings/settings'); // Settings/users From 144fa4f947817d21cd97bea2976e168351317423 Mon Sep 17 00:00:00 2001 From: Atmos4 Date: Fri, 5 Apr 2024 17:56:01 +0200 Subject: [PATCH 2/2] 171: improve migration page - add helpers and better structure to handle route protection - improve rollback to prevent data corruption - improve user experience --- .../data_migrations/dataMigrationUtils.php | 12 +++ database/{ => data_migrations}/migrate_db.php | 2 +- database/data_migrations/race_to_activity.php | 98 +++++++++++++++++++ database/race_to_activity.php | 72 -------------- engine/helpers.php | 15 ++- routes.php | 8 +- 6 files changed, 126 insertions(+), 81 deletions(-) create mode 100644 database/data_migrations/dataMigrationUtils.php rename database/{ => data_migrations}/migrate_db.php (97%) create mode 100644 database/data_migrations/race_to_activity.php delete mode 100644 database/race_to_activity.php diff --git a/database/data_migrations/dataMigrationUtils.php b/database/data_migrations/dataMigrationUtils.php new file mode 100644 index 00000000..37da1dbd --- /dev/null +++ b/database/data_migrations/dataMigrationUtils.php @@ -0,0 +1,12 @@ +createQuery("SELECT r, e, re, c FROM Race r JOIN r.event e LEFT JOIN r.entries re LEFT JOIN r.categories c")->getResult(); +} + +/** @return Activity[] */ +function getActivities(): array +{ + return em()->createQuery("SELECT a, c FROM Activity a LEFT JOIN a.categories c")->getResult(); +} \ No newline at end of file diff --git a/database/migrate_db.php b/database/data_migrations/migrate_db.php similarity index 97% rename from database/migrate_db.php rename to database/data_migrations/migrate_db.php index c4a52f6d..067314e0 100644 --- a/database/migrate_db.php +++ b/database/data_migrations/migrate_db.php @@ -1,5 +1,5 @@ debug("races", ["races" => $races]); +logger()->debug("activities", ["activities" => $activities]); + +if ($v_up->valid()) { + + #migrate race + foreach ($races as $race) { + $newActivity = new Activity(); + $newActivity->name = $race->name; + $newActivity->date = $race->date; + $newActivity->location_label = $race->place; + $newActivity->location_url = ''; + $newActivity->description = ''; + $newActivity->type = ActivityType::RACE; + $newActivity->event = $race->event; + em()->persist($newActivity); + + #create activity entries corresponding to the race entries, and connect them to the new activity + foreach ($race->entries as $entry) { + $newEntry = new ActivityEntry(); + $newEntry->user = $entry->user; + $newEntry->activity = $newActivity; + $newEntry->category = $entry->category; + $newEntry->present = $entry->present; + $newEntry->comment = $entry->comment; + em()->persist($newEntry); + } + + foreach ($race->categories as $c) { + $c->activity = $newActivity; + } + } + em()->flush(); + Toast::success("Migration de $raceCount courses vers les activités ✅"); + redirect("/dev/migrate_activities"); +} + +if ($v_down->valid()) { + foreach ($activities as $activity) { + foreach ($activity->categories as $c) { + if ($c->race) { + $activity->categories->removeElement($c); + $c->activity = null; + } + } + em()->remove($activity); + } + em()->flush(); + Toast::success("Suppression de $activityCount activités 💥"); + redirect("/dev/migrate_activities"); +} + +$status = match (true) { + ($activityCount === 0) => 'ready to migrate', + ($activityCount === $raceCount) => 'migration successful', + ($activityCount > $raceCount) => "dangerous!! More activities than races", + default => "unknown", +}; + +page("Races to activities"); +?> +
+

Status: + +

+
    +
  • Races: + +
  • +
  • Activities: + +
  • +
+

Actions:

+
+
+ render_validation() ?> + + +
+ render_validation() ?> + + +
+
\ No newline at end of file diff --git a/database/race_to_activity.php b/database/race_to_activity.php deleted file mode 100644 index 9e500d67..00000000 --- a/database/race_to_activity.php +++ /dev/null @@ -1,72 +0,0 @@ -createQuery("SELECT r FROM Race r JOIN Event e JOIN RaceEntry re JOIN Category c")->getResult(); -$activities = em()->getRepository(Activity::class)->findAll(); - -$v_up = new Validator(action: "migrate_activities_up"); - -$v_down = new Validator(action: "migrate_activities_down"); - -$logger->debug("races", $races); -$logger->debug("activities", $activities); - -if ($v_up->valid()) { - - #migrate race - foreach ($races as $race) { - $newActivity = new Activity(); - $newActivity->name = $race->name; - $newActivity->date = $race->date; - $newActivity->location_label = $race->place; - $newActivity->location_url = ''; - $newActivity->description = ''; - $newActivity->type = ActivityType::RACE; - $newActivity->event = $race->event; - em()->persist($newActivity); - - #create activity entries corresponding to the race entries, and connect them to the new activity - foreach ($race->entries as $entry) { - $newEntry = new ActivityEntry(); - $newEntry->user = $entry->user; - $newEntry->activity = $newActivity; - $newEntry->category = $entry->category; - $newEntry->present = $entry->present; - $newEntry->comment = $entry->comment; - em()->persist($newEntry); - } - } - em()->flush(); -} - -if ($v_down->valid()) { - foreach ($activities as $activity) { - em()->remove($activity); - } - em()->flush(); -} - -page("Migration")->disableNav(); -?> -valid()): - $count = count($races); - echo "Migration de $count courses vers les activités ✅"; -elseif ($v_down->valid()): - $count = count($activities); - echo "Suppression de $count activités 💥"; -else: ?> -
- render_validation() ?> -

Up

-

Sûr de vouloir migrer ? -

- - -
- render_validation() ?> -

Down

-

Sûr de vouloir revenir en arrière ? -

- - - \ No newline at end of file diff --git a/engine/helpers.php b/engine/helpers.php index 0ccfffb7..ac79de47 100644 --- a/engine/helpers.php +++ b/engine/helpers.php @@ -121,7 +121,7 @@ function restrict_access($permissions = []) if (!AuthService::create()->isUserLoggedIn()) redirect("/"); - if (!isset ($_SESSION['user_permission']) || (count($permissions) && !in_array($_SESSION['user_permission'], $permissions))) { + if (!isset($_SESSION['user_permission']) || (count($permissions) && !in_array($_SESSION['user_permission'], $permissions))) { $permission = $_SESSION['user_permission']?->value ?? "non authenticated user"; if (get_header('HX-Request')) { // This is a bit lazy but it's the idea @@ -138,7 +138,7 @@ function force_404($message = "") function has_session($key): bool { - return isset ($_SESSION[$key]); + return isset($_SESSION[$key]); } function restrict_dev() @@ -148,6 +148,13 @@ function restrict_dev() } } +function restrict_environment($key) +{ + if (!env('DEVELOPMENT') && !env($key)) { + force_404(); + } +} + /** * Format a date. * @param string|int|DateTime $date The date either as a string, a timestamp or a DateTime. @@ -163,14 +170,14 @@ function format_date($date, string $format = null) /** CSRF Protection */ function set_csrf() { - if (!isset ($_SESSION["csrf"])) { + if (!isset($_SESSION["csrf"])) { $_SESSION["csrf"] = bin2hex(random_bytes(50)); } return ''; } function is_csrf_valid() { - if (!isset ($_SESSION['csrf']) || !isset ($_POST['csrf'])) { + if (!isset($_SESSION['csrf']) || !isset($_POST['csrf'])) { return false; } if ($_SESSION['csrf'] != $_POST['csrf']) { diff --git a/routes.php b/routes.php index 6630fbc4..dfc313b6 100644 --- a/routes.php +++ b/routes.php @@ -24,14 +24,14 @@ Router::add('/dev/ovh/redirections/$id', 'pages/dev/ovh/redirections'); Router::add('/dev/ovh/test-api', 'pages/dev/ovh/test_api.php'); - // --- migration --- - Router::add('/dev/migrate', '../database/migrate_db'); - Router::add('/dev/migrate_activities', '../database/race_to_activity'); - // ---experiments Router::add('/dev/toast', 'pages/dev/test_toast'); Router::add('/dev/random', 'pages/dev/test_random'); } +// DANGER ZONE: migrations - Make sure to protect those routes with `restrict_environment` +Router::add('/dev/migrate', '../database/data_migrations/migrate_db'); +Router::add('/dev/migrate_activities', '../database/data_migrations/race_to_activity'); +// END OF DANGER ZONE // Events Router::add('/evenements', 'pages/events/event_list/event_list');
- name ?> + + name ?> - date) ?> + + date) ?> - place ?> + + location_url): ?> + location_url ?> target=”_blank”>location_label ?> + + location_label ?> +