Skip to content

Commit 78ba69a

Browse files
committed
feat: support other contacts
Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
1 parent 89b55fe commit 78ba69a

4 files changed

Lines changed: 79 additions & 18 deletions

File tree

lib/Controller/ConfigController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class ConfigController extends Controller {
3636

3737
public const DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive.readonly';
3838
public const CONTACTS_SCOPE = 'https://www.googleapis.com/auth/contacts.readonly';
39+
public const CONTACTS_OTHER_SCOPE = 'https://www.googleapis.com/auth/contacts.other.readonly';
3940
public const CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly';
4041
public const CALENDAR_EVENTS_SCOPE = 'https://www.googleapis.com/auth/calendar.events.readonly';
4142
public const PHOTOS_SCOPE = 'https://www.googleapis.com/auth/photoslibrary.readonly';
@@ -177,6 +178,7 @@ public function oauthRedirect(string $code = '', string $state = '', string $sco
177178
$scopesArray = [
178179
'can_access_drive' => in_array(self::DRIVE_SCOPE, $scopes) ? 1 : 0,
179180
'can_access_contacts' => in_array(self::CONTACTS_SCOPE, $scopes) ? 1 : 0,
181+
'can_access_other_contacts' => in_array(self::CONTACTS_OTHER_SCOPE, $scopes) ? 1 : 0,
180182
'can_access_photos' => in_array(self::PHOTOS_SCOPE, $scopes) ? 1 : 0,
181183
'can_access_calendar' => (in_array(self::CALENDAR_SCOPE, $scopes) && in_array(self::CALENDAR_EVENTS_SCOPE, $scopes)) ? 1 : 0,
182184
];

lib/Service/GoogleContactsAPIService.php

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use OCA\DAV\CardDAV\CardDavBackend;
1919
use OCA\Google\AppInfo\Application;
2020
use OCP\Contacts\IManager as IContactManager;
21+
use OCP\IConfig;
2122
use Psr\Log\LoggerInterface;
2223
use Sabre\VObject\Component\VCard;
2324
use Throwable;
@@ -33,6 +34,7 @@ public function __construct(
3334
private IContactManager $contactsManager,
3435
private CardDavBackend $cdBackend,
3536
private GoogleAPIService $googleApiService,
37+
private IConfig $config,
3638
) {
3739
}
3840

@@ -72,29 +74,40 @@ public function getContactGroupsById(string $userId): array {
7274
* @return array
7375
*/
7476
public function getContactNumber(string $userId): array {
75-
$nbContacts = 0;
7677
$params = [
7778
'personFields' => implode(',', [
7879
'names',
7980
]),
80-
'pageSize' => 100,
8181
];
82-
do {
83-
$result = $this->googleApiService->request($userId, 'v1/people/me/connections', $params, 'GET', 'https://people.googleapis.com/');
84-
if (isset($result['error'])) {
85-
return $result;
82+
$result = [];
83+
$contacts = $this->googleApiService->request($userId, 'v1/people/me/connections', $params, 'GET', 'https://people.googleapis.com/');
84+
if (isset($contacts['error'])) {
85+
return $contacts;
86+
}
87+
$result['nbContacts'] = $contacts['totalItems'] ?? 0;
88+
$otherContacts = $this->config->getUserValue($userId, Application::APP_ID, 'consider_other_contacts', '0');
89+
if ($otherContacts == '1') {
90+
$params = [
91+
'readMask' => implode(',', [
92+
'names',
93+
'emailAddresses',
94+
]),
95+
];
96+
$otherContacts = $this->googleApiService->request($userId, 'v1/otherContacts', $params, 'GET', 'https://people.googleapis.com/');
97+
if (isset($otherContacts['error'])) {
98+
return $otherContacts;
8699
}
87-
$nbContacts += count($result['connections'] ?? []);
88-
$params['pageToken'] = $result['nextPageToken'] ?? '';
89-
} while (isset($result['nextPageToken']));
90-
return ['nbContacts' => $nbContacts];
100+
$result['nbOtherContacts'] = $otherContacts['totalSize'] ?? 0;
101+
}
102+
return $result;
91103
}
92104

93105
/**
94106
* @param string $userId
107+
* @param bool $otherContacts
95108
* @return Generator
96109
*/
97-
public function getContactList(string $userId): Generator {
110+
public function getContactList(string $userId, bool $otherContacts = false): Generator {
98111
$params = [
99112
'personFields' => implode(',', [
100113
'addresses',
@@ -127,6 +140,31 @@ public function getContactList(string $userId): Generator {
127140
}
128141
$params['pageToken'] = $result['nextPageToken'] ?? '';
129142
} while (isset($result['nextPageToken']));
143+
if ($otherContacts) {
144+
$params = [
145+
'readMask' => implode(',', [
146+
'emailAddresses',
147+
'metadata',
148+
'names',
149+
'phoneNumbers',
150+
'photos',
151+
]),
152+
'sources' => 'READ_SOURCE_TYPE_CONTACT',
153+
'pageSize' => 100,
154+
];
155+
do {
156+
$result = $this->googleApiService->request($userId, 'v1/otherContacts', $params, 'GET', 'https://people.googleapis.com/');
157+
if (isset($result['error'])) {
158+
return $result;
159+
}
160+
if (isset($result['otherContacts']) && is_array($result['otherContacts'])) {
161+
foreach ($result['otherContacts'] as $contact) {
162+
yield $contact;
163+
}
164+
}
165+
$params['pageToken'] = $result['nextPageToken'] ?? '';
166+
} while (isset($result['nextPageToken']));
167+
}
130168
return [];
131169
}
132170

@@ -166,9 +204,9 @@ public function importContacts(string $userId, ?string $uri, int $key, ?string $
166204
}
167205
$existingAddressBook = $addressBook;
168206
}
169-
207+
$otherContacts = $this->config->getUserValue($userId, Application::APP_ID, 'consider_other_contacts', '0') === '1';
170208
$groupsById = $this->getContactGroupsById($userId);
171-
$contacts = $this->getContactList($userId);
209+
$contacts = $this->getContactList($userId, $otherContacts);
172210
$nbAdded = 0;
173211
$nbUpdated = 0;
174212
$totalContactNumber = 0;

lib/Settings/Personal.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
use OCA\Google\Service\SecretService;
99
use OCP\AppFramework\Http\TemplateResponse;
1010
use OCP\AppFramework\Services\IInitialState;
11+
use OCP\Files\Folder;
1112
use OCP\Files\IRootFolder;
1213
use OCP\Files\NotFoundException;
1314
use OCP\Files\NotPermittedException;
1415
use OCP\IConfig;
1516
use OCP\IUserManager;
1617
use OCP\Settings\ISettings;
18+
use Throwable;
1719

1820
class Personal implements ISettings {
1921

@@ -45,6 +47,7 @@ public function getForm(): TemplateResponse {
4547
$photoOutputDir = $photoOutputDir ?: '/Google Photos';
4648
$considerSharedFiles = $this->config->getUserValue($this->userId, Application::APP_ID, 'consider_shared_files', '0') === '1';
4749
$considerSharedAlbums = $this->config->getUserValue($this->userId, Application::APP_ID, 'consider_shared_albums', '0') === '1';
50+
$considerOtherContacts = $this->config->getUserValue($this->userId, Application::APP_ID, 'consider_other_contacts', '0') === '1';
4851
$documentFormat = $this->config->getUserValue($this->userId, Application::APP_ID, 'document_format', 'openxml');
4952
if (!in_array($documentFormat, ['openxml', 'opendoc'])) {
5053
$documentFormat = 'openxml';
@@ -83,6 +86,7 @@ public function getForm(): TemplateResponse {
8386
'user_quota' => $user === null ? '' : $user->getQuota(),
8487
'consider_shared_files' => $considerSharedFiles,
8588
'consider_shared_albums' => $considerSharedAlbums,
89+
'consider_other_contacts' => $considerOtherContacts,
8690
'document_format' => $documentFormat,
8791
'drive_output_dir' => $driveOutputDir,
8892
'photo_output_dir' => $photoOutputDir,
@@ -101,16 +105,16 @@ public function getPriority(): int {
101105
}
102106

103107
/**
104-
* @param \OCP\Files\Folder $userRoot
108+
* @param Folder $userRoot
105109
* @param string $outputDir
106110
* @return bool|float|int
107111
* @throws NotFoundException
108112
*/
109-
public static function getFreeSpace(\OCP\Files\Folder $userRoot, string $outputDir) {
113+
public static function getFreeSpace(Folder $userRoot, string $outputDir) {
110114
try {
111115
// OutputDir can be on an external storage which can have more free space
112116
$freeSpace = $userRoot->get($outputDir)->getStorage()->free_space('/');
113-
} catch (\Throwable $e) {
117+
} catch (Throwable $e) {
114118
$freeSpace = false;
115119
}
116120
return $freeSpace !== false && $freeSpace > 0 ? $freeSpace : $userRoot->getStorage()->free_space('/');

src/components/PersonalSettings.vue

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,22 @@
2828
</NcButton>
2929
</div>
3030
<br>
31-
<div v-if="nbContacts > 0"
31+
<div v-if="nbContacts + nbOtherContacts >= 0"
3232
id="google-contacts">
3333
<h3>{{ t('integration_google', 'Contacts') }}</h3>
34+
<div class="line">
35+
<NcCheckboxRadioSwitch v-if="!importingContacts && state.user_scopes.can_access_other_contacts"
36+
:model-value="state.consider_other_contacts"
37+
@update:model-value="onContactsConsiderOtherChange">
38+
{{ t('integration_google', 'Include other contacts') }}
39+
</NcCheckboxRadioSwitch>
40+
</div>
3441
<div class="line">
3542
<label>
3643
<AccountGroupIcon />
37-
{{ t('integration_google', '{amount} Google contacts', { amount: nbContacts }) }}
44+
{{ state.consider_other_contacts
45+
? t('integration_google', '{amount} Google + {otherAmount} other contacts', { amount: nbContacts, otherAmount: nbOtherContacts })
46+
: t('integration_google', '{amount} Google contacts', { amount: nbContacts }) }}
3847
</label>
3948
<NcButton @click="onImportContacts">
4049
<template #icon>
@@ -310,8 +319,10 @@ export default {
310319
calendars: [],
311320
importingCalendar: {},
312321
// contacts
322+
considerOtherContacts: false,
313323
addressbooks: [],
314324
nbContacts: 0,
325+
nbOtherContacts: 0,
315326
showAddressBooks: false,
316327
selectedAddressBook: 0,
317328
newAddressBookName: 'Google Contacts import',
@@ -466,6 +477,7 @@ export default {
466477
'https://www.googleapis.com/auth/contacts.readonly',
467478
'https://www.googleapis.com/auth/photoslibrary.readonly',
468479
'https://www.googleapis.com/auth/drive.readonly',
480+
'https://www.googleapis.com/auth/contacts.other.readonly',
469481
]
470482
const requestUrl = 'https://accounts.google.com/o/oauth2/v2/auth?'
471483
+ 'client_id=' + encodeURIComponent(this.state.client_id)
@@ -598,6 +610,7 @@ export default {
598610
.then((response) => {
599611
if (response.data && Object.keys(response.data).length > 0) {
600612
this.nbContacts = response.data.nbContacts
613+
this.nbOtherContacts = response.data.nbOtherContacts ?? 0
601614
}
602615
})
603616
.catch((error) => {
@@ -816,6 +829,10 @@ export default {
816829
myHumanFileSize(bytes, approx = false, si = false, dp = 1) {
817830
return humanFileSize(bytes, approx, si, dp)
818831
},
832+
onContactsConsiderOtherChange(newValue) {
833+
this.state.consider_other_contacts = newValue
834+
this.saveOptions({ consider_other_contacts: this.state.consider_other_contacts ? '1' : '0' }, this.getNbGoogleContacts)
835+
},
819836
onDriveConsiderSharedChange(newValue) {
820837
this.state.consider_shared_files = !newValue
821838
this.saveOptions({ consider_shared_files: this.state.consider_shared_files ? '1' : '0' }, this.getGoogleDriveInfo)

0 commit comments

Comments
 (0)