Collect recent contact interactionstags/v19.0.0beta1
@@ -16,6 +16,7 @@ | |||
!/apps/accessibility | |||
!/apps/cloud_federation_api | |||
!/apps/comments | |||
!/apps/contactsinteraction | |||
!/apps/dav | |||
!/apps/files | |||
!/apps/federation |
@@ -0,0 +1,26 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
\OC::$server->query(\OCA\ContactsInteraction\AppInfo\Application::class); |
@@ -0,0 +1,30 @@ | |||
<?xml version="1.0"?> | |||
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd"> | |||
<id>contactsinteraction</id> | |||
<name>Contacts Interaction</name> | |||
<summary>Manages interaction between users and contacts</summary> | |||
<description>Collect data about user and contacts interactions and provide an address book for the data</description> | |||
<version>1.0.0</version> | |||
<licence>agpl</licence> | |||
<author>Christoph Wurst</author> | |||
<namespace>ContactsInteraction</namespace> | |||
<types> | |||
<dav/> | |||
</types> | |||
<default_enable/> | |||
<category>integration</category> | |||
<category>social</category> | |||
<bugs>https://github.com/nextcloud/server/issues</bugs> | |||
<dependencies> | |||
<nextcloud min-version="19" max-version="19"/> | |||
</dependencies> | |||
<background-jobs> | |||
<job>OCA\ContactsInteraction\BackgroundJob\CleanupJob</job> | |||
</background-jobs> | |||
<sabre> | |||
<address-book-plugins> | |||
<plugin>OCA\ContactsInteraction\AddressBookProvider</plugin> | |||
</address-book-plugins> | |||
</sabre> | |||
</info> |
@@ -0,0 +1,7 @@ | |||
<?php | |||
// autoload.php @generated by Composer | |||
require_once __DIR__ . '/composer/autoload_real.php'; | |||
return ComposerAutoloaderInitContactsInteraction::getLoader(); |
@@ -0,0 +1,13 @@ | |||
{ | |||
"config" : { | |||
"vendor-dir": ".", | |||
"optimize-autoloader": true, | |||
"classmap-authoritative": true, | |||
"autoloader-suffix": "ContactsInteraction" | |||
}, | |||
"autoload" : { | |||
"psr-4": { | |||
"OCA\\ContactsInteraction\\": "../lib/" | |||
} | |||
} | |||
} |
@@ -0,0 +1,445 @@ | |||
<?php | |||
/* | |||
* This file is part of Composer. | |||
* | |||
* (c) Nils Adermann <naderman@naderman.de> | |||
* Jordi Boggiano <j.boggiano@seld.be> | |||
* | |||
* For the full copyright and license information, please view the LICENSE | |||
* file that was distributed with this source code. | |||
*/ | |||
namespace Composer\Autoload; | |||
/** | |||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader. | |||
* | |||
* $loader = new \Composer\Autoload\ClassLoader(); | |||
* | |||
* // register classes with namespaces | |||
* $loader->add('Symfony\Component', __DIR__.'/component'); | |||
* $loader->add('Symfony', __DIR__.'/framework'); | |||
* | |||
* // activate the autoloader | |||
* $loader->register(); | |||
* | |||
* // to enable searching the include path (eg. for PEAR packages) | |||
* $loader->setUseIncludePath(true); | |||
* | |||
* In this example, if you try to use a class in the Symfony\Component | |||
* namespace or one of its children (Symfony\Component\Console for instance), | |||
* the autoloader will first look for the class under the component/ | |||
* directory, and it will then fallback to the framework/ directory if not | |||
* found before giving up. | |||
* | |||
* This class is loosely based on the Symfony UniversalClassLoader. | |||
* | |||
* @author Fabien Potencier <fabien@symfony.com> | |||
* @author Jordi Boggiano <j.boggiano@seld.be> | |||
* @see http://www.php-fig.org/psr/psr-0/ | |||
* @see http://www.php-fig.org/psr/psr-4/ | |||
*/ | |||
class ClassLoader | |||
{ | |||
// PSR-4 | |||
private $prefixLengthsPsr4 = array(); | |||
private $prefixDirsPsr4 = array(); | |||
private $fallbackDirsPsr4 = array(); | |||
// PSR-0 | |||
private $prefixesPsr0 = array(); | |||
private $fallbackDirsPsr0 = array(); | |||
private $useIncludePath = false; | |||
private $classMap = array(); | |||
private $classMapAuthoritative = false; | |||
private $missingClasses = array(); | |||
private $apcuPrefix; | |||
public function getPrefixes() | |||
{ | |||
if (!empty($this->prefixesPsr0)) { | |||
return call_user_func_array('array_merge', $this->prefixesPsr0); | |||
} | |||
return array(); | |||
} | |||
public function getPrefixesPsr4() | |||
{ | |||
return $this->prefixDirsPsr4; | |||
} | |||
public function getFallbackDirs() | |||
{ | |||
return $this->fallbackDirsPsr0; | |||
} | |||
public function getFallbackDirsPsr4() | |||
{ | |||
return $this->fallbackDirsPsr4; | |||
} | |||
public function getClassMap() | |||
{ | |||
return $this->classMap; | |||
} | |||
/** | |||
* @param array $classMap Class to filename map | |||
*/ | |||
public function addClassMap(array $classMap) | |||
{ | |||
if ($this->classMap) { | |||
$this->classMap = array_merge($this->classMap, $classMap); | |||
} else { | |||
$this->classMap = $classMap; | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-0 directories for a given prefix, either | |||
* appending or prepending to the ones previously set for this prefix. | |||
* | |||
* @param string $prefix The prefix | |||
* @param array|string $paths The PSR-0 root directories | |||
* @param bool $prepend Whether to prepend the directories | |||
*/ | |||
public function add($prefix, $paths, $prepend = false) | |||
{ | |||
if (!$prefix) { | |||
if ($prepend) { | |||
$this->fallbackDirsPsr0 = array_merge( | |||
(array) $paths, | |||
$this->fallbackDirsPsr0 | |||
); | |||
} else { | |||
$this->fallbackDirsPsr0 = array_merge( | |||
$this->fallbackDirsPsr0, | |||
(array) $paths | |||
); | |||
} | |||
return; | |||
} | |||
$first = $prefix[0]; | |||
if (!isset($this->prefixesPsr0[$first][$prefix])) { | |||
$this->prefixesPsr0[$first][$prefix] = (array) $paths; | |||
return; | |||
} | |||
if ($prepend) { | |||
$this->prefixesPsr0[$first][$prefix] = array_merge( | |||
(array) $paths, | |||
$this->prefixesPsr0[$first][$prefix] | |||
); | |||
} else { | |||
$this->prefixesPsr0[$first][$prefix] = array_merge( | |||
$this->prefixesPsr0[$first][$prefix], | |||
(array) $paths | |||
); | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-4 directories for a given namespace, either | |||
* appending or prepending to the ones previously set for this namespace. | |||
* | |||
* @param string $prefix The prefix/namespace, with trailing '\\' | |||
* @param array|string $paths The PSR-4 base directories | |||
* @param bool $prepend Whether to prepend the directories | |||
* | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function addPsr4($prefix, $paths, $prepend = false) | |||
{ | |||
if (!$prefix) { | |||
// Register directories for the root namespace. | |||
if ($prepend) { | |||
$this->fallbackDirsPsr4 = array_merge( | |||
(array) $paths, | |||
$this->fallbackDirsPsr4 | |||
); | |||
} else { | |||
$this->fallbackDirsPsr4 = array_merge( | |||
$this->fallbackDirsPsr4, | |||
(array) $paths | |||
); | |||
} | |||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) { | |||
// Register directories for a new namespace. | |||
$length = strlen($prefix); | |||
if ('\\' !== $prefix[$length - 1]) { | |||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | |||
} | |||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | |||
$this->prefixDirsPsr4[$prefix] = (array) $paths; | |||
} elseif ($prepend) { | |||
// Prepend directories for an already registered namespace. | |||
$this->prefixDirsPsr4[$prefix] = array_merge( | |||
(array) $paths, | |||
$this->prefixDirsPsr4[$prefix] | |||
); | |||
} else { | |||
// Append directories for an already registered namespace. | |||
$this->prefixDirsPsr4[$prefix] = array_merge( | |||
$this->prefixDirsPsr4[$prefix], | |||
(array) $paths | |||
); | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-0 directories for a given prefix, | |||
* replacing any others previously set for this prefix. | |||
* | |||
* @param string $prefix The prefix | |||
* @param array|string $paths The PSR-0 base directories | |||
*/ | |||
public function set($prefix, $paths) | |||
{ | |||
if (!$prefix) { | |||
$this->fallbackDirsPsr0 = (array) $paths; | |||
} else { | |||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-4 directories for a given namespace, | |||
* replacing any others previously set for this namespace. | |||
* | |||
* @param string $prefix The prefix/namespace, with trailing '\\' | |||
* @param array|string $paths The PSR-4 base directories | |||
* | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function setPsr4($prefix, $paths) | |||
{ | |||
if (!$prefix) { | |||
$this->fallbackDirsPsr4 = (array) $paths; | |||
} else { | |||
$length = strlen($prefix); | |||
if ('\\' !== $prefix[$length - 1]) { | |||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | |||
} | |||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | |||
$this->prefixDirsPsr4[$prefix] = (array) $paths; | |||
} | |||
} | |||
/** | |||
* Turns on searching the include path for class files. | |||
* | |||
* @param bool $useIncludePath | |||
*/ | |||
public function setUseIncludePath($useIncludePath) | |||
{ | |||
$this->useIncludePath = $useIncludePath; | |||
} | |||
/** | |||
* Can be used to check if the autoloader uses the include path to check | |||
* for classes. | |||
* | |||
* @return bool | |||
*/ | |||
public function getUseIncludePath() | |||
{ | |||
return $this->useIncludePath; | |||
} | |||
/** | |||
* Turns off searching the prefix and fallback directories for classes | |||
* that have not been registered with the class map. | |||
* | |||
* @param bool $classMapAuthoritative | |||
*/ | |||
public function setClassMapAuthoritative($classMapAuthoritative) | |||
{ | |||
$this->classMapAuthoritative = $classMapAuthoritative; | |||
} | |||
/** | |||
* Should class lookup fail if not found in the current class map? | |||
* | |||
* @return bool | |||
*/ | |||
public function isClassMapAuthoritative() | |||
{ | |||
return $this->classMapAuthoritative; | |||
} | |||
/** | |||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled. | |||
* | |||
* @param string|null $apcuPrefix | |||
*/ | |||
public function setApcuPrefix($apcuPrefix) | |||
{ | |||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; | |||
} | |||
/** | |||
* The APCu prefix in use, or null if APCu caching is not enabled. | |||
* | |||
* @return string|null | |||
*/ | |||
public function getApcuPrefix() | |||
{ | |||
return $this->apcuPrefix; | |||
} | |||
/** | |||
* Registers this instance as an autoloader. | |||
* | |||
* @param bool $prepend Whether to prepend the autoloader or not | |||
*/ | |||
public function register($prepend = false) | |||
{ | |||
spl_autoload_register(array($this, 'loadClass'), true, $prepend); | |||
} | |||
/** | |||
* Unregisters this instance as an autoloader. | |||
*/ | |||
public function unregister() | |||
{ | |||
spl_autoload_unregister(array($this, 'loadClass')); | |||
} | |||
/** | |||
* Loads the given class or interface. | |||
* | |||
* @param string $class The name of the class | |||
* @return bool|null True if loaded, null otherwise | |||
*/ | |||
public function loadClass($class) | |||
{ | |||
if ($file = $this->findFile($class)) { | |||
includeFile($file); | |||
return true; | |||
} | |||
} | |||
/** | |||
* Finds the path to the file where the class is defined. | |||
* | |||
* @param string $class The name of the class | |||
* | |||
* @return string|false The path if found, false otherwise | |||
*/ | |||
public function findFile($class) | |||
{ | |||
// class map lookup | |||
if (isset($this->classMap[$class])) { | |||
return $this->classMap[$class]; | |||
} | |||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { | |||
return false; | |||
} | |||
if (null !== $this->apcuPrefix) { | |||
$file = apcu_fetch($this->apcuPrefix.$class, $hit); | |||
if ($hit) { | |||
return $file; | |||
} | |||
} | |||
$file = $this->findFileWithExtension($class, '.php'); | |||
// Search for Hack files if we are running on HHVM | |||
if (false === $file && defined('HHVM_VERSION')) { | |||
$file = $this->findFileWithExtension($class, '.hh'); | |||
} | |||
if (null !== $this->apcuPrefix) { | |||
apcu_add($this->apcuPrefix.$class, $file); | |||
} | |||
if (false === $file) { | |||
// Remember that this class does not exist. | |||
$this->missingClasses[$class] = true; | |||
} | |||
return $file; | |||
} | |||
private function findFileWithExtension($class, $ext) | |||
{ | |||
// PSR-4 lookup | |||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; | |||
$first = $class[0]; | |||
if (isset($this->prefixLengthsPsr4[$first])) { | |||
$subPath = $class; | |||
while (false !== $lastPos = strrpos($subPath, '\\')) { | |||
$subPath = substr($subPath, 0, $lastPos); | |||
$search = $subPath . '\\'; | |||
if (isset($this->prefixDirsPsr4[$search])) { | |||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); | |||
foreach ($this->prefixDirsPsr4[$search] as $dir) { | |||
if (file_exists($file = $dir . $pathEnd)) { | |||
return $file; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// PSR-4 fallback dirs | |||
foreach ($this->fallbackDirsPsr4 as $dir) { | |||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { | |||
return $file; | |||
} | |||
} | |||
// PSR-0 lookup | |||
if (false !== $pos = strrpos($class, '\\')) { | |||
// namespaced class name | |||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) | |||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); | |||
} else { | |||
// PEAR-like class name | |||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; | |||
} | |||
if (isset($this->prefixesPsr0[$first])) { | |||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { | |||
if (0 === strpos($class, $prefix)) { | |||
foreach ($dirs as $dir) { | |||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | |||
return $file; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// PSR-0 fallback dirs | |||
foreach ($this->fallbackDirsPsr0 as $dir) { | |||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | |||
return $file; | |||
} | |||
} | |||
// PSR-0 include paths. | |||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { | |||
return $file; | |||
} | |||
return false; | |||
} | |||
} | |||
/** | |||
* Scope isolated include. | |||
* | |||
* Prevents access to $this/self from included files. | |||
*/ | |||
function includeFile($file) | |||
{ | |||
include $file; | |||
} |
@@ -0,0 +1,21 @@ | |||
Copyright (c) Nils Adermann, Jordi Boggiano | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is furnished | |||
to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. | |||
@@ -0,0 +1,19 @@ | |||
<?php | |||
// autoload_classmap.php @generated by Composer | |||
$vendorDir = dirname(dirname(__FILE__)); | |||
$baseDir = $vendorDir; | |||
return array( | |||
'OCA\\ContactsInteraction\\AddressBook' => $baseDir . '/../lib/AddressBook.php', | |||
'OCA\\ContactsInteraction\\AddressBookProvider' => $baseDir . '/../lib/AddressBookProvider.php', | |||
'OCA\\ContactsInteraction\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php', | |||
'OCA\\ContactsInteraction\\BackgroundJob\\CleanupJob' => $baseDir . '/../lib/BackgroundJob/CleanupJob.php', | |||
'OCA\\ContactsInteraction\\Card' => $baseDir . '/../lib/Card.php', | |||
'OCA\\ContactsInteraction\\Db\\CardSearchDao' => $baseDir . '/../lib/Db/CardSearchDao.php', | |||
'OCA\\ContactsInteraction\\Db\\RecentContact' => $baseDir . '/../lib/Db/RecentContact.php', | |||
'OCA\\ContactsInteraction\\Db\\RecentContactMapper' => $baseDir . '/../lib/Db/RecentContactMapper.php', | |||
'OCA\\ContactsInteraction\\Listeners\\ContactInteractionListener' => $baseDir . '/../lib/Listeners/ContactInteractionListener.php', | |||
'OCA\\ContactsInteraction\\Migration\\Version010000Date20200304152605' => $baseDir . '/../lib/Migration/Version010000Date20200304152605.php', | |||
); |
@@ -0,0 +1,9 @@ | |||
<?php | |||
// autoload_namespaces.php @generated by Composer | |||
$vendorDir = dirname(dirname(__FILE__)); | |||
$baseDir = $vendorDir; | |||
return array( | |||
); |
@@ -0,0 +1,10 @@ | |||
<?php | |||
// autoload_psr4.php @generated by Composer | |||
$vendorDir = dirname(dirname(__FILE__)); | |||
$baseDir = $vendorDir; | |||
return array( | |||
'OCA\\ContactsInteraction\\' => array($baseDir . '/../lib'), | |||
); |
@@ -0,0 +1,46 @@ | |||
<?php | |||
// autoload_real.php @generated by Composer | |||
class ComposerAutoloaderInitContactsInteraction | |||
{ | |||
private static $loader; | |||
public static function loadClassLoader($class) | |||
{ | |||
if ('Composer\Autoload\ClassLoader' === $class) { | |||
require __DIR__ . '/ClassLoader.php'; | |||
} | |||
} | |||
/** | |||
* @return \Composer\Autoload\ClassLoader | |||
*/ | |||
public static function getLoader() | |||
{ | |||
if (null !== self::$loader) { | |||
return self::$loader; | |||
} | |||
spl_autoload_register(array('ComposerAutoloaderInitContactsInteraction', 'loadClassLoader'), true, true); | |||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(); | |||
spl_autoload_unregister(array('ComposerAutoloaderInitContactsInteraction', 'loadClassLoader')); | |||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); | |||
if ($useStaticLoader) { | |||
require_once __DIR__ . '/autoload_static.php'; | |||
call_user_func(\Composer\Autoload\ComposerStaticInitContactsInteraction::getInitializer($loader)); | |||
} else { | |||
$classMap = require __DIR__ . '/autoload_classmap.php'; | |||
if ($classMap) { | |||
$loader->addClassMap($classMap); | |||
} | |||
} | |||
$loader->setClassMapAuthoritative(true); | |||
$loader->register(true); | |||
return $loader; | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
<?php | |||
// autoload_static.php @generated by Composer | |||
namespace Composer\Autoload; | |||
class ComposerStaticInitContactsInteraction | |||
{ | |||
public static $prefixLengthsPsr4 = array ( | |||
'O' => | |||
array ( | |||
'OCA\\ContactsInteraction\\' => 24, | |||
), | |||
); | |||
public static $prefixDirsPsr4 = array ( | |||
'OCA\\ContactsInteraction\\' => | |||
array ( | |||
0 => __DIR__ . '/..' . '/../lib', | |||
), | |||
); | |||
public static $classMap = array ( | |||
'OCA\\ContactsInteraction\\AddressBook' => __DIR__ . '/..' . '/../lib/AddressBook.php', | |||
'OCA\\ContactsInteraction\\AddressBookProvider' => __DIR__ . '/..' . '/../lib/AddressBookProvider.php', | |||
'OCA\\ContactsInteraction\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php', | |||
'OCA\\ContactsInteraction\\BackgroundJob\\CleanupJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupJob.php', | |||
'OCA\\ContactsInteraction\\Card' => __DIR__ . '/..' . '/../lib/Card.php', | |||
'OCA\\ContactsInteraction\\Db\\CardSearchDao' => __DIR__ . '/..' . '/../lib/Db/CardSearchDao.php', | |||
'OCA\\ContactsInteraction\\Db\\RecentContact' => __DIR__ . '/..' . '/../lib/Db/RecentContact.php', | |||
'OCA\\ContactsInteraction\\Db\\RecentContactMapper' => __DIR__ . '/..' . '/../lib/Db/RecentContactMapper.php', | |||
'OCA\\ContactsInteraction\\Listeners\\ContactInteractionListener' => __DIR__ . '/..' . '/../lib/Listeners/ContactInteractionListener.php', | |||
'OCA\\ContactsInteraction\\Migration\\Version010000Date20200304152605' => __DIR__ . '/..' . '/../lib/Migration/Version010000Date20200304152605.php', | |||
); | |||
public static function getInitializer(ClassLoader $loader) | |||
{ | |||
return \Closure::bind(function () use ($loader) { | |||
$loader->prefixLengthsPsr4 = ComposerStaticInitContactsInteraction::$prefixLengthsPsr4; | |||
$loader->prefixDirsPsr4 = ComposerStaticInitContactsInteraction::$prefixDirsPsr4; | |||
$loader->classMap = ComposerStaticInitContactsInteraction::$classMap; | |||
}, null, ClassLoader::class); | |||
} | |||
} |
@@ -0,0 +1,178 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction; | |||
use Exception; | |||
use OCA\ContactsInteraction\AppInfo\Application; | |||
use OCA\ContactsInteraction\Db\RecentContact; | |||
use OCA\ContactsInteraction\Db\RecentContactMapper; | |||
use OCA\DAV\CardDAV\Integration\ExternalAddressBook; | |||
use OCA\DAV\DAV\Sharing\Plugin; | |||
use OCP\AppFramework\Db\DoesNotExistException; | |||
use OCP\IL10N; | |||
use Sabre\DAV\Exception\NotFound; | |||
use Sabre\DAV\Exception\NotImplemented; | |||
use Sabre\DAV\PropPatch; | |||
use Sabre\DAVACL\ACLTrait; | |||
use Sabre\DAVACL\IACL; | |||
class AddressBook extends ExternalAddressBook implements IACL { | |||
public const URI = 'recent'; | |||
use ACLTrait; | |||
/** @var RecentContactMapper */ | |||
private $mapper; | |||
/** @var IL10N */ | |||
private $l10n; | |||
/** @var string */ | |||
private $principalUri; | |||
public function __construct(RecentContactMapper $mapper, | |||
IL10N $l10n, | |||
string $principalUri) { | |||
parent::__construct(Application::APP_ID, self::URI); | |||
$this->mapper = $mapper; | |||
$this->l10n = $l10n; | |||
$this->principalUri = $principalUri; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function delete(): void { | |||
throw new Exception("This addressbook is immutable"); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function createFile($name, $data = null) { | |||
throw new Exception("This addressbook is immutable"); | |||
} | |||
/** | |||
* @inheritDoc | |||
* @throws NotFound | |||
*/ | |||
public function getChild($name) { | |||
try { | |||
return new Card( | |||
$this->mapper->find( | |||
$this->getUid(), | |||
(int)$name | |||
), | |||
$this->principalUri, | |||
$this->getACL() | |||
); | |||
} catch (DoesNotExistException $ex) { | |||
throw new NotFound("Contact does not exist: " . $ex->getMessage(), 0, $ex); | |||
} | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function getChildren(): array { | |||
return array_map( | |||
function (RecentContact $contact) { | |||
return new Card( | |||
$contact, | |||
$this->principalUri, | |||
$this->getACL() | |||
); | |||
}, | |||
$this->mapper->findAll($this->getUid()) | |||
); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function childExists($name) { | |||
try { | |||
$this->mapper->find( | |||
$this->getUid(), | |||
(int)$name | |||
); | |||
return true; | |||
} catch (DoesNotExistException $e) { | |||
return false; | |||
} | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function getLastModified() { | |||
throw new NotImplemented(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function propPatch(PropPatch $propPatch) { | |||
throw new Exception("This addressbook is immutable"); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function getProperties($properties) { | |||
return [ | |||
'principaluri' => $this->principalUri, | |||
'{DAV:}displayname' => $this->l10n->t('Recently contacted'), | |||
'{' . Plugin::NS_OWNCLOUD . '}read-only' => true, | |||
]; | |||
} | |||
public function getOwner(): string { | |||
return $this->principalUri; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function getACL() { | |||
return [ | |||
[ | |||
'privilege' => '{DAV:}read', | |||
'principal' => $this->getOwner(), | |||
'protected' => true, | |||
], | |||
]; | |||
} | |||
private function getUid(): string { | |||
list(, $uid) = \Sabre\Uri\split($this->principalUri); | |||
return $uid; | |||
} | |||
} |
@@ -0,0 +1,81 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction; | |||
use OCA\ContactsInteraction\AppInfo\Application; | |||
use OCA\ContactsInteraction\Db\RecentContactMapper; | |||
use OCA\DAV\CardDAV\Integration\ExternalAddressBook; | |||
use OCA\DAV\CardDAV\Integration\IAddressBookProvider; | |||
use OCP\IL10N; | |||
class AddressBookProvider implements IAddressBookProvider { | |||
/** @var RecentContactMapper */ | |||
private $mapper; | |||
/** @var IL10N */ | |||
private $l10n; | |||
public function __construct(RecentContactMapper $mapper, IL10N $l10n) { | |||
$this->mapper = $mapper; | |||
$this->l10n = $l10n; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function getAppId(): string { | |||
return Application::APP_ID; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function fetchAllForAddressBookHome(string $principalUri): array { | |||
return [ | |||
new AddressBook($this->mapper, $this->l10n, $principalUri) | |||
]; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function hasAddressBookInAddressBookHome(string $principalUri, string $uri): bool { | |||
return $uri === AddressBook::URI; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
public function getAddressBookInAddressBookHome(string $principalUri, string $uri): ?ExternalAddressBook { | |||
if ($uri === AddressBook::URI) { | |||
return new AddressBook($this->mapper, $this->l10n, $principalUri); | |||
} | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction\AppInfo; | |||
use OCA\ContactsInteraction\AddressBook; | |||
use OCA\ContactsInteraction\Listeners\ContactInteractionListener; | |||
use OCA\ContactsInteraction\Store; | |||
use OCP\AppFramework\App; | |||
use OCP\AppFramework\IAppContainer; | |||
use OCP\Contacts\Events\ContactInteractedWithEvent; | |||
use OCP\EventDispatcher\IEventDispatcher; | |||
use OCP\EventDispatcher\IEventListener; | |||
use OCP\IL10N; | |||
class Application extends App { | |||
public const APP_ID = 'contactsinteraction'; | |||
public function __construct() { | |||
parent::__construct(self::APP_ID); | |||
$this->registerListeners($this->getContainer()->query(IEventDispatcher::class)); | |||
} | |||
private function registerListeners(IEventDispatcher $dispatcher): void { | |||
$dispatcher->addServiceListener(ContactInteractedWithEvent::class, ContactInteractionListener::class); | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction\BackgroundJob; | |||
use OCA\ContactsInteraction\Db\RecentContactMapper; | |||
use OCP\AppFramework\Utility\ITimeFactory; | |||
use OCP\BackgroundJob\TimedJob; | |||
class CleanupJob extends TimedJob { | |||
/** @var RecentContactMapper */ | |||
private $mapper; | |||
public function __construct(ITimeFactory $time, | |||
RecentContactMapper $mapper) { | |||
parent::__construct($time); | |||
$this->setInterval(12 * 60 * 60); | |||
$this->mapper = $mapper; | |||
} | |||
protected function run($argument) { | |||
$time = $this->time->getDateTime(); | |||
$time->modify('-7days'); | |||
$this->mapper->cleanUp($time->getTimestamp()); | |||
} | |||
} |
@@ -0,0 +1,137 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction; | |||
use OCA\ContactsInteraction\Db\RecentContact; | |||
use Sabre\CardDAV\ICard; | |||
use Sabre\DAV\Exception\NotImplemented; | |||
use Sabre\DAVACL\ACLTrait; | |||
use Sabre\DAVACL\IACL; | |||
class Card implements ICard, IACL { | |||
use ACLTrait; | |||
/** @var RecentContact */ | |||
private $contact; | |||
/** @var string */ | |||
private $principal; | |||
/** @var array */ | |||
private $acls; | |||
public function __construct(RecentContact $contact, string $principal, array $acls) { | |||
$this->contact = $contact; | |||
$this->principal = $principal; | |||
$this->acls = $acls; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function getOwner(): ?string { | |||
$this->principal; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function getACL(): array { | |||
return $this->acls; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function setAcls(array $acls): void { | |||
throw new NotImplemented(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function put($data): ?string { | |||
throw new NotImplemented(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function get() { | |||
return $this->contact->getCard(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function getContentType(): ?string { | |||
return 'text/vcard; charset=utf-8'; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function getETag(): ?string { | |||
return null; | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function getSize(): int { | |||
throw new NotImplemented(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function delete(): void { | |||
throw new NotImplemented(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function getName(): string { | |||
return (string) $this->contact->getId(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function setName($name): void { | |||
throw new NotImplemented(); | |||
} | |||
/** | |||
* @inheritDoc | |||
*/ | |||
function getLastModified(): ?int { | |||
return $this->contact->getLastContact(); | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction\Db; | |||
use OCP\DB\QueryBuilder\IQueryBuilder; | |||
use OCP\IDBConnection; | |||
use OCP\IUser; | |||
class CardSearchDao { | |||
/** @var IDBConnection */ | |||
private $db; | |||
public function __construct(IDBConnection $db) { | |||
$this->db = $db; | |||
} | |||
public function findExisting(IUser $user, | |||
?string $uid, | |||
?string $email, | |||
?string $cloudId): ?string { | |||
$addressbooksQuery = $this->db->getQueryBuilder(); | |||
$cardQuery = $this->db->getQueryBuilder(); | |||
$propQuery = $this->db->getQueryBuilder(); | |||
$propOr = $propQuery->expr()->orX(); | |||
if ($uid !== null) { | |||
$propOr->add($propQuery->expr()->andX( | |||
$propQuery->expr()->eq('name', $cardQuery->createNamedParameter('UID')), | |||
$propQuery->expr()->eq('value', $cardQuery->createNamedParameter($uid)) | |||
)); | |||
} | |||
if ($email !== null) { | |||
$propOr->add($propQuery->expr()->andX( | |||
$propQuery->expr()->eq('name', $cardQuery->createNamedParameter('EMAIL')), | |||
$propQuery->expr()->eq('value', $cardQuery->createNamedParameter($email)) | |||
)); | |||
} | |||
if ($cloudId !== null) { | |||
$propOr->add($propQuery->expr()->andX( | |||
$propQuery->expr()->eq('name', $cardQuery->createNamedParameter('CLOUD')), | |||
$propQuery->expr()->eq('value', $cardQuery->createNamedParameter($cloudId)) | |||
)); | |||
} | |||
$addressbooksQuery->selectDistinct('id') | |||
->from('addressbooks') | |||
->where($addressbooksQuery->expr()->eq('principaluri', $cardQuery->createNamedParameter("principals/users/" . $user->getUID()))); | |||
$propQuery->selectDistinct('cardid') | |||
->from('cards_properties') | |||
->where($propQuery->expr()->in('addressbookid', $propQuery->createFunction($addressbooksQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY)) | |||
->andWhere($propOr) | |||
->groupBy('cardid'); | |||
$cardQuery->select('carddata') | |||
->from('cards') | |||
->where($cardQuery->expr()->in('id', $cardQuery->createFunction($propQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY)) | |||
->andWhere($cardQuery->expr()->in('addressbookid', $cardQuery->createFunction($addressbooksQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY)) | |||
->setMaxResults(1); | |||
$result = $cardQuery->execute(); | |||
/** @var string|false $card */ | |||
$card = $result->fetchColumn(0); | |||
if ($card === false) { | |||
return null; | |||
} | |||
return $card; | |||
} | |||
} |
@@ -0,0 +1,73 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction\Db; | |||
use OCP\AppFramework\Db\Entity; | |||
/** | |||
* @method void setActorUid(string $uid) | |||
* @method string|null getActorUid() | |||
* @method void setUid(string $uid) | |||
* @method string|null getUid() | |||
* @method void setEmail(string $email) | |||
* @method string|null getEmail() | |||
* @method void setFederatedCloudId(string $federatedCloudId) | |||
* @method string|null getFederatedCloudId() | |||
* @method void setCard(string $card) | |||
* @method string getCard() | |||
* @method void setLastContact(int $lastContact) | |||
* @method int getLastContact() | |||
*/ | |||
class RecentContact extends Entity { | |||
/** @var string */ | |||
protected $actorUid; | |||
/** @var string|null */ | |||
protected $uid; | |||
/** @var string|null */ | |||
protected $email; | |||
/** @var string|null */ | |||
protected $federatedCloudId; | |||
/** @var string */ | |||
protected $card; | |||
/** @var int */ | |||
protected $lastContact; | |||
public function __construct() { | |||
$this->addType('actorUid', 'string'); | |||
$this->addType('uid', 'string'); | |||
$this->addType('email', 'string'); | |||
$this->addType('federatedCloudId', 'string'); | |||
$this->addType('card', 'string'); | |||
$this->addType('lastContact', 'int'); | |||
} | |||
} |
@@ -0,0 +1,118 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction\Db; | |||
use OCP\AppFramework\Db\DoesNotExistException; | |||
use OCP\AppFramework\Db\QBMapper; | |||
use OCP\IDBConnection; | |||
use OCP\IUser; | |||
class RecentContactMapper extends QBMapper { | |||
public const TABLE_NAME = 'recent_contact'; | |||
public function __construct(IDBConnection $db) { | |||
parent::__construct($db, self::TABLE_NAME); | |||
} | |||
/** | |||
* @return RecentContact[] | |||
*/ | |||
public function findAll(string $uid): array { | |||
$qb = $this->db->getQueryBuilder(); | |||
$select = $qb | |||
->select('*') | |||
->from($this->getTableName()) | |||
->where($qb->expr()->eq('actor_uid', $qb->createNamedParameter($uid))); | |||
return $this->findEntities($select); | |||
} | |||
/** | |||
* @param string $uid | |||
* @param int $id | |||
* | |||
* @return RecentContact | |||
* @throws DoesNotExistException | |||
*/ | |||
public function find(string $uid, int $id): RecentContact { | |||
$qb = $this->db->getQueryBuilder(); | |||
$select = $qb | |||
->select('*') | |||
->from($this->getTableName()) | |||
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, $qb::PARAM_INT))) | |||
->andWhere($qb->expr()->eq('actor_uid', $qb->createNamedParameter($uid))); | |||
return $this->findEntity($select); | |||
} | |||
/** | |||
* @param IUser $user | |||
* @param string|null $uid | |||
* @param string|null $email | |||
* @param string|null $cloudId | |||
* | |||
* @return RecentContact[] | |||
*/ | |||
public function findMatch(IUser $user, | |||
?string $uid, | |||
?string $email, | |||
?string $cloudId): array { | |||
$qb = $this->db->getQueryBuilder(); | |||
$or = $qb->expr()->orX(); | |||
if ($uid !== null) { | |||
$or->add($qb->expr()->eq('uid', $qb->createNamedParameter($uid))); | |||
} | |||
if ($email !== null) { | |||
$or->add($qb->expr()->eq('email', $qb->createNamedParameter($email))); | |||
} | |||
if ($cloudId !== null) { | |||
$or->add($qb->expr()->eq('federated_cloud_id', $qb->createNamedParameter($cloudId))); | |||
} | |||
$select = $qb | |||
->select('*') | |||
->from($this->getTableName()) | |||
->where($or) | |||
->andWhere($qb->expr()->eq('actor_uid', $qb->createNamedParameter($user->getUID()))); | |||
return $this->findEntities($select); | |||
} | |||
public function cleanUp(int $olderThan): void { | |||
$qb = $this->db->getQueryBuilder(); | |||
$delete = $qb | |||
->delete($this->getTableName()) | |||
->where($qb->expr()->lt('last_contact', $qb->createNamedParameter($olderThan))); | |||
$delete->execute(); | |||
} | |||
} |
@@ -0,0 +1,171 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction\Listeners; | |||
use OCA\ContactsInteraction\Db\CardSearchDao; | |||
use OCA\ContactsInteraction\Db\RecentContact; | |||
use OCA\ContactsInteraction\Db\RecentContactMapper; | |||
use OCP\AppFramework\Utility\ITimeFactory; | |||
use OCP\Contacts\Events\ContactInteractedWithEvent; | |||
use OCP\EventDispatcher\Event; | |||
use OCP\EventDispatcher\IEventListener; | |||
use OCP\IL10N; | |||
use OCP\ILogger; | |||
use OCP\IUserManager; | |||
use Sabre\VObject\Component\VCard; | |||
use Sabre\VObject\Reader; | |||
use Sabre\VObject\UUIDUtil; | |||
use Throwable; | |||
class ContactInteractionListener implements IEventListener { | |||
/** @var RecentContactMapper */ | |||
private $mapper; | |||
/** @var CardSearchDao */ | |||
private $cardSearchDao; | |||
/** @var IUserManager */ | |||
private $userManager; | |||
/** @var ITimeFactory */ | |||
private $timeFactory; | |||
/** @var IL10N */ | |||
private $l10n; | |||
/** @var ILogger */ | |||
private $logger; | |||
public function __construct(RecentContactMapper $mapper, | |||
CardSearchDao $cardSearchDao, | |||
IUserManager $userManager, | |||
ITimeFactory $timeFactory, | |||
IL10N $l10nFactory, | |||
ILogger $logger) { | |||
$this->mapper = $mapper; | |||
$this->cardSearchDao = $cardSearchDao; | |||
$this->userManager = $userManager; | |||
$this->timeFactory = $timeFactory; | |||
$this->l10n = $l10nFactory; | |||
$this->logger = $logger; | |||
} | |||
public function handle(Event $event): void { | |||
if (!($event instanceof ContactInteractedWithEvent)) { | |||
return; | |||
} | |||
if ($event->getUid() === null && $event->getEmail() === null && $event->getFederatedCloudId() === null) { | |||
$this->logger->warning("Contact interaction event has no user identifier set"); | |||
return; | |||
} | |||
$existing = $this->mapper->findMatch( | |||
$event->getActor(), | |||
$event->getUid(), | |||
$event->getEmail(), | |||
$event->getFederatedCloudId() | |||
); | |||
if (!empty($existing)) { | |||
$now = $this->timeFactory->getTime(); | |||
foreach ($existing as $c) { | |||
$c->setLastContact($now); | |||
$this->mapper->update($c); | |||
} | |||
return; | |||
} | |||
$contact = new RecentContact(); | |||
$contact->setActorUid($event->getActor()->getUID()); | |||
if ($event->getUid() !== null) { | |||
$contact->setUid($event->getUid()); | |||
} | |||
if ($event->getEmail() !== null) { | |||
$contact->setEmail($event->getEmail()); | |||
} | |||
if ($event->getFederatedCloudId() !== null) { | |||
$contact->setFederatedCloudId($event->getFederatedCloudId()); | |||
} | |||
$contact->setLastContact($this->timeFactory->getTime()); | |||
$copy = $this->cardSearchDao->findExisting( | |||
$event->getActor(), | |||
$event->getUid(), | |||
$event->getEmail(), | |||
$event->getFederatedCloudId() | |||
); | |||
if ($copy !== null) { | |||
try { | |||
$parsed = Reader::read($copy, Reader::OPTION_FORGIVING); | |||
$parsed->CATEGORIES = $this->l10n->t('Recently contacted'); | |||
$contact->setCard($parsed->serialize()); | |||
} catch (Throwable $e) { | |||
$this->logger->logException($e, [ | |||
'message' => 'Could not parse card to add recent category: ' . $e->getMessage(), | |||
'level' => ILogger::WARN, | |||
]); | |||
$contact->setCard($copy); | |||
} | |||
} else { | |||
$contact->setCard($this->generateCard($contact)); | |||
} | |||
$this->mapper->insert($contact); | |||
} | |||
private function getDisplayName(?string $uid): ?string { | |||
if ($uid === null) { | |||
return null; | |||
} | |||
if (($user = $this->userManager->get($uid)) === null) { | |||
return null; | |||
} | |||
return $user->getDisplayName(); | |||
} | |||
private function generateCard(RecentContact $contact): string { | |||
$props = [ | |||
'URI' => UUIDUtil::getUUID(), | |||
'FN' => $this->getDisplayName($contact->getUid()) ?? $contact->getEmail() ?? $contact->getFederatedCloudId(), | |||
'CATEGORIES' => $this->l10n->t('Recently contacted'), | |||
]; | |||
if ($contact->getUid() !== null) { | |||
$props['X-NEXTCLOUD-UID'] = $contact->getUid(); | |||
} | |||
if ($contact->getEmail() !== null) { | |||
$props['EMAIL'] = $contact->getEmail(); | |||
} | |||
if ($contact->getFederatedCloudId() !== null) { | |||
$props['CLOUD'] = $contact->getFederatedCloudId(); | |||
} | |||
return (new VCard($props))->serialize(); | |||
} | |||
} |
@@ -0,0 +1,93 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\ContactsInteraction\Migration; | |||
use Closure; | |||
use OCA\ContactsInteraction\Db\RecentContactMapper; | |||
use OCP\DB\ISchemaWrapper; | |||
use OCP\Migration\IOutput; | |||
use OCP\Migration\SimpleMigrationStep; | |||
class Version010000Date20200304152605 extends SimpleMigrationStep { | |||
/** | |||
* @param IOutput $output | |||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` | |||
* @param array $options | |||
* | |||
* @return ISchemaWrapper | |||
*/ | |||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ISchemaWrapper { | |||
/** @var ISchemaWrapper $schema */ | |||
$schema = $schemaClosure(); | |||
$table = $schema->createTable(RecentContactMapper::TABLE_NAME); | |||
$table->addColumn('id', 'integer', [ | |||
'autoincrement' => true, | |||
'notnull' => true, | |||
'length' => 4, | |||
]); | |||
$table->addColumn('actor_uid', 'string', [ | |||
'notnull' => true, | |||
'length' => 64, | |||
]); | |||
$table->addColumn('uid', 'string', [ | |||
'notnull' => false, | |||
'length' => 64, | |||
]); | |||
$table->addColumn('email', 'string', [ | |||
'notnull' => false, | |||
'length' => 255, | |||
]); | |||
$table->addColumn('federated_cloud_id', 'string', [ | |||
'notnull' => false, | |||
'length' => 255, | |||
]); | |||
$table->addColumn('card', 'blob', [ | |||
'notnull' => true, | |||
]); | |||
$table->addColumn('last_contact', 'integer', [ | |||
'notnull' => true, | |||
'length' => 4, | |||
]); | |||
$table->setPrimaryKey(['id']); | |||
// To find all recent entries | |||
$table->addIndex(['actor_uid'], RecentContactMapper::TABLE_NAME . '_actor_uid'); | |||
// To find a specific entry | |||
$table->addIndex(['id', 'actor_uid'], RecentContactMapper::TABLE_NAME . '_id_uid'); | |||
// To find all recent entries with a given UID | |||
$table->addIndex(['uid'], RecentContactMapper::TABLE_NAME . '_uid'); | |||
// To find all recent entries with a given email address | |||
$table->addIndex(['email'], RecentContactMapper::TABLE_NAME . '_email'); | |||
// To find all recent entries with a give federated cloud id | |||
$table->addIndex(['federated_cloud_id'], RecentContactMapper::TABLE_NAME . '_fed_id'); | |||
// For the cleanup | |||
$table->addIndex(['last_contact'], RecentContactMapper::TABLE_NAME . '_last_contact'); | |||
return $schema; | |||
} | |||
} |
@@ -28,11 +28,14 @@ declare(strict_types=1); | |||
namespace OCA\DAV\CardDAV; | |||
use OCA\DAV\AppInfo\PluginManager; | |||
use OCA\DAV\CardDAV\Integration\IAddressBookProvider; | |||
use OCA\DAV\CardDAV\Integration\ExternalAddressBook; | |||
use OCP\IConfig; | |||
use OCP\IL10N; | |||
use Sabre\CardDAV\Backend; | |||
use Sabre\DAV\Exception\MethodNotAllowed; | |||
use Sabre\CardDAV\IAddressBook; | |||
use function array_map; | |||
use Sabre\DAV\MkCol; | |||
class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { | |||
@@ -56,7 +59,7 @@ class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { | |||
/** | |||
* Returns a list of address books | |||
* | |||
* @return array | |||
* @return IAddressBook[] | |||
*/ | |||
function getChildren() { | |||
if ($this->l10n === null) { | |||
@@ -67,6 +70,7 @@ class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { | |||
} | |||
$addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri); | |||
/** @var IAddressBook[] $objects */ | |||
$objects = array_map(function(array $addressBook) { | |||
if ($addressBook['principaluri'] === 'principals/system/system') { | |||
return new SystemAddressbook($this->carddavBackend, $addressBook, $this->l10n, $this->config); | |||
@@ -74,11 +78,12 @@ class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome { | |||
return new AddressBook($this->carddavBackend, $addressBook, $this->l10n); | |||
}, $addressBooks); | |||
foreach ($this->pluginManager->getAddressBookPlugins() as $plugin) { | |||
$plugin->fetchAllForAddressBookHome($this->principalUri); | |||
} | |||
return $objects; | |||
/** @var IAddressBook[][] $objectsFromPlugins */ | |||
$objectsFromPlugins = array_map(function(IAddressBookProvider $plugin): array { | |||
return $plugin->fetchAllForAddressBookHome($this->principalUri); | |||
}, $this->pluginManager->getAddressBookPlugins()); | |||
return array_merge($objects, ...$objectsFromPlugins); | |||
} | |||
public function createExtendedCollection($name, MkCol $mkCol) { |
@@ -50,6 +50,7 @@ return array( | |||
'OCA\\Files_Sharing\\ISharedStorage' => $baseDir . '/../lib/ISharedStorage.php', | |||
'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php', | |||
'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', | |||
'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => $baseDir . '/../lib/Listener/ShareInteractionListener.php', | |||
'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => $baseDir . '/../lib/Listener/UserAddedToGroupListener.php', | |||
'OCA\\Files_Sharing\\Listener\\UserShareAcceptanceListener' => $baseDir . '/../lib/Listener/UserShareAcceptanceListener.php', | |||
'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => $baseDir . '/../lib/Middleware/OCSShareAPIMiddleware.php', |
@@ -65,6 +65,7 @@ class ComposerStaticInitFiles_Sharing | |||
'OCA\\Files_Sharing\\ISharedStorage' => __DIR__ . '/..' . '/../lib/ISharedStorage.php', | |||
'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php', | |||
'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', | |||
'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => __DIR__ . '/..' . '/../lib/Listener/ShareInteractionListener.php', | |||
'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => __DIR__ . '/..' . '/../lib/Listener/UserAddedToGroupListener.php', | |||
'OCA\\Files_Sharing\\Listener\\UserShareAcceptanceListener' => __DIR__ . '/..' . '/../lib/Listener/UserShareAcceptanceListener.php', | |||
'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/OCSShareAPIMiddleware.php', |
@@ -36,9 +36,9 @@ use OCA\Files_Sharing\Capabilities; | |||
use OCA\Files_Sharing\Controller\ExternalSharesController; | |||
use OCA\Files_Sharing\Controller\ShareController; | |||
use OCA\Files_Sharing\External\Manager; | |||
use OCA\Files_Sharing\Listener\GlobalShareAcceptanceListener; | |||
use OCA\Files_Sharing\Listener\LoadAdditionalListener; | |||
use OCA\Files_Sharing\Listener\LoadSidebarListener; | |||
use OCA\Files_Sharing\Listener\ShareInteractionListener; | |||
use OCA\Files_Sharing\Listener\UserAddedToGroupListener; | |||
use OCA\Files_Sharing\Listener\UserShareAcceptanceListener; | |||
use OCA\Files_Sharing\Middleware\OCSShareAPIMiddleware; | |||
@@ -213,6 +213,7 @@ class Application extends App { | |||
// sidebar and files scripts | |||
$dispatcher->addServiceListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class); | |||
$dispatcher->addServiceListener(LoadSidebar::class, LoadSidebarListener::class); | |||
$dispatcher->addServiceListener(ShareCreatedEvent::class, ShareInteractionListener::class); | |||
$dispatcher->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function() { | |||
\OCP\Util::addScript('files_sharing', 'dist/collaboration'); | |||
}); |
@@ -0,0 +1,95 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCA\Files_Sharing\Listener; | |||
use OCP\Contacts\Events\ContactInteractedWithEvent; | |||
use OCP\EventDispatcher\Event; | |||
use OCP\EventDispatcher\IEventDispatcher; | |||
use OCP\EventDispatcher\IEventListener; | |||
use OCP\ILogger; | |||
use OCP\IUserManager; | |||
use OCP\Share\Events\ShareCreatedEvent; | |||
use OCP\Share\IShare; | |||
use function in_array; | |||
class ShareInteractionListener implements IEventListener { | |||
private const SUPPORTED_SHARE_TYPES = [ | |||
IShare::TYPE_USER, | |||
IShare::TYPE_EMAIL, | |||
IShare::TYPE_REMOTE, | |||
]; | |||
/** @var IEventDispatcher */ | |||
private $dispatcher; | |||
/** @var IUserManager */ | |||
private $userManager; | |||
/** @var ILogger */ | |||
private $logger; | |||
public function __construct(IEventDispatcher $dispatcher, | |||
IUserManager $userManager, | |||
ILogger $logger) { | |||
$this->dispatcher = $dispatcher; | |||
$this->userManager = $userManager; | |||
$this->logger = $logger; | |||
} | |||
public function handle(Event $event): void { | |||
if (!($event instanceof ShareCreatedEvent)) { | |||
// Unrelated | |||
return; | |||
} | |||
$share = $event->getShare(); | |||
if (!in_array($share->getShareType(), self::SUPPORTED_SHARE_TYPES, true)) { | |||
$this->logger->debug('Share type does not allow to emit interaction event'); | |||
return; | |||
} | |||
$actor = $this->userManager->get($share->getSharedBy()); | |||
if ($actor === null) { | |||
$this->logger->warning('Share was not created by a user, can\'t emit interaction event'); | |||
return; | |||
} | |||
$interactionEvent = new ContactInteractedWithEvent($actor); | |||
switch ($share->getShareType()) { | |||
case IShare::TYPE_USER: | |||
$interactionEvent->setUid($share->getSharedWith()); | |||
break; | |||
case IShare::TYPE_EMAIL: | |||
$interactionEvent->setEmail($share->getSharedWith()); | |||
break; | |||
case IShare::TYPE_REMOTE: | |||
$interactionEvent->setFederatedCloudId($share->getSharedWith()); | |||
break; | |||
} | |||
$this->dispatcher->dispatchTyped($interactionEvent); | |||
} | |||
} |
@@ -66,7 +66,7 @@ class ListApps extends Base { | |||
} else { | |||
$shippedFilter = null; | |||
} | |||
$apps = \OC_App::getAllApps(); | |||
$enabledApps = $disabledApps = []; | |||
$versions = \OC_App::getAppVersions(); |
@@ -5,6 +5,7 @@ | |||
"admin_audit", | |||
"cloud_federation_api", | |||
"comments", | |||
"contactsinteraction", | |||
"dav", | |||
"encryption", | |||
"federatedfilesharing", |
@@ -147,6 +147,7 @@ return array( | |||
'OCP\\Contacts\\ContactsMenu\\IEntry' => $baseDir . '/lib/public/Contacts/ContactsMenu/IEntry.php', | |||
'OCP\\Contacts\\ContactsMenu\\ILinkAction' => $baseDir . '/lib/public/Contacts/ContactsMenu/ILinkAction.php', | |||
'OCP\\Contacts\\ContactsMenu\\IProvider' => $baseDir . '/lib/public/Contacts/ContactsMenu/IProvider.php', | |||
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => $baseDir . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php', | |||
'OCP\\Contacts\\IManager' => $baseDir . '/lib/public/Contacts/IManager.php', | |||
'OCP\\DB\\ISchemaWrapper' => $baseDir . '/lib/public/DB/ISchemaWrapper.php', | |||
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => $baseDir . '/lib/public/DB/QueryBuilder/ICompositeExpression.php', |
@@ -176,6 +176,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c | |||
'OCP\\Contacts\\ContactsMenu\\IEntry' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IEntry.php', | |||
'OCP\\Contacts\\ContactsMenu\\ILinkAction' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/ILinkAction.php', | |||
'OCP\\Contacts\\ContactsMenu\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IProvider.php', | |||
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => __DIR__ . '/../../..' . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php', | |||
'OCP\\Contacts\\IManager' => __DIR__ . '/../../..' . '/lib/public/Contacts/IManager.php', | |||
'OCP\\DB\\ISchemaWrapper' => __DIR__ . '/../../..' . '/lib/public/DB/ISchemaWrapper.php', | |||
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/ICompositeExpression.php', |
@@ -0,0 +1,136 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> | |||
* | |||
* @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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
namespace OCP\Contacts\Events; | |||
use OCP\EventDispatcher\Event; | |||
use OCP\IUser; | |||
/** | |||
* An event that allows apps to notify other components about an interaction | |||
* between two users. This can be used to build better recommendations and | |||
* suggestions in user interfaces. | |||
* | |||
* Emitters should add at least one identifier (uid, email, federated cloud ID) | |||
* of the recipient of the interaction. | |||
* | |||
* @since 19.0.0 | |||
*/ | |||
class ContactInteractedWithEvent extends Event { | |||
/** @var IUser */ | |||
private $actor; | |||
/** @var string|null */ | |||
private $uid; | |||
/** @var string|null */ | |||
private $email; | |||
/** @var string|null */ | |||
private $federatedCloudId; | |||
/** | |||
* @param IUser $actor the user who started the interaction | |||
* | |||
* @since 19.0.0 | |||
*/ | |||
public function __construct(IUser $actor) { | |||
parent::__construct(); | |||
$this->actor = $actor; | |||
} | |||
/** | |||
* @return IUser | |||
* @since 19.0.0 | |||
*/ | |||
public function getActor(): IUser { | |||
return $this->actor; | |||
} | |||
/** | |||
* @return string|null | |||
* @since 19.0.0 | |||
*/ | |||
public function getUid(): ?string { | |||
return $this->uid; | |||
} | |||
/** | |||
* Set the uid of the person interacted with, if known | |||
* | |||
* @param string $uid | |||
* | |||
* @return self | |||
* @since 19.0.0 | |||
*/ | |||
public function setUid(string $uid): self { | |||
$this->uid = $uid; | |||
return $this; | |||
} | |||
/** | |||
* @return string|null | |||
* @since 19.0.0 | |||
*/ | |||
public function getEmail(): ?string { | |||
return $this->email; | |||
} | |||
/** | |||
* Set the email of the person interacted with, if known | |||
* | |||
* @param string $email | |||
* | |||
* @return self | |||
* @since 19.0.0 | |||
*/ | |||
public function setEmail(string $email): self { | |||
$this->email = $email; | |||
return $this; | |||
} | |||
/** | |||
* @return string|null | |||
* @since 19.0.0 | |||
*/ | |||
public function getFederatedCloudId(): ?string { | |||
return $this->federatedCloudId; | |||
} | |||
/** | |||
* Set the federated cloud of the person interacted with, if known | |||
* | |||
* @param string $federatedCloudId | |||
* | |||
* @return self | |||
* @since 19.0.0 | |||
*/ | |||
public function setFederatedCloudId(string $federatedCloudId): self { | |||
$this->federatedCloudId = $federatedCloudId; | |||
return $this; | |||
} | |||
} |