Skip to content

Commit

Permalink
Merge pull request #940 from nextcloud/public-page
Browse files Browse the repository at this point in the history
Public page for MyMaps
  • Loading branch information
tacruc authored Jan 27, 2023
2 parents 5c38001 + aefc184 commit 6304f1e
Show file tree
Hide file tree
Showing 35 changed files with 2,141 additions and 226 deletions.
35 changes: 32 additions & 3 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,33 @@
['name' => 'page#indexMyMap', 'url' => '/m/{myMapId}', 'verb' => 'GET'],
['name' => 'page#do_echo', 'url' => '/echo', 'verb' => 'POST'],
['name' => 'page#openGeoLink', 'url' => '/openGeoLink/{url}', 'verb' => 'GET'],
['name' => 'public_page#sharedFavoritesCategory', 'url' => '/s/favorites/{token}', 'verb' => 'GET'],
['name' => 'public_favorite_page#sharedFavoritesCategory', 'url' => '/s/favorites/{token}', 'verb' => 'GET'],
['name' => 'PublicPage#showShare', 'url' => '/s/{token}', 'verb' => 'GET'],
['name' => 'PublicPage#showAuthenticate', 'url' => '/s/{token}/authenticate/{redirect}', 'verb' => 'GET'],
['name' => 'PublicPage#authenticate', 'url' => '/s/{token}/authenticate/{redirect}', 'verb' => 'POST'],


// utils
['name' => 'utils#getOptionsValues', 'url' => '/getOptionsValues', 'verb' => 'GET'],
['name' => 'utils#saveOptionValue', 'url' => '/saveOptionValue', 'verb' => 'POST'],
['name' => 'utils#setRoutingSettings', 'url' => '/setRoutingSettings', 'verb' => 'POST'],
['name' => 'utils#getTrafficStyle', 'url' => '/style/traffic', 'verb' => 'GET'],
['name' => 'PublicUtils#getOptionsValues', 'url' => '/s/{token}/getOptionsValues', 'verb' => 'GET'],
['name' => 'PublicUtils#saveOptionValue', 'url' => '/s/{token}/saveOptionValue', 'verb' => 'POST'],
['name' => 'PublicUtils#setRoutingSettings', 'url' => '/s/{token}/setRoutingSettings', 'verb' => 'POST'],
['name' => 'PublicUtils#getTrafficStyle', 'url' => '/s/{token}/style/traffic', 'verb' => 'GET'],

// photos
['name' => 'photos#getPhotosFromDb', 'url' => '/photos', 'verb' => 'GET'],
['name' => 'photos#getNonLocalizedPhotosFromDb', 'url' => '/photos/nonlocalized', 'verb' => 'GET'],
['name' => 'photos#getPhotos', 'url' => '/photos', 'verb' => 'GET'],
['name' => 'photos#getNonLocalizedPhotos', 'url' => '/photos/nonlocalized', 'verb' => 'GET'],
['name' => 'photos#placePhotos', 'url' => '/photos', 'verb' => 'POST'],
['name' => 'photos#resetPhotosCoords', 'url' => '/photos', 'verb' => 'DELETE'],
['name' => 'photos#clearCache', 'url' => '/photos/clearCache', 'verb' => 'GET'],

['name' => 'PublicPhotos#getPhotos', 'url' => '/s/{token}/photos', 'verb' => 'GET'],
['name' => 'PublicPhotos#getNonLocalizedPhotos', 'url' => '/s/{token}/photos/nonlocalized', 'verb' => 'GET'],
['name' => 'PublicPhotos#clearCache', 'url' => '/s/{token}/photos/clearCache', 'verb' => 'GET'],

// contacts
['name' => 'contacts#getContacts', 'url' => '/contacts', 'verb' => 'GET'],
['name' => 'contacts#searchContacts', 'url' => '/contacts-search', 'verb' => 'GET'],
Expand All @@ -37,6 +48,9 @@
['name' => 'contacts#deleteContactAddress', 'url' => '/contacts/{bookid}/{uri}', 'verb' => 'DELETE'],
['name' => 'contacts#getContactLetterAvatar', 'url' => '/contacts-avatar', 'verb' => 'GET'],

['name' => 'PublicContacts#getContacts', 'url' => '/s/{token}/contacts', 'verb' => 'GET'],
['name' => 'PublicContacts#getContactLetterAvatar', 'url' => '/s/{token}/contacts-avatar', 'verb' => 'GET'],

