diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 559660c4..2430a859 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -11,6 +11,9 @@ on: # Enable manual run workflow_dispatch: +permissions: + contents: read + concurrency: group: "${{ github.workflow }}-${{ github.ref }}" cancel-in-progress: true @@ -213,3 +216,97 @@ jobs: run: | cd galette-core/galette/plugins/plugin-events ../../vendor/bin/phpunit --test-suffix=.php --bootstrap tests/TestsBootstrap.php --no-coverage --process-isolation tests/GaletteEvents/ + + upgrade: + runs-on: ubuntu-latest + + strategy: + matrix: + db-image: ['mysql:8.4', 'mariadb:11', 'postgres:17'] + fail-fast: false + + env: + DB: ${{ matrix.db-image }} + + services: + # Label used to access the service container + db: + # Docker Hub image + image: ${{ matrix.db-image }} + # Provide env variables for both mysql and pgsql + env: + POSTGRES_USER: galette_tests + POSTGRES_PASSWORD: g@l3tte + POSTGRES_DB: galette_tests + MYSQL_USER: galette_tests + MYSQL_PASSWORD: g@l3tte + MYSQL_ROOT_PASSWORD: g@l3tte + MYSQL_DATABASE: galette_tests + # Open network ports for both mysql and pgsql + ports: + - 3306:3306 + - 5432:5432 + # Set health checks to wait until postgres has started + options: >- + --health-cmd="bash -c 'if [[ -n $(command -v pg_isready) ]]; then pg_isready; else if [[ -n $(command -v mysqladmin) ]]; then mysqladmin ping; else mariadb-admin ping; fi fi'" + --health-interval=10s + --health-timeout=5s + --health-retries=10 + + name: Upgrade from previous release on ${{ matrix.db-image }} + + steps: + - name: PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + tools: composer, pecl + coverage: none + extensions: apcu + ini-values: apc.enable_cli=1 + + - name: Build Galette + uses: galette/.github/actions/build-galette@main + with: + php-version: '8.4' + + - name: Checkout plugin + uses: actions/checkout@v7 + with: + path: galette-core/galette/plugins/plugin-events + fetch-depth: 0 + + - name: Find previous release + run: | + cd galette-core/galette/plugins/plugin-events + echo "PREVIOUS_RELEASE=$(git tag --list '[0-9]*' --sort=-v:refname --no-contains HEAD | head -n1)" >> $GITHUB_ENV + + - name: Install previous release for PostgreSQL + env: + PGPASSWORD: g@l3tte + run: | + cd galette-core + bin/console galette:install -v --dbtype=pgsql --dbhost=localhost --dbname=galette_tests --dbuser=galette_tests --dbpass=g@l3tte --admin=admin --password=admin --no-interaction -w + git -C galette/plugins/plugin-events show "$PREVIOUS_RELEASE:scripts/pgsql.sql" \ + | psql -v ON_ERROR_STOP=1 -h localhost -U galette_tests galette_tests + if: startsWith(matrix.db-image, 'postgres') + + - name: Install previous release for MariaDB + run: | + cd galette-core + mysql -e 'create database IF NOT EXISTS galette_tests;' -u galette_tests --password=g@l3tte -h 127.0.0.1 -P 3306 + bin/console galette:install -v --dbtype=mysql --dbhost=127.0.0.1 --dbname=galette_tests --dbuser=galette_tests --dbpass=g@l3tte --admin=admin --password=admin --no-interaction -w + git -C galette/plugins/plugin-events show "$PREVIOUS_RELEASE:scripts/mysql.sql" \ + | mysql -u galette_tests --password=g@l3tte -h 127.0.0.1 -P 3306 galette_tests + if: startsWith(matrix.db-image, 'mysql') || startsWith(matrix.db-image, 'mariadb') + + - name: Upgrade + run: | + cd galette-core + bin/console galette:plugins:install-db --no-interaction plugin-events | tee upgrade.log + grep -q 'Database for plugin "plugin-events" upgraded' upgrade.log + + - name: Unit tests + run: | + cd galette-core/galette/plugins/plugin-events + ../../vendor/bin/phpunit --test-suffix=.php --bootstrap tests/TestsBootstrap.php --no-coverage --process-isolation tests/GaletteEvents/ diff --git a/_define.php b/_define.php index b664e066..93ea4e6e 100644 --- a/_define.php +++ b/_define.php @@ -48,5 +48,5 @@ 'events_calendar' => 'member', 'ajax-events_calendar' => 'member' ], - dbver: 1.00 + dbver: 1.1 ); diff --git a/lang/events.pot b/lang/events.pot index 9c786da6..abb9c884 100644 --- a/lang/events.pot +++ b/lang/events.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-25 04:15+0200\n" +"POT-Creation-Date: 2026-09-27 08:45+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,81 +18,93 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -#: ../lib/GaletteEvents/Event.php:188 +#: ../lib/GaletteEvents/Event.php:182 msgid "Begin date is mandatory" msgstr "" -#: ../lib/GaletteEvents/Event.php:212 ../templates/default/event.html.twig:40 +#: ../lib/GaletteEvents/Event.php:206 ../templates/default/event.html.twig:40 msgid "Begin date" msgstr "" -#: ../lib/GaletteEvents/Event.php:214 ../templates/default/event.html.twig:46 +#: ../lib/GaletteEvents/Event.php:208 ../templates/default/event.html.twig:46 msgid "End date" msgstr "" -#: ../lib/GaletteEvents/Event.php:232 +#: ../lib/GaletteEvents/Event.php:226 msgid "End date must be later or equal to begin date" msgstr "" -#: ../lib/GaletteEvents/Event.php:238 ../lib/GaletteEvents/Activity.php:155 +#: ../lib/GaletteEvents/Event.php:232 ../lib/GaletteEvents/Activity.php:155 msgid "Name is mandatory" msgstr "" -#: ../lib/GaletteEvents/Event.php:254 +#: ../lib/GaletteEvents/Event.php:248 msgid "Please select a group you own!" msgstr "" -#: ../lib/GaletteEvents/Event.php:261 +#: ../lib/GaletteEvents/Event.php:255 msgid "Town is mandatory" msgstr "" -#: ../lib/GaletteEvents/Event.php:388 +#: ../lib/GaletteEvents/Event.php:380 msgid "Event added" msgstr "" -#: ../lib/GaletteEvents/Event.php:392 +#: ../lib/GaletteEvents/Event.php:384 msgid "Fail to add new event." msgstr "" -#: ../lib/GaletteEvents/Event.php:411 +#: ../lib/GaletteEvents/Event.php:403 msgid "Event updated" msgstr "" -#: ../lib/GaletteEvents/Controllers/CsvController.php:54 -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:257 +#. TRANS: %1$s is the group name, %2$s the number of events +#: ../lib/GaletteEvents/PluginEventProvider.php:58 +#, php-format +msgid "" +"Group \"%1$s\" is used by %2$s event, it cannot be deleted. Remove the event " +"or change its group first." +msgid_plural "" +"Group \"%1$s\" is used by %2$s events, it cannot be deleted. Remove the " +"events or change their group first." +msgstr[0] "" +msgstr[1] "" + +#: ../lib/GaletteEvents/Controllers/CsvController.php:86 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:226 #: ../templates/default/booking.html.twig:33 ../templates/default/booking.html.twig:39 #: ../templates/default/bookings.html.twig:49 ../templates/default/bookings.html.twig:77 msgid "Event" msgstr "" -#: ../lib/GaletteEvents/Controllers/CsvController.php:58 +#: ../lib/GaletteEvents/Controllers/CsvController.php:90 #: ../templates/default/event.html.twig:86 msgid "Zip code" msgstr "" -#: ../lib/GaletteEvents/Controllers/CsvController.php:64 +#: ../lib/GaletteEvents/Controllers/CsvController.php:96 #: ../templates/default/booking.html.twig:63 msgid "Number of persons" msgstr "" -#: ../lib/GaletteEvents/Controllers/CsvController.php:79 +#: ../lib/GaletteEvents/Controllers/CsvController.php:111 #: ../templates/default/booking.html.twig:115 msgid "Amount" msgstr "" -#: ../lib/GaletteEvents/Controllers/CsvController.php:81 +#: ../lib/GaletteEvents/Controllers/CsvController.php:113 #: ../templates/default/booking.html.twig:127 msgid "Bank name" msgstr "" #. TRANS: Bank check number -#: ../lib/GaletteEvents/Controllers/CsvController.php:83 +#: ../lib/GaletteEvents/Controllers/CsvController.php:115 #: ../templates/default/booking.html.twig:133 msgid "Check number" msgstr "" #. TRANS: this is a filename: all lowercase, no special character, no space. -#: ../lib/GaletteEvents/Controllers/CsvController.php:138 +#: ../lib/GaletteEvents/Controllers/CsvController.php:170 msgid "bookingslist" msgstr "" @@ -100,79 +112,86 @@ msgstr "" msgid "Events management" msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:153 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:128 msgid "Javascript libraries has not been built!" msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:162 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:139 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:137 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:136 msgid "Events calendar" msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:336 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:288 msgid "Activity has been attached to event." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:337 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:289 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:295 msgid "Do not forget to store the event" msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:339 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:291 +#: ../templates/default/event.html.twig:179 +msgid "Please choose an activity to add" +msgstr "" + +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:294 msgid "Activity has been detached from event." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:348 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:303 msgid "New event has been successfully added." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:350 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:305 msgid "Event has been modified." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:354 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:308 msgid "An error occurred while storing the event." msgstr "" #. TRANS: %1$s is the event name -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:448 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:417 #, php-format msgid "Remove event '%1$s'" msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:133 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:134 msgid "Bookings management" msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:291 -msgid "No action was matching." +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:258 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:322 +msgid "No booking was selected, please check at least one." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:296 -msgid "No booking was selected, please check at least one." +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:317 +msgid "No action was matching." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:332 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:381 msgid "Booking" msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:457 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:510 msgid "New booking has been successfully added." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:459 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:512 msgid "Booking has been modified." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:463 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:516 msgid "An error occurred while storing the booking." msgstr "" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:471 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:524 msgid "Do not forget to store the booking" msgstr "" #. TRANS: %1$s is the member name, %2$s the event name. -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:568 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:641 #, php-format msgid "Remove booking for %1$s on %2$s" msgstr "" @@ -203,51 +222,63 @@ msgstr "" msgid "Remove activity %1$s" msgstr "" -#: ../lib/GaletteEvents/Booking.php:175 +#: ../lib/GaletteEvents/Booking.php:177 msgid "Event is mandatory" msgstr "" +#: ../lib/GaletteEvents/Booking.php:183 +msgid "This event cannot be booked." +msgstr "" + #. TRANS: %1$s is activity name -#: ../lib/GaletteEvents/Booking.php:187 +#: ../lib/GaletteEvents/Booking.php:193 #, php-format msgid "%1$s is mandatory for this event!" msgstr "" -#: ../lib/GaletteEvents/Booking.php:222 +#: ../lib/GaletteEvents/Booking.php:231 +msgid "Amount must be a number." +msgstr "" + +#: ../lib/GaletteEvents/Booking.php:236 msgid "Please specify amount if booking has been paid ;)" msgstr "" -#: ../lib/GaletteEvents/Booking.php:245 +#: ../lib/GaletteEvents/Booking.php:257 msgid "Member is mandatory" msgstr "" -#: ../lib/GaletteEvents/Booking.php:257 +#: ../lib/GaletteEvents/Booking.php:271 +msgid "You can only book other members on events of groups you manage." +msgstr "" + +#: ../lib/GaletteEvents/Booking.php:281 msgid "There must be at least one person" msgstr "" -#: ../lib/GaletteEvents/Booking.php:266 +#: ../lib/GaletteEvents/Booking.php:290 msgid "Booking date is mandatory!" msgstr "" -#: ../lib/GaletteEvents/Booking.php:290 +#: ../lib/GaletteEvents/Booking.php:314 msgid "booking date" msgstr "" #. TRANS: first replacement is member name, second is event name -#: ../lib/GaletteEvents/Booking.php:312 +#: ../lib/GaletteEvents/Booking.php:336 #, php-format msgid "A booking already exists for %1$s in %2$s" msgstr "" -#: ../lib/GaletteEvents/Booking.php:378 +#: ../lib/GaletteEvents/Booking.php:402 msgid "Booking added" msgstr "" -#: ../lib/GaletteEvents/Booking.php:382 +#: ../lib/GaletteEvents/Booking.php:406 msgid "Fail to add new booking." msgstr "" -#: ../lib/GaletteEvents/Booking.php:401 +#: ../lib/GaletteEvents/Booking.php:425 msgid "Booking updated" msgstr "" @@ -263,62 +294,62 @@ msgstr "" msgid "Activity updated" msgstr "" -#: ../lib/GaletteEvents/Repository/Events.php:196 +#: ../lib/GaletteEvents/Repository/Events.php:170 msgid "Event information" msgstr "" -#: ../lib/GaletteEvents/Repository/Events.php:200 +#: ../lib/GaletteEvents/Repository/Events.php:174 msgid "Start date:" msgstr "" -#: ../lib/GaletteEvents/Repository/Events.php:201 +#: ../lib/GaletteEvents/Repository/Events.php:175 msgid "End date:" msgstr "" -#: ../lib/GaletteEvents/Repository/Events.php:202 +#: ../lib/GaletteEvents/Repository/Events.php:176 msgid "Location:" msgstr "" -#: ../lib/GaletteEvents/Repository/Events.php:204 +#: ../lib/GaletteEvents/Repository/Events.php:178 msgid "Comment:" msgstr "" #. TRANS: %1$s is the number of paid attendees -#: ../lib/GaletteEvents/Repository/Events.php:221 +#: ../lib/GaletteEvents/Repository/Events.php:195 #, php-format msgid "%1$s paid" msgstr "" -#: ../lib/GaletteEvents/Repository/Events.php:226 +#: ../lib/GaletteEvents/Repository/Events.php:200 msgid "Attendees:" msgstr "" -#: ../lib/GaletteEvents/Repository/Events.php:234 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:96 +#: ../lib/GaletteEvents/Repository/Events.php:208 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:93 #: ../templates/default/booking.html.twig:78 ../templates/default/event.html.twig:108 msgid "Activities" msgstr "" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:55 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:59 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:58 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:62 #: ../templates/default/activities.html.twig:41 ../templates/default/activities.html.twig:74 msgid "Events" msgstr "" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:66 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:138 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:69 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:135 msgid "Calendar" msgstr "" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:79 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:75 msgid "Bookings" msgstr "" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:159 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:156 msgid "New event booking" msgstr "" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:215 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:212 msgid "Upcoming events" msgstr "" @@ -374,7 +405,7 @@ msgstr "" msgid "Today" msgstr "" -#: ../templates/default/calendar.html.twig:36 ../templates/default/bookings.html.twig:43 +#: ../templates/default/calendar.html.twig:33 ../templates/default/bookings.html.twig:43 msgid "New booking" msgstr "" @@ -555,7 +586,7 @@ msgstr "" msgid "No activity has been found" msgstr "" -#: ../templates/default/event.html.twig:19 +#: ../templates/default/event.html.twig:17 msgid "Is open" msgstr "" @@ -607,10 +638,6 @@ msgstr "" msgid "No activity available in the database." msgstr "" -#: ../templates/default/event.html.twig:179 -msgid "Please choose an activity to add" -msgstr "" - #: ../templates/default/event.html.twig:186 msgid "Please choose an activity to remove" msgstr "" diff --git a/lang/events_en_US.po b/lang/events_en_US.po index 39c6d7b9..8dc055eb 100644 --- a/lang/events_en_US.po +++ b/lang/events_en_US.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-25 04:15+0200\n" -"PO-Revision-Date: 2026-09-25 04:15+0200\n" +"POT-Creation-Date: 2026-09-27 08:45+0200\n" +"PO-Revision-Date: 2026-09-27 08:45+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: en_US\n" @@ -17,48 +17,64 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../lib/GaletteEvents/Event.php:188 +#: ../lib/GaletteEvents/Event.php:182 msgid "Begin date is mandatory" msgstr "Begin date is mandatory" -#: ../lib/GaletteEvents/Event.php:212 ../templates/default/event.html.twig:40 +#: ../lib/GaletteEvents/Event.php:206 ../templates/default/event.html.twig:40 msgid "Begin date" msgstr "Begin date" -#: ../lib/GaletteEvents/Event.php:214 ../templates/default/event.html.twig:46 +#: ../lib/GaletteEvents/Event.php:208 ../templates/default/event.html.twig:46 msgid "End date" msgstr "End date" -#: ../lib/GaletteEvents/Event.php:232 +#: ../lib/GaletteEvents/Event.php:226 msgid "End date must be later or equal to begin date" msgstr "End date must be later or equal to begin date" -#: ../lib/GaletteEvents/Event.php:238 ../lib/GaletteEvents/Activity.php:155 +#: ../lib/GaletteEvents/Event.php:232 ../lib/GaletteEvents/Activity.php:155 msgid "Name is mandatory" msgstr "Name is mandatory" -#: ../lib/GaletteEvents/Event.php:254 +#: ../lib/GaletteEvents/Event.php:248 msgid "Please select a group you own!" msgstr "Please select a group you own!" -#: ../lib/GaletteEvents/Event.php:261 +#: ../lib/GaletteEvents/Event.php:255 msgid "Town is mandatory" msgstr "Town is mandatory" -#: ../lib/GaletteEvents/Event.php:388 +#: ../lib/GaletteEvents/Event.php:380 msgid "Event added" msgstr "Event added" -#: ../lib/GaletteEvents/Event.php:392 +#: ../lib/GaletteEvents/Event.php:384 msgid "Fail to add new event." msgstr "Fail to add new event." -#: ../lib/GaletteEvents/Event.php:411 +#: ../lib/GaletteEvents/Event.php:403 msgid "Event updated" msgstr "Event updated" -#: ../lib/GaletteEvents/Controllers/CsvController.php:54 -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:257 +#. TRANS: %1$s is the group name, %2$s the number of events +#: ../lib/GaletteEvents/PluginEventProvider.php:58 +#, php-format +msgid "" +"Group \"%1$s\" is used by %2$s event, it cannot be deleted. Remove the event " +"or change its group first." +msgid_plural "" +"Group \"%1$s\" is used by %2$s events, it cannot be deleted. Remove the " +"events or change their group first." +msgstr[0] "" +"Group \"%1$s\" is used by %2$s event, it cannot be deleted. Remove the event " +"or change its group first." +msgstr[1] "" +"Group \"%1$s\" is used by %2$s events, it cannot be deleted. Remove the " +"events or change their group first." + +#: ../lib/GaletteEvents/Controllers/CsvController.php:86 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:226 #: ../templates/default/booking.html.twig:33 #: ../templates/default/booking.html.twig:39 #: ../templates/default/bookings.html.twig:49 @@ -66,34 +82,34 @@ msgstr "Event updated" msgid "Event" msgstr "Event" -#: ../lib/GaletteEvents/Controllers/CsvController.php:58 +#: ../lib/GaletteEvents/Controllers/CsvController.php:90 #: ../templates/default/event.html.twig:86 msgid "Zip code" msgstr "Zip code" -#: ../lib/GaletteEvents/Controllers/CsvController.php:64 +#: ../lib/GaletteEvents/Controllers/CsvController.php:96 #: ../templates/default/booking.html.twig:63 msgid "Number of persons" msgstr "Number of persons" -#: ../lib/GaletteEvents/Controllers/CsvController.php:79 +#: ../lib/GaletteEvents/Controllers/CsvController.php:111 #: ../templates/default/booking.html.twig:115 msgid "Amount" msgstr "Amount" -#: ../lib/GaletteEvents/Controllers/CsvController.php:81 +#: ../lib/GaletteEvents/Controllers/CsvController.php:113 #: ../templates/default/booking.html.twig:127 msgid "Bank name" msgstr "Bank name" #. TRANS: Bank check number -#: ../lib/GaletteEvents/Controllers/CsvController.php:83 +#: ../lib/GaletteEvents/Controllers/CsvController.php:115 #: ../templates/default/booking.html.twig:133 msgid "Check number" msgstr "Check number" #. TRANS: this is a filename: all lowercase, no special character, no space. -#: ../lib/GaletteEvents/Controllers/CsvController.php:138 +#: ../lib/GaletteEvents/Controllers/CsvController.php:170 msgid "bookingslist" msgstr "bookingslist" @@ -101,79 +117,86 @@ msgstr "bookingslist" msgid "Events management" msgstr "Events management" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:153 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:128 msgid "Javascript libraries has not been built!" msgstr "Javascript libraries has not been built!" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:162 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:139 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:137 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:136 msgid "Events calendar" msgstr "Events calendar" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:336 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:288 msgid "Activity has been attached to event." msgstr "Activity has been attached to event." -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:337 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:289 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:295 msgid "Do not forget to store the event" msgstr "Do not forget to store the event" -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:339 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:291 +#: ../templates/default/event.html.twig:179 +msgid "Please choose an activity to add" +msgstr "Please choose an activity to add" + +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:294 msgid "Activity has been detached from event." msgstr "Activity has been detached from event." -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:348 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:303 msgid "New event has been successfully added." msgstr "New event has been successfully added." -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:350 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:305 msgid "Event has been modified." msgstr "Event has been modified." -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:354 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:308 msgid "An error occurred while storing the event." msgstr "An error occurred while storing the event." #. TRANS: %1$s is the event name -#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:448 +#: ../lib/GaletteEvents/Controllers/Crud/EventsController.php:417 #, php-format msgid "Remove event '%1$s'" msgstr "Remove event '%1$s'" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:133 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:134 msgid "Bookings management" msgstr "Bookings management" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:291 -msgid "No action was matching." -msgstr "No action was matching." - -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:296 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:258 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:322 msgid "No booking was selected, please check at least one." msgstr "No booking was selected, please check at least one." -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:332 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:317 +msgid "No action was matching." +msgstr "No action was matching." + +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:381 msgid "Booking" msgstr "Booking" -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:457 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:510 msgid "New booking has been successfully added." msgstr "New booking has been successfully added." -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:459 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:512 msgid "Booking has been modified." msgstr "Booking has been modified." -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:463 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:516 msgid "An error occurred while storing the booking." msgstr "An error occurred while storing the booking." -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:471 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:524 msgid "Do not forget to store the booking" msgstr "Do not forget to store the booking" #. TRANS: %1$s is the member name, %2$s the event name. -#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:568 +#: ../lib/GaletteEvents/Controllers/Crud/BookingsController.php:641 #, php-format msgid "Remove booking for %1$s on %2$s" msgstr "Remove booking for %1$s on %2$s" @@ -204,51 +227,63 @@ msgstr "An error occurred while storing the activity." msgid "Remove activity %1$s" msgstr "Remove activity %1$s" -#: ../lib/GaletteEvents/Booking.php:175 +#: ../lib/GaletteEvents/Booking.php:177 msgid "Event is mandatory" msgstr "Event is mandatory" +#: ../lib/GaletteEvents/Booking.php:183 +msgid "This event cannot be booked." +msgstr "This event cannot be booked." + #. TRANS: %1$s is activity name -#: ../lib/GaletteEvents/Booking.php:187 +#: ../lib/GaletteEvents/Booking.php:193 #, php-format msgid "%1$s is mandatory for this event!" msgstr "%1$s is mandatory for this event!" -#: ../lib/GaletteEvents/Booking.php:222 +#: ../lib/GaletteEvents/Booking.php:231 +msgid "Amount must be a number." +msgstr "Amount must be a number." + +#: ../lib/GaletteEvents/Booking.php:236 msgid "Please specify amount if booking has been paid ;)" msgstr "Please specify amount if booking has been paid ;)" -#: ../lib/GaletteEvents/Booking.php:245 +#: ../lib/GaletteEvents/Booking.php:257 msgid "Member is mandatory" msgstr "Member is mandatory" -#: ../lib/GaletteEvents/Booking.php:257 +#: ../lib/GaletteEvents/Booking.php:271 +msgid "You can only book other members on events of groups you manage." +msgstr "You can only book other members on events of groups you manage." + +#: ../lib/GaletteEvents/Booking.php:281 msgid "There must be at least one person" msgstr "There must be at least one person" -#: ../lib/GaletteEvents/Booking.php:266 +#: ../lib/GaletteEvents/Booking.php:290 msgid "Booking date is mandatory!" msgstr "Booking date is mandatory!" -#: ../lib/GaletteEvents/Booking.php:290 +#: ../lib/GaletteEvents/Booking.php:314 msgid "booking date" msgstr "booking date" #. TRANS: first replacement is member name, second is event name -#: ../lib/GaletteEvents/Booking.php:312 +#: ../lib/GaletteEvents/Booking.php:336 #, php-format msgid "A booking already exists for %1$s in %2$s" msgstr "A booking already exists for %1$s in %2$s" -#: ../lib/GaletteEvents/Booking.php:378 +#: ../lib/GaletteEvents/Booking.php:402 msgid "Booking added" msgstr "Booking added" -#: ../lib/GaletteEvents/Booking.php:382 +#: ../lib/GaletteEvents/Booking.php:406 msgid "Fail to add new booking." msgstr "Fail to add new booking." -#: ../lib/GaletteEvents/Booking.php:401 +#: ../lib/GaletteEvents/Booking.php:425 msgid "Booking updated" msgstr "Booking updated" @@ -264,64 +299,64 @@ msgstr "Fail to add new activity." msgid "Activity updated" msgstr "Activity updated" -#: ../lib/GaletteEvents/Repository/Events.php:196 +#: ../lib/GaletteEvents/Repository/Events.php:170 msgid "Event information" msgstr "Event information" -#: ../lib/GaletteEvents/Repository/Events.php:200 +#: ../lib/GaletteEvents/Repository/Events.php:174 msgid "Start date:" msgstr "Start date:" -#: ../lib/GaletteEvents/Repository/Events.php:201 +#: ../lib/GaletteEvents/Repository/Events.php:175 msgid "End date:" msgstr "End date:" -#: ../lib/GaletteEvents/Repository/Events.php:202 +#: ../lib/GaletteEvents/Repository/Events.php:176 msgid "Location:" msgstr "Location:" -#: ../lib/GaletteEvents/Repository/Events.php:204 +#: ../lib/GaletteEvents/Repository/Events.php:178 msgid "Comment:" msgstr "Comment:" #. TRANS: %1$s is the number of paid attendees -#: ../lib/GaletteEvents/Repository/Events.php:221 +#: ../lib/GaletteEvents/Repository/Events.php:195 #, php-format msgid "%1$s paid" msgstr "%1$s paid" -#: ../lib/GaletteEvents/Repository/Events.php:226 +#: ../lib/GaletteEvents/Repository/Events.php:200 msgid "Attendees:" msgstr "Attendees:" -#: ../lib/GaletteEvents/Repository/Events.php:234 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:96 +#: ../lib/GaletteEvents/Repository/Events.php:208 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:93 #: ../templates/default/booking.html.twig:78 #: ../templates/default/event.html.twig:108 msgid "Activities" msgstr "Activities" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:55 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:59 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:58 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:62 #: ../templates/default/activities.html.twig:41 #: ../templates/default/activities.html.twig:74 msgid "Events" msgstr "Events" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:66 -#: ../lib/GaletteEvents/PluginGaletteEvents.php:138 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:69 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:135 msgid "Calendar" msgstr "Calendar" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:79 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:75 msgid "Bookings" msgstr "Bookings" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:159 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:156 msgid "New event booking" msgstr "New event booking" -#: ../lib/GaletteEvents/PluginGaletteEvents.php:215 +#: ../lib/GaletteEvents/PluginGaletteEvents.php:212 msgid "Upcoming events" msgstr "Upcoming events" @@ -382,7 +417,7 @@ msgstr "Month calendar" msgid "Today" msgstr "Today" -#: ../templates/default/calendar.html.twig:36 +#: ../templates/default/calendar.html.twig:33 #: ../templates/default/bookings.html.twig:43 msgid "New booking" msgstr "New booking" @@ -584,7 +619,7 @@ msgstr "Inactive" msgid "No activity has been found" msgstr "No activity has been found" -#: ../templates/default/event.html.twig:19 +#: ../templates/default/event.html.twig:17 msgid "Is open" msgstr "Is open" @@ -636,10 +671,6 @@ msgstr "Required" msgid "No activity available in the database." msgstr "No activity available in the database." -#: ../templates/default/event.html.twig:179 -msgid "Please choose an activity to add" -msgstr "Please choose an activity to add" - #: ../templates/default/event.html.twig:186 msgid "Please choose an activity to remove" msgstr "Please choose an activity to remove" diff --git a/lib/GaletteEvents/Activity.php b/lib/GaletteEvents/Activity.php index 62047e6a..49e57f52 100644 --- a/lib/GaletteEvents/Activity.php +++ b/lib/GaletteEvents/Activity.php @@ -200,7 +200,7 @@ public function store(): bool if (empty($this->id)) { //we're inserting a new event - $this->creation_date = date("Y-m-d H:i:s"); + $this->creation_date = date("Y-m-d"); $values['creation_date'] = $this->creation_date; $insert = $this->zdb->insert($this->getTableName()); diff --git a/lib/GaletteEvents/Booking.php b/lib/GaletteEvents/Booking.php index 07587d15..01fe5b7e 100644 --- a/lib/GaletteEvents/Booking.php +++ b/lib/GaletteEvents/Booking.php @@ -381,7 +381,7 @@ public function store(): bool if (empty($this->id)) { //we're inserting a new event - $this->creation_date = date("Y-m-d H:i:s"); + $this->creation_date = date("Y-m-d"); $values['creation_date'] = $this->creation_date; $insert = $this->zdb->insert($this->getTableName()); diff --git a/lib/GaletteEvents/Event.php b/lib/GaletteEvents/Event.php index b02a95c8..3a0bba4d 100644 --- a/lib/GaletteEvents/Event.php +++ b/lib/GaletteEvents/Event.php @@ -359,7 +359,7 @@ public function store(): bool if (empty($this->id)) { //we're inserting a new event - $this->creation_date = date("Y-m-d H:i:s"); + $this->creation_date = date("Y-m-d"); $values['creation_date'] = $this->creation_date; $insert = $this->zdb->insert($this->getTableName()); diff --git a/lib/GaletteEvents/PluginEventProvider.php b/lib/GaletteEvents/PluginEventProvider.php new file mode 100644 index 00000000..bd7ad767 --- /dev/null +++ b/lib/GaletteEvents/PluginEventProvider.php @@ -0,0 +1,89 @@ + + */ +class PluginEventProvider implements ListenerSubscriber +{ + /** + * Constructor + * + * Built while plugins are loaded: the database is resolved only + * when an event is emitted. + * + * @param ContainerInterface $container Container + */ + public function __construct(private readonly ContainerInterface $container) + { + } + + /** + * Set up listeners + * + * @param ListenerRegistry $acceptor Listener + */ + public function subscribeListeners(ListenerRegistry $acceptor): void + { + $acceptor->subscribeTo( + 'group.before_remove', + function (GaletteEvent $event): void { + /** @var Group $group */ + $group = $event->getObject(); + $count = $this->countGroupEvents((int)$group->getId()); + if ($count > 0) { + $group->preventRemoval( + sprintf( + _Tn( + //TRANS: %1$s is the group name, %2$s the number of events + 'Group "%1$s" is used by %2$s event, it cannot be deleted. Remove the event or change its group first.', + 'Group "%1$s" is used by %2$s events, it cannot be deleted. Remove the events or change their group first.', + $count, + 'events' + ), + $group->getName(), + $count + ) + ); + } + } + ); + } + + /** + * Count events of a group + * + * Events restrict the removal of their group, which would otherwise + * make them visible to every member. + * + * @param int $group_id Group identifier + */ + private function countGroupEvents(int $group_id): int + { + /** @var Db $zdb */ + $zdb = $this->container->get(Db::class); + $select = $zdb->select(EVENTS_PREFIX . Event::TABLE); + $select->columns(['counter' => new Expression('COUNT(' . Event::PK . ')')]); + $select->where([Group::PK => $group_id]); + return (int)$zdb->execute($select)->current()->counter; + } +} diff --git a/lib/GaletteEvents/PluginGaletteEvents.php b/lib/GaletteEvents/PluginGaletteEvents.php index 9cefa598..7320afa9 100644 --- a/lib/GaletteEvents/PluginGaletteEvents.php +++ b/lib/GaletteEvents/PluginGaletteEvents.php @@ -19,11 +19,14 @@ use Galette\Core\Plugins\MenuProviderInterface; use Galette\Core\Plugins\NewsProviderInterface; use Galette\Entity\Adherent; +use Galette\Entity\Group; use Galette\Core\GalettePlugin; use Galette\IO\News\Entry; use Galette\IO\News\Post; use GaletteEvents\Filters\EventsList; use GaletteEvents\Repository\Events; +use Laminas\Db\Metadata\Object\ConstraintObject; +use Laminas\Db\Metadata\Source\Factory; /** * Galette Events plugin @@ -218,4 +221,28 @@ public function isInstalled(): bool { return $this->zdb->tableExists(EVENTS_PREFIX . Event::TABLE); } + + /** + * Version of tables installed before plugins versions were recorded + * + * Since 1.1, amounts are no longer floating point numbers on PostgreSQL, + * and foreign keys are named on MySQL. + */ + public function getLegacyDbVersion(): ?float + { + $metadata = Factory::createSourceFromAdapter($this->zdb->db); + if ($this->zdb->isPostgres()) { + $amount = $metadata->getColumn('payment_amount', PREFIX_DB . EVENTS_PREFIX . Booking::TABLE); + return $amount->getDataType() === 'real' ? 1.0 : null; + } + + $table = PREFIX_DB . EVENTS_PREFIX . Event::TABLE; + /** @var ConstraintObject $constraint */ + foreach ($metadata->getConstraints($table) as $constraint) { + if ($constraint->isForeignKey() && $constraint->getColumns() === [Group::PK]) { + return $constraint->getName() === $table . '_id_group_fkey' ? null : 1.0; + } + } + return null; + } } diff --git a/scripts/mysql.sql b/scripts/mysql.sql index 465b4bea..f49dcb40 100644 --- a/scripts/mysql.sql +++ b/scripts/mysql.sql @@ -26,8 +26,9 @@ CREATE TABLE galette_events_events ( comment text, color varchar(7), PRIMARY KEY (id_event), - FOREIGN KEY (id_group) REFERENCES galette_groups (id_group) ON DELETE RESTRICT ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + CONSTRAINT galette_events_events_id_group_fkey FOREIGN KEY (id_group) + REFERENCES galette_groups (id_group) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; -- -- Table structure for table `galette_events_bookings` @@ -40,7 +41,7 @@ CREATE TABLE galette_events_bookings ( id_adh int(10) unsigned NOT NULL, booking_date date NOT NULL default '1901-01-01', is_paid tinyint(1) NOT NULL default 0, - payment_amount decimal(15, 2) default '0', + payment_amount decimal(15,2) default '0', payment_method tinyint(3) unsigned NOT NULL default '0', bank_name varchar(100) default NULL, check_number varchar(50) default NULL, @@ -48,10 +49,12 @@ CREATE TABLE galette_events_bookings ( creation_date date NOT NULL default '1901-01-01', comment text, PRIMARY KEY (id_booking), - UNIQUE KEY (id_event, id_adh), - FOREIGN KEY (id_event) REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, - FOREIGN KEY (id_adh) REFERENCES galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + UNIQUE KEY galette_events_bookings_id_event_id_adh_key (id_event, id_adh), + CONSTRAINT galette_events_bookings_id_event_fkey FOREIGN KEY (id_event) + REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT galette_events_bookings_id_adh_fkey FOREIGN KEY (id_adh) + REFERENCES galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; -- -- Table structure for table `galette_events_activities` @@ -65,28 +68,32 @@ CREATE TABLE galette_events_activities ( creation_date date NOT NULL default '1901-01-01', comment text, PRIMARY KEY (id_activity) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; DROP TABLE IF EXISTS galette_events_activitiesevents; CREATE TABLE galette_events_activitiesevents ( id_event int(10) NOT NULL, id_activity int(10) NOT NULL, status tinyint(1) NOT NULL, - PRIMARY KEY(id_event,id_activity), - FOREIGN KEY (id_event) REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, - FOREIGN KEY (id_activity) REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + PRIMARY KEY (id_event, id_activity), + CONSTRAINT galette_events_activitiesevents_id_event_fkey FOREIGN KEY (id_event) + REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT galette_events_activitiesevents_id_activity_fkey FOREIGN KEY (id_activity) + REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; -DROP TABLE IF EXISTS galette_events_activitiesbookings CASCADE; +DROP TABLE IF EXISTS galette_events_activitiesbookings; CREATE TABLE galette_events_activitiesbookings ( id_activitybooking int(10) NOT NULL auto_increment, id_activity int(10) NOT NULL, id_booking int(10) NOT NULL, - checked tinyint(1) default 0, + checked tinyint(1) NOT NULL default 0, PRIMARY KEY (id_activitybooking), - UNIQUE KEY (id_activity, id_booking), - FOREIGN KEY (id_activity) REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE, - FOREIGN KEY (id_booking) REFERENCES galette_events_bookings (id_booking) ON DELETE CASCADE ON UPDATE CASCADE -); + UNIQUE KEY galette_events_activitiesbookings_id_activity_id_booking_key (id_activity, id_booking), + CONSTRAINT galette_events_activitiesbookings_id_activity_fkey FOREIGN KEY (id_activity) + REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT galette_events_activitiesbookings_id_booking_fkey FOREIGN KEY (id_booking) + REFERENCES galette_events_bookings (id_booking) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; SET FOREIGN_KEY_CHECKS=1; diff --git a/scripts/pgsql.sql b/scripts/pgsql.sql index 0d080798..7d3fc35c 100644 --- a/scripts/pgsql.sql +++ b/scripts/pgsql.sql @@ -23,7 +23,7 @@ CREATE TABLE galette_events_events ( begin_date date default '19010101' NOT NULL, end_date date default '19010101' NOT NULL, creation_date date default '19010101' NOT NULL, - is_open boolean default TRUE, + is_open boolean default TRUE NOT NULL, id_group integer REFERENCES galette_groups(id_group) ON DELETE RESTRICT ON UPDATE CASCADE default NULL, comment text, color character varying(7), @@ -45,11 +45,11 @@ CREATE SEQUENCE galette_events_bookings_id_seq DROP TABLE IF EXISTS galette_events_bookings CASCADE; CREATE TABLE galette_events_bookings ( id_booking integer DEFAULT nextval('galette_events_bookings_id_seq'::text) NOT NULL, - id_event integer REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, - id_adh integer REFERENCES galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE, + id_event integer NOT NULL REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, + id_adh integer NOT NULL REFERENCES galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE, booking_date date default '19010101' NOT NULL, - is_paid boolean default FALSE, - payment_amount real default '0', + is_paid boolean default FALSE NOT NULL, + payment_amount numeric(15,2) default '0', payment_method smallint default '0' NOT NULL, bank_name character varying(100) default NULL, check_number character varying(50) default NULL, @@ -76,7 +76,7 @@ DROP TABLE IF EXISTS galette_events_activities CASCADE; CREATE TABLE galette_events_activities ( id_activity integer DEFAULT nextval('galette_events_activities_id_seq'::text) NOT NULL, name character varying(150) NOT NULL, - is_active boolean default TRUE, + is_active boolean default TRUE NOT NULL, creation_date date default '19010101' NOT NULL, comment text, PRIMARY KEY (id_activity) @@ -101,9 +101,9 @@ CREATE SEQUENCE galette_events_activitiesbookings_id_seq DROP TABLE IF EXISTS galette_events_activitiesbookings CASCADE; CREATE TABLE galette_events_activitiesbookings ( id_activitybooking integer DEFAULT nextval('galette_events_activitiesbookings_id_seq'::text) NOT NULL, - id_activity integer REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE, - id_booking integer REFERENCES galette_events_bookings (id_booking) ON DELETE CASCADE ON UPDATE CASCADE, - checked boolean default FALSE, + id_activity integer NOT NULL REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE, + id_booking integer NOT NULL REFERENCES galette_events_bookings (id_booking) ON DELETE CASCADE ON UPDATE CASCADE, + checked boolean default FALSE NOT NULL, PRIMARY KEY (id_activitybooking), UNIQUE (id_activity, id_booking) ); diff --git a/scripts/upgrade-to-1.1-mysql.sql b/scripts/upgrade-to-1.1-mysql.sql new file mode 100644 index 00000000..a022f00c --- /dev/null +++ b/scripts/upgrade-to-1.1-mysql.sql @@ -0,0 +1,125 @@ +-- +-- This file is part of Galette Events plugin (https://galette.eu). +-- SPDX-FileCopyrightText: Copyright © 2018-2026 The Galette Team +-- SPDX-License-Identifier: GPL-3.0-or-later +-- + +-- Align schema with PostgreSQL one: utf8mb4, named foreign keys. +-- Foreign keys names depend on the MySQL version that created them, and +-- MySQL cannot drop them conditionally: tables holding some are rebuilt. +SET FOREIGN_KEY_CHECKS=0; + +ALTER TABLE galette_events_activities CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci; +-- Conversion turns text into mediumtext to keep its capacity in bytes +ALTER TABLE galette_events_activities MODIFY comment text; + +CREATE TABLE galette_events_events_new ( + id_event int(10) NOT NULL auto_increment, + name varchar(150) NOT NULL, + address varchar(150) NOT NULL default '', + zip varchar(10) NOT NULL default '', + town varchar(50) NOT NULL default '', + country varchar(50) default NULL, + begin_date date NOT NULL default '1901-01-01', + end_date date NOT NULL default '1901-01-01', + creation_date date NOT NULL default '1901-01-01', + is_open tinyint(1) NOT NULL default 1, + id_group int unsigned default NULL, + comment text, + color varchar(7), + PRIMARY KEY (id_event), + CONSTRAINT galette_events_events_id_group_fkey FOREIGN KEY (id_group) + REFERENCES galette_groups (id_group) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +INSERT INTO galette_events_events_new + (id_event, name, address, zip, town, country, begin_date, end_date, creation_date, + is_open, id_group, comment) +SELECT id_event, name, address, zip, town, country, begin_date, end_date, creation_date, + is_open, id_group, comment +FROM galette_events_events; + +-- Color came with 2.1.0, but its update script never ran: installations +-- created before do not have the column. +SET @events_color = ( + SELECT IF( + COUNT(*) > 0, + 'UPDATE galette_events_events_new n INNER JOIN galette_events_events o ON o.id_event = n.id_event SET n.color = o.color', + 'DO 0' + ) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'galette_events_events' AND COLUMN_NAME = 'color' +); +PREPARE events_color FROM @events_color; +EXECUTE events_color; +DEALLOCATE PREPARE events_color; + +CREATE TABLE galette_events_bookings_new ( + id_booking int(10) NOT NULL auto_increment, + id_event int(10) NOT NULL, + id_adh int(10) unsigned NOT NULL, + booking_date date NOT NULL default '1901-01-01', + is_paid tinyint(1) NOT NULL default 0, + payment_amount decimal(15,2) default '0', + payment_method tinyint(3) unsigned NOT NULL default '0', + bank_name varchar(100) default NULL, + check_number varchar(50) default NULL, + number_people int(4) default NULL, + creation_date date NOT NULL default '1901-01-01', + comment text, + PRIMARY KEY (id_booking), + UNIQUE KEY galette_events_bookings_id_event_id_adh_key (id_event, id_adh), + CONSTRAINT galette_events_bookings_id_event_fkey FOREIGN KEY (id_event) + REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT galette_events_bookings_id_adh_fkey FOREIGN KEY (id_adh) + REFERENCES galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +INSERT INTO galette_events_bookings_new + (id_booking, id_event, id_adh, booking_date, is_paid, payment_amount, payment_method, + bank_name, check_number, number_people, creation_date, comment) +SELECT id_booking, id_event, id_adh, booking_date, is_paid, payment_amount, payment_method, + bank_name, check_number, number_people, creation_date, comment +FROM galette_events_bookings; + +CREATE TABLE galette_events_activitiesevents_new ( + id_event int(10) NOT NULL, + id_activity int(10) NOT NULL, + status tinyint(1) NOT NULL, + PRIMARY KEY (id_event, id_activity), + CONSTRAINT galette_events_activitiesevents_id_event_fkey FOREIGN KEY (id_event) + REFERENCES galette_events_events (id_event) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT galette_events_activitiesevents_id_activity_fkey FOREIGN KEY (id_activity) + REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +INSERT INTO galette_events_activitiesevents_new (id_event, id_activity, status) +SELECT id_event, id_activity, status +FROM galette_events_activitiesevents; + +CREATE TABLE galette_events_activitiesbookings_new ( + id_activitybooking int(10) NOT NULL auto_increment, + id_activity int(10) NOT NULL, + id_booking int(10) NOT NULL, + checked tinyint(1) NOT NULL default 0, + PRIMARY KEY (id_activitybooking), + UNIQUE KEY galette_events_activitiesbookings_id_activity_id_booking_key (id_activity, id_booking), + CONSTRAINT galette_events_activitiesbookings_id_activity_fkey FOREIGN KEY (id_activity) + REFERENCES galette_events_activities (id_activity) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT galette_events_activitiesbookings_id_booking_fkey FOREIGN KEY (id_booking) + REFERENCES galette_events_bookings (id_booking) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci; + +INSERT INTO galette_events_activitiesbookings_new (id_activitybooking, id_activity, id_booking, checked) +SELECT id_activitybooking, id_activity, id_booking, COALESCE(checked, 0) +FROM galette_events_activitiesbookings; + +DROP TABLE galette_events_activitiesbookings, galette_events_activitiesevents, + galette_events_bookings, galette_events_events; + +RENAME TABLE galette_events_events_new TO galette_events_events, + galette_events_bookings_new TO galette_events_bookings, + galette_events_activitiesevents_new TO galette_events_activitiesevents, + galette_events_activitiesbookings_new TO galette_events_activitiesbookings; + +SET FOREIGN_KEY_CHECKS=1; diff --git a/scripts/upgrade-to-1.1-pgsql.sql b/scripts/upgrade-to-1.1-pgsql.sql new file mode 100644 index 00000000..22e9d80b --- /dev/null +++ b/scripts/upgrade-to-1.1-pgsql.sql @@ -0,0 +1,34 @@ +-- +-- This file is part of Galette Events plugin (https://galette.eu). +-- SPDX-FileCopyrightText: Copyright © 2018-2026 The Galette Team +-- SPDX-License-Identifier: GPL-3.0-or-later +-- + +-- Color came with 2.1.0, but its update script never ran: installations +-- created before do not have the column. +ALTER TABLE galette_events_events ADD COLUMN IF NOT EXISTS color character varying(7); + +-- Amounts were stored as floating point numbers +ALTER TABLE galette_events_bookings + ALTER COLUMN payment_amount TYPE numeric(15,2) USING ROUND(CAST(payment_amount AS numeric), 2), + ALTER COLUMN payment_amount SET DEFAULT '0'; + +-- A booking always has an event and a member, a booked activity an activity and a booking +DELETE FROM galette_events_bookings WHERE id_event IS NULL OR id_adh IS NULL; +DELETE FROM galette_events_activitiesbookings WHERE id_activity IS NULL OR id_booking IS NULL; +ALTER TABLE galette_events_bookings + ALTER COLUMN id_event SET NOT NULL, + ALTER COLUMN id_adh SET NOT NULL; +ALTER TABLE galette_events_activitiesbookings + ALTER COLUMN id_activity SET NOT NULL, + ALTER COLUMN id_booking SET NOT NULL; + +-- Flags are never unknown, as on MySQL +UPDATE galette_events_events SET is_open = TRUE WHERE is_open IS NULL; +ALTER TABLE galette_events_events ALTER COLUMN is_open SET NOT NULL; +UPDATE galette_events_bookings SET is_paid = FALSE WHERE is_paid IS NULL; +ALTER TABLE galette_events_bookings ALTER COLUMN is_paid SET NOT NULL; +UPDATE galette_events_activities SET is_active = TRUE WHERE is_active IS NULL; +ALTER TABLE galette_events_activities ALTER COLUMN is_active SET NOT NULL; +UPDATE galette_events_activitiesbookings SET checked = FALSE WHERE checked IS NULL; +ALTER TABLE galette_events_activitiesbookings ALTER COLUMN checked SET NOT NULL; diff --git a/scripts/upgrade-to-2.0-mysql.sql b/scripts/upgrade-to-2.0-mysql.sql deleted file mode 100644 index 4b6becac..00000000 --- a/scripts/upgrade-to-2.0-mysql.sql +++ /dev/null @@ -1,7 +0,0 @@ --- --- This file is part of Galette Events plugin (https://galette.eu). --- SPDX-FileCopyrightText: Copyright © 2018-2026 The Galette Team --- SPDX-License-Identifier: GPL-3.0-or-later --- - -ALTER TABLE galette_events_events ADD `color` varchar(7); diff --git a/scripts/upgrade-to-2.0-pgsql.sql b/scripts/upgrade-to-2.0-pgsql.sql deleted file mode 100644 index 2638d370..00000000 --- a/scripts/upgrade-to-2.0-pgsql.sql +++ /dev/null @@ -1,7 +0,0 @@ --- --- This file is part of Galette Events plugin (https://galette.eu). --- SPDX-FileCopyrightText: Copyright © 2018-2026 The Galette Team --- SPDX-License-Identifier: GPL-3.0-or-later --- - -ALTER TABLE galette_events_events ADD COLUMN color character varying(7); diff --git a/tests/GaletteEvents/tests/units/Activity.php b/tests/GaletteEvents/tests/units/Activity.php index 0d6eb03e..668aa59c 100644 --- a/tests/GaletteEvents/tests/units/Activity.php +++ b/tests/GaletteEvents/tests/units/Activity.php @@ -79,6 +79,8 @@ public function testCrud(): void $this->assertTrue($activity->store()); $first_id = $activity->getId(); $this->assertGreaterThan(0, $first_id); + //creation date column holds no time + $this->assertSame(date('Y-m-d'), $activity->getCreationDate(false)); $this->assertTrue($activity->load($first_id)); $this->assertSame('Test activity', $activity->getName()); diff --git a/tests/GaletteEvents/tests/units/PluginEventProvider.php b/tests/GaletteEvents/tests/units/PluginEventProvider.php new file mode 100644 index 00000000..f946cf77 --- /dev/null +++ b/tests/GaletteEvents/tests/units/PluginEventProvider.php @@ -0,0 +1,104 @@ + + */ +class PluginEventProvider extends GaletteRoutingTestCase +{ + use EventsFixtures; + + protected int $seed = 20260927101512; + protected bool $load_plugins = true; + + /** + * Cleanup after each test method + */ + public function tearDown(): void + { + $this->login->logout(); + $this->cleanEvents(); + parent::tearDown(); + } + + /** + * Remove a group from core route + * + * @param int $group_id Group ID + */ + private function removeGroup(int $group_id): void + { + $this->logSuperAdmin(); + $request = $this->createRequest('doRemoveGroup', ['id' => (string)$group_id], 'POST'); + $request = $request->withParsedBody(['id' => (string)$group_id, 'confirm' => true, 'cascade' => true]); + $response = $this->app->handle($request); + $this->login->logout(); + $this->assertSame(301, $response->getStatusCode()); + } + + /** + * Test a group holding events cannot be removed + */ + public function testGroupWithEventsIsNotRemoved(): void + { + global $zdb; + $zdb = $this->zdb; + + $group = $this->createGroup('Jedi'); + $group_id = $group->getId(); + $this->insertEvent('Council', ['id_group' => $group_id]); + $this->insertEvent('Training', ['id_group' => $group_id]); + $this->insertEvent('Public event'); + + $this->removeGroup($group_id); + $message = 'Group "Jedi" is used by 2 events, it cannot be deleted. Remove the events or change their group first.'; + $this->expectLogEntry(\Analog\Analog::WARNING, 'Group "Jedi" cannot be removed: ' . $message); + $this->expectFlashData(['error_detected' => [$message]]); + $this->assertTrue((new Group())->load($group_id)); + + //a subgroup holding an event prevents cascade removal of its parent + $parent = $this->createGroup('Order'); + $group->setParentGroup($parent->getId()); + $this->assertTrue($group->store()); + $this->zdb->execute( + $this->zdb->delete(EVENTS_PREFIX . \GaletteEvents\Event::TABLE)->where(['name' => 'Training']) + ); + + $this->removeGroup($parent->getId()); + $message = 'Group "Jedi" is used by 1 event, it cannot be deleted. Remove the event or change its group first.'; + $this->expectLogEntry(\Analog\Analog::WARNING, 'Group "Order" cannot be removed: ' . $message); + $this->expectFlashData(['error_detected' => [$message]]); + $this->assertTrue((new Group())->load($parent->getId())); + } + + /** + * Test a group without events is removed + */ + public function testGroupWithoutEventsIsRemoved(): void + { + global $zdb; + $zdb = $this->zdb; + + $group_id = $this->createGroup('Sith')->getId(); + $this->insertEvent('Public event'); + + $this->removeGroup($group_id); + $this->expectFlashData(['success_detected' => ['Successfully deleted!']]); + $this->assertFalse((new Group())->load($group_id)); + } +} diff --git a/tests/GaletteEvents/tests/units/PluginGaletteEvents.php b/tests/GaletteEvents/tests/units/PluginGaletteEvents.php index ed229455..67e2c03d 100644 --- a/tests/GaletteEvents/tests/units/PluginGaletteEvents.php +++ b/tests/GaletteEvents/tests/units/PluginGaletteEvents.php @@ -146,4 +146,12 @@ public function testIsInstalled(): void { $this->assertTrue($this->getPlugin()->isInstalled()); } + + /** + * Test tables installed from current scripts are not taken for legacy ones + */ + public function testGetLegacyDbVersion(): void + { + $this->assertNull($this->getPlugin()->getLegacyDbVersion()); + } }