From 22f519e641a3b9e7ce671cdfebf614b85d25c326 Mon Sep 17 00:00:00 2001 From: brantje Date: Fri, 23 Sep 2016 16:52:41 +0200 Subject: [PATCH] Add support for activity app --- appinfo/app.php | 9 +- controller/credentialcontroller.php | 42 ++++- lib/Activity.php | 268 ++++++++++++++++++++++++++++ lib/AppInfo/Application.php | 5 +- lib/Db/CredentialMapper.php | 6 + lib/Service/ActivityService.php | 67 +++++++ lib/Service/CredentialService.php | 9 +- lib/Service/CronService.php | 11 +- 8 files changed, 410 insertions(+), 7 deletions(-) create mode 100644 lib/Activity.php create mode 100644 lib/Service/ActivityService.php diff --git a/appinfo/app.php b/appinfo/app.php index 537de901..d7f99536 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -15,7 +15,7 @@ namespace OCA\Passman\AppInfo; use OCP\Util; use OCP\BackgroundJob; use OCA\Passman\Notifier; - +use OCA\Passman\Activity; require_once __DIR__ . '/autoload.php'; $app = new \OCA\Passman\AppInfo\Application(); @@ -36,6 +36,13 @@ $manager->registerNotifier(function() { ]; }); +$manager = \OC::$server->getActivityManager(); +$manager->registerExtension(function() { + return new Activity( + \OC::$server->getL10NFactory() + ); +}); + /** * Loading translations * diff --git a/controller/credentialcontroller.php b/controller/credentialcontroller.php index 96e35046..9c8651c3 100644 --- a/controller/credentialcontroller.php +++ b/controller/credentialcontroller.php @@ -15,19 +15,23 @@ use OCP\IRequest; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\ApiController; use OCA\Passman\Service\CredentialService; - +use OCA\Passman\Activity; +use OCA\Passman\Service\ActivityService; class CredentialController extends ApiController { private $userId; private $credentialService; + private $activityService; public function __construct($AppName, IRequest $request, $UserId, - CredentialService $credentialService) { + CredentialService $credentialService, + ActivityService $activityService) { parent::__construct($AppName, $request); $this->userId = $UserId; $this->credentialService = $credentialService; + $this->activityService = $activityService; } /** @@ -63,6 +67,11 @@ class CredentialController extends ApiController { ); $credential = $this->credentialService->createCredential($credential); + $link = ''; // @TODO create direct link to credential + $this->activityService->add( + Activity::SUBJECT_ITEM_CREATED_SELF, array($label, $this->userId), + '', array(), + $link, $this->userId, Activity::TYPE_ITEM_ACTION); return new JSONResponse($credential); } @@ -104,7 +113,36 @@ class CredentialController extends ApiController { 'hidden' => $hidden, 'otp' => $otp, ); + + + $storedCredential = $this->credentialService->getCredentialById($credential_id); + $link = ''; // @TODO create direct link to credential + + if (($storedCredential->getDeleteTime() == 0) && $delete_time > 0) { + $this->activityService->add( + 'item_deleted_self', array($label, $this->userId), + '', array(), + $link, $this->userId, Activity::TYPE_ITEM_ACTION); + } else if (($storedCredential->getDeleteTime() > 0) && $delete_time == 0) { + $this->activityService->add( + 'item_recovered_self', array($label, $this->userId), + '', array(), + $link, $this->userId, Activity::TYPE_ITEM_ACTION); + } else if ($label != $storedCredential->getLabel()) { + $this->activityService->add( + 'item_renamed_self', array($storedCredential->getLabel(), $label, $this->userId), + '', array(), + $link, $this->userId, Activity::TYPE_ITEM_ACTION); + } else { + $this->activityService->add( + 'item_edited_self', array($label, $this->userId), + '', array(), + $link, $this->userId, Activity::TYPE_ITEM_ACTION); + } + + $credential = $this->credentialService->updateCredential($credential); + return new JSONResponse($credential); } diff --git a/lib/Activity.php b/lib/Activity.php new file mode 100644 index 00000000..97061845 --- /dev/null +++ b/lib/Activity.php @@ -0,0 +1,268 @@ + + * @copyright Sander Brand 2016 + */ +namespace OCA\Passman; + +class Activity implements \OCP\Activity\IExtension { + const TYPE_ITEM_ACTION = 'passman_item_action'; + const TYPE_ITEM_EXPIRED = 'passman_item_expired'; + const TYPE_ITEM_SHARED = 'passman_item_shared'; + const TYPE_ITEM_RENAMED = 'passman_item_renamed'; + + const SUBJECT_ITEM_CREATED = 'item_created'; + const SUBJECT_ITEM_CREATED_SELF = 'item_created_self'; + const SUBJECT_ITEM_EDITED = 'item_edited'; + const SUBJECT_ITEM_EDITED_SELF = 'item_edited_self'; + const SUBJECT_APPLY_REV = 'item_apply_revision'; + const SUBJECT_APPLY_REV_SELF = 'item_apply_revision_self'; + const SUBJECT_ITEM_DELETED = 'item_deleted'; + const SUBJECT_ITEM_DELETED_SELF = 'item_deleted_self'; + const SUBJECT_ITEM_RECOVERED = 'item_recovered'; + const SUBJECT_ITEM_RECOVERED_SELF = 'item_recovered_self'; + const SUBJECT_ITEM_DESTROYED = 'item_destroyed'; + const SUBJECT_ITEM_DESTROYED_SELF = 'item_destroyed_self'; + const SUBJECT_ITEM_EXPIRED = 'item_expired'; + const SUBJECT_ITEM_SHARED = 'item_shared'; + const SUBJECT_ITEM_RENAMED = 'item_renamed'; + const SUBJECT_ITEM_RENAMED_SELF = 'item_renamed_self'; + + + /** + * The extension can return an array of additional notification types. + * If no additional types are to be added false is to be returned + * + * @param string $languageCode + * @return array|false + */ + public function getNotificationTypes($languageCode) { + $l = \OC::$server->getL10N('passman', $languageCode); + return array( + self::TYPE_ITEM_ACTION => $l->t('A Passman item has been created, modified or deleted'), + self::TYPE_ITEM_EXPIRED => $l->t('A Passman item has expired'), + self::TYPE_ITEM_SHARED => $l->t('A Passman item has been shared'), + self::TYPE_ITEM_RENAMED => $l->t('A Passman item has been renamed') + ); + } + + /** + * The extension can filter the types based on the filter if required. + * In case no filter is to be applied false is to be returned unchanged. + * + * @param array $types + * @param string $filter + * @return array|false + */ + public function filterNotificationTypes($types, $filter) { + return $types; + } + + /** + * For a given method additional types to be displayed in the settings can be returned. + * In case no additional types are to be added false is to be returned. + * + * @param string $method + * @return array|false + */ + public function getDefaultTypes($method) { + if ($method === 'stream') { + return array( + self::TYPE_ITEM_ACTION, + self::TYPE_ITEM_EXPIRED, + self::TYPE_ITEM_SHARED, + self::TYPE_ITEM_EXPIRED, + self::TYPE_ITEM_RENAMED, + ); + } + if ($method === 'email') { + return array( + self::TYPE_ITEM_EXPIRED, + ); + } + return false; + } + + /** + * The extension can translate a given message to the requested languages. + * If no translation is available false is to be returned. + * + * @param string $app + * @param string $text + * @param array $params + * @param boolean $stripPath + * @param boolean $highlightParams + * @param string $languageCode + * @return string|false + */ + public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) { + $l = new \OC_L10N('passman', $languageCode); + if ($app === 'passman') { + switch ($text) { + case self::SUBJECT_ITEM_CREATED: + return $l->t('%1$s has been created by %2$s', $params)->__toString(); + case self::SUBJECT_ITEM_CREATED_SELF: + return $l->t('You created %1$s', $params)->__toString(); + case self::SUBJECT_ITEM_EDITED: + return $l->t('%1$s has been updated by %2$s', $params)->__toString(); + case self::SUBJECT_ITEM_EDITED_SELF: + return $l->t('You updated %1$s', $params)->__toString(); + case self::SUBJECT_APPLY_REV: + return $l->t('%2$s has revised %1$s to the revision of %3$s', $params)->__toString(); + case self::SUBJECT_APPLY_REV_SELF: + return $l->t('You reverted %1$s back to the revision of %3$s', $params)->__toString(); + case self::SUBJECT_ITEM_RENAMED: + return $l->t('%3$s has renamed %1$s to %2$s', $params)->__toString(); + case self::SUBJECT_ITEM_RENAMED_SELF: + return $l->t('You renamed %1$s to %2$s', $params)->__toString(); + case self::SUBJECT_ITEM_DELETED: + return $l->t('%1$s has been deleted by %2$s', $params)->__toString(); + case self::SUBJECT_ITEM_DELETED_SELF: + return $l->t('You deleted %1$s', $params)->__toString(); + case self::SUBJECT_ITEM_RECOVERED: + return $l->t('%1$s has been recovered by %2$s', $params)->__toString(); + case self::SUBJECT_ITEM_RECOVERED_SELF: + return $l->t('You recovered %1$s', $params)->__toString(); + case self::SUBJECT_ITEM_DESTROYED: + return $l->t('%1$s has been permanently deleted by %2$s', $params)->__toString(); + case self::SUBJECT_ITEM_DESTROYED_SELF: + return $l->t('You permanently deleted %1$s', $params)->__toString(); + case self::SUBJECT_ITEM_EXPIRED: + return $l->t('The password of %1$s has expired, renew it now.', $params)->__toString(); + case self::SUBJECT_ITEM_SHARED: + return $l->t('%s has been shared', $params)->__toString(); + } + } + return false; + } + + /** + * The extension can define the type of parameters for translation + * + * Currently known types are: + * * file => will strip away the path of the file and add a tooltip with it + * * username => will add the avatar of the user + * + * @param string $app + * @param string $text + * @return array|false + */ + public function getSpecialParameterList($app, $text) { + if ($app === 'passman') { + switch ($text) { + case self::SUBJECT_ITEM_CREATED: + case self::SUBJECT_ITEM_CREATED_SELF: + case self::SUBJECT_ITEM_EDITED: + case self::SUBJECT_ITEM_EDITED_SELF: + case self::SUBJECT_ITEM_DELETED: + case self::SUBJECT_ITEM_DELETED_SELF: + case self::SUBJECT_ITEM_RECOVERED: + case self::SUBJECT_ITEM_RECOVERED_SELF: + case self::SUBJECT_ITEM_DESTROYED: + case self::SUBJECT_ITEM_DESTROYED_SELF: + return array( + 0 => 'passman', + 1 => 'username', + ); + case self::SUBJECT_APPLY_REV: + case self::SUBJECT_APPLY_REV_SELF: + return array( + 0 => 'passman', + 1 => 'username', + 2 => '', //unknown + ); + case self::SUBJECT_ITEM_EXPIRED: + case self::SUBJECT_ITEM_RENAMED_SELF: + case self::SUBJECT_ITEM_RENAMED: + case self::SUBJECT_ITEM_SHARED: + return array( + 0 => 'passman', + ); + } + } + return false; + } + + /** + * A string naming the css class for the icon to be used can be returned. + * If no icon is known for the given type false is to be returned. + * + * @param string $type + * @return string|false + */ + public function getTypeIcon($type) { + switch ($type) { + case self::TYPE_ITEM_ACTION: + case self::TYPE_ITEM_EXPIRED: + return 'icon-password'; + case self::TYPE_ITEM_SHARED: + return 'icon-share'; + case self::TYPE_ITEM_RENAMED: + return ''; + } + return false; + } + + /** + * The extension can define the parameter grouping by returning the index as integer. + * In case no grouping is required false is to be returned. + * + * @param array $activity + * @return integer|false + */ + public function getGroupParameter($activity) { + return false; + } + + /** + * The extension can define additional navigation entries. The array returned has to contain two keys 'top' + * and 'apps' which hold arrays with the relevant entries. + * If no further entries are to be added false is no be returned. + * + * @return array|false + */ + public function getNavigation() { + $l = \OC::$server->getL10N('passman'); + return array( + 'top' => array(), + 'apps' => array( + array( + 'id' => 'passman', + 'name' => (string) $l->t('Passwords'), + 'url' => '',//FIXME: $this->URLGenerator->linkToRoute('activity.Activities.showList', array('filter' => 'passman')), + ), + ), + ); + } + + /** + * The extension can check if a customer filter (given by a query string like filter=abc) is valid or not. + * + * @param string $filterValue + * @return boolean + */ + public function isFilterValid($filterValue) { + return $filterValue === 'passman'; + } + + /** + * For a given filter the extension can specify the sql query conditions including parameters for that query. + * In case the extension does not know the filter false is to be returned. + * The query condition and the parameters are to be returned as array with two elements. + * E.g. return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%')); + * + * @param string $filter + * @return array|false + */ + public function getQueryForFilter($filter) { + if ($filter === 'passman') { + return array('`app` = ?', array('passman')); + } + return false; + } +} \ No newline at end of file diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 14d26be3..1269468e 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -16,6 +16,7 @@ use OCA\Passman\Controller\CredentialController; use OCA\Passman\Controller\PageController; use OCA\Passman\Controller\ShareController; use OCA\Passman\Controller\VaultController; +use OCA\Passman\Service\ActivityService; use OCA\Passman\Service\CronService; use OCA\Passman\Service\CredentialService; use OCA\Passman\Utility\Utils; @@ -63,7 +64,8 @@ class Application extends App { $c->query('CredentialService'), $c->query('Logger'), $c->query('Utils'), - $c->query('NotificationService') + $c->query('NotificationService'), + $c->query('ActivityService') ); }); @@ -78,6 +80,7 @@ class Application extends App { $container->registerAlias('VaultController', VaultController::class); $container->registerAlias('CredentialService', CredentialService::class); $container->registerAlias('NotificationService', NotificationService::class); + $container->registerAlias('ActivityService', ActivityService::class); $container->registerAlias('Utils', Utils::class); } diff --git a/lib/Db/CredentialMapper.php b/lib/Db/CredentialMapper.php index f37e1e16..99845d18 100644 --- a/lib/Db/CredentialMapper.php +++ b/lib/Db/CredentialMapper.php @@ -38,6 +38,12 @@ class CredentialMapper extends Mapper { return $this->findEntities($sql, [$timestamp]); } + public function getCredentialById($credential_id){ + $sql = 'SELECT * FROM `*PREFIX*passman_credentials` ' . + 'WHERE `id` = ?'; + return $this->findEntity($sql,[$credential_id]); + } + public function create($raw_credential){ $credential = new Credential(); diff --git a/lib/Service/ActivityService.php b/lib/Service/ActivityService.php new file mode 100644 index 00000000..0bb6a8a0 --- /dev/null +++ b/lib/Service/ActivityService.php @@ -0,0 +1,67 @@ + + * @copyright Sander Brand 2016 + */ + +namespace OCA\Passman\Service; + +use OCP\IConfig; +use OCP\AppFramework\Db\DoesNotExistException; + +use OCA\Passman\Db\FileMapper; + + +class ActivityService { + + private $manager; + + public function __construct() { + $this->manager = \OC::$server->getActivityManager(); + } + + /** + * @subject = One of these: item_created, item_edited, item_apply_revision + * item_deleted, item_recovered, item_destroyed, + * item_expired, item_shared + * + * + * + * + * @subjectParams = Subject | Subject params + * item_created = array($itemName,$user) + * item_edited = array($itemName,$user) + * item_apply_revision = array($itemName,$user,$revision); + * item_deleted = array($itemName,$user) + * item_recovered = array($itemName,$user) + * item_destroyed = array($itemName,$user) + * item_expired = array($itemName) + * item_shared = array($itemName) + * @message = Custom message (not needed) + * @messageParams = Message params (not needed) + * @link = will be -> /apps/activity/$link + * @user = Target user + * @type = Can be passman_password or passman_password_shared + * @priority = Int -> [10,20,30,40,50] + */ + public function add($subject,$subjectParams=array(), + $message='',$messageParams=array(), + $link='',$user=null,$type='') { + $activity = $this->manager->generateEvent(); + $activity->setType($type); + $activity->setApp('passman'); + $activity->setSubject($subject, $subjectParams); + $activity->setLink($link); + $activity->setAffectedUser($user); + $activity->setAuthor($user); + $activity->setTimestamp(time()); + $activity->setMessage($message, $messageParams); + print_r($this->manager->publish($activity)); + return array('success'=>'ok'); + } +} \ No newline at end of file diff --git a/lib/Service/CredentialService.php b/lib/Service/CredentialService.php index 04fef2c0..035e4101 100644 --- a/lib/Service/CredentialService.php +++ b/lib/Service/CredentialService.php @@ -33,10 +33,15 @@ class CredentialService { return $this->credentialMapper->update($credential); } - public function getCredentialsByVaultId($vault_id, $user_id){ + public function getCredentialsByVaultId($vault_id, $user_id) { return $this->credentialMapper->getCredentialsByVaultId($vault_id, $user_id); } - public function getExpiredCredentials($timestamp){ + + public function getExpiredCredentials($timestamp) { return $this->credentialMapper->getExpiredCredentials($timestamp); } + + public function getCredentialById($credential_id){ + return $this->credentialMapper->getCredentialById($credential_id); + } } \ No newline at end of file diff --git a/lib/Service/CronService.php b/lib/Service/CronService.php index a32abde9..bdba3941 100644 --- a/lib/Service/CronService.php +++ b/lib/Service/CronService.php @@ -15,6 +15,7 @@ use OCP\IConfig; use OCP\AppFramework\Db\DoesNotExistException; use OCP\ILogger; use OCA\Passman\Utility\Utils; +use OCA\Passman\Activity; class CronService { @@ -22,12 +23,14 @@ class CronService { private $logger; private $utils; private $notificationService; + private $activityService; - public function __construct(CredentialService $credentialService, ILogger $logger, Utils $utils, NotificationService $notificationService) { + public function __construct(CredentialService $credentialService, ILogger $logger, Utils $utils, NotificationService $notificationService, ActivityService $activityService) { $this->credentialService = $credentialService; $this->logger = $logger; $this->utils = $utils; $this->notificationService = $notificationService; + $this->activityService = $activityService; } public function expireCredentials() { @@ -35,6 +38,12 @@ class CronService { $expired_credentials = $this->credentialService->getExpiredCredentials($this->utils->getTime()); foreach($expired_credentials as $credential){ $this->notificationService->credentialExpiredNotification($credential); + $link = ''; // @TODO create direct link to credential + $this->activityService->add( + Activity::SUBJECT_ITEM_EXPIRED, array($credential->getLabel(), $credential->getUserId()), + '', array(), + $link, $credential->getUserId(), Activity::TYPE_ITEM_ACTION); + } } } \ No newline at end of file