Passed
Push — master ( dc3e05...4deff3 )
by Christoph
12:00 queued 10s
created

Registry::notifyAboutReachedUserLimit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 0
dl 0
loc 14
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 *
7
 *
8
 * @author Julius Härtl <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Roeland Jago Douma <[email protected]>
11
 *
12
 * @license GNU AGPL version 3 or any later version
13
 *
14
 * This program is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License as
16
 * published by the Free Software Foundation, either version 3 of the
17
 * License, or (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26
 *
27
 */
28
29
namespace OC\Support\Subscription;
30
31
use OC\User\Backend;
32
use OCP\AppFramework\QueryException;
33
use OCP\IConfig;
34
use OCP\IGroupManager;
35
use OCP\IServerContainer;
36
use OCP\IUserManager;
37
use OCP\Notification\IManager;
38
use OCP\Support\Subscription\Exception\AlreadyRegisteredException;
39
use OCP\Support\Subscription\IRegistry;
40
use OCP\Support\Subscription\ISubscription;
41
use OCP\Support\Subscription\ISupportedApps;
42
use Psr\Log\LoggerInterface;
43
44
class Registry implements IRegistry {
45
46
	/** @var ISubscription */
47
	private $subscription = null;
48
49
	/** @var string */
50
	private $subscriptionService = null;
51
52
	/** @var IConfig */
53
	private $config;
54
55
	/** @var IServerContainer */
56
	private $container;
57
	/** @var IUserManager */
58
	private $userManager;
59
	/** @var IGroupManager */
60
	private $groupManager;
61
	/** @var LoggerInterface */
62
	private $logger;
63
	/** @var IManager */
64
	private $notificationManager;
65
66
	public function __construct(IConfig $config,
67
								IServerContainer $container,
68
								IUserManager $userManager,
69
								IGroupManager $groupManager,
70
								LoggerInterface $logger,
71
								IManager $notificationManager) {
72
		$this->config = $config;
73
		$this->container = $container;
74
		$this->userManager = $userManager;
75
		$this->groupManager = $groupManager;
76
		$this->logger = $logger;
77
		$this->notificationManager = $notificationManager;
78
	}
79
80
	private function getSubscription(): ?ISubscription {
81
		if ($this->subscription === null && $this->subscriptionService !== null) {
82
			try {
83
				$this->subscription = $this->container->query($this->subscriptionService);
84
			} catch (QueryException $e) {
85
				// Ignore this
86
			}
87
		}
88
89
		return $this->subscription;
90
	}
91
92
	/**
93
	 * Register a subscription instance. In case it is called multiple times the
94
	 * first one is used.
95
	 *
96
	 * @param ISubscription $subscription
97
	 * @throws AlreadyRegisteredException
98
	 *
99
	 * @since 17.0.0
100
	 */
101
	public function register(ISubscription $subscription): void {
102
		if ($this->subscription !== null || $this->subscriptionService !== null) {
103
			throw new AlreadyRegisteredException();
104
		}
105
		$this->subscription = $subscription;
106
	}
107
108
	public function registerService(string $subscriptionService): void {
109
		if ($this->subscription !== null || $this->subscriptionService !== null) {
110
			throw new AlreadyRegisteredException();
111
		}
112
113
		$this->subscriptionService = $subscriptionService;
114
	}
115
116
117
	/**
118
	 * Fetches the list of app IDs that are supported by the subscription
119
	 *
120
	 * @since 17.0.0
121
	 */
122
	public function delegateGetSupportedApps(): array {
123
		if ($this->getSubscription() instanceof ISupportedApps) {
124
			return $this->getSubscription()->getSupportedApps();
125
		}
126
		return [];
127
	}
128
129
	/**
130
	 * Indicates if a valid subscription is available
131
	 *
132
	 * @since 17.0.0
133
	 */
134
	public function delegateHasValidSubscription(): bool {
135
		// Allow overwriting this manually for environments where the subscription information cannot be fetched
136
		if ($this->config->getSystemValueBool('has_valid_subscription')) {
137
			return true;
138
		}
139
140
		if ($this->getSubscription() instanceof ISubscription) {
0 ignored issues
show
introduced by
$this->getSubscription() is always a sub-type of OCP\Support\Subscription\ISubscription.
Loading history...
141
			return $this->getSubscription()->hasValidSubscription();
142
		}
143
		return false;
144
	}
145
146
	/**
147
	 * Indicates if the subscription has extended support
148
	 *
149
	 * @since 17.0.0
150
	 */
151
	public function delegateHasExtendedSupport(): bool {
152
		if ($this->getSubscription() instanceof ISubscription) {
0 ignored issues
show
introduced by
$this->getSubscription() is always a sub-type of OCP\Support\Subscription\ISubscription.
Loading history...
153
			return $this->getSubscription()->hasExtendedSupport();
154
		}
155
		return false;
156
	}
157
158
159
	/**
160
	 * Indicates if a hard user limit is reached and no new users should be created
161
	 *
162
	 * @since 21.0.0
163
	 */
164
	public function delegateIsHardUserLimitReached(): bool {
165
		$subscription = $this->getSubscription();
166
		if ($subscription instanceof ISubscription &&
167
			$subscription->hasValidSubscription()) {
168
			$userLimitReached = $subscription->isHardUserLimitReached();
169
			if ($userLimitReached) {
170
				$this->notifyAboutReachedUserLimit();
171
			}
172
			return $userLimitReached;
173
		}
174
175
		$isOneClickInstance = $this->config->getSystemValueBool('one-click-instance', false);
176
177
		if (!$isOneClickInstance) {
178
			return false;
179
		}
180
181
		$userCount = $this->getUserCount();
182
		$hardUserLimit = $this->config->getSystemValue('one-click-instance.user-limit', 50);
183
184
		$userLimitReached = $userCount >= $hardUserLimit;
185
		if ($userLimitReached) {
186
			$this->notifyAboutReachedUserLimit();
187
		}
188
		return $userLimitReached;
189
	}
190
191
	private function getUserCount(): int {
192
		$userCount = 0;
193
		$backends = $this->userManager->getBackends();
194
		foreach ($backends as $backend) {
195
			if ($backend->implementsActions(Backend::COUNT_USERS)) {
196
				$backendUsers = $backend->countUsers();
0 ignored issues
show
Bug introduced by
The method countUsers() does not exist on OCP\UserInterface. It seems like you code against a sub-type of said class. However, the method does not exist in OC\User\Backend or OCP\User\Backend\ABackend. Are you sure you never get one of those? ( Ignorable by Annotation )

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

196
				/** @scrutinizer ignore-call */ 
197
    $backendUsers = $backend->countUsers();
Loading history...
197
				if ($backendUsers !== false) {
198
					$userCount += $backendUsers;
199
				} else {
200
					// TODO what if the user count can't be determined?
201
					$this->logger->warning('Can not determine user count for ' . get_class($backend), ['app' => 'lib']);
202
				}
203
			}
204
		}
205
206
		$disabledUsers = $this->config->getUsersForUserValue('core', 'enabled', 'false');
207
		$disabledUsersCount = count($disabledUsers);
208
		$userCount = $userCount - $disabledUsersCount;
209
210
		if ($userCount < 0) {
211
			$userCount = 0;
212
213
			// this should never happen
214
			$this->logger->warning("Total user count was negative (users: $userCount, disabled: $disabledUsersCount)", ['app' => 'lib']);
215
		}
216
217
		return $userCount;
218
	}
219
220
	private function notifyAboutReachedUserLimit() {
221
		$admins = $this->groupManager->get('admin')->getUsers();
222
		foreach ($admins as $admin) {
223
			$notification = $this->notificationManager->createNotification();
224
225
			$notification->setApp('core')
226
				->setUser($admin->getUID())
227
				->setDateTime(new \DateTime())
228
				->setObject('user_limit_reached', '1')
229
				->setSubject('user_limit_reached');
230
			$this->notificationManager->notify($notification);
231
		}
232
233
		$this->logger->warning('The user limit was reached and the new user was not created', ['app' => 'lib']);
234
	}
235
}
236