// routing
['name' => 'routing#exportRoute', 'url' => '/exportRoute', 'verb' => 'POST'],

Expand Down Expand Up @@ -72,6 +86,13 @@
['name' => 'favorites#deleteFavorite', 'url' => '/favorites/{id}', 'verb' => 'DELETE'],
['name' => 'favorites#deleteFavorites', 'url' => '/favorites', 'verb' => 'DELETE'],

['name' => 'PublicFavorites#getFavorites', 'url' => '/s/{token}/favorites', 'verb' => 'GET'],
['name' => 'PublicFavorites#addFavorite', 'url' => '/s/{token}/favorite', 'verb' => 'POST'],
['name' => 'PublicFavorites#addFavorites', 'url' => '/s/{token}/favorites', 'verb' => 'POST'],
['name' => 'PublicFavorites#editFavorite', 'url' => '/s/{token}/favorites/{id}', 'verb' => 'PUT'],
['name' => 'PublicFavorites#deleteFavorite', 'url' => '/s/{token}/favorites/{id}', 'verb' => 'DELETE'],
['name' => 'PublicFavorites#deleteFavorites', 'url' => '/s/{token}/favorites', 'verb' => 'DELETE'],

// favorite categories
['name' => 'favorites#renameCategories', 'url' => '/favorites-category', 'verb' => 'PUT'],
['name' => 'favorites#getSharedCategories', 'url' => '/favorites-category/shared', 'verb' => 'GET'],
Expand All @@ -83,12 +104,20 @@
['name' => 'favorites#exportFavorites', 'url' => '/export/favorites', 'verb' => 'POST'],
['name' => 'favorites#importFavorites', 'url' => '/import/favorites', 'verb' => 'POST'],

['name' => 'PublicFavorites#renameCategories', 'url' => '/s/{token}/favorites-category', 'verb' => 'PUT'],
['name' => 'PublicFavorites#getSharedCategories', 'url' => '/s/{token}/favorites-category/shared', 'verb' => 'GET'],

// tracks
['name' => 'tracks#getTracks', 'url' => '/tracks', 'verb' => 'GET'],
['name' => 'tracks#getTrackFileContent', 'url' => '/tracks/{id}', 'verb' => 'GET'],
['name' => 'tracks#getTrackContentByFileId', 'url' => '/tracks/file/{id}', 'verb' => 'GET'],
['name' => 'tracks#editTrack', 'url' => '/tracks/{id}', 'verb' => 'PUT'],

['name' => 'PublicTracks#getTracks', 'url' => '/s/{token}/tracks', 'verb' => 'GET'],
['name' => 'PublicTracks#getTrackFileContent', 'url' => '/s/{token}/tracks/{id}', 'verb' => 'GET'],
['name' => 'PublicTracks#getTrackContentByFileId', 'url' => '/s/{token}/tracks/file/{id}', 'verb' => 'GET'],
['name' => 'PublicTracks#editTrack', 'url' => '/s/{token}/tracks/{id}', 'verb' => 'PUT'],

