From c0bbb1e2c46f797506881c92041fe5053f47e0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20Pl=C3=B6ger?= Date: Fri, 9 Jan 2026 15:10:57 +0100 Subject: [PATCH 1/5] added: Integrated iCal import and export features --- actions/event_manager/export/ical.php | 93 ++++ actions/event_manager/import/ical.php | 51 ++ .../ColdTrick/EventManager/Menus/Entity.php | 34 ++ .../ColdTrick/EventManager/Menus/Filter.php | 23 + classes/Event.php | 151 ++++++ composer.json | 3 +- composer.lock | 456 +++++------------- elgg-plugin.php | 17 + languages/de.php | 37 +- languages/en.php | 36 +- .../forms/event_manager/export/ical.mjs | 70 +++ .../forms/event_manager/export/ical.php | 143 ++++++ .../forms/event_manager/import/ical.mjs | 70 +++ .../forms/event_manager/import/ical.php | 87 ++++ .../plugins/event_manager/settings.php | 11 + views/default/resources/event/export/ical.php | 29 ++ views/default/resources/event/import/ical.php | 27 ++ views/ical/resources/event/export.php | 30 ++ 18 files changed, 1023 insertions(+), 345 deletions(-) create mode 100644 actions/event_manager/export/ical.php create mode 100644 actions/event_manager/import/ical.php create mode 100644 views/default/forms/event_manager/export/ical.mjs create mode 100644 views/default/forms/event_manager/export/ical.php create mode 100644 views/default/forms/event_manager/import/ical.mjs create mode 100644 views/default/forms/event_manager/import/ical.php create mode 100644 views/default/resources/event/export/ical.php create mode 100644 views/default/resources/event/import/ical.php create mode 100644 views/ical/resources/event/export.php diff --git a/actions/event_manager/export/ical.php b/actions/event_manager/export/ical.php new file mode 100644 index 0000000..17afcc1 --- /dev/null +++ b/actions/event_manager/export/ical.php @@ -0,0 +1,93 @@ +getTimestamp(); +} + +$end_date = get_input('end_date', ''); +if ($end_date == '') { + $end_date = DateTime::createFromFormat('U', time()) + ->add(DateInterval::createFromDateString('1 month')) + ->getTimestamp(); +} else { + $end_date = DateTime::createFromFormat($date_format, $end_date)->getTimestamp(); +} + +$region = get_input('region', ''); +$event_type = get_input('event_type', ''); + +$owner = get_input('owner', ''); +$group = get_input('group', ''); + +$options = [ + 'types' => ['object'], + 'subTypes' => [Event::SUBTYPE], + 'metadata_name_value_pairs' => [ + [ + 'name' => 'event_start', + 'operand' => '>=', + 'value' => $start_date, + ], + [ + 'name' => 'event_end', + 'operand' => '<=', + 'value' => $end_date, + ], + ] +]; + +if ($region != '') { + $options['metadata_name_value_pairs'][] = [ + 'name' => 'region', + 'operand' => 'IN', + 'value' => $region, + ]; +} + +if ($event_type != '') { + $options['metadata_name_value_pairs'][] = [ + 'name' => 'event_type', + 'operand' => 'IN', + 'value' => $event_type, + ]; +} + +switch ($calendar_type) { + case 'group': + $options['container_guids'] = [$group]; + break; + case 'owner': + $options['owner_guids'] = [$owner]; + break; +} + +$events = elgg_get_entities($options); + +use Kigkonsult\Icalcreator\Vcalendar; + +/** @noinspection PhpUnhandledExceptionInspection */ +/** @noinspection PhpClassConstantAccessedViaChildClassInspection */ +$vcalendar = Vcalendar::factory( + [ + Vcalendar::UNIQUE_ID => 'https://github.com/ColdTrick/event_manager', + ] +) + ->setMethod(Vcalendar::PUBLISH) + ->setXprop(Vcalendar::X_WR_CALNAME, 'Exported event') + ->setXprop(Vcalendar::X_WR_CALDESC, 'Exported events from event_manager') + ->setXprop(Vcalendar::X_WR_RELCALID, elgg_get_site_url()) + ->setXprop(Vcalendar::X_WR_TIMEZONE, date_default_timezone_get()); + +foreach ($events as $event) { + /** @noinspection PhpUnhandledExceptionInspection */ + $vcalendar->setComponent($event->toVEvent()); +} + +/** @noinspection PhpUnhandledExceptionInspection */ +return elgg_download_response($vcalendar->createCalendar(), 'export.ics'); diff --git a/actions/event_manager/import/ical.php b/actions/event_manager/import/ical.php new file mode 100644 index 0000000..db79bd8 --- /dev/null +++ b/actions/event_manager/import/ical.php @@ -0,0 +1,51 @@ + 'https://github.com/ColdTrick/event_manager', + ] +); +try { + $vcalendar->parse($file->getContent()); +} catch (Exception $e) { + return elgg_error_response('Error parsing calendar: ' . $e); +} + +$event_counter = 0; + +/** @var Vevent $component */ +foreach ($vcalendar->getComponents('Vevent') as $component) { + try { + $event = Event::fromVEvent($component); + + switch ($calendar_type) { + case 'group': + $event->setContainerGUID($group); + break; + case 'owner': + $event->owner_guid = $owner; + break; + } + + $event->save(); + $event_counter++; + } catch (Exception $e) { + return elgg_error_response( + elgg_echo('event_manager:ical_direct:import:failure', [$e]) + ); + } +} + +return elgg_ok_response( + '', + elgg_echo('event_manager:ical_direct:import:success', [$event_counter]) +); diff --git a/classes/ColdTrick/EventManager/Menus/Entity.php b/classes/ColdTrick/EventManager/Menus/Entity.php index 28085dd..58acfae 100644 --- a/classes/ColdTrick/EventManager/Menus/Entity.php +++ b/classes/ColdTrick/EventManager/Menus/Entity.php @@ -148,4 +148,38 @@ public static function registerEventUnsubscribe(\Elgg\Event $event): ?MenuItems return $result; } + + /** + * Adds menu items to the event entity menu for exporting it to ical + * + * @param \Elgg\Event $event 'register', 'menu:entity' + * + * @return null|MenuItems + */ + public static function registerICalExport(\Elgg\Event $event): ?MenuItems { + $entity = $event->getEntityParam(); + if (!$entity instanceof \Event) { + return null; + } + + if (!elgg_get_plugin_setting('ical_direct', 'event_manager')) { + return null; + } + + // show an ical export link + $result = $event->getValue(); + + $result[] = \ElggMenuItem::factory([ + 'name' => 'ical-export', + 'icon' => 'calendar-plus', + 'text' => elgg_echo('event_manager:ical_direct:export'), + 'href' => elgg_generate_url('default:object:event:export', [ + 'guid' => $entity->guid, + 'view' => 'ical' + ]), + 'priority' => 300, + ]); + + return $result; + } } diff --git a/classes/ColdTrick/EventManager/Menus/Filter.php b/classes/ColdTrick/EventManager/Menus/Filter.php index bc78ce2..6514467 100644 --- a/classes/ColdTrick/EventManager/Menus/Filter.php +++ b/classes/ColdTrick/EventManager/Menus/Filter.php @@ -75,6 +75,29 @@ public static function registerEventsList(\Elgg\Event $event): MenuItems { 'priority' => 400, ]); } + + if (elgg_get_plugin_setting('ical_direct', 'event_manager')) { + $result[] = \ElggMenuItem::factory([ + 'name' => 'export-ical', + 'text' => elgg_echo('event_manager:ical_direct:export'), + 'href' => elgg_http_add_url_query_elements(elgg_generate_url('collection:ical:export'), [ + 'list_route' => elgg_get_current_route_name(), + 'route_parameters' => elgg_get_current_route()->getMatchedParameters(), + ]), + 'priority' => 500, + 'selected' => $selected === 'export-ical', + ]); + $result[] = \ElggMenuItem::factory([ + 'name' => 'import-ical', + 'text' => elgg_echo('event_manager:ical_direct:import'), + 'href' => elgg_http_add_url_query_elements(elgg_generate_url('collection:ical:import'), [ + 'list_route' => elgg_get_current_route_name(), + 'route_parameters' => elgg_get_current_route()->getMatchedParameters(), + ]), + 'priority' => 500, + 'selected' => $selected === 'import-ical', + ]); + } return $result; } diff --git a/classes/Event.php b/classes/Event.php index c9b665e..655d201 100644 --- a/classes/Event.php +++ b/classes/Event.php @@ -1,9 +1,11 @@ 'user', // trigger search fields generation + 'type_subtype_pairs' => [ + 'user' => ELGG_ENTITIES_ANY_VALUE, + 'object' => [ + EventRegistration::SUBTYPE, + ], + ], + 'relationship_guid' => $this->guid, + 'relationship' => 'event_attending', + 'no_results' => true, + 'order_by' => new OrderByClause('r.time_created', 'DESC'), + ]; + return elgg_get_entities($options); + } + /** * Counts the waiters * @@ -1159,4 +1185,129 @@ public function getOrganizers(array $options = []): int|array { return elgg_get_entities($options); } + + /** + * Returns the VEvent representation of this event. + * + * @return Vevent + * @throws Exception + */ + public function toVEvent(): Vevent { + $timezone = \Kigkonsult\Icalcreator\Util\DateTimeZoneFactory::factory(date_default_timezone_get()); + $dtstart = DateTimeImmutable::createFromFormat('Y-m-d\\TH:i:s', $this->getStartDate('Y-m-d\\TH:i:s'), $timezone); + $dtend = DateTimeImmutable::createFromFormat('Y-m-d\\TH:i:s', $this->getEndDate('Y-m-d\\TH:i:s'), $timezone); + /** @noinspection PhpUnhandledExceptionInspection */ + $vevent = Vevent::factory( + null, + $dtstart, + $dtend, + null, + $this->title + ) + ->setDescription($this->shortdescription) + ->setDtstamp(DateTimeImmutable::createFromFormat('c', $this->getTimeCreated())) + ->setComment($this->description) + ->setLocation($this->location); + + $organizers = $this->getOrganizers(); + if (count($organizers) > 0 && isset($organizers[0]->email)) { + $vevent->setOrganizer($organizers[0]->email); + } + + if ($this->countAttendees() > 0) { + foreach ($this->getAttendees() as $attendee) { + $vevent->setAttendee($attendee->email); + } + } + + foreach ($this->getContacts() as $contact) { + if ($contact instanceof ElggUser && isset($contact->email)) { + $vevent->setContact($contact->email); + } + } + + if ($this->website) { + $vevent->setXprop('X-WEBSITE', $this->website); + } + + if ($this->region) { + $vevent->setXprop('X-PROP-REGION', $this->region); + } + + if ($this->venue) { + $vevent->setXprop('X-PROP-VENUE', $this->venue); + } + + if ($this->event_type) { + $vevent->setXprop('X-PROP-TYPE', $this->event_type); + } + + return $vevent; + } + + /** + * Generates a new event based on an iCal Vevent + * + * @param Vevent $vevent Source iCal Vevent to convert + * @return Event + * @throws Exception + */ + public static function fromVEvent(Vevent $vevent): Event { + $event = new Event(); + $event->event_start = $vevent->getDtstart()->getTimestamp() + $vevent->getDtstart()->getOffset(); + $event->event_end = $vevent->getDtend()->getTimestamp() + $vevent->getDtend()->getOffset(); + $event->title = $vevent->getSummary(); + $event->shortdescription = $vevent->getDescription(); + $event->description = $vevent->getComment(); + $event->location = $vevent->getLocation(); + + if ($vevent->isOrganizerSet()) { + $organizer = elgg_get_user_by_email($vevent->getOrganizer()); + if (is_null($organizer)) { + $event->organizer = $vevent->getOrganizer(); + } else { + $event->organizer_guids = [$organizer->guid]; + } + } + + if ($vevent->isAttendeeSet()) { + foreach ($vevent->getAllAttendee() as $attendee) { + $attendee_object = elgg_get_user_by_email($attendee); + if (!is_null($attendee_object)) { + $event->addRelationship($attendee_object->guid, 'event_attending'); + } + } + } + + if ($vevent->isContactSet()) { + foreach ($vevent->getAllContact() as $contact) { + $contact_object = elgg_get_user_by_email($contact); + if (!is_null($contact_object)) { + if (!is_array($event->contact_guids)) { + $event->contact_guids = []; + } + + $event->contact_guids[] = $contact_object->guid; + } + } + } + + if ($vevent->isXpropSet('X-WEBSITE')) { + $event->website = $vevent->getXprop('X-WEBSITE')[1]; + } + + if ($vevent->isXpropSet('X-PROP-REGION')) { + $event->region = $vevent->getXprop('X-PROP-REGION')[1]; + } + + if ($vevent->isXpropSet('X-PROP-VENUE')) { + $event->venue = $vevent->getXprop('X-PROP-VENUE')[1]; + } + + if ($vevent->isXpropSet('X-PROP-TYPE')) { + $event->event_type = $vevent->getXprop('X-PROP-TYPE')[1]; + } + + return $event; + } } diff --git a/composer.json b/composer.json index fcff4d5..f3f0c71 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ }, "require": { "dompdf/dompdf" : "~3.1.0", - "npm-asset/fullcalendar": "~6.1.0" + "npm-asset/fullcalendar": "~6.1.0", + "kigkonsult/icalcreator": "~2.41" }, "repositories": [ { diff --git a/composer.lock b/composer.lock index 127dec0..0060804 100644 --- a/composer.lock +++ b/composer.lock @@ -4,256 +4,160 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ed4a108af4e355cd8ac3748f5131e037", + "content-hash": "4125385fe420528e33bde0d77594307b", "packages": [ { - "name": "dompdf/dompdf", - "version": "v3.1.0", + "name": "composer/installers", + "version": "v2.3.0", "source": { "type": "git", - "url": "https://github.com/dompdf/dompdf.git", - "reference": "a51bd7a063a65499446919286fb18b518177155a" + "url": "https://github.com/composer/installers.git", + "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a", - "reference": "a51bd7a063a65499446919286fb18b518177155a", + "url": "https://api.github.com/repos/composer/installers/zipball/12fb2dfe5e16183de69e784a7b84046c43d97e8e", + "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e", "shasum": "" }, "require": { - "dompdf/php-font-lib": "^1.0.0", - "dompdf/php-svg-lib": "^1.0.0", - "ext-dom": "*", - "ext-mbstring": "*", - "masterminds/html5": "^2.0", - "php": "^7.1 || ^8.0" + "composer-plugin-api": "^1.0 || ^2.0", + "php": "^7.2 || ^8.0" }, "require-dev": { - "ext-gd": "*", - "ext-json": "*", - "ext-zip": "*", - "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", - "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" - }, - "suggest": { - "ext-gd": "Needed to process images", - "ext-gmagick": "Improves image processing performance", - "ext-imagick": "Improves image processing performance", - "ext-zlib": "Needed for pdf stream compression" - }, - "type": "library", - "autoload": { - "psr-4": { - "Dompdf\\": "src/" + "composer/composer": "^1.10.27 || ^2.7", + "composer/semver": "^1.7.2 || ^3.4.0", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-phpunit": "^1", + "symfony/phpunit-bridge": "^7.1.1", + "symfony/process": "^5 || ^6 || ^7" + }, + "type": "composer-plugin", + "extra": { + "class": "Composer\\Installers\\Plugin", + "branch-alias": { + "dev-main": "2.x-dev" }, - "classmap": [ - "lib/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1" - ], - "authors": [ - { - "name": "The Dompdf Community", - "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" - } - ], - "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", - "homepage": "https://github.com/dompdf/dompdf", - "support": { - "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v3.1.0" - }, - "time": "2025-01-15T14:09:04+00:00" - }, - { - "name": "dompdf/php-font-lib", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", - "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0" + "plugin-modifies-install-path": true }, - "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" - }, - "type": "library", "autoload": { "psr-4": { - "FontLib\\": "src/FontLib" + "Composer\\Installers\\": "src/Composer/Installers" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-2.1-or-later" + "MIT" ], "authors": [ { - "name": "The FontLib Community", - "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/dompdf/php-font-lib", - "support": { - "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/1.0.1" - }, - "time": "2024-12-02T14:37:59+00:00" - }, - { - "name": "dompdf/php-svg-lib", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af", - "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0", - "sabberworm/php-css-parser": "^8.4" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Svg\\": "src/Svg" + "name": "Kyle Robinson Young", + "email": "kyle@dontkry.com", + "homepage": "https://github.com/shama" } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" ], - "authors": [ - { - "name": "The SvgLib Community", - "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" - } + "description": "A multi-framework Composer library installer", + "homepage": "https://composer.github.io/installers/", + "keywords": [ + "Dolibarr", + "Eliasis", + "Hurad", + "ImageCMS", + "Kanboard", + "Lan Management System", + "MODX Evo", + "MantisBT", + "Mautic", + "Maya", + "OXID", + "Plentymarkets", + "Porto", + "RadPHP", + "SMF", + "Starbug", + "Thelia", + "Whmcs", + "WolfCMS", + "agl", + "annotatecms", + "attogram", + "bitrix", + "cakephp", + "chef", + "cockpit", + "codeigniter", + "concrete5", + "concreteCMS", + "croogo", + "dokuwiki", + "drupal", + "eZ Platform", + "elgg", + "expressionengine", + "fuelphp", + "grav", + "installer", + "itop", + "known", + "kohana", + "laravel", + "lavalite", + "lithium", + "magento", + "majima", + "mako", + "matomo", + "mediawiki", + "miaoxing", + "modulework", + "modx", + "moodle", + "osclass", + "pantheon", + "phpbb", + "piwik", + "ppi", + "processwire", + "puppet", + "pxcms", + "reindex", + "roundcube", + "shopware", + "silverstripe", + "sydes", + "sylius", + "tastyigniter", + "wordpress", + "yawik", + "zend", + "zikula" ], - "description": "A library to read, parse and export to PDF SVG files.", - "homepage": "https://github.com/dompdf/php-svg-lib", "support": { - "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0" - }, - "time": "2024-04-29T13:26:35+00:00" - }, - { - "name": "masterminds/html5", - "version": "2.10.0", - "source": { - "type": "git", - "url": "https://github.com/Masterminds/html5-php.git", - "reference": "fcf91eb64359852f00d921887b219479b4f21251" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", - "reference": "fcf91eb64359852f00d921887b219479b4f21251", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Masterminds\\": "src" - } + "issues": "https://github.com/composer/installers/issues", + "source": "https://github.com/composer/installers/tree/v2.3.0" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "funding": [ { - "name": "Matt Butcher", - "email": "technosophos@gmail.com" + "url": "https://packagist.com", + "type": "custom" }, { - "name": "Matt Farina", - "email": "matt@mattfarina.com" + "url": "https://github.com/composer", + "type": "github" }, { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" } ], - "description": "An HTML5 parser and serializer.", - "homepage": "http://masterminds.github.io/html5-php", - "keywords": [ - "HTML5", - "dom", - "html", - "parser", - "querypath", - "serializer", - "xml" - ], - "support": { - "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" - }, - "time": "2025-07-25T09:04:22+00:00" - }, - { - "name": "npm-asset/fullcalendar", - "version": "6.1.18", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-6.1.18.tgz" - }, - "require": { - "npm-asset/fullcalendar--core": "~6.1.18", - "npm-asset/fullcalendar--daygrid": "~6.1.18", - "npm-asset/fullcalendar--interaction": "~6.1.18", - "npm-asset/fullcalendar--list": "~6.1.18", - "npm-asset/fullcalendar--multimonth": "~6.1.18", - "npm-asset/fullcalendar--timegrid": "~6.1.18" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] + "time": "2024-06-24T20:46:46+00:00" }, { "name": "npm-asset/fullcalendar--core", - "version": "6.1.19", + "version": "6.1.20", "dist": { "type": "tar", - "url": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.19.tgz" + "url": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.20.tgz" }, "require": { "npm-asset/preact": "~10.12.1" @@ -263,72 +167,6 @@ "MIT" ] }, - { - "name": "npm-asset/fullcalendar--daygrid", - "version": "6.1.18", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.18.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, - { - "name": "npm-asset/fullcalendar--interaction", - "version": "6.1.18", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.18.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, - { - "name": "npm-asset/fullcalendar--list", - "version": "6.1.18", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.18.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, - { - "name": "npm-asset/fullcalendar--multimonth", - "version": "6.1.18", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.18.tgz" - }, - "require": { - "npm-asset/fullcalendar--daygrid": "~6.1.18" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, - { - "name": "npm-asset/fullcalendar--timegrid", - "version": "6.1.18", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.18.tgz" - }, - "require": { - "npm-asset/fullcalendar--daygrid": "~6.1.18" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, { "name": "npm-asset/preact", "version": "10.12.1", @@ -340,72 +178,6 @@ "license": [ "MIT" ] - }, - { - "name": "sabberworm/php-css-parser", - "version": "v8.9.0", - "source": { - "type": "git", - "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9", - "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" - }, - "require-dev": { - "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41", - "rawr/cross-data-providers": "^2.0.0" - }, - "suggest": { - "ext-mbstring": "for parsing UTF-8 CSS" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Sabberworm\\CSS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Raphael Schweikert" - }, - { - "name": "Oliver Klee", - "email": "github@oliverklee.de" - }, - { - "name": "Jake Hotson", - "email": "jake.github@qzdesign.co.uk" - } - ], - "description": "Parser for CSS Files written in PHP", - "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", - "keywords": [ - "css", - "parser", - "stylesheet" - ], - "support": { - "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0" - }, - "time": "2025-07-11T13:20:48+00:00" } ], "packages-dev": [], diff --git a/elgg-plugin.php b/elgg-plugin.php index 6cf9c67..a65397c 100644 --- a/elgg-plugin.php +++ b/elgg-plugin.php @@ -35,6 +35,7 @@ 'show_service_outlookcom' => 1, 'show_service_outlook' => 1, 'show_service_appleical' => 1, + 'ical_direct' => 1, ], 'entities' => [ [ @@ -168,6 +169,10 @@ 'path' => '/event/unsubscribe/request/{guid}', 'resource' => 'event/unsubscribe/request', ], + 'default:object:event:export' => [ + 'path' => '/event/export/{guid}', + 'resource' => 'event/export', + ], 'default:object:event:register' => [ 'path' => '/event/register/{guid}/{relation?}', 'resource' => 'event/register', @@ -225,6 +230,14 @@ 'path' => '/event', 'resource' => 'event/upcoming', ], + 'collection:ical:export' => [ + 'path' => '/event/export/ical', + 'resource' => 'event/export/ical', + ], + 'collection:ical:import' => [ + 'path' => '/event/import/ical', + 'resource' => 'event/import/ical', + ], 'default:event_manager:calendar' => [ 'path' => '/event_manager/calendar', 'controller' => \ColdTrick\EventManager\Controllers\Calendar::class, @@ -258,6 +271,9 @@ 'event_manager/day/edit' => [], 'event_manager/delete_program_item' => [], + + 'event_manager/export/ical' => [], + 'event_manager/import/ical' => [], ], 'widgets' => [ 'events' => [ @@ -338,6 +354,7 @@ '\ColdTrick\EventManager\Menus\Entity::registerAttendeeActions' => [], '\ColdTrick\EventManager\Menus\Entity::registerEventUnsubscribe' => ['priority' => 600], '\ColdTrick\EventManager\Menus\Entity::registerMailAttendees' => [], + '\ColdTrick\EventManager\Menus\Entity::registerICalExport' => [], ], 'menu:event_files' => [ '\ColdTrick\EventManager\Menus\EventFiles::registerFiles' => [], diff --git a/languages/de.php b/languages/de.php index c42dbaf..e4423dc 100644 --- a/languages/de.php +++ b/languages/de.php @@ -34,7 +34,7 @@ 'event_manager:personwaitinglist' => 'Personen auf der Warteliste', 'event_manager:peoplewaitinglist' => 'Personen auf der Warteliste', 'event_manager:registration:view:savetopdf' => 'als PDF speichern', - 'event_manager:edit:title' => ' erstelle / bearbeite Veranstaltung', + 'event_manager:edit:title' => 'Veranstaltung bearbeiten', 'event_manager:edit:upload:title' => 'Datei(en) zu deiner Veranstaltung hinzufügen', 'event_manager:edit:form:tabs:profile' => 'Profile', 'event_manager:edit:form:tabs:profile:toggle' => 'Hier können Sie weitere Veranstaltungs-Details konfigurieren', @@ -301,4 +301,39 @@ 'event_manager:addevent:mail:service:outlook' => 'Outlook', 'event_manager:addevent:mail:service:outlookcom' => 'Outlook.com', 'event_manager:addevent:mail:service:yahoo' => 'Yahoo', + + 'event_manager:settings:ical_direct' => 'Integriertes iCal', + 'event_manager:settings:ical_direct:enable' => 'Die internen iCal-Features aktivieren', + 'event_manager:settings:ical_direct:enable:help' => 'Die integrierten iCal-Features für Export und Import aktivieren', + 'event_manager:ical_direct:export' => 'iCal-Export', + 'event_manager:ical_direct:export:calendar_type' => 'Kalender', + 'event_manager:ical_direct:export:calendar_type:help' => 'Wöhle den zu exportierenden Kalender aus', + 'event_manager:ical_direct:calendar_type:all' => 'Alle', + 'event_manager:ical_direct:calendar_type:group' => 'Gruppe', + 'event_manager:ical_direct:calendar_type:owner' => 'Benutzer*in', + 'event_manager:ical_direct:export:owner' => 'Benutzer*in', + 'event_manager:ical_direct:export:owner:help' => 'Wähle die Benutzer*in aus, deren Kalender exportiert werden soll', + 'event_manager:ical_direct:export:group' => 'Guppe', + 'event_manager:ical_direct:export:group:help' => 'Wähle die Gruppe aus, deren Kalender exportiert werden soll', + 'event_manager:ical_direct:export:timespan' => 'Zeitbereich für den Export', + 'event_manager:ical_direct:export:start' => 'Startdatum', + 'event_manager:ical_direct:export:end' => 'Enddatum', + 'event_manager:ical_direct:export:region' => 'Region', + 'event_manager:ical_direct:export:region:help' => 'Wähle eine oder mehr Regionen aus, um nach diesen zu filtern', + 'event_manager:ical_direct:export:type' => 'Typ', + 'event_manager:ical_direct:export:type:help' => 'Wähle einen oder mehrere Eventtypen aus, um nach diesen zu filtern', + 'event_manager:ical_direct:export:submit' => 'Exportieren', + + 'event_manager:ical_direct:import' => 'iCal importieren', + 'event_manager:ical_direct:import:calendar_type' => 'Kalender', + 'event_manager:ical_direct:import:calendar_type:help' => 'Wähle den Zielkalender für den Import', + 'event_manager:ical_direct:import:owner' => 'Benutzer*in', + 'event_manager:ical_direct:import:owner:help' => 'Wähle die Benutzer*in in deren Kalender die Datei importiert wird', + 'event_manager:ical_direct:import:group' => 'Gruppe', + 'event_manager:ical_direct:import:group:help' => 'Wähle die Gruppe in deren Kalender die Datei importiert wird', + 'event_manager:ical_direct:import:file' => 'Import-Datei', + 'event_manager:ical_direct:import:file:help' => 'ICS-Datei für den Import', + 'event_manager:ical_direct:import:submit' => 'Importieren', + 'event_manager:ical_direct:import:success' => '%d Einträge erfolgreich importiert', + 'event_manager:ical_direct:import:failure' => 'Konnte Datei nicht importieren: %s', ); diff --git a/languages/en.php b/languages/en.php index 79dc411..a87b2fa 100644 --- a/languages/en.php +++ b/languages/en.php @@ -452,5 +452,39 @@ 'event_manager:upgrade:2023030700:title' => "Move event header images to new image location", 'event_manager:upgrade:2023030700:description' => "In Elgg 5 there is built in header image support. This migration moves old icons uploaded with events to this new location.", - + 'event_manager:settings:ical_direct' => 'Embedded iCal', + 'event_manager:settings:ical_direct:enable' => 'Enable embedded iCal features', + 'event_manager:settings:ical_direct:enable:help' => 'Enable the embeded iCal-features for export and import', + 'event_manager:ical_direct:export' => 'Export to iCal', + 'event_manager:ical_direct:export:calendar_type' => 'Calendar', + 'event_manager:ical_direct:export:calendar_type:help' => 'Select the calendar to export', + 'event_manager:ical_direct:calendar_type:all' => 'All', + 'event_manager:ical_direct:calendar_type:group' => 'Group', + 'event_manager:ical_direct:calendar_type:owner' => 'User', + 'event_manager:ical_direct:export:owner' => 'User', + 'event_manager:ical_direct:export:owner:help' => 'Select the user whose calendar will be exported', + 'event_manager:ical_direct:export:group' => 'Group', + 'event_manager:ical_direct:export:group:help' => 'Select the group which calendar will be exported', + 'event_manager:ical_direct:export:timespan' => 'Export timespan', + 'event_manager:ical_direct:export:start' => 'Start date', + 'event_manager:ical_direct:export:end' => 'End date', + 'event_manager:ical_direct:export:region' => 'Region', + 'event_manager:ical_direct:export:region:help' => 'Select one or more regions to filter for', + 'event_manager:ical_direct:export:type' => 'Type', + 'event_manager:ical_direct:export:type:help' => 'Select one or more event types to filter for', + 'event_manager:ical_direct:export:submit' => 'Export', + + 'event_manager:ical_direct:import' => 'Import iCal', + 'event_manager:ical_direct:import:calendar_type' => 'Calendar', + 'event_manager:ical_direct:import:calendar_type:help' => 'Select the calendar to import into', + 'event_manager:ical_direct:import:owner' => 'User', + 'event_manager:ical_direct:import:owner:help' => 'Select the user whose calendar will be used for the import', + 'event_manager:ical_direct:import:group' => 'Group', + 'event_manager:ical_direct:import:group:help' => 'Select the group which calendar will be user for the import', + 'event_manager:ical_direct:import:file' => 'Import file', + 'event_manager:ical_direct:import:file:help' => 'ICS file to import', + 'event_manager:ical_direct:import:submit' => 'Import', + 'event_manager:ical_direct:import:success' => 'Successfully imported %d entries', + 'event_manager:ical_direct:import:failure' => 'Could not import calendar file: %s', + ); diff --git a/views/default/forms/event_manager/export/ical.mjs b/views/default/forms/event_manager/export/ical.mjs new file mode 100644 index 0000000..9510c3d --- /dev/null +++ b/views/default/forms/event_manager/export/ical.mjs @@ -0,0 +1,70 @@ +import 'jquery'; + +var calendar_type_selector = 'select[name="calendar_type"]'; + +/** + * Toggle owner input visibility based on the value + * of the calendar type selector + * + * @param {jQuery} $calendar_type Select object + * @returns {void} + */ +function toggleOwner($calendar_type) { + var $form = $calendar_type.closest('form'); + if (!$form.length) { + return; + } + + if ($calendar_type[0].value === "owner") { + $('[name="owner"]', $form).each(function() { + $(this).prop('required', true); + $(this).closest('.elgg-field').removeClass('hidden'); + }); + + } else { + $('[name="owner"]', $form).each(function() { + $(this).prop('required', false); + $(this).closest('.elgg-field').addClass('hidden'); + }); + } +} + +$(document).on('change', calendar_type_selector, function() { + toggleOwner($(this)); +}); + +toggleOwner($(calendar_type_selector)); + + +/** + * Toggle group input visibility based on the value + * of the calendar type selector + * + * @param {jQuery} $calendar_type Select object + * @returns {void} + */ +function toggleGroup($calendar_type) { + var $form = $calendar_type.closest('form'); + if (!$form.length) { + return; + } + + if ($calendar_type[0].value === "group") { + $('[name="group"]', $form).each(function() { + $(this).prop('required', true); + $(this).closest('.elgg-field').removeClass('hidden'); + }); + + } else { + $('[name="group"]', $form).each(function() { + $(this).prop('required', false); + $(this).closest('.elgg-field').addClass('hidden'); + }); + } +} + +$(document).on('change', calendar_type_selector, function() { + toggleGroup($(this)); +}); + +toggleGroup($(calendar_type_selector)); diff --git a/views/default/forms/event_manager/export/ical.php b/views/default/forms/event_manager/export/ical.php new file mode 100644 index 0000000..99559cd --- /dev/null +++ b/views/default/forms/event_manager/export/ical.php @@ -0,0 +1,143 @@ + [ + 'text' => elgg_echo('event_manager:ical_direct:calendar_type:all'), + 'selected' => $calendar_type_selected == 'all', + 'value' => 'all', + ], + 'group' => [ + 'text' => elgg_echo('event_manager:ical_direct:calendar_type:group'), + 'selected' => $calendar_type_selected == 'group', + 'value' => 'group', + ], + 'owner' => [ + 'text' => elgg_echo('event_manager:ical_direct:calendar_type:owner'), + 'selected' => $calendar_type_selected == 'owner', + 'value' => 'owner', + ], +]; + +echo elgg_view_field([ + '#type' => 'select', + '#label' => elgg_echo('event_manager:ical_direct:export:calendar_type'), + '#help' => elgg_echo('event_manager:ical_direct:export:calendar_type:help'), + 'required' => true, + 'name' => 'calendar_type', + 'options_values' => $calendar_type_options, +]); + +$owner = ''; + +if (array_key_exists('username', $route_parameters)) { + $owner = elgg_get_user_by_username($route_parameters['username'])->getGUID(); +} + +echo elgg_view_field([ + '#type' => 'userpicker', + '#label' => elgg_echo('event_manager:ical_direct:export:owner'), + '#help' => elgg_echo('event_manager:ical_direct:export:owner:help'), + 'required' => true, + 'name' => 'owner', + 'limit' => 1, + 'values' => [$owner], +]); + + +$group = ''; + +if (array_key_exists('guid', $route_parameters)) { + $group = $route_parameters['guid']; +} + +echo elgg_view_field([ + '#type' => 'grouppicker', + '#label' => elgg_echo('event_manager:ical_direct:export:group'), + '#help' => elgg_echo('event_manager:ical_direct:export:group:help'), + 'required' => true, + 'name' => 'group', + 'limit' => 1, + 'values' => [$group], +]); + +// Filter timespan + +echo elgg_view_field([ + '#type' => 'fieldset', + 'legend' => elgg_echo('event_manager:ical_direct:export:timespan'), + 'fields' => [ + [ + '#type' => 'date', + '#label' => elgg_echo('event_manager:ical_direct:export:start'), + 'required' => true, + 'name' => 'start_date', + 'value' => time(), + ], + [ + '#type' => 'date', + '#label' => elgg_echo('event_manager:ical_direct:export:end'), + 'required' => true, + 'name' => 'end_date', + 'value' => DateTime::createFromFormat('U', time())->add(DateInterval::createFromDateString('1 month'))->getTimestamp() + ] + ] +]); + +// Filter region + +$region_settings = trim((string) elgg_get_plugin_setting('region_list', 'event_manager')); +$region_list = explode(',', $region_settings); +$region_options = array_reduce($region_list, function ($options, $value){ + $options[$value] = [ + 'text' => $value + ]; + return $options; +}, []); +echo elgg_view_field([ + '#type' => 'select', + '#label' => elgg_echo('event_manager:ical_direct:export:region'), + '#help' => elgg_echo('event_manager:ical_direct:export:region:help'), + 'required' => false, + 'multiple' => true, + 'name' => 'region', + 'options_values' => $region_options, +]); + +// Filter type + +$type_settings = trim((string) elgg_get_plugin_setting('type_list', 'event_manager')); +$type_list = explode(',', $type_settings); +$type_options = array_reduce($type_list, function ($options, $value){ + $options[$value] = [ + 'text' => $value + ]; + return $options; +}, []); +echo elgg_view_field([ + '#type' => 'select', + '#label' => elgg_echo('event_manager:ical_direct:export:type'), + '#help' => elgg_echo('event_manager:ical_direct:export:type:help'), + 'required' => false, + 'multiple' => true, + 'name' => 'event_type', + 'options_values' => $type_options, +]); + +elgg_set_form_footer( + elgg_view_field([ + '#type' => 'submit', + 'text' => elgg_echo('event_manager:ical_direct:export:submit'), + ]) +); diff --git a/views/default/forms/event_manager/import/ical.mjs b/views/default/forms/event_manager/import/ical.mjs new file mode 100644 index 0000000..9510c3d --- /dev/null +++ b/views/default/forms/event_manager/import/ical.mjs @@ -0,0 +1,70 @@ +import 'jquery'; + +var calendar_type_selector = 'select[name="calendar_type"]'; + +/** + * Toggle owner input visibility based on the value + * of the calendar type selector + * + * @param {jQuery} $calendar_type Select object + * @returns {void} + */ +function toggleOwner($calendar_type) { + var $form = $calendar_type.closest('form'); + if (!$form.length) { + return; + } + + if ($calendar_type[0].value === "owner") { + $('[name="owner"]', $form).each(function() { + $(this).prop('required', true); + $(this).closest('.elgg-field').removeClass('hidden'); + }); + + } else { + $('[name="owner"]', $form).each(function() { + $(this).prop('required', false); + $(this).closest('.elgg-field').addClass('hidden'); + }); + } +} + +$(document).on('change', calendar_type_selector, function() { + toggleOwner($(this)); +}); + +toggleOwner($(calendar_type_selector)); + + +/** + * Toggle group input visibility based on the value + * of the calendar type selector + * + * @param {jQuery} $calendar_type Select object + * @returns {void} + */ +function toggleGroup($calendar_type) { + var $form = $calendar_type.closest('form'); + if (!$form.length) { + return; + } + + if ($calendar_type[0].value === "group") { + $('[name="group"]', $form).each(function() { + $(this).prop('required', true); + $(this).closest('.elgg-field').removeClass('hidden'); + }); + + } else { + $('[name="group"]', $form).each(function() { + $(this).prop('required', false); + $(this).closest('.elgg-field').addClass('hidden'); + }); + } +} + +$(document).on('change', calendar_type_selector, function() { + toggleGroup($(this)); +}); + +toggleGroup($(calendar_type_selector)); diff --git a/views/default/forms/event_manager/import/ical.php b/views/default/forms/event_manager/import/ical.php new file mode 100644 index 0000000..37c9a89 --- /dev/null +++ b/views/default/forms/event_manager/import/ical.php @@ -0,0 +1,87 @@ + [ + 'text' => elgg_echo('event_manager:ical_direct:calendar_type:all'), + 'selected' => $calendar_type_selected == 'all', + 'value' => 'all', + ], + 'group' => [ + 'text' => elgg_echo('event_manager:ical_direct:calendar_type:group'), + 'selected' => $calendar_type_selected == 'group', + 'value' => 'group', + ], + 'owner' => [ + 'text' => elgg_echo('event_manager:ical_direct:calendar_type:owner'), + 'selected' => $calendar_type_selected == 'owner', + 'value' => 'owner', + ], +]; + +echo elgg_view_field([ + '#type' => 'select', + '#label' => elgg_echo('event_manager:ical_direct:import:calendar_type'), + '#help' => elgg_echo('event_manager:ical_direct:import:calendar_type:help'), + 'required' => true, + 'name' => 'calendar_type', + 'options_values' => $calendar_type_options, +]); + +$owner = ''; + +if (array_key_exists('username', $route_parameters)) { + $owner = elgg_get_user_by_username($route_parameters['username'])->getGUID(); +} + +echo elgg_view_field([ + '#type' => 'userpicker', + '#label' => elgg_echo('event_manager:ical_direct:import:owner'), + '#help' => elgg_echo('event_manager:ical_direct:import:owner:help'), + 'required' => true, + 'name' => 'owner', + 'limit' => 1, + 'values' => [$owner], +]); + + +$group = ''; + +if (array_key_exists('guid', $route_parameters)) { + $group = $route_parameters['guid']; +} + +echo elgg_view_field([ + '#type' => 'grouppicker', + '#label' => elgg_echo('event_manager:ical_direct:import:group'), + '#help' => elgg_echo('event_manager:ical_direct:import:group:help'), + 'required' => true, + 'name' => 'group', + 'limit' => 1, + 'values' => [$group], +]); + +echo elgg_view_field([ + '#type' => 'file', + '#label' => elgg_echo('event_manager:ical_direct:import:file'), + '#help' => elgg_echo('event_manager:ical_direct:import:file:help'), + 'name' => 'import' +]); + +elgg_set_form_footer( + elgg_view_field([ + '#type' => 'submit', + 'text' => elgg_echo('event_manager:ical_direct:import:submit'), + ]) +); diff --git a/views/default/plugins/event_manager/settings.php b/views/default/plugins/event_manager/settings.php index 59be23c..4bb0354 100644 --- a/views/default/plugins/event_manager/settings.php +++ b/views/default/plugins/event_manager/settings.php @@ -75,6 +75,17 @@ echo elgg_view_module('info', elgg_echo('event_manager:settings:maps'), $maps); +// iCal direct features +$ical_direct .= elgg_view_field([ + '#type' => 'switch', + '#label' => elgg_echo('event_manager:settings:ical_direct:enable'), + '#help' => elgg_echo('event_manager:settings:ical_direct:enable:help'), + 'name' => 'params[ical_direct]', + 'value' => $plugin->ical_direct, +]); + +echo elgg_view_module('info', elgg_echo('event_manager:settings:ical_direct'), $ical_direct); + // AddEvent options $add_event = elgg_view_field([ '#type' => 'select', diff --git a/views/default/resources/event/export/ical.php b/views/default/resources/event/export/ical.php new file mode 100644 index 0000000..e77a4c6 --- /dev/null +++ b/views/default/resources/event/export/ical.php @@ -0,0 +1,29 @@ +guid, 'group'); + elgg_group_tool_gatekeeper('event_manager'); + + elgg_push_collection_breadcrumbs('object', \Event::SUBTYPE, $page_owner); +} else { + $page_owner = null; + elgg_set_page_owner_guid(0); +} + +$content = elgg_view_form( + 'event_manager/export/ical', + [ + 'prevent_double_submit' => false + ], + [ + 'list_route' => get_input('list_route'), + 'route_parameters' => get_input('route_parameters'), + ] +); + +echo elgg_view_page(elgg_echo('event_manager:ical_direct:export'), [ + 'content' => $content, + 'filter_id' => 'events', + 'filter_value' => 'export-ical', +]); diff --git a/views/default/resources/event/import/ical.php b/views/default/resources/event/import/ical.php new file mode 100644 index 0000000..a2b2151 --- /dev/null +++ b/views/default/resources/event/import/ical.php @@ -0,0 +1,27 @@ +guid, 'group'); + elgg_group_tool_gatekeeper('event_manager'); + + elgg_push_collection_breadcrumbs('object', \Event::SUBTYPE, $page_owner); +} else { + $page_owner = null; + elgg_set_page_owner_guid(0); +} + +$content = elgg_view_form( + 'event_manager/import/ical', + [], + [ + 'list_route' => get_input('list_route'), + 'route_parameters' => get_input('route_parameters'), + ] +); + +echo elgg_view_page(elgg_echo('event_manager:ical_direct:import'), [ + 'content' => $content, + 'filter_id' => 'events', + 'filter_value' => 'import-ical', +]); diff --git a/views/ical/resources/event/export.php b/views/ical/resources/event/export.php new file mode 100644 index 0000000..133953c --- /dev/null +++ b/views/ical/resources/event/export.php @@ -0,0 +1,30 @@ + 'https://github.com/ColdTrick/event_manager', + ] +) + ->setMethod(Vcalendar::PUBLISH) + ->setXprop(Vcalendar::X_WR_CALNAME, 'Exported event') + ->setXprop(Vcalendar::X_WR_CALDESC, 'Single exported event from event_manager') + ->setXprop(Vcalendar::X_WR_RELCALID, elgg_get_site_url() . '#' . $guid) + ->setXprop(Vcalendar::X_WR_TIMEZONE, date_default_timezone_get()); + + +/** @noinspection PhpUnhandledExceptionInspection */ +$vcalendar->setComponent($event->toVEvent()); + +/** @noinspection PhpUnhandledExceptionInspection */ +echo $vcalendar->returnCalendar(true, false, false, 'export.ics'); From 9a2baf84e2be87cc09f5507e89dfa04c448b9728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20Pl=C3=B6ger?= Date: Mon, 16 Feb 2026 10:42:36 +0100 Subject: [PATCH 2/5] fixed: Updated composer.lock --- composer.lock | 827 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 715 insertions(+), 112 deletions(-) diff --git a/composer.lock b/composer.lock index 0060804..4864caf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,153 +4,356 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4125385fe420528e33bde0d77594307b", + "content-hash": "a107c54557e6cf51aa2e1acd33ef2480", "packages": [ { - "name": "composer/installers", - "version": "v2.3.0", + "name": "dompdf/dompdf", + "version": "v3.1.4", "source": { "type": "git", - "url": "https://github.com/composer/installers.git", - "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e" + "url": "https://github.com/dompdf/dompdf.git", + "reference": "db712c90c5b9868df3600e64e68da62e78a34623" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/12fb2dfe5e16183de69e784a7b84046c43d97e8e", - "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/db712c90c5b9868df3600e64e68da62e78a34623", + "reference": "db712c90c5b9868df3600e64e68da62e78a34623", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": "^7.2 || ^8.0" + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", + "ext-dom": "*", + "ext-mbstring": "*", + "masterminds/html5": "^2.0", + "php": "^7.1 || ^8.0" }, "require-dev": { - "composer/composer": "^1.10.27 || ^2.7", - "composer/semver": "^1.7.2 || ^3.4.0", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-phpunit": "^1", - "symfony/phpunit-bridge": "^7.1.1", - "symfony/process": "^5 || ^6 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "Composer\\Installers\\Plugin", - "branch-alias": { - "dev-main": "2.x-dev" + "ext-gd": "*", + "ext-json": "*", + "ext-zip": "*", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" + }, + "suggest": { + "ext-gd": "Needed to process images", + "ext-gmagick": "Improves image processing performance", + "ext-imagick": "Improves image processing performance", + "ext-zlib": "Needed for pdf stream compression" + }, + "type": "library", + "autoload": { + "psr-4": { + "Dompdf\\": "src/" }, - "plugin-modifies-install-path": true + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" + } + ], + "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", + "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/v3.1.4" + }, + "time": "2025-10-29T12:43:30+00:00" + }, + { + "name": "dompdf/php-font-lib", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a" }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a", + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12" + }, + "type": "library", "autoload": { "psr-4": { - "Composer\\Installers\\": "src/Composer/Installers" + "FontLib\\": "src/FontLib" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.2" + }, + "time": "2026-01-20T14:10:26+00:00" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1", + "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4 || ^9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" ], "authors": [ { - "name": "Kyle Robinson Young", - "email": "kyle@dontkry.com", - "homepage": "https://github.com/shama" + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" } ], - "description": "A multi-framework Composer library installer", - "homepage": "https://composer.github.io/installers/", + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.2" + }, + "time": "2026-01-02T16:01:13+00:00" + }, + { + "name": "kigkonsult/icalcreator", + "version": "v2.41.92", + "source": { + "type": "git", + "url": "https://github.com/iCalcreator/iCalcreator.git", + "reference": "a4d35d7a58c08b816dc8a7778db19f461c1429bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/iCalcreator/iCalcreator/zipball/a4d35d7a58c08b816dc8a7778db19f461c1429bd", + "reference": "a4d35d7a58c08b816dc8a7778db19f461c1429bd", + "shasum": "" + }, + "require": { + "ext-intl": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-zlib": "*", + "php": ">=8.0" + }, + "require-dev": { + "degraciamathieu/php-arguments-detector": ">=0.5.0", + "ext-xdebug": "*", + "phpcompatibility/php-compatibility": ">=9.3.5", + "phpmd/phpmd": ">=2.13.0", + "phpstan/phpstan": ">=0.9.3", + "phpunit/phpunit": ">=6.5.13", + "squizlabs/php_codesniffer": ">=3.5.5", + "vimeo/psalm": "*" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "Kigkonsult\\Icalcreator\\": [ + "src/" + ] + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Kjell-Inge Gustafsson", + "email": "ical@kigkonsult.se" + } + ], + "description": "iCalcreator is the PHP implementation of rfc2445/rfc5545 and rfc updates, management of calendar information", "keywords": [ - "Dolibarr", - "Eliasis", - "Hurad", - "ImageCMS", - "Kanboard", - "Lan Management System", - "MODX Evo", - "MantisBT", - "Mautic", - "Maya", - "OXID", - "Plentymarkets", - "Porto", - "RadPHP", - "SMF", - "Starbug", - "Thelia", - "Whmcs", - "WolfCMS", - "agl", - "annotatecms", - "attogram", - "bitrix", - "cakephp", - "chef", - "cockpit", - "codeigniter", - "concrete5", - "concreteCMS", - "croogo", - "dokuwiki", - "drupal", - "eZ Platform", - "elgg", - "expressionengine", - "fuelphp", - "grav", - "installer", - "itop", - "known", - "kohana", - "laravel", - "lavalite", - "lithium", - "magento", - "majima", - "mako", - "matomo", - "mediawiki", - "miaoxing", - "modulework", - "modx", - "moodle", - "osclass", - "pantheon", - "phpbb", - "piwik", - "ppi", - "processwire", - "puppet", - "pxcms", - "reindex", - "roundcube", - "shopware", - "silverstripe", - "sydes", - "sylius", - "tastyigniter", - "wordpress", - "yawik", - "zend", - "zikula" + "alarm", + "availability", + "calendar", + "daylight", + "event", + "ical", + "json", + "location", + "management", + "participant", + "resource", + "rfc2445", + "rfc5545", + "rfc5870", + "rfc6321", + "rfc6868", + "rfc7529", + "rfc7808", + "rfc7953", + "rfc7986", + "rfc9073", + "rfc9074", + "standard", + "todo", + "vCalendar", + "valarm", + "vevent", + "vfreebusy", + "vjournal", + "vtimezone", + "vtodo", + "xml" ], "support": { - "issues": "https://github.com/composer/installers/issues", - "source": "https://github.com/composer/installers/tree/v2.3.0" + "issues": "https://github.com/iCalcreator/iCalcreator/issues", + "source": "https://github.com/iCalcreator/iCalcreator/tree/v2.41.92" }, "funding": [ { - "url": "https://packagist.com", - "type": "custom" + "url": "https://paypal.me/kigkonsult", + "type": "other" }, { - "url": "https://github.com/composer", - "type": "github" + "url": "https://www.buymeacoffee.com/kigkonsult", + "type": "other" + } + ], + "time": "2025-01-17T10:06:29+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "fcf91eb64359852f00d921887b219479b4f21251" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" }, { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" } ], - "time": "2024-06-24T20:46:46+00:00" + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + }, + "time": "2025-07-25T09:04:22+00:00" + }, + { + "name": "npm-asset/fullcalendar", + "version": "6.1.20", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/fullcalendar/-/fullcalendar-6.1.20.tgz" + }, + "require": { + "npm-asset/fullcalendar--core": "~6.1.20", + "npm-asset/fullcalendar--daygrid": "~6.1.20", + "npm-asset/fullcalendar--interaction": "~6.1.20", + "npm-asset/fullcalendar--list": "~6.1.20", + "npm-asset/fullcalendar--multimonth": "~6.1.20", + "npm-asset/fullcalendar--timegrid": "~6.1.20" + }, + "type": "npm-asset", + "license": [ + "MIT" + ] }, { "name": "npm-asset/fullcalendar--core", @@ -167,6 +370,72 @@ "MIT" ] }, + { + "name": "npm-asset/fullcalendar--daygrid", + "version": "6.1.20", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.20.tgz" + }, + "type": "npm-asset", + "license": [ + "MIT" + ] + }, + { + "name": "npm-asset/fullcalendar--interaction", + "version": "6.1.20", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.20.tgz" + }, + "type": "npm-asset", + "license": [ + "MIT" + ] + }, + { + "name": "npm-asset/fullcalendar--list", + "version": "6.1.20", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.20.tgz" + }, + "type": "npm-asset", + "license": [ + "MIT" + ] + }, + { + "name": "npm-asset/fullcalendar--multimonth", + "version": "6.1.20", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.20.tgz" + }, + "require": { + "npm-asset/fullcalendar--daygrid": "~6.1.20" + }, + "type": "npm-asset", + "license": [ + "MIT" + ] + }, + { + "name": "npm-asset/fullcalendar--timegrid", + "version": "6.1.20", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.20.tgz" + }, + "require": { + "npm-asset/fullcalendar--daygrid": "~6.1.20" + }, + "type": "npm-asset", + "license": [ + "MIT" + ] + }, { "name": "npm-asset/preact", "version": "10.12.1", @@ -178,12 +447,346 @@ "license": [ "MIT" ] + }, + { + "name": "sabberworm/php-css-parser", + "version": "v9.1.0", + "source": { + "type": "git", + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb", + "reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.3" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "1.12.28 || 2.1.25", + "phpstan/phpstan-phpunit": "1.4.2 || 2.0.7", + "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.6", + "phpunit/phpunit": "8.5.46", + "rawr/phpunit-data-provider": "3.3.1", + "rector/rector": "1.2.10 || 2.1.7", + "rector/type-perfect": "1.0.0 || 2.1.0" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.1.0" + }, + "time": "2025-09-14T07:37:21+00:00" + }, + { + "name": "thecodingmachine/safe", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^10", + "squizlabs/php_codesniffer": "^3.2" + }, + "type": "library", + "autoload": { + "files": [ + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gettext.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rnp.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "classmap": [ + "lib/DateTime.php", + "lib/DateTimeImmutable.php", + "lib/Exceptions/", + "generated/Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/OskarStark", + "type": "github" + }, + { + "url": "https://github.com/shish", + "type": "github" + }, + { + "url": "https://github.com/silasjoisten", + "type": "github" + }, + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2026-02-04T18:08:13+00:00" + } + ], + "packages-dev": [ + { + "name": "elgg/sniffs", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Elgg/elgg-coding-standards.git", + "reference": "7d757f3fbebf7686fb75f500ffb38102e0131865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Elgg/elgg-coding-standards/zipball/7d757f3fbebf7686fb75f500ffb38102e0131865", + "reference": "7d757f3fbebf7686fb75f500ffb38102e0131865", + "shasum": "" + }, + "require": { + "squizlabs/php_codesniffer": "^3.9.0" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-0": { + "Elgg_Sniffs_": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-only" + ], + "description": "Elgg coding standards", + "support": { + "issues": "https://github.com/Elgg/elgg-coding-standards/issues", + "source": "https://github.com/Elgg/elgg-coding-standards/tree/master" + }, + "time": "2025-06-19T09:53:40+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.13.5", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-04T16:30:35+00:00" } ], - "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "elgg/sniffs": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": {}, From 01bf912ef39a5d775b467c1b39fbab090d81bb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20Pl=C3=B6ger?= Date: Mon, 16 Feb 2026 10:48:21 +0100 Subject: [PATCH 3/5] fixed: Updated composer.lock and composer.json --- composer.json | 5 ++++- composer.lock | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f3f0c71..19926da 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "require": { "dompdf/dompdf" : "~3.1.0", "npm-asset/fullcalendar": "~6.1.0", - "kigkonsult/icalcreator": "~2.41" + "kigkonsult/icalcreator": "^2.41" }, "repositories": [ { @@ -27,5 +27,8 @@ }, "conflict": { "elgg/elgg": "<6.3.1" + }, + "require-dev": { + "elgg/sniffs": "dev-master" } } diff --git a/composer.lock b/composer.lock index 4864caf..b9df162 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a107c54557e6cf51aa2e1acd33ef2480", + "content-hash": "3fd57025e88f340effc374940cbd6366", "packages": [ { "name": "dompdf/dompdf", From d8f7138fa82d9b9c84b21b7e5aba45f829a03103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20Pl=C3=B6ger?= Date: Wed, 18 Feb 2026 13:47:19 +0100 Subject: [PATCH 4/5] fixed: First fixes of PR --- actions/event_manager/export/ical.php | 74 ++++++++++------ actions/event_manager/import/ical.php | 78 +++++++++++----- classes/Event.php | 9 -- composer.json | 3 - composer.lock | 123 +------------------------- languages/en.php | 16 +++- 6 files changed, 121 insertions(+), 182 deletions(-) diff --git a/actions/event_manager/export/ical.php b/actions/event_manager/export/ical.php index 17afcc1..29d3ec1 100644 --- a/actions/event_manager/export/ical.php +++ b/actions/event_manager/export/ical.php @@ -3,15 +3,15 @@ $calendar_type = get_input('calendar_type', 'all'); $date_format = elgg_get_config('date_format', elgg_echo('input:date_format')); -$start_date = get_input('start_date', ''); -if ($start_date == '') { +$start_date = (string) get_input('start_date'); +if (empty($start_date)) { $start_date = time(); } else { $start_date = DateTime::createFromFormat($date_format, $start_date)->getTimestamp(); } -$end_date = get_input('end_date', ''); -if ($end_date == '') { +$end_date = (string) get_input('end_date'); +if (empty($end_date)) { $end_date = DateTime::createFromFormat('U', time()) ->add(DateInterval::createFromDateString('1 month')) ->getTimestamp(); @@ -19,11 +19,11 @@ $end_date = DateTime::createFromFormat($date_format, $end_date)->getTimestamp(); } -$region = get_input('region', ''); -$event_type = get_input('event_type', ''); +$region = (string) get_input('region'); +$event_type = (string) get_input('event_type'); -$owner = get_input('owner', ''); -$group = get_input('group', ''); +$owner = (string) get_input('owner'); +$group = (string) get_input('group'); $options = [ 'types' => ['object'], @@ -42,7 +42,7 @@ ] ]; -if ($region != '') { +if (!empty($region)) { $options['metadata_name_value_pairs'][] = [ 'name' => 'region', 'operand' => 'IN', @@ -50,7 +50,7 @@ ]; } -if ($event_type != '') { +if (!empty($event_type)) { $options['metadata_name_value_pairs'][] = [ 'name' => 'event_type', 'operand' => 'IN', @@ -60,34 +60,56 @@ switch ($calendar_type) { case 'group': + if (empty($group)) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:export:errors:groupempty')); + } + $options['container_guids'] = [$group]; break; case 'owner': + if (empty($owner)) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:export:errors:ownerempty')); + } + + if (elgg_is_admin_logged_in() || $owner === elgg_get_logged_in_user_guid()) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:export:errors:ownermismatch')); + } + $options['owner_guids'] = [$owner]; break; } +/** @var Event[] $events */ $events = elgg_get_entities($options); +use Kigkonsult\Icalcreator\IcalInterface; use Kigkonsult\Icalcreator\Vcalendar; -/** @noinspection PhpUnhandledExceptionInspection */ -/** @noinspection PhpClassConstantAccessedViaChildClassInspection */ -$vcalendar = Vcalendar::factory( - [ - Vcalendar::UNIQUE_ID => 'https://github.com/ColdTrick/event_manager', - ] -) - ->setMethod(Vcalendar::PUBLISH) - ->setXprop(Vcalendar::X_WR_CALNAME, 'Exported event') - ->setXprop(Vcalendar::X_WR_CALDESC, 'Exported events from event_manager') - ->setXprop(Vcalendar::X_WR_RELCALID, elgg_get_site_url()) - ->setXprop(Vcalendar::X_WR_TIMEZONE, date_default_timezone_get()); +try { + $vcalendar = Vcalendar::factory( + [ + IcalInterface::UNIQUE_ID => 'https://github.com/ColdTrick/event_manager', + ] + ) + ->setMethod(IcalInterface::PUBLISH) + ->setXprop(IcalInterface::X_WR_CALNAME, 'Exported event') + ->setXprop(IcalInterface::X_WR_CALDESC, 'Exported events from event_manager') + ->setXprop(IcalInterface::X_WR_RELCALID, elgg_get_site_url()) + ->setXprop(IcalInterface::X_WR_TIMEZONE, date_default_timezone_get()); +} catch (Exception $e) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:export:errors:errorinstantiatingcalendar', [$e])); +} foreach ($events as $event) { - /** @noinspection PhpUnhandledExceptionInspection */ - $vcalendar->setComponent($event->toVEvent()); + try { + $vcalendar->setComponent($event->toVEvent()); + } catch (Exception $e) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:export:errors:erroraddingevent', [$e])); + } } -/** @noinspection PhpUnhandledExceptionInspection */ -return elgg_download_response($vcalendar->createCalendar(), 'export.ics'); +try { + return elgg_download_response($vcalendar->createCalendar(), 'export.ics'); +} catch (Exception $e) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:export:errors:errorcreatingcalendar', [$e])); +} diff --git a/actions/event_manager/import/ical.php b/actions/event_manager/import/ical.php index db79bd8..7e36633 100644 --- a/actions/event_manager/import/ical.php +++ b/actions/event_manager/import/ical.php @@ -1,23 +1,29 @@ 'https://github.com/ColdTrick/event_manager', - ] -); +try { + $vcalendar = Vcalendar::factory( + [ + IcalInterface::UNIQUE_ID => 'https://github.com/ColdTrick/event_manager', + ] + ); +} catch (Exception $e) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:errorinstantiatingcalendar', [$e])); +} + try { $vcalendar->parse($file->getContent()); } catch (Exception $e) { - return elgg_error_response('Error parsing calendar: ' . $e); + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:errorpparsingcalendar', [$e])); } $event_counter = 0; @@ -26,23 +32,49 @@ foreach ($vcalendar->getComponents('Vevent') as $component) { try { $event = Event::fromVEvent($component); - - switch ($calendar_type) { - case 'group': - $event->setContainerGUID($group); - break; - case 'owner': - $event->owner_guid = $owner; - break; - } - - $event->save(); - $event_counter++; } catch (Exception $e) { - return elgg_error_response( - elgg_echo('event_manager:ical_direct:import:failure', [$e]) - ); + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:errorconvertingevent', [$e])); } + + switch ($calendar_type) { + case 'group': + if (empty($group)) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:groupempty')); + } + + $group_guid = $group[0]; + $group = get_entity($group_guid); + if (!$group instanceof \ElggGroup) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:invalidgroup')); + } + + if (elgg_is_admin_logged_in() || $group->canWriteToContainer(elgg_get_logged_in_user_guid())) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:grouppermission')); + } + + $event->setContainerGUID($group_guid); + break; + case 'owner': + if (empty($owner)) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:ownerempty')); + } + + $owner_guid = $owner[0]; + $owner = get_entity($owner_guid); + if (!$owner instanceof \ElggUser) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:invalidgroup')); + } + + if (elgg_is_admin_logged_in() || $owner_guid === elgg_get_logged_in_user_guid()) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:ownermismatch')); + } + + $event->owner_guid = $owner_guid; + break; + } + + $event->save(); + $event_counter++; } return elgg_ok_response( diff --git a/classes/Event.php b/classes/Event.php index 655d201..de6ee2c 100644 --- a/classes/Event.php +++ b/classes/Event.php @@ -1270,15 +1270,6 @@ public static function fromVEvent(Vevent $vevent): Event { } } - if ($vevent->isAttendeeSet()) { - foreach ($vevent->getAllAttendee() as $attendee) { - $attendee_object = elgg_get_user_by_email($attendee); - if (!is_null($attendee_object)) { - $event->addRelationship($attendee_object->guid, 'event_attending'); - } - } - } - if ($vevent->isContactSet()) { foreach ($vevent->getAllContact() as $contact) { $contact_object = elgg_get_user_by_email($contact); diff --git a/composer.json b/composer.json index 19926da..ce7315d 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,5 @@ }, "conflict": { "elgg/elgg": "<6.3.1" - }, - "require-dev": { - "elgg/sniffs": "dev-master" } } diff --git a/composer.lock b/composer.lock index b9df162..993d910 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3fd57025e88f340effc374940cbd6366", + "content-hash": "4393d2a789e3e889ed1f276b84d0b32c", "packages": [ { "name": "dompdf/dompdf", @@ -666,127 +666,10 @@ "time": "2026-02-04T18:08:13+00:00" } ], - "packages-dev": [ - { - "name": "elgg/sniffs", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Elgg/elgg-coding-standards.git", - "reference": "7d757f3fbebf7686fb75f500ffb38102e0131865" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Elgg/elgg-coding-standards/zipball/7d757f3fbebf7686fb75f500ffb38102e0131865", - "reference": "7d757f3fbebf7686fb75f500ffb38102e0131865", - "shasum": "" - }, - "require": { - "squizlabs/php_codesniffer": "^3.9.0" - }, - "default-branch": true, - "type": "library", - "autoload": { - "psr-0": { - "Elgg_Sniffs_": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-only" - ], - "description": "Elgg coding standards", - "support": { - "issues": "https://github.com/Elgg/elgg-coding-standards/issues", - "source": "https://github.com/Elgg/elgg-coding-standards/tree/master" - }, - "time": "2025-06-19T09:53:40+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.13.5", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-11-04T16:30:35+00:00" - } - ], + "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "elgg/sniffs": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": {}, diff --git a/languages/en.php b/languages/en.php index a87b2fa..ad6cac1 100644 --- a/languages/en.php +++ b/languages/en.php @@ -473,6 +473,12 @@ 'event_manager:ical_direct:export:type' => 'Type', 'event_manager:ical_direct:export:type:help' => 'Select one or more event types to filter for', 'event_manager:ical_direct:export:submit' => 'Export', + 'event_manager:ical_direct:export:errors:groupempty' => 'No group specified', + 'event_manager:ical_direct:export:errors:ownerempty' => 'No owner specified', + 'event_manager:ical_direct:export:errors:ownermismatch' => 'You need to be an administrator to export other user\'s calendars', + 'event_manager:ical_direct:export:errors:errorinstantiatingcalendar' => 'Error instantiating calendar: %s', + 'event_manager:ical_direct:export:errors:erroraddingevent' => 'Error adding event to calendar: %s', + 'event_manager:ical_direct:export:errors:errorcreatingcalendar' => 'Error creating calendar: %s', 'event_manager:ical_direct:import' => 'Import iCal', 'event_manager:ical_direct:import:calendar_type' => 'Calendar', @@ -485,6 +491,14 @@ 'event_manager:ical_direct:import:file:help' => 'ICS file to import', 'event_manager:ical_direct:import:submit' => 'Import', 'event_manager:ical_direct:import:success' => 'Successfully imported %d entries', - 'event_manager:ical_direct:import:failure' => 'Could not import calendar file: %s', + 'event_manager:ical_direct:import:errors:groupempty' => 'No group specified', + 'event_manager:ical_direct:import:errors:invalidgroup' => 'Invalid group specified', + 'event_manager:ical_direct:import:errors:ownerempty' => 'No owner specified', + 'event_manager:ical_direct:import:errors:invalidowner' => 'Invalid owner specified', + 'event_manager:ical_direct:import:errors:ownermismatch' => 'You need to be an administrator to import other user\'s calendars', + 'event_manager:ical_direct:import:errors:grouppermission' => 'You need to be an administrator or be able to write to the target group', + 'event_manager:ical_direct:import:errors:errorinstantiatingcalendar' => 'Error instantiating calendar: %s', + 'event_manager:ical_direct:import:errors:errorconvertingevent' => 'Error converting to event: %s', + 'event_manager:ical_direct:import:errors:errorpparsingcalendar' => 'Error parsing calendar file: %s', ); From 2ada5f84405b1dcae83a0f94dc81c2db57723053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20Pl=C3=B6ger?= Date: Thu, 19 Feb 2026 10:03:33 +0100 Subject: [PATCH 5/5] fixed: Sanity Check import Missing German error translations --- actions/event_manager/import/ical.php | 4 ++++ languages/de.php | 17 ++++++++++++++++- languages/en.php | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/actions/event_manager/import/ical.php b/actions/event_manager/import/ical.php index 7e36633..3cd66a8 100644 --- a/actions/event_manager/import/ical.php +++ b/actions/event_manager/import/ical.php @@ -10,6 +10,10 @@ $group = (array) get_input('group'); $file = elgg_get_uploaded_file('import'); +if (!$file) { + return elgg_error_response(elgg_echo('event_manager:ical_direct:import:errors:missingfile')); +} + try { $vcalendar = Vcalendar::factory( [ diff --git a/languages/de.php b/languages/de.php index e4423dc..12c0f14 100644 --- a/languages/de.php +++ b/languages/de.php @@ -323,6 +323,12 @@ 'event_manager:ical_direct:export:type' => 'Typ', 'event_manager:ical_direct:export:type:help' => 'Wähle einen oder mehrere Eventtypen aus, um nach diesen zu filtern', 'event_manager:ical_direct:export:submit' => 'Exportieren', + 'event_manager:ical_direct:export:errors:groupempty' => 'Keine Gruppe angegeben', + 'event_manager:ical_direct:export:errors:ownerempty' => 'Kein Besitzer angegeben', + 'event_manager:ical_direct:export:errors:ownermismatch' => 'Du musst ein Administrator sein, um die Kalender anderer Benutzer zu exportieren', + 'event_manager:ical_direct:export:errors:errorinstantiatingcalendar' => 'Fehler beim Instanzieren des Kalenders: %s', + 'event_manager:ical_direct:export:errors:erroraddingevent' => 'Fehler beim Hinzufügen eines Events zum Kalender: %s', + 'event_manager:ical_direct:export:errors:errorcreatingcalendar' => 'Fehler beim Erzeugen des Kalenders: %s', 'event_manager:ical_direct:import' => 'iCal importieren', 'event_manager:ical_direct:import:calendar_type' => 'Kalender', @@ -335,5 +341,14 @@ 'event_manager:ical_direct:import:file:help' => 'ICS-Datei für den Import', 'event_manager:ical_direct:import:submit' => 'Importieren', 'event_manager:ical_direct:import:success' => '%d Einträge erfolgreich importiert', - 'event_manager:ical_direct:import:failure' => 'Konnte Datei nicht importieren: %s', + 'event_manager:ical_direct:import:errors:groupempty' => 'Keine Gruppe angegeben', + 'event_manager:ical_direct:import:errors:invalidgroup' => 'Ungültige Gruppe angegeben', + 'event_manager:ical_direct:import:errors:ownerempty' => 'Kein Besitzer angegeben', + 'event_manager:ical_direct:import:errors:invalidowner' => 'Ungültigen Besitzer angegeben', + 'event_manager:ical_direct:import:errors:ownermismatch' => 'Du musst ein Administrator sein, um einen Kalender für einen anderen Benutzer zu importieren.', + 'event_manager:ical_direct:import:errors:grouppermission' => 'Du musst ein Administrator sein oder eine Schreibberechtigung für die Gruppe haben', + 'event_manager:ical_direct:import:errors:errorinstantiatingcalendar' => 'Fehler beim Instanzieren des Kalenders: %s', + 'event_manager:ical_direct:import:errors:errorconvertingevent' => 'Fehler bei der Konvertierung eines Events: %s', + 'event_manager:ical_direct:import:errors:errorpparsingcalendar' => 'Fehler beim Parsen der iCal-Datei: %s', + 'event_manager:ical_direct:import:errors:missingfile' => 'Fehlende iCal-Datei', ); diff --git a/languages/en.php b/languages/en.php index ad6cac1..268ead3 100644 --- a/languages/en.php +++ b/languages/en.php @@ -500,5 +500,6 @@ 'event_manager:ical_direct:import:errors:errorinstantiatingcalendar' => 'Error instantiating calendar: %s', 'event_manager:ical_direct:import:errors:errorconvertingevent' => 'Error converting to event: %s', 'event_manager:ical_direct:import:errors:errorpparsingcalendar' => 'Error parsing calendar file: %s', + 'event_manager:ical_direct:import:errors:missingfile' => 'Missing iCal file', );