]> git.mxchange.org Git - friendica.git/blobdiff - mod/events.php
Merge pull request #10332 from annando/calender-download
[friendica.git] / mod / events.php
index 9e75e1d2e764c3c81d63d08a41bf91494dc30986..2bbf4e6a3b10de0422645d97968429d2083ee25a 100644 (file)
@@ -1,24 +1,42 @@
 <?php
 /**
- * @file mod/events.php
- * @brief The events module
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The events module
  */
 
 use Friendica\App;
 use Friendica\Content\Nav;
 use Friendica\Content\Widget\CalendarExport;
 use Friendica\Core\ACL;
-use Friendica\Core\L10n;
 use Friendica\Core\Logger;
+use Friendica\Core\Protocol;
 use Friendica\Core\Renderer;
 use Friendica\Core\Theme;
 use Friendica\Core\Worker;
 use Friendica\Database\DBA;
 use Friendica\DI;
+use Friendica\Model\Conversation;
 use Friendica\Model\Event;
 use Friendica\Model\Item;
-use Friendica\Model\Profile;
+use Friendica\Model\Post;
 use Friendica\Model\User;
+use Friendica\Module\BaseProfile;
 use Friendica\Module\Security\Login;
 use Friendica\Util\DateTimeFormat;
 use Friendica\Util\Strings;
@@ -41,7 +59,7 @@ function events_init(App $a)
                DI::page()['aside'] = '';
        }
 
-       $cal_widget = CalendarExport::getHTML();
+       $cal_widget = CalendarExport::getHTML(local_user());
 
        DI::page()['aside'] .= $cal_widget;
 
@@ -50,9 +68,7 @@ function events_init(App $a)
 
 function events_post(App $a)
 {
-
-       Logger::log('post: ' . print_r($_REQUEST, true), Logger::DATA);
-
+       Logger::debug('post', ['request' => $_REQUEST]);
        if (!local_user()) {
                return;
        }
@@ -67,6 +83,8 @@ function events_post(App $a)
        $adjust   = intval($_POST['adjust'] ?? 0);
        $nofinish = intval($_POST['nofinish'] ?? 0);
 
+       $share = intval($_POST['share'] ?? 0);
+
        // The default setting for the `private` field in event_store() is false, so mirror that
        $private_event = false;
 
@@ -114,65 +132,62 @@ function events_post(App $a)
        ];
 
        $action = ($event_id == '') ? 'new' : 'event/' . $event_id;
-       $onerror_path = 'events/' . $action . '?' . http_build_query($params, null, null, PHP_QUERY_RFC3986);
+       $onerror_path = 'events/' . $action . '?' . http_build_query($params, '', '&', PHP_QUERY_RFC3986);
 
        if (strcmp($finish, $start) < 0 && !$nofinish) {
-               notice(L10n::t('Event can not end before it has started.') . EOL);
+               notice(DI::l10n()->t('Event can not end before it has started.'));
                if (intval($_REQUEST['preview'])) {
-                       echo L10n::t('Event can not end before it has started.');
+                       echo DI::l10n()->t('Event can not end before it has started.');
                        exit();
                }
                DI::baseUrl()->redirect($onerror_path);
        }
 
        if (!$summary || ($start === DBA::NULL_DATETIME)) {
-               notice(L10n::t('Event title and start time are required.') . EOL);
+               notice(DI::l10n()->t('Event title and start time are required.'));
                if (intval($_REQUEST['preview'])) {
-                       echo L10n::t('Event title and start time are required.');
+                       echo DI::l10n()->t('Event title and start time are required.');
                        exit();
                }
                DI::baseUrl()->redirect($onerror_path);
        }
 
-       $share = intval($_POST['share'] ?? 0);
-
-       $c = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
-               intval(local_user())
-       );
-
-       if (DBA::isResult($c)) {
-               $self = $c[0]['id'];
-       } else {
-               $self = 0;
-       }
+       $self = \Friendica\Model\Contact::getPublicIdByUserId($uid);
 
