diff --git a/mod/cal.php b/mod/cal.php index 4c22232d27..d5b0487a4a 100644 --- a/mod/cal.php +++ b/mod/cal.php @@ -34,7 +34,6 @@ use Friendica\Model\Event; use Friendica\Model\Item; use Friendica\Model\User; use Friendica\Module\BaseProfile; -use Friendica\Module\Response; use Friendica\Network\HTTPException; use Friendica\Util\DateTimeFormat; use Friendica\Util\Temporal; @@ -101,15 +100,8 @@ function cal_content(App $a) $m = 0; $ignored = (!empty($_REQUEST['ignored']) ? intval($_REQUEST['ignored']) : 0); - $format = 'ical'; - if (DI::args()->getArgc() == 4 && DI::args()->getArgv()[2] == 'export') { - $mode = 'export'; - $format = DI::args()->getArgv()[3]; - } - // Setup permissions structures $owner_uid = intval($owner['uid']); - $nick = $owner['nickname']; $contact_id = DI::userSession()->getRemoteContactID($owner['uid']); @@ -258,40 +250,4 @@ function cal_content(App $a) return $o; } - - if ($mode == 'export') { - if (!$owner_uid) { - DI::sysmsg()->addNotice(DI::l10n()->t('User not found')); - return; - } - - // Get the export data by uid - $evexport = Event::exportListByUserId($owner_uid, $format); - - if (!$evexport["success"]) { - if ($evexport["content"]) { - DI::sysmsg()->addNotice(DI::l10n()->t('This calendar format is not supported')); - } else { - DI::sysmsg()->addNotice(DI::l10n()->t('No exportable data found')); - } - - // If it the own calendar return to the events page - // otherwise to the profile calendar page - if (DI::userSession()->getLocalUserId() === $owner_uid) { - $return_path = "events"; - } else { - $return_path = "cal/" . $nick; - } - - DI::baseUrl()->redirect($return_path); - } - - // If nothing went wrong we can echo the export content - if ($evexport["success"]) { - header('content-disposition: attachment; filename="' . DI::l10n()->t('calendar') . '-' . $nick . '.' . $evexport["extension"] . '"'); - System::httpExit($evexport["content"], Response::TYPE_BLANK, 'text/calendar'); - } - - return; - } } diff --git a/src/Model/Event.php b/src/Model/Event.php index a738428eaa..9a75152724 100644 --- a/src/Model/Event.php +++ b/src/Model/Event.php @@ -670,7 +670,6 @@ class Event switch ($format) { // Format the exported data as a CSV file. case "csv": - header("Content-type: text/csv"); $o .= '"Subject", "Start Date", "Start Time", "Description", "End Date", "End Time", "Location"' . PHP_EOL; foreach ($events as $event) { @@ -691,7 +690,6 @@ class Event // Format the exported data as a ics file. case "ical": - header("Content-type: text/ics"); $o = 'BEGIN:VCALENDAR' . PHP_EOL . 'VERSION:2.0' . PHP_EOL . 'PRODID:-//friendica calendar export//0.1//EN' . PHP_EOL; @@ -705,6 +703,8 @@ class Event // also long lines SHOULD be split at 75 characters length foreach ($events as $event) { $o .= 'BEGIN:VEVENT' . PHP_EOL; + $o .= 'UID:' . $event['id'] . PHP_EOL; + $o .= 'DTSTAMP:' . DateTimeFormat::utc($event['created'], 'Ymd\THis\Z') . PHP_EOL; if ($event['start']) { $o .= 'DTSTART:' . DateTimeFormat::utc($event['start'], 'Ymd\THis\Z') . PHP_EOL; @@ -736,7 +736,6 @@ class Event } $o .= 'END:VEVENT' . PHP_EOL; - $o .= PHP_EOL; } $o .= 'END:VCALENDAR' . PHP_EOL; @@ -768,7 +767,7 @@ class Event return $return; } - $fields = ['start', 'finish', 'summary', 'desc', 'location', 'nofinish']; + $fields = ['id', 'created', 'start', 'finish', 'summary', 'desc', 'location', 'nofinish']; $conditions = ['uid' => $uid, 'cid' => 0]; diff --git a/src/Module/Calendar/Export.php b/src/Module/Calendar/Export.php new file mode 100644 index 0000000000..30a1bc44de --- /dev/null +++ b/src/Module/Calendar/Export.php @@ -0,0 +1,109 @@ +. + * + */ + +namespace Friendica\Module\Calendar; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Core\L10n; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Model\Event; +use Friendica\Model\User; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +/** + * Controller to export a calendar from a given user + */ +class Export extends BaseModule +{ + const EXPORT_ICAL = 'ical'; + const EXPORT_CSV = 'csv'; + + const DEFAULT_EXPORT = self::EXPORT_ICAL; + + /** @var IHandleUserSessions */ + protected $session; + /** @var SystemMessages */ + protected $sysMessages; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, SystemMessages $sysMessages, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->sysMessages = $sysMessages; + } + + protected function rawContent(array $request = []) + { + $owner = User::getByNickname($this->parameters['nickname'], ['uid']); + if (empty($owner)) { + throw new HTTPException\NotFoundException($this->t('User not found.')); + } + $ownerUid = $owner['uid']; + $format = $this->parameters['format'] ?: static::DEFAULT_EXPORT; + + // Get the export data by uid + $evexport = Event::exportListByUserId($ownerUid, $format); + + if (!$evexport["success"]) { + if ($evexport["content"]) { + $this->sysMessages->addNotice($this->t('This calendar format is not supported')); + } else { + $this->sysMessages->addNotice($this->t('No exportable data found')); + } + + // If it is the own calendar return to the events page + // otherwise to the profile calendar page + if ($this->session->getLocalUserId() === $ownerUid) { + $returnPath = 'events'; + } else { + $returnPath = 'events/' . $this->parameters['nickname']; + } + + $this->baseUrl->redirect($returnPath); + } + + // If nothing went wrong we can echo the export content + if ($evexport["success"]) { + $this->response->setHeader(sprintf('Content-Disposition: attachment; filename="%s-%s.%s"', + $this->t('calendar'), + $this->parameters['nickname'], + $evexport["extension"] + )); + + switch ($format) { + case static::EXPORT_ICAL: + $this->response->setType(Response::TYPE_BLANK, 'text/ics'); + break; + case static::EXPORT_CSV: + $this->response->setType(Response::TYPE_BLANK, 'text/csv'); + break; + } + + $this->response->addContent($evexport['content']); + } + } +} diff --git a/src/Module/Events/Json.php b/src/Module/Calendar/Json.php similarity index 94% rename from src/Module/Events/Json.php rename to src/Module/Calendar/Json.php index 2072c4f32f..08481e6aca 100644 --- a/src/Module/Events/Json.php +++ b/src/Module/Calendar/Json.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Module\Events; +namespace Friendica\Module\Calendar; use Friendica\Core\System; use Friendica\Database\DBA; @@ -51,17 +51,17 @@ class Json extends \Friendica\BaseModule $start = sprintf('%d-%d-%d %d:%d:%d', $y, $m, 1, 0, 0, 0); $finish = sprintf('%d-%d-%d %d:%d:%d', $y, $m, $dim, 23, 59, 59); - if (!empty($_GET['start'])) { - $start = $_GET['start']; + if (!empty($request['start'])) { + $start = $request['start']; } - if (!empty($_GET['end'])) { - $finish = $_GET['end']; + if (!empty($request['end'])) { + $finish = $request['end']; } // put the event parametes in an array so we can better transmit them $event_params = [ - 'event_id' => intval($_GET['id'] ?? 0), + 'event_id' => intval($request['id'] ?? 0), 'start' => $start, 'finish' => $finish, 'ignore' => 0, diff --git a/static/routes.config.php b/static/routes.config.php index 6f05faee2d..c03a4b7710 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -365,6 +365,9 @@ return [ '/bookmarklet' => [Module\Bookmarklet::class, [R::GET]], + '/calendar/{nickname}/export[/{format}]' => [Module\Calendar\Export::class, [R::GET]], + '/calendar/json' => [Module\Calendar\Json::class, [R::GET]], + '/community[/{content}]' => [Module\Conversation\Community::class, [R::GET]], '/compose[/{type}]' => [Module\Item\Compose::class, [R::GET, R::POST]], @@ -398,8 +401,6 @@ return [ '/dirfind' => [Module\Search\Directory::class, [R::GET]], '/directory' => [Module\Directory::class, [R::GET]], - '/events/json' => [Module\Events\Json::class, [R::GET]], - '/featured/{nickname}' => [Module\ActivityPub\Featured::class, [R::GET]], '/feed' => [ diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 581632207f..9154133605 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2022.12-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-10-31 19:59+0000\n" +"POT-Creation-Date: 2022-11-02 14:17+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" -#: mod/cal.php:45 mod/cal.php:49 mod/redir.php:35 mod/redir.php:176 +#: mod/cal.php:44 mod/cal.php:48 mod/redir.php:35 mod/redir.php:176 #: src/Module/Contact/Follow.php:69 src/Module/Conversation/Community.php:193 #: src/Module/Debug/ItemBody.php:38 src/Module/Diaspora/Receive.php:57 #: src/Module/Item/Follow.php:41 src/Module/Item/Ignore.php:41 @@ -27,8 +27,9 @@ msgstr "" msgid "Access denied." msgstr "" -#: mod/cal.php:62 mod/cal.php:79 mod/photos.php:68 mod/photos.php:139 -#: mod/photos.php:793 src/Model/Profile.php:234 src/Module/Feed.php:72 +#: mod/cal.php:61 mod/cal.php:78 mod/photos.php:68 mod/photos.php:139 +#: mod/photos.php:793 src/Model/Profile.php:234 +#: src/Module/Calendar/Export.php:63 src/Module/Feed.php:72 #: src/Module/HCard.php:51 src/Module/Profile/Common.php:40 #: src/Module/Profile/Common.php:51 src/Module/Profile/Contacts.php:39 #: src/Module/Profile/Contacts.php:49 src/Module/Profile/Media.php:38 @@ -38,73 +39,54 @@ msgstr "" msgid "User not found." msgstr "" -#: mod/cal.php:121 mod/display.php:259 src/Module/Profile/Profile.php:93 +#: mod/cal.php:113 mod/display.php:259 src/Module/Profile/Profile.php:93 #: src/Module/Profile/Profile.php:108 src/Module/Profile/Status.php:109 #: src/Module/Update/Profile.php:55 msgid "Access to this profile has been restricted." msgstr "" -#: mod/cal.php:242 mod/events.php:375 src/Content/Nav.php:196 +#: mod/cal.php:234 mod/events.php:375 src/Content/Nav.php:196 #: src/Content/Nav.php:260 src/Module/BaseProfile.php:84 #: src/Module/BaseProfile.php:95 view/theme/frio/theme.php:241 #: view/theme/frio/theme.php:245 msgid "Events" msgstr "" -#: mod/cal.php:243 mod/events.php:376 +#: mod/cal.php:235 mod/events.php:376 msgid "View" msgstr "" -#: mod/cal.php:244 mod/events.php:378 +#: mod/cal.php:236 mod/events.php:378 msgid "Previous" msgstr "" -#: mod/cal.php:245 mod/events.php:379 src/Module/Install.php:214 +#: mod/cal.php:237 mod/events.php:379 src/Module/Install.php:214 msgid "Next" msgstr "" -#: mod/cal.php:248 mod/events.php:384 src/Model/Event.php:460 +#: mod/cal.php:240 mod/events.php:384 src/Model/Event.php:460 msgid "today" msgstr "" -#: mod/cal.php:249 mod/events.php:385 src/Model/Event.php:461 +#: mod/cal.php:241 mod/events.php:385 src/Model/Event.php:461 #: src/Util/Temporal.php:341 msgid "month" msgstr "" -#: mod/cal.php:250 mod/events.php:386 src/Model/Event.php:462 +#: mod/cal.php:242 mod/events.php:386 src/Model/Event.php:462 #: src/Util/Temporal.php:342 msgid "week" msgstr "" -#: mod/cal.php:251 mod/events.php:387 src/Model/Event.php:463 +#: mod/cal.php:243 mod/events.php:387 src/Model/Event.php:463 #: src/Util/Temporal.php:343 msgid "day" msgstr "" -#: mod/cal.php:252 mod/events.php:388 +#: mod/cal.php:244 mod/events.php:388 msgid "list" msgstr "" -#: mod/cal.php:264 src/Console/User.php:182 src/Model/User.php:663 -#: src/Module/Admin/Users/Active.php:73 src/Module/Admin/Users/Blocked.php:74 -#: src/Module/Admin/Users/Index.php:80 src/Module/Admin/Users/Pending.php:71 -#: src/Module/Api/Twitter/ContactEndpoint.php:74 -msgid "User not found" -msgstr "" - -#: mod/cal.php:273 -msgid "This calendar format is not supported" -msgstr "" - -#: mod/cal.php:275 -msgid "No exportable data found" -msgstr "" - -#: mod/cal.php:291 -msgid "calendar" -msgstr "" - #: mod/display.php:140 mod/photos.php:797 #: src/Module/Conversation/Community.php:187 src/Module/Directory.php:48 #: src/Module/Search/Index.php:64 @@ -391,7 +373,7 @@ msgid "Description:" msgstr "" #: mod/events.php:505 src/Content/Widget/VCard.php:104 src/Model/Event.php:80 -#: src/Model/Event.php:107 src/Model/Event.php:469 src/Model/Event.php:919 +#: src/Model/Event.php:107 src/Model/Event.php:469 src/Model/Event.php:918 #: src/Model/Profile.php:373 src/Module/Contact/Profile.php:370 #: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:187 #: src/Module/Profile/Profile.php:193 @@ -1629,6 +1611,13 @@ msgstr "" msgid "Enter user nickname: " msgstr "" +#: src/Console/User.php:182 src/Model/User.php:663 +#: src/Module/Admin/Users/Active.php:73 src/Module/Admin/Users/Blocked.php:74 +#: src/Module/Admin/Users/Index.php:80 src/Module/Admin/Users/Pending.php:71 +#: src/Module/Api/Twitter/ContactEndpoint.php:74 +msgid "User not found" +msgstr "" + #: src/Console/User.php:202 msgid "Enter new password: " msgstr "" @@ -3548,12 +3537,12 @@ msgid "l F d, Y \\@ g:i A \\G\\M\\TP (e)" msgstr "" #: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:467 -#: src/Model/Event.php:901 +#: src/Model/Event.php:900 msgid "Starts:" msgstr "" #: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:468 -#: src/Model/Event.php:905 +#: src/Model/Event.php:904 msgid "Finishes:" msgstr "" @@ -3585,32 +3574,32 @@ msgstr "" msgid "Delete event" msgstr "" -#: src/Model/Event.php:857 src/Module/Debug/Localtime.php:38 +#: src/Model/Event.php:856 src/Module/Debug/Localtime.php:38 msgid "l F d, Y \\@ g:i A" msgstr "" -#: src/Model/Event.php:858 +#: src/Model/Event.php:857 msgid "D g:i A" msgstr "" -#: src/Model/Event.php:859 +#: src/Model/Event.php:858 msgid "g:i A" msgstr "" -#: src/Model/Event.php:920 src/Model/Event.php:922 +#: src/Model/Event.php:919 src/Model/Event.php:921 msgid "Show map" msgstr "" -#: src/Model/Event.php:921 +#: src/Model/Event.php:920 msgid "Hide map" msgstr "" -#: src/Model/Event.php:1014 +#: src/Model/Event.php:1013 #, php-format msgid "%s's birthday" msgstr "" -#: src/Model/Event.php:1015 +#: src/Model/Event.php:1014 #, php-format msgid "Happy Birthday %s" msgstr "" @@ -6677,6 +6666,18 @@ msgstr "" msgid "The post was created" msgstr "" +#: src/Module/Calendar/Export.php:73 +msgid "This calendar format is not supported" +msgstr "" + +#: src/Module/Calendar/Export.php:75 +msgid "No exportable data found" +msgstr "" + +#: src/Module/Calendar/Export.php:92 +msgid "calendar" +msgstr "" + #: src/Module/Contact.php:88 #, php-format msgid "%d contact edited." diff --git a/view/templates/event_head.tpl b/view/templates/event_head.tpl index 3075408063..1627bd6996 100644 --- a/view/templates/event_head.tpl +++ b/view/templates/event_head.tpl @@ -81,7 +81,7 @@ week: '{{$i18n.week|escape:'quotes'}}', day: '{{$i18n.day|escape:'quotes'}}' }, - events: '{{$baseurl}}{{$module_url}}/json/', + events: '{{$baseurl}}/calendar/json', header: { left: 'prev,next today', center: 'title', diff --git a/view/templates/widget/events.tpl b/view/templates/widget/events.tpl index 81dde70463..10f142cb39 100644 --- a/view/templates/widget/events.tpl +++ b/view/templates/widget/events.tpl @@ -3,7 +3,7 @@

{{$etitle}}

diff --git a/view/theme/quattro/templates/events_reminder.tpl b/view/theme/quattro/templates/events_reminder.tpl index d0bc1f481c..8c9bf4e977 100644 --- a/view/theme/quattro/templates/events_reminder.tpl +++ b/view/theme/quattro/templates/events_reminder.tpl @@ -22,7 +22,7 @@ year: yesterday.getFullYear(), month: yesterday.getMonth(), date: yesterday.getDate(), - events: '{{$baseurl}}/events/json/', + events: '{{$baseurl}}/calendar/json', header: false, timeFormat: 'H(:mm)', defaultView: 'basicWeek', diff --git a/view/theme/vier/templates/event_head.tpl b/view/theme/vier/templates/event_head.tpl index 2c7b3070a7..817204a31c 100644 --- a/view/theme/vier/templates/event_head.tpl +++ b/view/theme/vier/templates/event_head.tpl @@ -87,7 +87,7 @@ week: '{{$i18n.week|escape:'quotes'}}', day: '{{$i18n.day|escape:'quotes'}}' }, - events: '{{$baseurl}}{{$module_url}}/json/', + events: '{{$baseurl}}/calendar/json', header: { left: 'prev,next today', center: 'title',