Skip to content

Commit

Permalink
fixup! feat: allow inviting contact groups
Browse files Browse the repository at this point in the history
  • Loading branch information
miaulalala committed Oct 9, 2024
1 parent 87da5c2 commit f464833
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 115 deletions.
2 changes: 2 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
['name' => 'contact#searchPhoto', 'url' => '/v1/autocompletion/photo', 'verb' => 'POST'],
// Circles
['name' => 'contact#getCircleMembers', 'url' => '/v1/circles/getmembers', 'verb' => 'GET'],
// Contact Groups
['name' => 'contact#getContactGroupMembers', 'url' => '/v1/autocompletion/groupmembers', 'verb' => 'POST'],
// Settings
['name' => 'settings#setConfig', 'url' => '/v1/config/{key}', 'verb' => 'POST'],
// Tools
Expand Down
173 changes: 72 additions & 101 deletions lib/Controller/ContactController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
*/
namespace OCA\Calendar\Controller;

use Exception;
use OCA\Calendar\Service\ContactsService;
use OCA\Calendar\Service\ServiceException;
use OCA\Circles\Exceptions\CircleNotFoundException;
use OCP\App\IAppManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\QueryException;
use OCP\Contacts\IManager;
Expand All @@ -24,31 +27,21 @@
* @package OCA\Calendar\Controller
*/
class ContactController extends Controller {
/** @var IManager */
private $contactsManager;

/** @var IAppManager */
private $appManager;

/** @var IUserManager */
private $userManager;

/**
* ContactController constructor.
*
* @param string $appName
* @param IRequest $request
* @param IManager $contacts
*/
public function __construct(string $appName,
public function __construct(
string $appName,
IRequest $request,
IManager $contacts,
IAppManager $appManager,
IUserManager $userManager) {
private IManager $contactsManager,
private IAppManager $appManager,
private IUserManager $userManager,
private ContactsService $contactsService,
) {
parent::__construct($appName, $request);
$this->contactsManager = $contacts;
$this->appManager = $appManager;
$this->userManager = $userManager;
}

/**
Expand All @@ -59,7 +52,7 @@ public function __construct(string $appName,
*
* @NoAdminRequired
*/
public function searchLocation(string $search):JSONResponse {
public function searchLocation(string $search): JSONResponse {
if (!$this->contactsManager->isEnabled()) {
return new JSONResponse();
}
Expand All @@ -69,23 +62,20 @@ public function searchLocation(string $search):JSONResponse {
$contacts = [];
foreach ($result as $r) {
// Information about system users is fetched via DAV nowadays
if (isset($r['isLocalSystemBook']) && $r['isLocalSystemBook']) {
if ($this->contactsService->isSystemBook($r)) {
continue;
}

if (!isset($r['ADR'])) {
continue;
}

$name = $this->getNameFromContact($r);
$name = $this->contactsService->getNameFromContact($r);
$photo = $this->contactsService->getPhotoUri($r);

if (\is_string($r['ADR'])) {
$r['ADR'] = [$r['ADR']];
}

$photo = isset($r['PHOTO'])
? $this->getPhotoUri($r['PHOTO'])
: null;

$addresses = [];
foreach ($r['ADR'] as $address) {
$addresses[] = trim(preg_replace("/\n+/", "\n", str_replace(';', "\n", $address)));
Expand Down Expand Up @@ -115,60 +105,72 @@ public function searchAttendee(string $search):JSONResponse {
return new JSONResponse();
}

$result = $this->contactsManager->search($search, ['FN', 'EMAIL', 'CATEGORIES']);
$result = $this->contactsManager->search($search, ['FN', 'EMAIL']);

$contacts = [];
foreach ($result as $r) {
// Information about system users is fetched via DAV nowadays
if (isset($r['isLocalSystemBook']) && $r['isLocalSystemBook']) {
if (!$this->contactsService->hasEmail($r) || $this->contactsService->isSystemBook($r)) {
continue;
}
$name = $this->contactsService->getNameFromContact($r);
$email = $this->contactsService->getEmail($r);
$photo = $this->contactsService->getPhotoUri($r);
$timezoneId = $this->contactsService->getTimezoneId($r);
$lang = $this->contactsService->getLanguageId($r);
$contacts[] = [
'name' => $name,
'emails' => $email,
'lang' => $lang,
'tzid' => $timezoneId,
'photo' => $photo,
'type' => 'individual'
];
}

$groups = $this->contactsManager->search($search, ['CATEGORIES']);
$filtered = $this->contactsService->filterGroupsWithCount($groups, $search);
foreach ($filtered as $groupName => $count) {
$contacts[] = [
'name' => $groupName,
'emails' => ['mailto:group+' . urlencode($groupName) . '@group'],
'lang' => '',
'tzid' => '',
'photo' => '',
'type' => 'contactsgroup',
'members' => $count,
];
}

if (!isset($r['EMAIL'])) {
continue;
}

$name = $this->getNameFromContact($r);
if (\is_string($r['EMAIL'])) {
$r['EMAIL'] = [$r['EMAIL']];
}

if(isset($r['CATEGORIES'])) {
$categories = explode(',', $r['CATEGORIES']);
}

$photo = isset($r['PHOTO'])
? $this->getPhotoUri($r['PHOTO'])
: null;
return new JSONResponse($contacts);
}

$lang = null;
if (isset($r['LANG'])) {
if (\is_array($r['LANG'])) {
$lang = $r['LANG'][0];
} else {
$lang = $r['LANG'];
}
}
#[NoAdminRequired]
public function getContactGroupMembers(string $groupName): JSONResponse {
if (!$this->contactsManager->isEnabled()) {
return new JSONResponse();
}

$timezoneId = null;
if (isset($r['TZ'])) {
if (\is_array($r['TZ'])) {
$timezoneId = $r['TZ'][0];
} else {
$timezoneId = $r['TZ'];
}
$groupmembers = $this->contactsManager->search($groupName, ['CATEGORIES'], ['strict_search' => true]);
$contacts = [];
foreach ($groupmembers as $r) {
if (!$this->contactsService->hasEmail($r) || $this->contactsService->isSystemBook($r)) {
continue;
}

$name = $this->contactsService->getNameFromContact($r);
$email = $this->contactsService->getEmail($r);
$photo = $this->contactsService->getPhotoUri($r);
$timezoneId = $this->contactsService->getTimezoneId($r);
$lang = $this->contactsService->getLanguageId($r);
$contacts[] = [
'name' => $name,
'emails' => $r['EMAIL'],
'emails' => $email,
'lang' => $lang,
'tzid' => $timezoneId,
'photo' => $photo,
'categories' => $categories ?? [],
'calendarUserType' => 'INDIVIDUAL',
'member' => 'mailto:group+' . $groupName . '@group',
];
}

return new JSONResponse($contacts);
}

Expand Down Expand Up @@ -248,17 +250,14 @@ public function searchPhoto(string $search):JSONResponse {
$result = $this->contactsManager->search($search, ['EMAIL']);

foreach ($result as $r) {
if (!isset($r['EMAIL'])) {
if (!$this->contactsService->hasEmail($r) || $this->contactsService->isSystemBook($r)) {
continue;
}

if (\is_string($r['EMAIL'])) {
$r['EMAIL'] = [$r['EMAIL']];
}
$email = $this->contactsService->getEmail($r['EMAIL']);

$match = false;
foreach ($r['EMAIL'] as $email) {
if ($email === $search) {
foreach ($email as $e) {
if ($e === $search) {
$match = true;
}
}
Expand All @@ -267,15 +266,12 @@ public function searchPhoto(string $search):JSONResponse {
continue;
}

if (!isset($r['PHOTO'])) {
$photo = $this->contactsService->getPhotoUri($r['PHOTO']);
if ($photo === null) {
continue;
}

$name = $this->getNameFromContact($r);
$photo = $this->getPhotoUri($r['PHOTO']);
if (!$photo) {
continue;
}
$name = $this->contactsService->getNameFromContact($r);

return new JSONResponse([
'name' => $name,
Expand All @@ -285,29 +281,4 @@ public function searchPhoto(string $search):JSONResponse {

return new JSONResponse([], Http::STATUS_NOT_FOUND);
}

/**
* Extract name from an array containing a contact's information
*
* @param array $r
* @return string
*/
private function getNameFromContact(array $r):string {
return $r['FN'] ?? '';
}

/**
* Get photo uri from contact
*
* @param string $raw
* @return string|null
*/
private function getPhotoUri(string $raw):?string {
$uriPrefix = 'VALUE=uri:';
if (substr($raw, 0, strlen($uriPrefix)) === $uriPrefix) {
return substr($raw, strpos($raw, 'http'));
}

return null;
}
}
92 changes: 92 additions & 0 deletions lib/Service/ContactsService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2014 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Calendar\Service;

class ContactsService {


public function isSystemBook(array $r): bool {
// Information about system users is fetched via DAV nowadays
return (isset($contact['isLocalSystemBook']) && $contact['isLocalSystemBook'] === true);

Check failure on line 15 in lib/Service/ContactsService.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

UndefinedVariable

lib/Service/ContactsService.php:15:17: UndefinedVariable: Cannot find referenced variable $contact (see https://psalm.dev/024)

Check failure on line 15 in lib/Service/ContactsService.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-stable30

UndefinedVariable

lib/Service/ContactsService.php:15:17: UndefinedVariable: Cannot find referenced variable $contact (see https://psalm.dev/024)
}

public function hasEmail(array $r): bool {
return !isset($r['EMAIL']);
}

/**
* Extract name from an array containing a contact's information
*
* @param array $r
* @return string
*/
public function getNameFromContact(array $r): string {
return $r['FN'] ?? '';
}

/**
* Get photo uri from contact
*
* @param string $raw
* @return string|null
*/
public function getPhotoUri(array $r): ?string {
if (!isset($r['PHOTO'])) {
return null;
}

$raw = $r['PHOTO'];
$uriPrefix = 'VALUE=uri:';
if (str_starts_with($raw, $uriPrefix)) {
return substr($raw, strpos($raw, 'http'));
}

return null;
}

public function getEmail(array $r): array {
if (\is_string($r['EMAIL'])) {
return [$r['EMAIL']];
}
return $r['EMAIL'];
}

public function getTimezoneId(array $r): ?string {
if (!isset($r['TZ'])) {
return null;
}

if (\is_array($r['TZ'])) {
return $r['TZ'][0];
}
return $r['TZ'];
}

public function getLanguageId(array $r): ?string {
if (!isset($r['LANG'])) {
return null;
}

if (\is_array($r['LANG'])) {
return $r['LANG'][0];
}
return $r['LANG'];
}

public function filterGroupsWithCount(array $groups, string $search): array {
//filter to be unique
$categoryMem = [];
foreach ($groups as $group) {
$categoryNames = explode(',', $group['CATEGORIES']);
$categoryMem[] = array_filter($categoryNames, static function ($cat) use ($search) {
return str_contains(strtolower($cat), $search);
});
}
return array_count_values(array_merge(...$categoryMem));
}
}
Loading

0 comments on commit f464833

Please sign in to comment.