+       $aclFormatter = DI::aclFormatter();
 
        if ($share) {
-
-               $aclFormatter = DI::aclFormatter();
-
-               $str_group_allow   = $aclFormatter->toString($_POST['group_allow'] ?? '');
-               $str_contact_allow = $aclFormatter->toString($_POST['contact_allow'] ?? '');
-               $str_group_deny    = $aclFormatter->toString($_POST['group_deny'] ?? '');
-               $str_contact_deny  = $aclFormatter->toString($_POST['contact_deny'] ?? '');
-
-               // Undo the pseudo-contact of self, since there are real contacts now
-               if (strpos($str_contact_allow, '<' . $self . '>') !== false) {
-                       $str_contact_allow = str_replace('<' . $self . '>', '', $str_contact_allow);
+               $user = User::getById($uid, ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']);
+               if (!DBA::isResult($user)) {
+                       return;
                }
-               // Make sure to set the `private` field as true. This is necessary to
-               // have the posts show up correctly in Diaspora if an event is created
-               // as visible only to self at first, but then edited to display to others.
-               if (strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) {
-                       $private_event = true;
+
+               $str_contact_allow = isset($_REQUEST['contact_allow']) ? $aclFormatter->toString($_REQUEST['contact_allow']) : $user['allow_cid'] ?? '';
+               $str_group_allow   = isset($_REQUEST['group_allow'])   ? $aclFormatter->toString($_REQUEST['group_allow'])   : $user['allow_gid'] ?? '';
+               $str_contact_deny  = isset($_REQUEST['contact_deny'])  ? $aclFormatter->toString($_REQUEST['contact_deny'])  : $user['deny_cid']  ?? '';
+               $str_group_deny    = isset($_REQUEST['group_deny'])    ? $aclFormatter->toString($_REQUEST['group_deny'])    : $user['deny_gid']  ?? '';
+
+               $visibility = $_REQUEST['visibility'] ?? '';
+               if ($visibility === 'public') {
+                       // The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected
+                       $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = '';
+               } else if ($visibility === 'custom') {
+                       // Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL
+                       // case that would make it public. So we always append the author's contact id to the allowed contacts.
+                       // See https://github.com/friendica/friendica/issues/9672
+                       $str_contact_allow .= $aclFormatter->toString($self);
                }
        } else {
-               // Note: do not set `private` field for self-only events. It will
-               // keep even you from seeing them!
-               $str_contact_allow = '<' . $self . '>';
+               $str_contact_allow = $aclFormatter->toString($self);
                $str_group_allow = $str_contact_deny = $str_group_deny = '';
        }
 
+       // Make sure to set the `private` field as true. This is necessary to
+       // have the posts show up correctly in Diaspora if an event is created
+       // as visible only to self at first, but then edited to display to others.
+       if (strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) {
+               $private_event = true;
+       }
 
        $datarray = [];
        $datarray['start']     = $start;
@@ -191,6 +206,9 @@ function events_post(App $a)
        $datarray['deny_gid']  = $str_group_deny;
        $datarray['private']   = $private_event;
        $datarray['id']        = $event_id;
+       $datarray['network']   = Protocol::DFRN;
+       $datarray['protocol']  = Conversation::PARCEL_DIRECT;
+       $datarray['direction'] = Conversation::PUSH;
 
        if (intval($_REQUEST['preview'])) {
                $html = Event::getHTML($datarray);
@@ -198,10 +216,10 @@ function events_post(App $a)
                exit();
        }
 
-       $item_id = Event::store($datarray);
+       $uri_id = Event::store($datarray);
 
        if (!$cid) {
-               Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $item_id);
+               Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, (int)$uri_id, (int)$uid);
        }
 
        DI::baseUrl()->redirect('events');
@@ -210,7 +228,7 @@ function events_post(App $a)
 function events_content(App $a)
 {
        if (!local_user()) {
-               notice(L10n::t('Permission denied.') . EOL);
+               notice(DI::l10n()->t('Permission denied.'));
                return Login::form();
        }
 
@@ -241,6 +259,11 @@ function events_content(App $a)
        // get the translation strings for the callendar
        $i18n = Event::getStrings();
 
+       DI::page()->registerStylesheet('view/asset/fullcalendar/dist/fullcalendar.min.css');
+       DI::page()->registerStylesheet('view/asset/fullcalendar/dist/fullcalendar.print.min.css', 'print');
+       DI::page()->registerFooterScript('view/asset/moment/min/moment-with-locales.min.js');
+       DI::page()->registerFooterScript('view/asset/fullcalendar/dist/fullcalendar.min.js');
+
        $htpl = Renderer::getMarkupTemplate('event_head.tpl');
        DI::page()['htmlhead'] .= Renderer::replaceMacros($htpl, [
                '$module_url' => '/events',
@@ -252,7 +275,7 @@ function events_content(App $a)
        $tabs = '';
        // tabs
        if ($a->theme_events_in_profile) {
-               $tabs = Profile::getTabs($a, 'events', true);
+               $tabs = BaseProfile::getTabsHTML($a, 'events', true);
        }
 
        $mode = 'view';
@@ -391,20 +414,20 @@ function events_content(App $a)
 
                $o = Renderer::replaceMacros($tpl, [
                        '$tabs'      => $tabs,
-                       '$title'     => L10n::t('Events'),
-                       '$view'      => L10n::t('View'),
-                       '$new_event' => [DI::baseUrl() . '/events/new', L10n::t('Create New Event'), '', ''],
-                       '$previous'  => [DI::baseUrl() . '/events/$prevyear/$prevmonth', L10n::t('Previous'), '', ''],
-                       '$next'      => [DI::baseUrl() . '/events/$nextyear/$nextmonth', L10n::t('Next'), '', ''],
+                       '$title'     => DI::l10n()->t('Events'),
+                       '$view'      => DI::l10n()->t('View'),
+                       '$new_event' => [DI::baseUrl() . '/events/new', DI::l10n()->t('Create New Event'), '', ''],
+                       '$previous'  => [DI::baseUrl() . '/events/$prevyear/$prevmonth', DI::l10n()->t('Previous'), '', ''],
+                       '$next'      => [DI::baseUrl() . '/events/$nextyear/$nextmonth', DI::l10n()->t('Next'), '', ''],
                        '$calendar'  => Temporal::getCalendarTable($y, $m, $links, ' eventcal'),
 
                        '$events'    => $events,
 
-                       '$today' => L10n::t('today'),
-                       '$month' => L10n::t('month'),
-                       '$week'  => L10n::t('week'),
-                       '$day'   => L10n::t('day'),
-                       '$list'  => L10n::t('list'),
+                       '$today' => DI::l10n()->t('today'),
+                       '$month' => DI::l10n()->t('month'),
+                       '$week'  => DI::l10n()->t('week'),
+                       '$day'   => DI::l10n()->t('day'),
+                       '$list'  => DI::l10n()->t('list'),
                ]);
 
                if (!empty($_GET['id'])) {
@@ -454,19 +477,19 @@ function events_content(App $a)
                $t_orig = $orig_event['summary']  ?? '';
                $d_orig = $orig_event['desc']     ?? '';
                $l_orig = $orig_event['location'] ?? '';
-               $eid = !empty($orig_event) ? $orig_event['id']  : 0;
-               $cid = !empty($orig_event) ? $orig_event['cid'] : 0;
-               $uri = !empty($orig_event) ? $orig_event['uri'] : '';
+               $eid = $orig_event['id'] ?? 0;
+               $cid = $orig_event['cid'] ?? 0;
+               $uri = $orig_event['uri'] ?? '';
 
                if ($cid || $mode === 'edit') {
                        $share_disabled = 'disabled="disabled"';
                }
 
-               $sdt = !empty($orig_event) ? $orig_event['start']  : 'now';
-               $fdt = !empty($orig_event) ? $orig_event['finish'] : 'now';
+               $sdt = $orig_event['start'] ?? 'now';
+               $fdt = $orig_event['finish'] ?? 'now';
 
                $tz = date_default_timezone_get();
-               if (!empty($orig_event)) {
+               if (isset($orig_event['adjust'])) {
                        $tz = ($orig_event['adjust'] ? date_default_timezone_get() : 'UTC');
                }
 
@@ -505,14 +528,14 @@ function events_content(App $a)
                        '$cid'  => $cid,
                        '$uri'  => $uri,
 
-                       '$title' => L10n::t('Event details'),
-                       '$desc' => L10n::t('Starting date and Title are required.'),
-                       '$s_text' => L10n::t('Event Starts:') . ' <span class="required" title="' . L10n::t('Required') . '">*</span>',
+                       '$title' => DI::l10n()->t('Event details'),
+                       '$desc' => DI::l10n()->t('Starting date and Title are required.'),
+                       '$s_text' => DI::l10n()->t('Event Starts:') . ' <span class="required" title="' . DI::l10n()->t('Required') . '">*</span>',
                        '$s_dsel' => Temporal::getDateTimeField(
                                new DateTime(),
                                DateTime::createFromFormat('Y', intval($syear) + 5),
                                DateTime::createFromFormat('Y-m-d H:i', "$syear-$smonth-$sday $shour:$sminute"),
-                               L10n::t('Event Starts:'),
+                               DI::l10n()->t('Event Starts:'),
                                'start_text',
                                true,
                                true,
@@ -520,39 +543,39 @@ function events_content(App $a)
                                '',
                                true
                        ),
-                       '$n_text' => L10n::t('Finish date/time is not known or not relevant'),
+                       '$n_text' => DI::l10n()->t('Finish date/time is not known or not relevant'),
                        '$n_checked' => $n_checked,
-                       '$f_text' => L10n::t('Event Finishes:'),
+                       '$f_text' => DI::l10n()->t('Event Finishes:'),
                        '$f_dsel' => Temporal::getDateTimeField(
                                new DateTime(),
                                DateTime::createFromFormat('Y', intval($fyear) + 5),
                                DateTime::createFromFormat('Y-m-d H:i', "$fyear-$fmonth-$fday $fhour:$fminute"),
-                               L10n::t('Event Finishes:'),
+                               DI::l10n()->t('Event Finishes:'),
                                'finish_text',
                                true,
                                true,
                                'start_text'
                        ),
-                       '$a_text' => L10n::t('Adjust for viewer timezone'),
+                       '$a_text' => DI::l10n()->t('Adjust for viewer timezone'),
                        '$a_checked' => $a_checked,
-                       '$d_text' => L10n::t('Description:'),
+                       '$d_text' => DI::l10n()->t('Description:'),
                        '$d_orig' => $d_orig,
-                       '$l_text' => L10n::t('Location:'),
+                       '$l_text' => DI::l10n()->t('Location:'),
                        '$l_orig' => $l_orig,
-                       '$t_text' => L10n::t('Title:') . ' <span class="required" title="' . L10n::t('Required') . '">*</span>',
+                       '$t_text' => DI::l10n()->t('Title:') . ' <span class="required" title="' . DI::l10n()->t('Required') . '">*</span>',
                        '$t_orig' => $t_orig,
-                       '$summary' => ['summary', L10n::t('Title:'), $t_orig, '', '*'],
-                       '$sh_text' => L10n::t('Share this event'),
-                       '$share' => ['share', L10n::t('Share this event'), $share_checked, '', $share_disabled],
+                       '$summary' => ['summary', DI::l10n()->t('Title:'), $t_orig, '', '*'],
+                       '$sh_text' => DI::l10n()->t('Share this event'),
+                       '$share' => ['share', DI::l10n()->t('Share this event'), $share_checked, '', $share_disabled],
                        '$sh_checked' => $share_checked,
-                       '$nofinish' => ['nofinish', L10n::t('Finish date/time is not known or not relevant'), $n_checked],
-                       '$adjust' => ['adjust', L10n::t('Adjust for viewer timezone'), $a_checked],
-                       '$preview' => L10n::t('Preview'),
+                       '$nofinish' => ['nofinish', DI::l10n()->t('Finish date/time is not known or not relevant'), $n_checked],
+                       '$adjust' => ['adjust', DI::l10n()->t('Adjust for viewer timezone'), $a_checked],
+                       '$preview' => DI::l10n()->t('Preview'),
                        '$acl' => $acl,
-                       '$submit' => L10n::t('Submit'),
-                       '$basic' => L10n::t('Basic'),
-                       '$advanced' => L10n::t('Advanced'),
-                       '$permissions' => L10n::t('Permissions'),
+                       '$submit' => DI::l10n()->t('Submit'),
+                       '$basic' => DI::l10n()->t('Basic'),
+                       '$advanced' => DI::l10n()->t('Advanced'),
+                       '$permissions' => DI::l10n()->t('Permissions'),
                ]);
 
                return $o;
@@ -567,10 +590,8 @@ function events_content(App $a)
                        Item::deleteForUser(['id' => $ev[0]['itemid']], local_user());
                }
 
-               if (Item::exists(['id' => $ev[0]['itemid']])) {
-                       notice(L10n::t('Failed to remove event') . EOL);
-               } else {
-                       info(L10n::t('Event removed') . EOL);
+               if (Post::exists(['id' => $ev[0]['itemid']])) {
+                       notice(DI::l10n()->t('Failed to remove event'));
                }
 
                DI::baseUrl()->redirect('events');