Passed
Push — master ( b552da...09c1d8 )
by Roeland
12:09 queued 12s
created

File::prepareRuleMatcher()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 11
rs 9.9666
cc 4
nc 5
nop 3
1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2019 Arthur Schiwon <[email protected]>
5
 *
6
 * @author Arthur Schiwon <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
namespace OCA\WorkflowEngine\Entity;
26
27
use OCP\EventDispatcher\Event;
28
use OCP\EventDispatcher\GenericEvent;
29
use OCP\Files\IRootFolder;
30
use OCP\Files\Node;
31
use OCP\Files\NotFoundException;
32
use OCP\IL10N;
33
use OCP\ILogger;
34
use OCP\IURLGenerator;
35
use OCP\IUserSession;
36
use OCP\Share\IManager as ShareManager;
37
use OCP\SystemTag\ISystemTag;
38
use OCP\SystemTag\ISystemTagManager;
39
use OCP\SystemTag\MapperEvent;
40
use OCP\WorkflowEngine\EntityContext\IDisplayText;
41
use OCP\WorkflowEngine\GenericEntityEvent;
42
use OCP\WorkflowEngine\IEntity;
43
use OCP\WorkflowEngine\IRuleMatcher;
44
45
class File implements IEntity, IDisplayText {
46
47
	private const EVENT_NAMESPACE = '\OCP\Files::';
48
49
	/** @var IL10N */
50
	protected $l10n;
51
	/** @var IURLGenerator */
52
	protected $urlGenerator;
53
	/** @var IRootFolder */
54
	protected $root;
55
	/** @var ILogger */
56
	protected $logger;
57
	/** @var string */
58
	protected $eventName;
59
	/** @var Event */
60
	protected $event;
61
	/** @var ShareManager */
62
	private $shareManager;
63
	/** @var IUserSession */
64
	private $userSession;
65
	/** @var ISystemTagManager */
66
	private $tagManager;
67
68
69
	public function __construct(
70
		IL10N $l10n,
71
		IURLGenerator $urlGenerator,
72
		IRootFolder $root,
73
		ILogger $logger,
74
		ShareManager $shareManager,
75
		IUserSession $userSession,
76
		ISystemTagManager $tagManager
77
	) {
78
		$this->l10n = $l10n;
79
		$this->urlGenerator = $urlGenerator;
80
		$this->root = $root;
81
		$this->logger = $logger;
82
		$this->shareManager = $shareManager;
83
		$this->userSession = $userSession;
84
		$this->tagManager = $tagManager;
85
	}
86
87
	public function getName(): string {
88
		return $this->l10n->t('File');
89
	}
90
91
	public function getIcon(): string {
92
		return $this->urlGenerator->imagePath('core', 'categories/files.svg');
93
	}
94
95
	public function getEvents(): array {
96
		return [
97
			new GenericEntityEvent($this->l10n->t('File created'), self::EVENT_NAMESPACE . 'postCreate'),
98
			new GenericEntityEvent($this->l10n->t('File updated'), self::EVENT_NAMESPACE . 'postWrite'),
99
			new GenericEntityEvent($this->l10n->t('File renamed'), self::EVENT_NAMESPACE . 'postRename'),
100
			new GenericEntityEvent($this->l10n->t('File deleted'), self::EVENT_NAMESPACE . 'postDelete'),
101
			new GenericEntityEvent($this->l10n->t('File accessed'), self::EVENT_NAMESPACE . 'postTouch'),
102
			new GenericEntityEvent($this->l10n->t('File copied'), self::EVENT_NAMESPACE . 'postCopy'),
103
			new GenericEntityEvent($this->l10n->t('Tag assigned'), MapperEvent::EVENT_ASSIGN),
104
		];
105
	}
106
107
	public function prepareRuleMatcher(IRuleMatcher $ruleMatcher, string $eventName, Event $event): void {
108
		if (!$event instanceof GenericEvent && !$event instanceof MapperEvent) {
109
			return;
110
		}
111
		$this->eventName = $eventName;
112
		$this->event = $event;
113
		try {
114
			$node = $this->getNode();
115
			$ruleMatcher->setEntitySubject($this, $node);
116
			$ruleMatcher->setFileInfo($node->getStorage(), $node->getPath());
117
		} catch (NotFoundException $e) {
118
			// pass
119
		}
120
	}
121
122
	public function isLegitimatedForUserId(string $uid): bool {
123
		try {
124
			$node = $this->getNode();
125
			if($node->getOwner()->getUID() === $uid) {
126
				return true;
127
			}
128
			$acl = $this->shareManager->getAccessList($node, true, true);
129
			return array_key_exists($uid, $acl['users']);
130
		} catch (NotFoundException $e) {
131
			return false;
132
		}
133
	}
134
135
	/**
136
	 * @throws NotFoundException
137
	 */
138
	protected function getNode(): Node {
139
		if (!$this->event instanceof GenericEvent && !$this->event instanceof MapperEvent) {
140
			throw new NotFoundException();
141
		}
142
		switch ($this->eventName) {
143
			case self::EVENT_NAMESPACE . 'postCreate':
144
			case self::EVENT_NAMESPACE . 'postWrite':
145
			case self::EVENT_NAMESPACE . 'postDelete':
146
			case self::EVENT_NAMESPACE . 'postTouch':
147
				return $this->event->getSubject();
0 ignored issues
show
Bug introduced by
The method getSubject() does not exist on OCP\SystemTag\MapperEvent. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

147
				return $this->event->/** @scrutinizer ignore-call */ getSubject();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
148
			case self::EVENT_NAMESPACE . 'postRename':
149
			case self::EVENT_NAMESPACE . 'postCopy':
150
				return $this->event->getSubject()[1];
151
			case MapperEvent::EVENT_ASSIGN:
152
				if (!$this->event instanceof MapperEvent || $this->event->getObjectType() !== 'files') {
153
					throw new NotFoundException();
154
				}
155
				$nodes = $this->root->getById((int)$this->event->getObjectId());
156
				if (is_array($nodes) && !empty($nodes)) {
157
					return array_shift($nodes);
158
				}
159
				break;
160
		}
161
		throw new NotFoundException();
162
	}
163
164
	public function getDisplayText(int $verbosity = 0): string {
165
		$user = $this->userSession->getUser();
166
		try {
167
			$node = $this->getNode();
168
		} catch (NotFoundException $e) {
169
			return '';
170
		}
171
172
		$options = [
173
			$user ? $user->getDisplayName() : $this->t('Someone'),
0 ignored issues
show
Bug introduced by
The method t() does not exist on OCA\WorkflowEngine\Entity\File. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

173
			$user ? $user->getDisplayName() : $this->/** @scrutinizer ignore-call */ t('Someone'),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
174
			$node->getName()
175
		];
176
177
		switch ($this->eventName) {
178
			case self::EVENT_NAMESPACE . 'postCreate':
179
				return $this->l10n->t('%s created %s', $options);
180
			case self::EVENT_NAMESPACE . 'postWrite':
181
				return $this->l10n->t('%s modified %s', $options);
182
			case self::EVENT_NAMESPACE . 'postDelete':
183
				return $this->l10n->t('%s deleted %s', $options);
184
			case self::EVENT_NAMESPACE . 'postTouch':
185
				return $this->l10n->t('%s accessed %s', $options);
186
			case self::EVENT_NAMESPACE . 'postRename':
187
				return $this->l10n->t('%s renamed %s', $options);
188
			case self::EVENT_NAMESPACE . 'postCopy':
189
				return $this->l10n->t('%s copied %s', $options);
190
			case MapperEvent::EVENT_ASSIGN:
191
				$tagNames = [];
192
				if($this->event instanceof MapperEvent) {
193
					$tagIDs = $this->event->getTags();
194
					$tagObjects = $this->tagManager->getTagsByIds($tagIDs);
195
					foreach ($tagObjects as $systemTag) {
196
						/** @var ISystemTag $systemTag */
197
						if($systemTag->isUserVisible()) {
198
							$tagNames[] = $systemTag->getName();
199
						}
200
					}
201
				}
202
				$filename = array_pop($options);
203
				$tagString = implode(', ', $tagNames);
204
				if($tagString === '') {
205
					return '';
206
				}
207
				array_push($options, $tagString, $filename);
208
				return $this->l10n->t('%s assigned %s to %s', $options);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
209
		}
210
	}
211
}
212