1
0
Fork 0

Add new public_calendar additional feature

- This gives anonymous access to public events
This commit is contained in:
Hypolite Petovan 2022-11-30 17:52:19 -05:00
parent ae76fa1174
commit 84b2a35e05
6 changed files with 169 additions and 162 deletions

View file

@ -120,6 +120,12 @@ class Feature
['tagadelic', DI::l10n()->t('Tag Cloud'), DI::l10n()->t('Provide a personal tag cloud on your profile page'), false, DI::config()->get('feature_lock', 'tagadelic', false)],
['profile_membersince', DI::l10n()->t('Display Membership Date'), DI::l10n()->t('Display membership date in profile'), false, DI::config()->get('feature_lock', 'profile_membersince', false)],
],
//Advanced Calendar Settings
'advanced_calendar' => [
DI::l10n()->t('Advanced Calendar Settings'),
['public_calendar', DI::l10n()->t('Allow anonymous access to your calendar'), DI::l10n()->t('Allows anonymous visitors to consult your calendar and your public events. Contact birthday events are private to you.'), false, DI::config()->get('feature_lock', 'public_calendar', false)],
]
];
// removed any locked features and remove the entire category if this makes it empty

View file

@ -21,6 +21,7 @@
namespace Friendica\Model;
use Friendica\Content\Feature;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
@ -28,8 +29,7 @@ use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Network\HTTPException\UnauthorizedException;
use Friendica\Network\HTTPException;
use Friendica\Protocol\Activity;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Map;
@ -503,25 +503,30 @@ class Event
* @param string $nickname
*
* @return array the owner array
* @throws NotFoundException The given nickname does not exist
* @throws UnauthorizedException The access for the given nickname is restricted
* @throws HTTPException\InternalServerErrorException
* @throws HTTPException\NotFoundException The given nickname does not exist
* @throws HTTPException\UnauthorizedException The access for the given nickname is restricted
*/
public static function getOwnerForNickname(string $nickname): array
{
$owner = User::getOwnerDataByNick($nickname);
if (empty($owner) || $owner['account_removed'] || $owner['account_expired']) {
throw new NotFoundException(DI::l10n()->t('User not found.'));
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
}
if ($owner['hidewall'] && !DI::userSession()->isAuthenticated()) {
throw new UnauthorizedException(DI::l10n()->t('Access to this profile has been restricted.'));
if (!DI::userSession()->isAuthenticated() && $owner['hidewall']) {
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Access to this profile has been restricted.'));
}
if (!DI::userSession()->isAuthenticated() && !Feature::isEnabled($owner['uid'], 'public_calendar')) {
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Permission denied.'));
}
return $owner;
}
/**
* Get an event by its event ID.
* Get an event by its event ID. Checks permissions.
*
* @param int $owner_uid The User ID of the owner of the event
* @param int $event_id The ID of the event in the event table
@ -529,37 +534,32 @@ class Event
* @return array Query result
* @throws \Exception
*/
public static function getByIdAndUid(int $owner_uid, int $event_id, string $nickname = null): array
public static function getByIdAndUid(int $owner_uid, int $event_id): array
{
if (!empty($nickname)) {
$owner = static::getOwnerForNickname($nickname);
$owner_uid = $owner['uid'];
// get the permissions
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
// we only want to have the events of the profile owner
$sql_extra = " AND `event`.`cid` = 0 " . $sql_perms;
} else {
$sql_extra = "";
}
// Only allow events if there is a valid owner_id.
if ($owner_uid == 0) {
return [];
}
// Query for the event by event id
$events = DBA::toArray(DBA::p("SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
LEFT JOIN `post-user` ON `post-user`.`event-id` = `event`.`id` AND `post-user`.`uid` = `event`.`uid`
WHERE `event`.`uid` = ? AND `event`.`id` = ? $sql_extra",
$owner_uid, $event_id));
// get the permissions
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
// Query for the event by event id
$events = DBA::toArray(DBA::p(
"SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
LEFT JOIN `post-user`
ON `post-user`.`event-id` = `event`.`id`
AND `post-user`.`uid` = `event`.`uid`
WHERE `event`.`id` = ?
AND `event`.`uid` = ?
$sql_perms",
$event_id, $owner_uid
));
if (empty($events)) {
throw new NotFoundException(DI::l10n()->t('Event not found.'));
} else {
$events = self::removeDuplicates($events);
return $events[0];
throw new HTTPException\NotFoundException(DI::l10n()->t('Event not found.'));
}
return $events[0];
}
/**
@ -568,34 +568,23 @@ class Event
* @param int $owner_uid The User ID of the owner of the events.
* @param string|null $start Start time of the timeframe.
* @param string|null $finish Finish time of the timeframe.
* @param bool $ignore
* @param string|null $nickname
* @param bool|null $ignore Filters ignored events (false: unignored events, true: ignored events, null: all events)
*
* @return array Query results.
* @throws NotFoundException
* @throws UnauthorizedException
* @throws HTTPException\NotFoundException
* @throws HTTPException\UnauthorizedException
*/
public static function getListByDate(int $owner_uid, string $start = null, string $finish = null, bool $ignore = false, string $nickname = null): array
public static function getListByDate(int $owner_uid, string $start = null, string $finish = null, ?bool $ignore = false): array
{
if (!empty($nickname)) {
$owner = static::getOwnerForNickname($nickname);
$owner_uid = $owner['uid'];
// get the permissions
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
// we only want to have the events of the profile owner
$sql_extra = " AND `event`.`cid` = 0 " . $sql_perms;
} else {
$sql_extra = "";
}
// Only allow events if there is a valid owner_id.
if ($owner_uid == 0) {
return [];
}
if (empty($start) || empty($finish)) {
// get the permissions
$sql_perms = Item::getPermissionsSQLByUserId($owner_uid);
if (empty($start) || empty($finish)) {
$y = intval(DateTimeFormat::localNow('Y'));
$m = intval(DateTimeFormat::localNow('m'));
@ -607,41 +596,36 @@ class Event
}
}
if ($ignore === true) {
$sql_ignore = " AND `event`.`ignore` = 1";
} elseif ($ignore === false) {
$sql_ignore = " AND `event`.`ignore` = 0";
} else {
$sql_ignore = "";
}
// Query for the event by date.
$events = DBA::toArray(DBA::p("SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
LEFT JOIN `post-user` ON `post-user`.`event-id` = `event`.`id` AND `post-user`.`uid` = `event`.`uid`
WHERE `event`.`uid` = ? AND `event`.`ignore` = ?
AND (`finish` >= ? OR (`nofinish` AND `start` >= ?)) AND `start` <= ?
" . $sql_extra,
$owner_uid, $ignore,
$start, $start, $finish
$events = DBA::toArray(DBA::p(
"SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event`
LEFT JOIN `post-user`
ON `post-user`.`event-id` = `event`.`id`
AND `post-user`.`uid` = `event`.`uid`
WHERE `event`.`uid` = ?
$sql_ignore
AND (`finish` >= ? OR (`nofinish` AND `start` >= ?))
AND `start` <= ?
$sql_perms",
$owner_uid,
$start, $start,
$finish
));
$events = self::removeDuplicates($events ?? []);
$events = self::removeDuplicates($events);
return self::sortByDate($events);
}
/**
* Convert an array query results in an array which could be used by the events template.
*
* @param array $event_result Event query array.
* @return array Event array for the template.
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function prepareListForTemplate(array $event_result): array
{
$event_list = [];
foreach ($event_result as $event) {
$event_list[] = static::prepareForItem($event);
}
return $event_list;
}
/**
* Convert an one event in an array which could be used by the events template.
* Convert an event in an array which could be used by the event template.
*
* @param array $event Event query array.
* @return array Event array for the template.
@ -687,11 +671,7 @@ class Event
[$title, $_trash] = explode("<br", BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['desc'])), BBCode::TWITTER_API);
}
$author_link = $event['author-link'];
$event['author-link'] = Contact::magicLink($author_link);
$html = self::getHTML($event);
$event['author-link'] = Contact::magicLink($event['author-link']);
$event['summary'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['summary']));
$event['desc'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['desc']));
$event['location'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['location']));
@ -708,7 +688,7 @@ class Event
'drop' => $drop,
'copy' => $copy,
'item' => $event,
'html' => $html,
'html' => self::getHTML($event),
'plink' => Item::getPlink($event),
];
}
@ -718,8 +698,6 @@ class Event
*
* @param array $events Query result for events.
* @param string $format The output format (ical/csv).
*
* @param string $timezone Timezone (missing parameter!)
* @return string Content according to selected export format.
*
* @todo Implement timezone support

View file

@ -23,9 +23,11 @@ namespace Friendica\Module;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Content\Feature;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\User;
class BaseProfile extends BaseModule
{
@ -87,9 +89,9 @@ class BaseProfile extends BaseModule
'id' => 'calendar-tab',
'accesskey' => 'c',
];
// if the user is not the owner of the calendar we only show a calendar
// with the public events of the calendar owner
} else {
$owner = User::getByNickname($nickname, ['uid']);
if(DI::userSession()->isAuthenticated() || $owner && Feature::isEnabled($owner['uid'], 'public_calendar')) {
$tabs[] = [
'label' => DI::l10n()->t('Calendar'),
'url' => DI::baseUrl() . '/calendar/show/' . $nickname,
@ -99,6 +101,7 @@ class BaseProfile extends BaseModule
'accesskey' => 'c',
];
}
}
if ($is_owner) {
$tabs[] = [

View file

@ -22,12 +22,14 @@
namespace Friendica\Module\Calendar\Event;
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\L10n;
use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\System;
use Friendica\Model\Event;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Model\User;
use Friendica\Module\Response;
use Friendica\Network\HTTPException;
use Friendica\Util\DateTimeFormat;
@ -43,24 +45,27 @@ class Get extends \Friendica\BaseModule
/** @var IHandleUserSessions */
protected $session;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, array $server, array $parameters = [])
public function __construct(App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->session = $session;
$this->app = $app;
}
protected function rawContent(array $request = [])
{
if (!$this->session->getLocalUserId()) {
$nickname = $this->parameters['nickname'] ?? $this->app->getLoggedInUserNickname();
if (!$nickname) {
throw new HTTPException\UnauthorizedException();
}
// get events by id or by date
$owner = Event::getOwnerForNickname($nickname);
if (!empty($request['id'])) {
$events = [Event::getByIdAndUid($this->session->getLocalUserId(), $request['id'], $this->parameters['nickname'] ?? null)];
$events = [Event::getByIdAndUid($owner['uid'], $request['id'])];
} else {
$events = Event::getListByDate($this->session->getLocalUserId(), $request['start'] ?? '', $request['end'] ?? '', false, $this->parameters['nickname'] ?? null);
$events = Event::getListByDate($owner['uid'], $request['start'] ?? '', $request['end'] ?? '');
}
System::jsonExit($events ? self::map($events) : []);

View file

@ -23,11 +23,13 @@ namespace Friendica\Module\Calendar\Event;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Content\Feature;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\System;
use Friendica\Model\Event;
use Friendica\Model\User;
use Friendica\Module\Response;
use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
@ -40,22 +42,27 @@ class Show extends BaseModule
{
/** @var IHandleUserSessions */
protected $session;
/** @var App */
private $app;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, array $server, array $parameters = [])
public function __construct(App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->session = $session;
$this->app = $app;
}
protected function rawContent(array $request = [])
{
if (!$this->session->getLocalUserId()) {
throw new HTTPException\UnauthorizedException($this->t('Permission denied.'));
$nickname = $this->parameters['nickname'] ?? $this->app->getLoggedInUserNickname();
if (!$nickname) {
throw new HTTPException\UnauthorizedException();
}
$event = Event::getByIdAndUid($this->session->getLocalUserId(), (int)$this->parameters['id'] ?? 0, $this->parameters['nickname'] ?? '');
$owner = Event::getOwnerForNickname($nickname);
$event = Event::getByIdAndUid($owner['uid'], (int)$this->parameters['id'] ?? 0);
if (empty($event)) {
throw new HTTPException\NotFoundException($this->t('Event not found.'));
}

View file

@ -23,6 +23,7 @@ namespace Friendica\Module\Calendar;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Content\Feature;
use Friendica\Content\Nav;
use Friendica\Content\Widget;
use Friendica\Core\L10n;
@ -30,9 +31,11 @@ use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\Theme;
use Friendica\Model\Event;
use Friendica\Model\User;
use Friendica\Module\BaseProfile;
use Friendica\Module\Response;
use Friendica\Module\Security\Login;
use Friendica\Network\HTTPException;
use Friendica\Navigation\SystemMessages;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
@ -60,7 +63,21 @@ class Show extends BaseModule
protected function content(array $request = []): string
{
if (!$this->session->getLocalUserId()) {
$nickname = $this->parameters['nickname'] ?? $this->app->getLoggedInUserNickname();
if (!$nickname) {
throw new HTTPException\UnauthorizedException();
}
$owner = User::getOwnerDataByNick($nickname);
if (!$owner || $owner['account_expired'] || $owner['account_removed']) {
throw new HTTPException\NotFoundException($this->t('User not found.'));
}
if (!$this->session->isAuthenticated() && $owner['hidewall']) {
$this->baseUrl->redirect('profile/' . $nickname . '/restricted');
}
if (!$this->session->isAuthenticated() && !Feature::isEnabled($owner['uid'], 'public_calendar')) {
$this->sysMessages->addNotice($this->t('Permission denied.'));
return Login::form();
}
@ -73,35 +90,26 @@ class Show extends BaseModule
$this->page->registerFooterScript('view/asset/moment/min/moment-with-locales.min.js');
$this->page->registerFooterScript('view/asset/fullcalendar/dist/fullcalendar.min.js');
$htpl = Renderer::getMarkupTemplate('calendar/calendar_head.tpl');
$is_owner = $nickname == $this->app->getLoggedInUserNickname();
$htpl = Renderer::getMarkupTemplate('calendar/calendar_head.tpl');
$this->page['htmlhead'] .= Renderer::replaceMacros($htpl, [
'$calendar_api' => 'calendar/api/get' . (!empty($this->parameters['nickname']) ? '/' . $this->parameters['nickname'] : ''),
'$event_api' => 'calendar/event/show' . (!empty($this->parameters['nickname']) ? '/' . $this->parameters['nickname'] : ''),
'$calendar_api' => 'calendar/api/get' . ($is_owner ? '' : '/' . $nickname),
'$event_api' => 'calendar/event/show' . ($is_owner ? '' : '/' . $nickname),
'$modparams' => 2,
'$i18n' => $i18n,
]);
$tabs = '';
if (empty($this->parameters['nickname'])) {
Nav::setSelected('home');
$tabs = BaseProfile::getTabsHTML($this->app, 'calendar', true, $this->app->getLoggedInUserNickname(), false);
$this->page['aside'] .= Widget\CalendarExport::getHTML($this->session->getLocalUserId());
} else {
$owner = Event::getOwnerForNickname($this->parameters['nickname']);
Nav::setSelected('calendar');
// get the tab navigation bar
$tabs = BaseProfile::getTabsHTML($this->app, 'calendar', false, $owner['nickname'], $owner['hide-friends']);
Nav::setSelected($is_owner ? 'home' : 'calendar');
if (!$is_owner) {
$this->page['aside'] .= Widget\VCard::getHTML($owner);
$this->page['aside'] .= Widget\CalendarExport::getHTML($owner['uid']);
}
$this->page['aside'] .= Widget\CalendarExport::getHTML($owner['uid']);
$tabs = BaseProfile::getTabsHTML('calendar', $is_owner, $nickname, !$is_owner && $owner['hide-friends']);
// ACL blocks are loaded in modals in frio
$this->page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
$this->page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));