// devices API
[
'name' => 'devices_api#preflighted_cors',
Expand Down
12 changes: 6 additions & 6 deletions lib/Controller/PhotosController.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ public function __construct($AppName,
* @NoCSRFRequired
* @return DataResponse
*/
public function getPhotosFromDb($myMapId=null): DataResponse {
public function getPhotos($myMapId=null): DataResponse {
$userFolder = $this->root->getUserFolder($this->userId);
if (is_null($myMapId) || $myMapId === "") {
$result = $this->geophotoService->getAllFromDB($this->userId, $userFolder);
$result = $this->geophotoService->getAll($this->userId, $userFolder);
} else {
$folders = $userFolder->getById($myMapId);
$folder = array_shift($folders);
$result = $this->geophotoService->getAllFromDB($this->userId, $folder, true, false);
$result = $this->geophotoService->getAll($this->userId, $folder, true, false);
}
return new DataResponse($result);
}
Expand All @@ -66,14 +66,14 @@ public function getPhotosFromDb($myMapId=null): DataResponse {
* @NoCSRFRequired
* @return DataResponse
*/
public function getNonLocalizedPhotosFromDb($myMapId=null): DataResponse {
public function getNonLocalizedPhotos($myMapId=null): DataResponse {
$userFolder = $this->root->getUserFolder($this->userId);
if (is_null($myMapId) || $myMapId === "") {
$result = $this->geophotoService->getNonLocalizedFromDB($this->userId, $userFolder);
$result = $this->geophotoService->getNonLocalized($this->userId, $userFolder);
} else {
$folders = $userFolder->getById($myMapId);
$folder = array_shift($folders);
$result = $this->geophotoService->getNonLocalizedFromDB($this->userId, $folder, true, false);
$result = $this->geophotoService->getNonLocalized($this->userId, $folder, true, false);
}
return new DataResponse($result);
}
Expand Down
281 changes: 281 additions & 0 deletions lib/Controller/PublicContactsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
<?php

/**
* Nextcloud - maps
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Julien Veyssier <eneiluj@posteo.net>
* @copyright Julien Veyssier 2019
*/

namespace OCA\Maps\Controller;

use OC\Files\Node\Node;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\IConfig;
use OCP\IInitialStateService;
use OCP\IRequest;
use OCP\IAvatarManager;
use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\AppFramework\Http\DataResponse;
use OCP\IDBConnection;
use OCP\AppFramework\Controller;
use OCP\Contacts\IManager;
use OCA\Maps\Service\AddressService;
use \OCP\DB\QueryBuilder\IQueryBuilder;
use \OCA\DAV\CardDAV\CardDavBackend;
use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager as ShareManager;
use \Sabre\VObject\Property\Text;
use \Sabre\VObject\Reader;

class PublicContactsController extends PublicPageController {
protected IManager $contactsManager;
protected AddressService $addressService;
protected IQueryBuilder $qb;
protected CardDavBackend $cdBackend;
protected IAvatarManager $avatarManager;
protected IRootFolder $root;

/**
* @param $appName
* @param IRequest $request
* @param IEventDispatcher $eventDispatcher
* @param IConfig $config
* @param IInitialStateService $initialStateService
* @param IURLGenerator $urlGenerator
* @param ShareManager $shareManager
* @param IUserManager $userManager
* @param ISession $session
* @param IDBConnection $dbconnection
* @param IManager $contactsManager
* @param AddressService $addressService
* @param CardDavBackend $cdBackend
* @param IAvatarManager $avatarManager
* @param IRootFolder $root
*/
public function __construct($appName,
IRequest $request,
IEventDispatcher $eventDispatcher,
IConfig $config,
IInitialStateService $initialStateService,
IURLGenerator $urlGenerator,
ShareManager $shareManager,
IUserManager $userManager,
ISession $session,
IManager $contactsManager,
IDBConnection $dbconnection,
AddressService $addressService,
CardDavBackend $cdBackend,
IAvatarManager $avatarManager,
IRootFolder $root){
parent::__construct($appName, $request, $eventDispatcher, $config, $initialStateService, $urlGenerator, $shareManager, $userManager, $session);
$this->avatarManager = $avatarManager;
$this->contactsManager = $contactsManager;
$this->addressService = $addressService;
$this->qb = $dbconnection->getQueryBuilder();
$this->cdBackend = $cdBackend;
$this->root = $root;
}

/**
* Validate the permissions of the share
*
* @param Share\IShare $share
* @return bool
*/
private function validateShare(\OCP\Share\IShare $share) {
// If the owner is disabled no access to the link is granted
$owner = $this->userManager->get($share->getShareOwner());
if ($owner === null || !$owner->isEnabled()) {
return false;
}

// If the initiator of the share is disabled no access is granted
$initiator = $this->userManager->get($share->getSharedBy());
if ($initiator === null || !$initiator->isEnabled()) {
return false;
}

return $share->getNode()->isReadable() && $share->getNode()->isShareable();
}

/**
* @return \OCP\Share\IShare
* @throws NotFoundException
*/
private function getShare() {
// Check whether share exists
try {
$share = $this->shareManager->getShareByToken($this->getToken());
} catch (ShareNotFound $e) {
// The share does not exists, we do not emit an ShareLinkAccessedEvent
throw new NotFoundException();
}

if (!$this->validateShare($share)) {
throw new NotFoundException();
}
return $share;
}

/**
* @return \OCP\Files\File|\OCP\Files\Folder
* @throws NotFoundException
*/
private function getShareNode() {
\OC_User::setIncognitoMode(true);

$share = $this->getShare();

return $share->getNode();
}

/**
* @PublicPage
*
* @return DataResponse
* @throws NotFoundException
* @throws NotPermittedException
* @throws \OCP\Files\InvalidPathException
*/
public function getContacts(): DataResponse {
$share = $this->getShare();
$permissions = $share->getPermissions();
$folder = $this->getShareNode();
$isReadable = (bool) ($permissions & (1 << 0));
if ($isReadable) {
//Fixme add contacts for my-maps
$result = [];
$files = $folder->search('.vcf');
foreach ($files as $file) {
// $cards = explode("END:VCARD\r\n", $file->getContent());
$cards = [$file->getContent()];
foreach ($cards as $card) {
$vcard = Reader::read($card."END:VCARD\r\n");
if (isset($vcard->GEO)) {
$geo = $vcard->GEO;
if (is_string($geo->getValue()) && strlen($geo->getValue()) > 1) {
$result[] = $this->vCardToArray($permissions, $file, $vcard, $geo->getValue());
} elseif (is_countable($geo) && count($geo)>0 && is_iterable($geo)) {
foreach ($geo as $g) {
if (strlen($g->getValue()) > 1) {
$result[] = $this->vCardToArray($permissions, $file, $vcard, $g->getValue());
}
}
}
}
if (isset($vcard->ADR) && count($vcard->ADR) > 0) {
foreach ($vcard->ADR as $adr) {
$geo = $this->addressService->addressToGeo($adr->getValue(), $file->getId());
//var_dump($adr->parameters()['TYPE']->getValue());
$adrtype = '';
if (isset($adr->parameters()['TYPE'])) {
$adrtype = $adr->parameters()['TYPE']->getValue();
}
if (is_string($geo) && strlen($geo) > 1) {
$result[] = $this->vCardToArray($permissions, $file, $vcard, $geo, $adrtype, $adr->getValue(), $file->getId());
}
}
}
}
}
return new DataResponse($result);
} else {
throw new NotPermittedException();
}
}

/**
* @param int $sharePermissions
* @param Node $file
* @param \Sabre\VObject\Document $vcard
* @param string $geo
* @param string|null $adrtype
* @param string|null $adr
* @param int|null $fileId
* @return array
* @throws NotFoundException
* @throws \OCP\Files\InvalidPathException
*/
private function vCardToArray(int $sharePermissions, Node $file, \Sabre\VObject\Document $vcard, string $geo, ?string $adrtype=null, ?string $adr=null, ?int $fileId = null): array {
$FNArray = $vcard->FN ? $vcard->FN->getJsonValue() : [];
$fn = array_shift($FNArray);
$NArray = $vcard->N ? $vcard->N->getJsonValue() : [];
$n = array_shift($NArray);
if (!is_null($n)) {
if (is_array($n)) {
$n = $this->N2FN(array_shift($n));
} elseif (is_string($n)) {
$n = $this->N2FN($n);
}

}
$UIDArray = $vcard->UID->getJsonValue();
$uid = array_shift($UIDArray);
$groups = $vcard->CATEGORIES;
if (!is_null($groups)) {
$groups = $groups->getValue();
} else {
$groups = '';
}
$result = [
'FN' => $fn ?? $n ?? '???',
'UID' => $uid,
'HAS_PHOTO' => (isset($vcard->PHOTO) && $vcard->PHOTO !== null),
'FILEID' => $fileId,
'ADR' => $adr ?? '',
'ADRTYPE' => $adrtype ?? '',
'PHOTO' => $vcard->PHOTO ?? '',
'GEO' => $geo,
'GROUPS' => $groups,
'isReadable' => $file->isReadable() && ($sharePermissions & (1 << 0)),
'isDeletable' => $file->isDeletable() && ($sharePermissions & (1 << 1)),
'isUpdateable' => $file->isUpdateable() && ($sharePermissions & (1 << 3)),
];
return $result;
}

/**
* @param string $n
* @return string|null
*/
private function N2FN(string $n): ?string {
if ($n) {
$spl = explode($n, ';');
if (count($spl) >= 4) {
return $spl[3] . ' ' . $spl[1] . ' ' . $spl[0];
}
else {
return null;
}
}
else {
return null;
}
}


/**
* @PublicPage
* @NoCSRFRequired
*
* @param string $name
* @return DataDisplayResponse
* @throws NotFoundException
* @throws NotPermittedException
*/
public function getContactLetterAvatar(string $name): DataDisplayResponse {
$av = $this->avatarManager->getGuestAvatar($name);
$avatarContent = $av->getFile(64)->getContent();
return new DataDisplayResponse($avatarContent);
}
}
Loading

0 comments on commit 6304f1e

Please sign in to comment.