diff --git a/css/icons.scss b/css/icons.scss
index 084df4e7b..76945ad4d 100644
--- a/css/icons.scss
+++ b/css/icons.scss
@@ -41,6 +41,7 @@
@include icon-black-white('twitter', 'contacts', 2); // “twitter (fab)” by fontawesome.com is licensed under CC BY 4.0. (https://fontawesome.com/icons/twitter?style=brands)
@include icon-black-white('diaspora', 'contacts', 2); // “diaspora (fab)” by fontawesome.com is licensed under CC BY 4.0. (https://fontawesome.com/icons/diaspora?style=brands)
@include icon-black-white('xing', 'contacts', 2); // “xing (fab)” by fontawesome.com is licensed under CC BY 4.0. (https://fontawesome.com/icons/xing?style=brands)
+@include icon-black-white('gravatar', 'contacts', 2); // “wordpress (fab)” by fontawesome.com is licensed under CC BY 4.0. (https://fontawesome.com/icons/wordpress?style=brands)
.icon-up-force-white {
// using #fffffe to trick the accessibility dark theme icon invert
diff --git a/img/gravatar.svg b/img/gravatar.svg
new file mode 100644
index 000000000..00a96cb01
--- /dev/null
+++ b/img/gravatar.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/lib/Service/Social/CompositeSocialProvider.php b/lib/Service/Social/CompositeSocialProvider.php
index 40d937e6e..8e9f3e897 100644
--- a/lib/Service/Social/CompositeSocialProvider.php
+++ b/lib/Service/Social/CompositeSocialProvider.php
@@ -37,17 +37,19 @@ public function __construct(InstagramProvider $instagramProvider,
TwitterProvider $twitterProvider,
TumblrProvider $tumblrProvider,
DiasporaProvider $diasporaProvider,
- XingProvider $xingProvider) {
+ XingProvider $xingProvider,
+ GravatarProvider $gravatarProvider) {
// This determines the priority of known providers
$this->providers = [
- 'instagram' => $instagramProvider,
- 'mastodon' => $mastodonProvider,
- 'twitter' => $twitterProvider,
- 'facebook' => $facebookProvider,
- 'tumblr' => $tumblrProvider,
- 'diaspora' => $diasporaProvider,
- 'xing' => $xingProvider,
+ $instagramProvider->name => $instagramProvider,
+ $mastodonProvider->name => $mastodonProvider,
+ $twitterProvider->name => $twitterProvider,
+ $facebookProvider->name => $facebookProvider,
+ $tumblrProvider->name => $tumblrProvider,
+ $diasporaProvider->name => $diasporaProvider,
+ $xingProvider->name => $xingProvider,
+ $gravatarProvider->name => $gravatarProvider
];
}
@@ -60,40 +62,31 @@ public function getSupportedNetworks() : array {
return array_keys($this->providers);
}
-
/**
* generate download url for a social entry
*
- * @param array socialEntries all social data from the contact
- * @param String network the choice which network to use (fallback: take first available)
+ * @param array contact all social data from the contact
+ * @param String network the choice which network to use
*
- * @returns String the url to the requested information or null in case of errors
+ * @returns ISocialProvider if provider of 'network' is found, otherwise null
*/
- public function getSocialConnector(array $socialEntries, string $network) : ?string {
+ public function getSocialConnector(string $network) : ?ISocialProvider {
$connector = null;
- $selection = $this->providers;
// check if dedicated network selected
if (isset($this->providers[$network])) {
- $selection = [$network => $this->providers[$network]];
+ $connector = $this->providers[$network];
}
+ return $connector;
+ }
- // check selected providers in order
- foreach ($selection as $type => $socialProvider) {
-
- // search for this network in user's profile
- foreach ($socialEntries as $socialEntry) {
- if (strtolower($type) === strtolower($socialEntry['type'])) {
- $profileId = $socialProvider->cleanupId($socialEntry['value']);
- if (!is_null($profileId)) {
- $connector = $socialProvider->getImageUrl($profileId);
- }
- break;
- }
- }
- if ($connector) {
- break;
- }
- }
- return ($connector);
+ /**
+ * generate download url for a social entry
+ *
+ * @param array contact all social data from the contact
+ *
+ * @return ISocialProvider[] all social providers
+ */
+ public function getSocialConnectors() : array {
+ return array_values($this->providers);
}
}
diff --git a/lib/Service/Social/DiasporaProvider.php b/lib/Service/Social/DiasporaProvider.php
index 73f85792c..44f46ae1f 100644
--- a/lib/Service/Social/DiasporaProvider.php
+++ b/lib/Service/Social/DiasporaProvider.php
@@ -30,41 +30,67 @@ class DiasporaProvider implements ISocialProvider {
/** @var IClientService */
private $httpClient;
- /** @var boolean */
+ /** @var bool */
private $looping;
+ /** @var string */
+ public $name = "diaspora";
+
public function __construct(IClientService $httpClient) {
$this->httpClient = $httpClient->NewClient();
$this->looping = false;
}
-
+
/**
- * Returns the profile-id
+ * Returns if this provider supports this contact
*
- * @param {string} the value from the contact's x-socialprofile
+ * @param {array} contact info
*
- * @return string
+ * @return bool
*/
- public function cleanupId(string $candidate):string {
- try {
- if (strpos($candidate, 'http') !== 0) {
- $user_server = explode('@', $candidate);
- $candidate = 'https://' . array_pop($user_server) . '/public/' . array_pop($user_server) . '.atom';
- }
- } catch (Exception $e) {
- $candidate = null;
- }
- return $candidate;
+ public function supportsContact(array $contact):bool {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $supports = false;
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if ($profile['type'] == $this->name) {
+ $supports = true;
+ break;
+ }
+ }
+ }
+ return $supports;
}
/**
+ * Returns all possible profile-picture urls
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $profileIds = $this->getProfileIds($contact);
+ $urls = array();
+
+ foreach($profileIds as $profileId) {
+ $url = $this->getImageUrl($profileId);
+ if (isset($url)) {
+ $urls[] = $url;
+ }
+ }
+
+ return $urls;
+ }
+
+ /**
* Returns the profile-picture url
*
* @param {string} profileId the profile-id
*
* @return string|null
*/
- public function getImageUrl(string $profileUrl):?string {
+ protected function getImageUrl(string $profileUrl):?string {
try {
$result = $this->httpClient->get($profileUrl);
$htmlResult = $result->getBody();
@@ -82,8 +108,51 @@ public function getImageUrl(string $profileUrl):?string {
}
}
return null;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
return null;
}
}
+
+ /**
+ * Returns all possible profile ids for contact
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ protected function getProfileIds($contact):array {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $profileIds = array();
+
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $profileId = $this->cleanupId($profile['value']);
+ if (isset($profileId)) {
+ $profileIds[] = $profileId;
+ }
+ }
+ }
+ }
+ return $profileIds;
+ }
+
+ /**
+ * Returns the profile-id
+ *
+ * @param {string} the value from the contact's x-socialprofile
+ *
+ * @return string
+ */
+ protected function cleanupId(string $candidate):?string {
+ try {
+ if (strpos($candidate, 'http') !== 0) {
+ $user_server = explode('@', $candidate);
+ $candidate = 'https://' . array_pop($user_server) . '/public/' . array_pop($user_server) . '.atom';
+ }
+ } catch (Exception $e) {
+ $candidate = null;
+ }
+ return $candidate;
+ }
}
diff --git a/lib/Service/Social/FacebookProvider.php b/lib/Service/Social/FacebookProvider.php
index 770ac45ae..2aa27f830 100644
--- a/lib/Service/Social/FacebookProvider.php
+++ b/lib/Service/Social/FacebookProvider.php
@@ -30,10 +30,52 @@ class FacebookProvider implements ISocialProvider {
/** @var IClientService */
private $httpClient;
+ /** @var string */
+ public $name = "facebook";
+
public function __construct(IClientService $httpClient) {
$this->httpClient = $httpClient->NewClient();
}
-
+
+ /**
+ * Returns if this provider supports this contact
+ *
+ * @param {array} contact info
+ *
+ * @return bool
+ */
+ public function supportsContact(array $contact):bool {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $supports = false;
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $supports = true;
+ break;
+ }
+ }
+ }
+ return $supports;
+ }
+
+ /**
+ * Returns the profile-picture url
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $profileIds = $this->getProfileIds($contact);
+ $urls = array();
+ foreach($profileIds as $profileId) {
+ $recipe = 'https://graph.facebook.com/{socialId}/picture?width=720';
+ $connector = str_replace("{socialId}", $profileId, $recipe);
+ $urls[] = $connector;
+ }
+ return $urls;
+ }
+
/**
* Returns the profile-id
*
@@ -41,7 +83,7 @@ public function __construct(IClientService $httpClient) {
*
* @return string
*/
- public function cleanupId(string $candidate):string {
+ protected function cleanupId(string $candidate):string {
$candidate = basename($candidate);
if (!is_numeric($candidate)) {
$candidate = $this->findFacebookId($candidate);
@@ -50,16 +92,23 @@ public function cleanupId(string $candidate):string {
}
/**
- * Returns the profile-picture url
+ * Returns all possible profile ids for contact
*
- * @param {string} profileId the profile-id
+ * @param {array} contact information
*
- * @return string
+ * @return array of string profile ids
*/
- public function getImageUrl(string $profileId):string {
- $recipe = 'https://graph.facebook.com/{socialId}/picture?width=720';
- $connector = str_replace("{socialId}", $profileId, $recipe);
- return $connector;
+ protected function getProfileIds($contact):array {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $profileIds = array();
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $profileIds[] = $this->cleanupId($profile['value']);
+ }
+ }
+ }
+ return $profileIds;
}
/**
diff --git a/lib/Service/Social/GravatarProvider.php b/lib/Service/Social/GravatarProvider.php
new file mode 100644
index 000000000..d735dd5bb
--- /dev/null
+++ b/lib/Service/Social/GravatarProvider.php
@@ -0,0 +1,81 @@
+
+ *
+ * @author leith
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Contacts\Service\Social;
+
+use OCP\Http\Client\IClientService;
+
+class GravatarProvider implements ISocialProvider {
+ /** @var string */
+ public $name = "gravatar";
+
+ public function __construct(IClientService $httpClient) {
+ $this->httpClient = $httpClient->NewClient();
+ }
+
+ /**
+ * Returns if this provider supports this contact
+ *
+ * @param {array} contact info
+ *
+ * @return bool
+ */
+ public function supportsContact(array $contact):bool {
+ $emails = $contact['EMAIL'];
+ return isset($emails) && count($emails);
+ }
+
+ /**
+ * Returns the profile-picture url
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $emails = $this->getProfileIds($contact);
+ $urls = array();
+ foreach($emails as $email) {
+ $hash = md5(strtolower(trim($email['value'])));
+ $recipe = 'https://www.gravatar.com/avatar/{hash}?s=720&d=404';
+ $connector = str_replace("{hash}", $hash, $recipe);
+ $urls[] = $connector;
+ }
+ return $urls;
+ }
+
+ /**
+ * Returns all possible profile ids for contact
+ *
+ * @param {array} contact information
+ *
+ * @return array of string profile ids
+ */
+ protected function getProfileIds(array $contact):array {
+ $emails = $contact['EMAIL'];
+ if (isset($emails)) {
+ return $emails;
+ }
+ return array();
+ }
+}
diff --git a/lib/Service/Social/ISocialProvider.php b/lib/Service/Social/ISocialProvider.php
index 1415f4d09..a21fe32bb 100644
--- a/lib/Service/Social/ISocialProvider.php
+++ b/lib/Service/Social/ISocialProvider.php
@@ -24,22 +24,21 @@
namespace OCA\Contacts\Service\Social;
interface ISocialProvider {
-
/**
- * Returns the profile-id
+ * Returns true if provider supports the contact
*
- * @param {string} the value from the contact's x-socialprofile
+ * @param {array} contact details
*
- * @return string
+ * @return boolean
*/
- public function cleanupId(string $candidate):?string ;
+ public function supportsContact(array $contact):bool ;
/**
- * Returns the profile-picture url
+ * Returns all possible profile-picture urls
*
- * @param {string} profileId the profile-id
+ * @param {array} contact information
*
- * @return string|null
+ * @return array
*/
- public function getImageUrl(string $profileId):?string ;
+ public function getImageUrls(array $contact):array ;
}
diff --git a/lib/Service/Social/InstagramProvider.php b/lib/Service/Social/InstagramProvider.php
index b7687e715..2cd3bf523 100644
--- a/lib/Service/Social/InstagramProvider.php
+++ b/lib/Service/Social/InstagramProvider.php
@@ -30,10 +30,53 @@ class InstagramProvider implements ISocialProvider {
/** @var IClientService */
private $httpClient;
+ /** @var string */
+ public $name = "instagram";
+
public function __construct(IClientService $httpClient) {
$this->httpClient = $httpClient->NewClient();
}
-
+
+ /**
+ * Returns if this provider supports this contact
+ *
+ * @param {array} contact info
+ *
+ * @return bool
+ */
+ public function supportsContact(array $contact):bool {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $supports = false;
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $supports = true;
+ break;
+ }
+ }
+ }
+ return $supports;
+ }
+
+ /**
+ * Returns the profile-picture url
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $profileIds = $this->getProfileIds($contact);
+ $urls = array();
+ foreach($profileIds as $profileId) {
+ $recipe = 'https://www.instagram.com/{socialId}/?__a=1';
+ $connector = str_replace("{socialId}", $profileId, $recipe);
+ $connector = $this->getFromJson($connector, 'graphql->user->profile_pic_url_hd');
+ $urls[] = $connector;
+ }
+ return $urls;
+ }
+
/**
* Returns the profile-id
*
@@ -41,25 +84,31 @@ public function __construct(IClientService $httpClient) {
*
* @return string
*/
- public function cleanupId(string $candidate):string {
+ protected function cleanupId(string $candidate):string {
$candidate = preg_replace('/^' . preg_quote('x-apple:', '/') . '/', '', $candidate);
return basename($candidate);
}
/**
- * Returns the profile-picture url
+ * Returns all possible profile ids for contact
*
- * @param {string} profileId the profile-id
+ * @param {array} contact information
*
- * @return string|null
+ * @return array of string profile ids
*/
- public function getImageUrl(string $profileId):?string {
- $recipe = 'https://www.instagram.com/{socialId}/?__a=1';
- $connector = str_replace("{socialId}", $profileId, $recipe);
- $connector = $this->getFromJson($connector, 'graphql->user->profile_pic_url_hd');
- return $connector;
+ protected function getProfileIds($contact):array {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $profileIds = array();
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $profileIds[] = $this->cleanupId($profile['value']);
+ }
+ }
+ }
+ return $profileIds;
}
-
+
/**
* extracts desired value from a json
*
@@ -81,7 +130,7 @@ protected function getFromJson(string $url, string $desired) : ?string {
$jsonResult = $jsonResult[$loc];
}
return $jsonResult;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
return null;
}
}
diff --git a/lib/Service/Social/MastodonProvider.php b/lib/Service/Social/MastodonProvider.php
index 74b68e96d..2c6cbd19c 100644
--- a/lib/Service/Social/MastodonProvider.php
+++ b/lib/Service/Social/MastodonProvider.php
@@ -30,34 +30,58 @@ class MastodonProvider implements ISocialProvider {
/** @var IClientService */
private $httpClient;
+ /** @var string */
+ public $name = "mastodon";
+
public function __construct(IClientService $httpClient) {
$this->httpClient = $httpClient->NewClient();
}
-
+
/**
- * Returns the profile-id
+ * Returns if this provider supports this contact
*
- * @param {string} the value from the contact's x-socialprofile
+ * @param {array} contact info
*
- * @return string
+ * @return bool
*/
- public function cleanupId(string $candidate):?string {
- $candidate = preg_replace('/^' . preg_quote('x-apple:', '/') . '/', '', $candidate);
- try {
- if (strpos($candidate, 'http') !== 0) {
- $user_server = explode('@', $candidate);
- $candidate = 'https://' . array_pop($user_server) . '/@' . array_pop($user_server);
+ public function supportsContact(array $contact):bool {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $supports = false;
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $supports = true;
+ break;
+ }
}
- } catch (Exception $e) {
- $candidate = null;
}
- return $candidate;
+ return $supports;
+ }
+
+ /**
+ * Returns all possible profile-picture urls
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $profileIds = $this->getProfileIds($contact);
+ $urls = array();
+
+ foreach($profileIds as $profileId) {
+ $url = $this->getImageUrl($profileId);
+ if (isset($url)) {
+ $urls[] = $url;
+ }
+ }
+ return $urls;
}
/**
* Returns the profile-picture url
*
- * @param {string} profileUrl link to the profile
+ * @param {array} contact information
*
* @return string|null
*/
@@ -72,8 +96,51 @@ public function getImageUrl(string $profileUrl):?string {
return $img->getAttribute("data-original");
}
return null;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
return null;
}
}
+
+ /**
+ * Returns all possible profile ids for contact
+ *
+ * @param {array} contact information
+ *
+ * @return array of possible profileIds
+ */
+ protected function getProfileIds($contact):array {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $profileIds = array();
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $profileId = $this->cleanupId($profile['value']);
+ if(isset($profileId)) {
+ $profileIds[] = $profileId;
+ }
+ }
+ }
+ }
+ return $profileIds;
+ }
+
+ /**
+ * Returns the profile-id
+ *
+ * @param {string} the value from the contact's x-socialprofile
+ *
+ * @return string
+ */
+ protected function cleanupId(string $candidate):?string {
+ $candidate = preg_replace('/^' . preg_quote('x-apple:', '/') . '/', '', $candidate);
+ try {
+ if (strpos($candidate, 'http') !== 0) {
+ $user_server = explode('@', $candidate);
+ $candidate = 'https://' . array_pop($user_server) . '/@' . array_pop($user_server);
+ }
+ } catch (\Exception $e) {
+ $candidate = null;
+ }
+ return $candidate;
+ }
}
diff --git a/lib/Service/Social/TumblrProvider.php b/lib/Service/Social/TumblrProvider.php
index a830b945b..e1c1d61ef 100644
--- a/lib/Service/Social/TumblrProvider.php
+++ b/lib/Service/Social/TumblrProvider.php
@@ -24,9 +24,51 @@
namespace OCA\Contacts\Service\Social;
class TumblrProvider implements ISocialProvider {
+ /** @var string */
+ public $name = "tumblr";
+
public function __construct() {
}
-
+
+ /**
+ * Returns if this provider supports this contact
+ *
+ * @param {array} contact info
+ *
+ * @return bool
+ */
+ public function supportsContact(array $contact):bool {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $supports = false;
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $supports = true;
+ break;
+ }
+ }
+ }
+ return $supports;
+ }
+
+ /**
+ * Returns the profile-picture url
+ *
+ * @param {string} profileId the profile-id
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $profileIds = $this->getProfileIds($contact);
+ $urls = array();
+ foreach($profileIds as $profileId) {
+ $recipe = 'https://api.tumblr.com/v2/blog/{socialId}/avatar/512';
+ $connector = str_replace("{socialId}", $profileId, $recipe);
+ $urls[] = $connector;
+ }
+ return $urls;
+ }
+
/**
* Returns the profile-id
*
@@ -34,7 +76,7 @@ public function __construct() {
*
* @return string
*/
- public function cleanupId(string $candidate):?string {
+ protected function cleanupId(string $candidate):?string {
$candidate = preg_replace('/^' . preg_quote('x-apple:', '/') . '/', '', $candidate);
$subdomain = '/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/i'; // subdomain
if (preg_match($subdomain, $candidate, $matches)) {
@@ -44,15 +86,22 @@ public function cleanupId(string $candidate):?string {
}
/**
- * Returns the profile-picture url
+ * Returns all possible profile ids for contact
*
- * @param {string} profileId the profile-id
+ * @param {array} contact information
*
- * @return string|null
+ * @return array of string profile ids
*/
- public function getImageUrl(string $profileId):?string {
- $recipe = 'https://api.tumblr.com/v2/blog/{socialId}/avatar/512';
- $connector = str_replace("{socialId}", $profileId, $recipe);
- return $connector;
+ protected function getProfileIds($contact):array {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $profileIds = array();
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $profileIds[] = $this->cleanupId($profile['value']);
+ }
+ }
+ }
+ return $profileIds;
}
}
diff --git a/lib/Service/Social/TwitterProvider.php b/lib/Service/Social/TwitterProvider.php
index 953eb1a09..ed249a0bb 100644
--- a/lib/Service/Social/TwitterProvider.php
+++ b/lib/Service/Social/TwitterProvider.php
@@ -26,14 +26,54 @@
use OCP\Http\Client\IClientService;
class TwitterProvider implements ISocialProvider {
-
/** @var IClientService */
private $httpClient;
+ /** @var string */
+ public $name = "twitter";
+
public function __construct(IClientService $httpClient) {
$this->httpClient = $httpClient->NewClient();
}
-
+
+ /**
+ * Returns if this provider supports this contact
+ *
+ * @param {array} contact info
+ *
+ * @return bool
+ */
+ public function supportsContact(array $contact):bool {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the profile-picture url
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $profileIds = $this->getProfileIds($contact);
+ $urls = array();
+ foreach($profileIds as $profileId) {
+ $recipe = 'https://mobile.twitter.com/{socialId}';
+ $connector = str_replace("{socialId}", $profileId, $recipe);
+ $connector = $this->getFromHtml($connector, '_normal');
+ $urls[] = $connector;
+ }
+ return $urls;
+ }
+
/**
* Returns the profile-id
*
@@ -41,7 +81,7 @@ public function __construct(IClientService $httpClient) {
*
* @return string
*/
- public function cleanupId(string $candidate):string {
+ protected function cleanupId(string $candidate):string {
$candidate = basename($candidate);
if ($candidate[0] === '@') {
$candidate = substr($candidate, 1);
@@ -50,19 +90,25 @@ public function cleanupId(string $candidate):string {
}
/**
- * Returns the profile-picture url
+ * Returns all possible profile ids for contact
*
- * @param {string} profileId the profile-id
+ * @param {array} contact information
*
- * @return string|null
+ * @return array of string profile ids
*/
- public function getImageUrl(string $profileId):?string {
- $recipe = 'https://mobile.twitter.com/{socialId}';
- $connector = str_replace("{socialId}", $profileId, $recipe);
- $connector = $this->getFromHtml($connector, '_normal');
- return $connector;
+ protected function getProfileIds($contact):array {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $profileIds = array();
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $profileIds[] = $this->cleanupId($profile['value']);
+ }
+ }
+ }
+ return $profileIds;
}
-
+
/**
* extracts desired value from an html page
*
@@ -88,7 +134,7 @@ protected function getFromHtml(string $url, string $desired) : ?string {
}
}
return null;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
return null;
}
}
diff --git a/lib/Service/Social/XingProvider.php b/lib/Service/Social/XingProvider.php
index 739d1fd2f..ce695607a 100644
--- a/lib/Service/Social/XingProvider.php
+++ b/lib/Service/Social/XingProvider.php
@@ -30,41 +30,64 @@ class XingProvider implements ISocialProvider {
/** @var IClientService */
private $httpClient;
- /** @var boolean */
- private $looping;
+ /** @var string */
+ public $name = "xing";
public function __construct(IClientService $httpClient) {
$this->httpClient = $httpClient->NewClient();
$this->looping = false;
}
-
+
/**
- * Returns the profile-id
+ * Returns if this provider supports this contact
*
- * @param {string} the value from the contact's x-socialprofile
+ * @param {array} contact info
*
- * @return string
+ * @return bool
*/
- public function cleanupId(string $candidate):string {
- $candidate = preg_replace('/^' . preg_quote('x-apple:', '/') . '/', '', $candidate);
- try {
- if (strpos($candidate, 'http') !== 0) {
- $candidate = 'https://www.xing.com/profile/' . $candidate;
+ public function supportsContact(array $contact):bool {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $supports = false;
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $supports = true;
+ break;
+ }
}
- } catch (Exception $e) {
- $candidate = null;
}
- return $candidate;
+ return $supports;
+ }
+
+ /**
+ * Returns all possible profile-picture urls
+ *
+ * @param {array} contact information
+ *
+ * @return array
+ */
+ public function getImageUrls(array $contact):array {
+ $profileIds = $this->getProfileIds($contact);
+ $urls = array();
+
+ foreach($profileIds as $profileId) {
+ $url = $this->getImageUrl($profileId);
+ if (isset($url)) {
+ $urls[] = $url;
+ }
+ }
+
+ return $urls;
}
/**
* Returns the profile-picture url
*
- * @param {string} profileId the profile-id
+ * @param {string} profile url
*
* @return string|null
*/
- public function getImageUrl(string $profileUrl):?string {
+ protected function getImageUrl(string $profileUrl):?string {
try {
$result = $this->httpClient->get($profileUrl);
$htmlResult = $result->getBody();
@@ -75,8 +98,50 @@ public function getImageUrl(string $profileUrl):?string {
}
// keyword not found, maybe page changed?
return null;
- } catch (Exception $e) {
+ } catch (\Exception $e) {
return null;
}
}
+
+ /**
+ * Returns the profile-id
+ *
+ * @param {string} the value from the contact's x-socialprofile
+ *
+ * @return string
+ */
+ protected function cleanupId(string $candidate):?string {
+ $candidate = preg_replace('/^' . preg_quote('x-apple:', '/') . '/', '', $candidate);
+ try {
+ if (strpos($candidate, 'http') !== 0) {
+ $candidate = 'https://www.xing.com/profile/' . $candidate;
+ }
+ } catch (\Exception $e) {
+ $candidate = null;
+ }
+ return $candidate;
+ }
+
+ /**
+ * Returns all possible profile ids for contact
+ *
+ * @param {array} contact information
+ *
+ * @return string of first profile url else null
+ */
+ protected function getProfileIds($contact):array {
+ $socialprofiles = $contact['X-SOCIALPROFILE'];
+ $profileIds = array();
+ if(isset($socialprofiles)) {
+ foreach($socialprofiles as $profile) {
+ if (strtolower($profile['type']) == $this->name) {
+ $profileId = $this->cleanupId($profile['value']);
+ if(isset($profileId)) {
+ $profileIds[] = $profileId;
+ }
+ }
+ }
+ }
+ return $profileIds;
+ }
}
diff --git a/lib/Service/SocialApiService.php b/lib/Service/SocialApiService.php
index 03484c99e..af07c998f 100644
--- a/lib/Service/SocialApiService.php
+++ b/lib/Service/SocialApiService.php
@@ -50,9 +50,9 @@ class SocialApiService {
private $config;
/** @var IClientService */
private $clientService;
- /** @var IL10N */
+ /** @var IL10N */
private $l10n;
- /** @var IURLGenerator */
+ /** @var IURLGenerator */
private $urlGen;
/** @var CardDavBackend */
private $davBackend;
@@ -84,7 +84,7 @@ public function __construct(
/**
* returns an array of supported social networks
*
- * @returns {array} array of the supported social networks
+ * @return {array} array of the supported social networks
*/
public function getSupportedNetworks() : array {
$syncAllowedByAdmin = $this->config->getAppValue($this->appName, 'allowSocialSync', 'yes');
@@ -168,7 +168,10 @@ protected function registerAddressbooks($userId, IManager $manager) {
* @returns {JSONResponse} an empty JSONResponse with respective http status code
*/
public function updateContact(string $addressbookId, string $contactId, string $network) : JSONResponse {
- $url = null;
+ $socialdata = null;
+ $imageType = null;
+ $urls = array();
+ $allConnectors = $this->socialProvider->getSocialConnectors();
try {
// get corresponding addressbook
@@ -179,20 +182,42 @@ public function updateContact(string $addressbookId, string $contactId, string $
// search contact in that addressbook, get social data
$contact = $addressBook->search($contactId, ['UID'], ['types' => true])[0];
- if (!isset($contact['X-SOCIALPROFILE'])) {
+
+ if (!isset($contact)) {
+ return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
+ }
+
+ if ($network) {
+ $allConnectors = [$this->socialProvider->getSocialConnector($network)];
+ }
+
+ $connectors = array_filter($allConnectors, function($connector) use($contact) {
+ return $connector->supportsContact($contact);
+ });
+
+ if (count($connectors) == 0) {
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
}
- $socialprofiles = $contact['X-SOCIALPROFILE'];
- // retrieve data
- $url = $this->socialProvider->getSocialConnector($socialprofiles, $network);
- if (empty($url)) {
+ foreach($connectors as $connector) {
+ $urls = array_merge($connector->getImageUrls($contact), $urls);
+ }
+
+ if (count($urls) == 0) {
return new JSONResponse([], Http::STATUS_BAD_REQUEST);
}
- $httpResult = $this->clientService->NewClient()->get($url);
- $socialdata = $httpResult->getBody();
- $imageType = $httpResult->getHeader('content-type');
+ foreach($urls as $url) {
+ try {
+ $httpResult = $this->clientService->NewClient()->get($url);
+ $socialdata = $httpResult->getBody();
+ $imageType = $httpResult->getHeader('content-type');
+ if (isset($socialdata) && isset($imageType)) {
+ break;
+ }
+ } catch(\Exception $e) {
+ }
+ }
if (!$socialdata || $imageType === null) {
return new JSONResponse([], Http::STATUS_NOT_FOUND);
diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue
index b13e94111..92b1befb7 100644
--- a/src/components/ContactDetails/ContactDetailsAvatar.vue
+++ b/src/components/ContactDetails/ContactDetailsAvatar.vue
@@ -196,11 +196,15 @@ export default {
return false
},
supportedSocial() {
+ const emails = this.contact.vCard.getAllProperties('email')
// get social networks set for the current contact
const available = this.contact.vCard.getAllProperties('x-socialprofile')
.map(a => a.jCal[1].type.toString().toLowerCase())
// get list of social networks that allow for avatar download
const supported = supportedNetworks.map(v => v.toLowerCase())
+ if (emails.length) {
+ available.push('gravatar')
+ }
// return supported social networks which are set
return supported.filter(i => available.includes(i))
.map(j => this.capitalize(j))