1
0

UsersController.php 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  6. * SPDX-License-Identifier: AGPL-3.0-only
  7. */
  8. namespace OCA\Provisioning_API\Controller;
  9. use InvalidArgumentException;
  10. use OC\Authentication\Token\RemoteWipe;
  11. use OC\KnownUser\KnownUserService;
  12. use OC\User\Backend;
  13. use OCA\Provisioning_API\ResponseDefinitions;
  14. use OCA\Settings\Mailer\NewUserMailHelper;
  15. use OCA\Settings\Settings\Admin\Users;
  16. use OCP\Accounts\IAccountManager;
  17. use OCP\Accounts\IAccountProperty;
  18. use OCP\Accounts\PropertyDoesNotExistException;
  19. use OCP\AppFramework\Http;
  20. use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
  21. use OCP\AppFramework\Http\Attribute\NoAdminRequired;
  22. use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
  23. use OCP\AppFramework\Http\Attribute\UserRateLimit;
  24. use OCP\AppFramework\Http\DataResponse;
  25. use OCP\AppFramework\OCS\OCSException;
  26. use OCP\AppFramework\OCS\OCSForbiddenException;
  27. use OCP\AppFramework\OCS\OCSNotFoundException;
  28. use OCP\AppFramework\OCSController;
  29. use OCP\EventDispatcher\IEventDispatcher;
  30. use OCP\Group\ISubAdmin;
  31. use OCP\HintException;
  32. use OCP\IConfig;
  33. use OCP\IGroup;
  34. use OCP\IGroupManager;
  35. use OCP\IL10N;
  36. use OCP\IPhoneNumberUtil;
  37. use OCP\IRequest;
  38. use OCP\IURLGenerator;
  39. use OCP\IUser;
  40. use OCP\IUserManager;
  41. use OCP\IUserSession;
  42. use OCP\L10N\IFactory;
  43. use OCP\Security\Events\GenerateSecurePasswordEvent;
  44. use OCP\Security\ISecureRandom;
  45. use OCP\User\Backend\ISetDisplayNameBackend;
  46. use OCP\Util;
  47. use Psr\Log\LoggerInterface;
  48. /**
  49. * @psalm-import-type Provisioning_APIUserDetails from ResponseDefinitions
  50. */
  51. class UsersController extends AUserData {
  52. private IL10N $l10n;
  53. public function __construct(
  54. string $appName,
  55. IRequest $request,
  56. IUserManager $userManager,
  57. IConfig $config,
  58. IGroupManager $groupManager,
  59. IUserSession $userSession,
  60. IAccountManager $accountManager,
  61. ISubAdmin $subAdminManager,
  62. IFactory $l10nFactory,
  63. private IURLGenerator $urlGenerator,
  64. private LoggerInterface $logger,
  65. private NewUserMailHelper $newUserMailHelper,
  66. private ISecureRandom $secureRandom,
  67. private RemoteWipe $remoteWipe,
  68. private KnownUserService $knownUserService,
  69. private IEventDispatcher $eventDispatcher,
  70. private IPhoneNumberUtil $phoneNumberUtil,
  71. ) {
  72. parent::__construct(
  73. $appName,
  74. $request,
  75. $userManager,
  76. $config,
  77. $groupManager,
  78. $userSession,
  79. $accountManager,
  80. $subAdminManager,
  81. $l10nFactory
  82. );
  83. $this->l10n = $l10nFactory->get($appName);
  84. }
  85. /**
  86. * Get a list of users
  87. *
  88. * @param string $search Text to search for
  89. * @param int|null $limit Limit the amount of groups returned
  90. * @param int $offset Offset for searching for groups
  91. * @return DataResponse<Http::STATUS_OK, array{users: list<string>}, array{}>
  92. *
  93. * 200: Users returned
  94. */
  95. #[NoAdminRequired]
  96. public function getUsers(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
  97. $user = $this->userSession->getUser();
  98. $users = [];
  99. // Admin? Or SubAdmin?
  100. $uid = $user->getUID();
  101. $subAdminManager = $this->groupManager->getSubAdmin();
  102. $isAdmin = $this->groupManager->isAdmin($uid);
  103. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
  104. if ($isAdmin || $isDelegatedAdmin) {
  105. $users = $this->userManager->search($search, $limit, $offset);
  106. } elseif ($subAdminManager->isSubAdmin($user)) {
  107. $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
  108. foreach ($subAdminOfGroups as $key => $group) {
  109. $subAdminOfGroups[$key] = $group->getGID();
  110. }
  111. $users = [];
  112. foreach ($subAdminOfGroups as $group) {
  113. $users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
  114. }
  115. }
  116. /** @var list<string> $users */
  117. $users = array_keys($users);
  118. return new DataResponse([
  119. 'users' => $users
  120. ]);
  121. }
  122. /**
  123. * Get a list of users and their details
  124. *
  125. * @param string $search Text to search for
  126. * @param int|null $limit Limit the amount of groups returned
  127. * @param int $offset Offset for searching for groups
  128. * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
  129. *
  130. * 200: Users details returned
  131. */
  132. #[NoAdminRequired]
  133. public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
  134. $currentUser = $this->userSession->getUser();
  135. $users = [];
  136. // Admin? Or SubAdmin?
  137. $uid = $currentUser->getUID();
  138. $subAdminManager = $this->groupManager->getSubAdmin();
  139. $isAdmin = $this->groupManager->isAdmin($uid);
  140. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
  141. if ($isAdmin || $isDelegatedAdmin) {
  142. $users = $this->userManager->search($search, $limit, $offset);
  143. $users = array_keys($users);
  144. } elseif ($subAdminManager->isSubAdmin($currentUser)) {
  145. $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
  146. foreach ($subAdminOfGroups as $key => $group) {
  147. $subAdminOfGroups[$key] = $group->getGID();
  148. }
  149. $users = [];
  150. foreach ($subAdminOfGroups as $group) {
  151. $users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
  152. }
  153. $users = array_merge(...$users);
  154. }
  155. $usersDetails = [];
  156. foreach ($users as $userId) {
  157. $userId = (string)$userId;
  158. try {
  159. $userData = $this->getUserData($userId);
  160. } catch (OCSNotFoundException $e) {
  161. // We still want to return all other accounts, but this one was removed from the backends
  162. // yet they are still in our database. Might be a LDAP remnant.
  163. $userData = null;
  164. $this->logger->warning('Found one enabled account that is removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
  165. }
  166. // Do not insert empty entry
  167. if ($userData !== null) {
  168. $usersDetails[$userId] = $userData;
  169. } else {
  170. // Logged user does not have permissions to see this user
  171. // only showing its id
  172. $usersDetails[$userId] = ['id' => $userId];
  173. }
  174. }
  175. return new DataResponse([
  176. 'users' => $usersDetails
  177. ]);
  178. }
  179. /**
  180. * Get the list of disabled users and their details
  181. *
  182. * @param string $search Text to search for
  183. * @param ?int $limit Limit the amount of users returned
  184. * @param int $offset Offset
  185. * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
  186. *
  187. * 200: Disabled users details returned
  188. */
  189. #[NoAdminRequired]
  190. public function getDisabledUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
  191. $currentUser = $this->userSession->getUser();
  192. if ($currentUser === null) {
  193. return new DataResponse(['users' => []]);
  194. }
  195. if ($limit !== null && $limit < 0) {
  196. throw new InvalidArgumentException("Invalid limit value: $limit");
  197. }
  198. if ($offset < 0) {
  199. throw new InvalidArgumentException("Invalid offset value: $offset");
  200. }
  201. $users = [];
  202. // Admin? Or SubAdmin?
  203. $uid = $currentUser->getUID();
  204. $subAdminManager = $this->groupManager->getSubAdmin();
  205. $isAdmin = $this->groupManager->isAdmin($uid);
  206. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
  207. if ($isAdmin || $isDelegatedAdmin) {
  208. $users = $this->userManager->getDisabledUsers($limit, $offset, $search);
  209. $users = array_map(fn (IUser $user): string => $user->getUID(), $users);
  210. } elseif ($subAdminManager->isSubAdmin($currentUser)) {
  211. $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
  212. $users = [];
  213. /* We have to handle offset ourselve for correctness */
  214. $tempLimit = ($limit === null ? null : $limit + $offset);
  215. foreach ($subAdminOfGroups as $group) {
  216. $users = array_unique(array_merge(
  217. $users,
  218. array_map(
  219. fn (IUser $user): string => $user->getUID(),
  220. array_filter(
  221. $group->searchUsers($search),
  222. fn (IUser $user): bool => !$user->isEnabled()
  223. )
  224. )
  225. ));
  226. if (($tempLimit !== null) && (count($users) >= $tempLimit)) {
  227. break;
  228. }
  229. }
  230. $users = array_slice($users, $offset, $limit);
  231. }
  232. $usersDetails = [];
  233. foreach ($users as $userId) {
  234. try {
  235. $userData = $this->getUserData($userId);
  236. } catch (OCSNotFoundException $e) {
  237. // We still want to return all other accounts, but this one was removed from the backends
  238. // yet they are still in our database. Might be a LDAP remnant.
  239. $userData = null;
  240. $this->logger->warning('Found one disabled account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
  241. }
  242. // Do not insert empty entry
  243. if ($userData !== null) {
  244. $usersDetails[$userId] = $userData;
  245. } else {
  246. // Currently logged in user does not have permissions to see this user
  247. // only showing its id
  248. $usersDetails[$userId] = ['id' => $userId];
  249. }
  250. }
  251. return new DataResponse([
  252. 'users' => $usersDetails
  253. ]);
  254. }
  255. /**
  256. * Gets the list of users sorted by lastLogin, from most recent to least recent
  257. *
  258. * @param string $search Text to search for
  259. * @param ?int $limit Limit the amount of users returned
  260. * @param int $offset Offset
  261. * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
  262. *
  263. * 200: Users details returned based on last logged in information
  264. */
  265. #[AuthorizedAdminSetting(settings:Users::class)]
  266. public function getLastLoggedInUsers(string $search = '',
  267. ?int $limit = null,
  268. int $offset = 0,
  269. ): DataResponse {
  270. $currentUser = $this->userSession->getUser();
  271. if ($currentUser === null) {
  272. return new DataResponse(['users' => []]);
  273. }
  274. if ($limit !== null && $limit < 0) {
  275. throw new InvalidArgumentException("Invalid limit value: $limit");
  276. }
  277. if ($offset < 0) {
  278. throw new InvalidArgumentException("Invalid offset value: $offset");
  279. }
  280. $users = [];
  281. // For Admin alone user sorting based on lastLogin. For sub admin and groups this is not supported
  282. $users = $this->userManager->getLastLoggedInUsers($limit, $offset, $search);
  283. $usersDetails = [];
  284. foreach ($users as $userId) {
  285. try {
  286. $userData = $this->getUserData($userId);
  287. } catch (OCSNotFoundException $e) {
  288. // We still want to return all other accounts, but this one was removed from the backends
  289. // yet they are still in our database. Might be a LDAP remnant.
  290. $userData = null;
  291. $this->logger->warning('Found one account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
  292. }
  293. // Do not insert empty entry
  294. if ($userData !== null) {
  295. $usersDetails[$userId] = $userData;
  296. } else {
  297. // Currently logged-in user does not have permissions to see this user
  298. // only showing its id
  299. $usersDetails[$userId] = ['id' => $userId];
  300. }
  301. }
  302. return new DataResponse([
  303. 'users' => $usersDetails
  304. ]);
  305. }
  306. /**
  307. * @NoSubAdminRequired
  308. *
  309. * Search users by their phone numbers
  310. *
  311. * @param string $location Location of the phone number (for country code)
  312. * @param array<string, list<string>> $search Phone numbers to search for
  313. * @return DataResponse<Http::STATUS_OK, array<string, string>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, list<empty>, array{}>
  314. *
  315. * 200: Users returned
  316. * 400: Invalid location
  317. */
  318. #[NoAdminRequired]
  319. public function searchByPhoneNumbers(string $location, array $search): DataResponse {
  320. if ($this->phoneNumberUtil->getCountryCodeForRegion($location) === null) {
  321. // Not a valid region code
  322. return new DataResponse([], Http::STATUS_BAD_REQUEST);
  323. }
  324. /** @var IUser $user */
  325. $user = $this->userSession->getUser();
  326. $knownTo = $user->getUID();
  327. $defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
  328. $normalizedNumberToKey = [];
  329. foreach ($search as $key => $phoneNumbers) {
  330. foreach ($phoneNumbers as $phone) {
  331. $normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $location);
  332. if ($normalizedNumber !== null) {
  333. $normalizedNumberToKey[$normalizedNumber] = (string)$key;
  334. }
  335. if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && str_starts_with($phone, '0')) {
  336. // If the number has a leading zero (no country code),
  337. // we also check the default phone region of the instance,
  338. // when it's different to the user's given region.
  339. $normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $defaultPhoneRegion);
  340. if ($normalizedNumber !== null) {
  341. $normalizedNumberToKey[$normalizedNumber] = (string)$key;
  342. }
  343. }
  344. }
  345. }
  346. $phoneNumbers = array_keys($normalizedNumberToKey);
  347. if (empty($phoneNumbers)) {
  348. return new DataResponse();
  349. }
  350. // Cleanup all previous entries and only allow new matches
  351. $this->knownUserService->deleteKnownTo($knownTo);
  352. $userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
  353. if (empty($userMatches)) {
  354. return new DataResponse();
  355. }
  356. $cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
  357. if (strpos($cloudUrl, 'http://') === 0) {
  358. $cloudUrl = substr($cloudUrl, strlen('http://'));
  359. } elseif (strpos($cloudUrl, 'https://') === 0) {
  360. $cloudUrl = substr($cloudUrl, strlen('https://'));
  361. }
  362. $matches = [];
  363. foreach ($userMatches as $phone => $userId) {
  364. // Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
  365. $matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
  366. $this->knownUserService->storeIsKnownToUser($knownTo, $userId);
  367. }
  368. return new DataResponse($matches);
  369. }
  370. /**
  371. * @throws OCSException
  372. */
  373. private function createNewUserId(): string {
  374. $attempts = 0;
  375. do {
  376. $uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
  377. if (!$this->userManager->userExists($uidCandidate)) {
  378. return $uidCandidate;
  379. }
  380. $attempts++;
  381. } while ($attempts < 10);
  382. throw new OCSException($this->l10n->t('Could not create non-existing user ID'), 111);
  383. }
  384. /**
  385. * Create a new user
  386. *
  387. * @param string $userid ID of the user
  388. * @param string $password Password of the user
  389. * @param string $displayName Display name of the user
  390. * @param string $email Email of the user
  391. * @param list<string> $groups Groups of the user
  392. * @param list<string> $subadmin Groups where the user is subadmin
  393. * @param string $quota Quota of the user
  394. * @param string $language Language of the user
  395. * @param ?string $manager Manager of the user
  396. * @return DataResponse<Http::STATUS_OK, array{id: string}, array{}>
  397. * @throws OCSException
  398. * @throws OCSForbiddenException Missing permissions to make user subadmin
  399. *
  400. * 200: User added successfully
  401. */
  402. #[PasswordConfirmationRequired]
  403. #[NoAdminRequired]
  404. public function addUser(
  405. string $userid,
  406. string $password = '',
  407. string $displayName = '',
  408. string $email = '',
  409. array $groups = [],
  410. array $subadmin = [],
  411. string $quota = '',
  412. string $language = '',
  413. ?string $manager = null,
  414. ): DataResponse {
  415. $user = $this->userSession->getUser();
  416. $isAdmin = $this->groupManager->isAdmin($user->getUID());
  417. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($user->getUID());
  418. $subAdminManager = $this->groupManager->getSubAdmin();
  419. if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
  420. $userid = $this->createNewUserId();
  421. }
  422. if ($this->userManager->userExists($userid)) {
  423. $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
  424. throw new OCSException($this->l10n->t('User already exists'), 102);
  425. }
  426. if ($groups !== []) {
  427. foreach ($groups as $group) {
  428. if (!$this->groupManager->groupExists($group)) {
  429. throw new OCSException($this->l10n->t('Group %1$s does not exist', [$group]), 104);
  430. }
  431. if (!$isAdmin && !($isDelegatedAdmin && $group !== 'admin') && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
  432. throw new OCSException($this->l10n->t('Insufficient privileges for group %1$s', [$group]), 105);
  433. }
  434. }
  435. } else {
  436. if (!$isAdmin && !$isDelegatedAdmin) {
  437. throw new OCSException($this->l10n->t('No group specified (required for sub-admins)'), 106);
  438. }
  439. }
  440. $subadminGroups = [];
  441. if ($subadmin !== []) {
  442. foreach ($subadmin as $groupid) {
  443. $group = $this->groupManager->get($groupid);
  444. // Check if group exists
  445. if ($group === null) {
  446. throw new OCSException($this->l10n->t('Sub-admin group does not exist'), 109);
  447. }
  448. // Check if trying to make subadmin of admin group
  449. if ($group->getGID() === 'admin') {
  450. throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
  451. }
  452. // Check if has permission to promote subadmins
  453. if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin && !$isDelegatedAdmin) {
  454. throw new OCSForbiddenException($this->l10n->t('No permissions to promote sub-admins'));
  455. }
  456. $subadminGroups[] = $group;
  457. }
  458. }
  459. $generatePasswordResetToken = false;
  460. if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
  461. throw new OCSException($this->l10n->t('Invalid password value'), 101);
  462. }
  463. if ($password === '') {
  464. if ($email === '') {
  465. throw new OCSException($this->l10n->t('An email address is required, to send a password link to the user.'), 108);
  466. }
  467. $passwordEvent = new GenerateSecurePasswordEvent();
  468. $this->eventDispatcher->dispatchTyped($passwordEvent);
  469. $password = $passwordEvent->getPassword();
  470. if ($password === null) {
  471. // Fallback: ensure to pass password_policy in any case
  472. $password = $this->secureRandom->generate(10)
  473. . $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
  474. . $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
  475. . $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
  476. . $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
  477. }
  478. $generatePasswordResetToken = true;
  479. }
  480. if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
  481. throw new OCSException($this->l10n->t('Required email address was not provided'), 110);
  482. }
  483. try {
  484. $newUser = $this->userManager->createUser($userid, $password);
  485. $this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
  486. foreach ($groups as $group) {
  487. $this->groupManager->get($group)->addUser($newUser);
  488. $this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
  489. }
  490. foreach ($subadminGroups as $group) {
  491. $subAdminManager->createSubAdmin($newUser, $group);
  492. }
  493. if ($displayName !== '') {
  494. try {
  495. $this->editUser($userid, self::USER_FIELD_DISPLAYNAME, $displayName);
  496. } catch (OCSException $e) {
  497. if ($newUser instanceof IUser) {
  498. $newUser->delete();
  499. }
  500. throw $e;
  501. }
  502. }
  503. if ($quota !== '') {
  504. $this->editUser($userid, self::USER_FIELD_QUOTA, $quota);
  505. }
  506. if ($language !== '') {
  507. $this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
  508. }
  509. /**
  510. * null -> nothing sent
  511. * '' -> unset manager
  512. * else -> set manager
  513. */
  514. if ($manager !== null) {
  515. $this->editUser($userid, self::USER_FIELD_MANAGER, $manager);
  516. }
  517. // Send new user mail only if a mail is set
  518. if ($email !== '') {
  519. $newUser->setEMailAddress($email);
  520. if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
  521. try {
  522. $emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
  523. $this->newUserMailHelper->sendMail($newUser, $emailTemplate);
  524. } catch (\Exception $e) {
  525. // Mail could be failing hard or just be plain not configured
  526. // Logging error as it is the hardest of the two
  527. $this->logger->error(
  528. "Unable to send the invitation mail to $email",
  529. [
  530. 'app' => 'ocs_api',
  531. 'exception' => $e,
  532. ]
  533. );
  534. }
  535. }
  536. }
  537. return new DataResponse(['id' => $userid]);
  538. } catch (HintException $e) {
  539. $this->logger->warning(
  540. 'Failed addUser attempt with hint exception.',
  541. [
  542. 'app' => 'ocs_api',
  543. 'exception' => $e,
  544. ]
  545. );
  546. throw new OCSException($e->getHint(), 107);
  547. } catch (OCSException $e) {
  548. $this->logger->warning(
  549. 'Failed addUser attempt with ocs exception.',
  550. [
  551. 'app' => 'ocs_api',
  552. 'exception' => $e,
  553. ]
  554. );
  555. throw $e;
  556. } catch (InvalidArgumentException $e) {
  557. $this->logger->error(
  558. 'Failed addUser attempt with invalid argument exception.',
  559. [
  560. 'app' => 'ocs_api',
  561. 'exception' => $e,
  562. ]
  563. );
  564. throw new OCSException($e->getMessage(), 101);
  565. } catch (\Exception $e) {
  566. $this->logger->error(
  567. 'Failed addUser attempt with exception.',
  568. [
  569. 'app' => 'ocs_api',
  570. 'exception' => $e
  571. ]
  572. );
  573. throw new OCSException('Bad request', 101);
  574. }
  575. }
  576. /**
  577. * @NoSubAdminRequired
  578. *
  579. * Get the details of a user
  580. *
  581. * @param string $userId ID of the user
  582. * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
  583. * @throws OCSException
  584. *
  585. * 200: User returned
  586. */
  587. #[NoAdminRequired]
  588. public function getUser(string $userId): DataResponse {
  589. $includeScopes = false;
  590. $currentUser = $this->userSession->getUser();
  591. if ($currentUser && $currentUser->getUID() === $userId) {
  592. $includeScopes = true;
  593. }
  594. $data = $this->getUserData($userId, $includeScopes);
  595. // getUserData returns null if not enough permissions
  596. if ($data === null) {
  597. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  598. }
  599. return new DataResponse($data);
  600. }
  601. /**
  602. * @NoSubAdminRequired
  603. *
  604. * Get the details of the current user
  605. *
  606. * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
  607. * @throws OCSException
  608. *
  609. * 200: Current user returned
  610. */
  611. #[NoAdminRequired]
  612. public function getCurrentUser(): DataResponse {
  613. $user = $this->userSession->getUser();
  614. if ($user) {
  615. /** @var Provisioning_APIUserDetails $data */
  616. $data = $this->getUserData($user->getUID(), true);
  617. return new DataResponse($data);
  618. }
  619. throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
  620. }
  621. /**
  622. * @NoSubAdminRequired
  623. *
  624. * Get a list of fields that are editable for the current user
  625. *
  626. * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
  627. * @throws OCSException
  628. *
  629. * 200: Editable fields returned
  630. */
  631. #[NoAdminRequired]
  632. public function getEditableFields(): DataResponse {
  633. $currentLoggedInUser = $this->userSession->getUser();
  634. if (!$currentLoggedInUser instanceof IUser) {
  635. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  636. }
  637. return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
  638. }
  639. /**
  640. * @NoSubAdminRequired
  641. *
  642. * Get a list of fields that are editable for a user
  643. *
  644. * @param string $userId ID of the user
  645. * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
  646. * @throws OCSException
  647. *
  648. * 200: Editable fields for user returned
  649. */
  650. #[NoAdminRequired]
  651. public function getEditableFieldsForUser(string $userId): DataResponse {
  652. $currentLoggedInUser = $this->userSession->getUser();
  653. if (!$currentLoggedInUser instanceof IUser) {
  654. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  655. }
  656. $permittedFields = [];
  657. if ($userId !== $currentLoggedInUser->getUID()) {
  658. $targetUser = $this->userManager->get($userId);
  659. if (!$targetUser instanceof IUser) {
  660. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  661. }
  662. $subAdminManager = $this->groupManager->getSubAdmin();
  663. $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
  664. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
  665. if (
  666. !($isAdmin || $isDelegatedAdmin)
  667. && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
  668. ) {
  669. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  670. }
  671. } else {
  672. $targetUser = $currentLoggedInUser;
  673. }
  674. // Editing self (display, email)
  675. if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
  676. if (
  677. $targetUser->getBackend() instanceof ISetDisplayNameBackend
  678. || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
  679. ) {
  680. $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
  681. }
  682. $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
  683. }
  684. $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
  685. $permittedFields[] = IAccountManager::PROPERTY_PHONE;
  686. $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
  687. $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
  688. $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
  689. $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
  690. $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
  691. $permittedFields[] = IAccountManager::PROPERTY_ROLE;
  692. $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
  693. $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
  694. $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
  695. $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
  696. return new DataResponse($permittedFields);
  697. }
  698. /**
  699. * @NoSubAdminRequired
  700. *
  701. * Update multiple values of the user's details
  702. *
  703. * @param string $userId ID of the user
  704. * @param string $collectionName Collection to update
  705. * @param string $key Key that will be updated
  706. * @param string $value New value for the key
  707. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  708. * @throws OCSException
  709. *
  710. * 200: User values edited successfully
  711. */
  712. #[PasswordConfirmationRequired]
  713. #[NoAdminRequired]
  714. #[UserRateLimit(limit: 5, period: 60)]
  715. public function editUserMultiValue(
  716. string $userId,
  717. string $collectionName,
  718. string $key,
  719. string $value,
  720. ): DataResponse {
  721. $currentLoggedInUser = $this->userSession->getUser();
  722. if ($currentLoggedInUser === null) {
  723. throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
  724. }
  725. $targetUser = $this->userManager->get($userId);
  726. if ($targetUser === null) {
  727. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  728. }
  729. $subAdminManager = $this->groupManager->getSubAdmin();
  730. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
  731. $isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID())
  732. || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser);
  733. $permittedFields = [];
  734. if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
  735. // Editing self (display, email)
  736. $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
  737. $permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
  738. } else {
  739. // Check if admin / subadmin
  740. if ($isAdminOrSubadmin || $isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) {
  741. // They have permissions over the user
  742. $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
  743. } else {
  744. // No rights
  745. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  746. }
  747. }
  748. // Check if permitted to edit this field
  749. if (!in_array($collectionName, $permittedFields)) {
  750. throw new OCSException('', 103);
  751. }
  752. switch ($collectionName) {
  753. case IAccountManager::COLLECTION_EMAIL:
  754. $userAccount = $this->accountManager->getAccount($targetUser);
  755. $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
  756. $mailCollection->removePropertyByValue($key);
  757. if ($value !== '') {
  758. $mailCollection->addPropertyWithDefaults($value);
  759. $property = $mailCollection->getPropertyByValue($key);
  760. if ($isAdminOrSubadmin && $property) {
  761. // admin set mails are auto-verified
  762. $property->setLocallyVerified(IAccountManager::VERIFIED);
  763. }
  764. }
  765. $this->accountManager->updateAccount($userAccount);
  766. if ($value === '' && $key === $targetUser->getPrimaryEMailAddress()) {
  767. $targetUser->setPrimaryEMailAddress('');
  768. }
  769. break;
  770. case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
  771. $userAccount = $this->accountManager->getAccount($targetUser);
  772. $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
  773. $targetProperty = null;
  774. foreach ($mailCollection->getProperties() as $property) {
  775. if ($property->getValue() === $key) {
  776. $targetProperty = $property;
  777. break;
  778. }
  779. }
  780. if ($targetProperty instanceof IAccountProperty) {
  781. try {
  782. $targetProperty->setScope($value);
  783. $this->accountManager->updateAccount($userAccount);
  784. } catch (InvalidArgumentException $e) {
  785. throw new OCSException('', 102);
  786. }
  787. } else {
  788. throw new OCSException('', 102);
  789. }
  790. break;
  791. default:
  792. throw new OCSException('', 103);
  793. }
  794. return new DataResponse();
  795. }
  796. /**
  797. * @NoSubAdminRequired
  798. *
  799. * Update a value of the user's details
  800. *
  801. * @param string $userId ID of the user
  802. * @param string $key Key that will be updated
  803. * @param string $value New value for the key
  804. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  805. * @throws OCSException
  806. *
  807. * 200: User value edited successfully
  808. */
  809. #[PasswordConfirmationRequired]
  810. #[NoAdminRequired]
  811. #[UserRateLimit(limit: 50, period: 60)]
  812. public function editUser(string $userId, string $key, string $value): DataResponse {
  813. $currentLoggedInUser = $this->userSession->getUser();
  814. $targetUser = $this->userManager->get($userId);
  815. if ($targetUser === null) {
  816. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  817. }
  818. $permittedFields = [];
  819. if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
  820. // Editing self (display, email)
  821. if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
  822. if (
  823. $targetUser->getBackend() instanceof ISetDisplayNameBackend
  824. || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
  825. ) {
  826. $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
  827. $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
  828. }
  829. $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
  830. }
  831. $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
  832. $permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
  833. $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
  834. $permittedFields[] = self::USER_FIELD_PASSWORD;
  835. $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
  836. if (
  837. $this->config->getSystemValue('force_language', false) === false ||
  838. $this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
  839. $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
  840. ) {
  841. $permittedFields[] = self::USER_FIELD_LANGUAGE;
  842. }
  843. if (
  844. $this->config->getSystemValue('force_locale', false) === false ||
  845. $this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
  846. $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
  847. ) {
  848. $permittedFields[] = self::USER_FIELD_LOCALE;
  849. $permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
  850. }
  851. $permittedFields[] = IAccountManager::PROPERTY_PHONE;
  852. $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
  853. $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
  854. $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
  855. $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
  856. $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
  857. $permittedFields[] = IAccountManager::PROPERTY_ROLE;
  858. $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
  859. $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
  860. $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
  861. $permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE;
  862. $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
  863. $permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
  864. $permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
  865. $permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
  866. $permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
  867. $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX;
  868. $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
  869. $permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
  870. $permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
  871. $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
  872. $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
  873. $permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX;
  874. $permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
  875. $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX;
  876. // If admin they can edit their own quota and manager
  877. $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
  878. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
  879. if ($isAdmin || $isDelegatedAdmin) {
  880. $permittedFields[] = self::USER_FIELD_QUOTA;
  881. $permittedFields[] = self::USER_FIELD_MANAGER;
  882. }
  883. } else {
  884. // Check if admin / subadmin
  885. $subAdminManager = $this->groupManager->getSubAdmin();
  886. if (
  887. $this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
  888. $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID()) && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')
  889. || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
  890. ) {
  891. // They have permissions over the user
  892. if (
  893. $targetUser->getBackend() instanceof ISetDisplayNameBackend
  894. || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
  895. ) {
  896. $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
  897. $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
  898. }
  899. $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
  900. $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
  901. $permittedFields[] = self::USER_FIELD_PASSWORD;
  902. $permittedFields[] = self::USER_FIELD_LANGUAGE;
  903. $permittedFields[] = self::USER_FIELD_LOCALE;
  904. $permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
  905. $permittedFields[] = IAccountManager::PROPERTY_PHONE;
  906. $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
  907. $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
  908. $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
  909. $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
  910. $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
  911. $permittedFields[] = IAccountManager::PROPERTY_ROLE;
  912. $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
  913. $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
  914. $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
  915. $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
  916. $permittedFields[] = self::USER_FIELD_QUOTA;
  917. $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
  918. $permittedFields[] = self::USER_FIELD_MANAGER;
  919. } else {
  920. // No rights
  921. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  922. }
  923. }
  924. // Check if permitted to edit this field
  925. if (!in_array($key, $permittedFields)) {
  926. throw new OCSException('', 113);
  927. }
  928. // Process the edit
  929. switch ($key) {
  930. case self::USER_FIELD_DISPLAYNAME:
  931. case IAccountManager::PROPERTY_DISPLAYNAME:
  932. try {
  933. $targetUser->setDisplayName($value);
  934. } catch (InvalidArgumentException $e) {
  935. throw new OCSException($e->getMessage(), 101);
  936. }
  937. break;
  938. case self::USER_FIELD_QUOTA:
  939. $quota = $value;
  940. if ($quota !== 'none' && $quota !== 'default') {
  941. if (is_numeric($quota)) {
  942. $quota = (float)$quota;
  943. } else {
  944. $quota = Util::computerFileSize($quota);
  945. }
  946. if ($quota === false) {
  947. throw new OCSException($this->l10n->t('Invalid quota value: %1$s', [$value]), 101);
  948. }
  949. if ($quota === -1) {
  950. $quota = 'none';
  951. } else {
  952. $maxQuota = (int)$this->config->getAppValue('files', 'max_quota', '-1');
  953. if ($maxQuota !== -1 && $quota > $maxQuota) {
  954. throw new OCSException($this->l10n->t('Invalid quota value. %1$s is exceeding the maximum quota', [$value]), 101);
  955. }
  956. $quota = Util::humanFileSize($quota);
  957. }
  958. }
  959. // no else block because quota can be set to 'none' in previous if
  960. if ($quota === 'none') {
  961. $allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
  962. if (!$allowUnlimitedQuota) {
  963. throw new OCSException($this->l10n->t('Unlimited quota is forbidden on this instance'), 101);
  964. }
  965. }
  966. $targetUser->setQuota($quota);
  967. break;
  968. case self::USER_FIELD_MANAGER:
  969. $targetUser->setManagerUids([$value]);
  970. break;
  971. case self::USER_FIELD_PASSWORD:
  972. try {
  973. if (strlen($value) > IUserManager::MAX_PASSWORD_LENGTH) {
  974. throw new OCSException($this->l10n->t('Invalid password value'), 101);
  975. }
  976. if (!$targetUser->canChangePassword()) {
  977. throw new OCSException($this->l10n->t('Setting the password is not supported by the users backend'), 112);
  978. }
  979. $targetUser->setPassword($value);
  980. } catch (HintException $e) { // password policy error
  981. throw new OCSException($e->getMessage(), 107);
  982. }
  983. break;
  984. case self::USER_FIELD_LANGUAGE:
  985. $languagesCodes = $this->l10nFactory->findAvailableLanguages();
  986. if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
  987. throw new OCSException($this->l10n->t('Invalid language'), 101);
  988. }
  989. $this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
  990. break;
  991. case self::USER_FIELD_LOCALE:
  992. if (!$this->l10nFactory->localeExists($value)) {
  993. throw new OCSException($this->l10n->t('Invalid locale'), 101);
  994. }
  995. $this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
  996. break;
  997. case self::USER_FIELD_FIRST_DAY_OF_WEEK:
  998. $intValue = (int)$value;
  999. if ($intValue < -1 || $intValue > 6) {
  1000. throw new OCSException($this->l10n->t('Invalid first day of week'), 101);
  1001. }
  1002. if ($intValue === -1) {
  1003. $this->config->deleteUserValue($targetUser->getUID(), 'core', AUserData::USER_FIELD_FIRST_DAY_OF_WEEK);
  1004. } else {
  1005. $this->config->setUserValue($targetUser->getUID(), 'core', AUserData::USER_FIELD_FIRST_DAY_OF_WEEK, $value);
  1006. }
  1007. break;
  1008. case self::USER_FIELD_NOTIFICATION_EMAIL:
  1009. $success = false;
  1010. if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {
  1011. try {
  1012. $targetUser->setPrimaryEMailAddress($value);
  1013. $success = true;
  1014. } catch (InvalidArgumentException $e) {
  1015. $this->logger->info(
  1016. 'Cannot set primary email, because provided address is not verified',
  1017. [
  1018. 'app' => 'provisioning_api',
  1019. 'exception' => $e,
  1020. ]
  1021. );
  1022. }
  1023. }
  1024. if (!$success) {
  1025. throw new OCSException('', 101);
  1026. }
  1027. break;
  1028. case IAccountManager::PROPERTY_EMAIL:
  1029. if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
  1030. $targetUser->setEMailAddress($value);
  1031. } else {
  1032. throw new OCSException('', 101);
  1033. }
  1034. break;
  1035. case IAccountManager::COLLECTION_EMAIL:
  1036. if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getSystemEMailAddress()) {
  1037. $userAccount = $this->accountManager->getAccount($targetUser);
  1038. $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
  1039. if ($mailCollection->getPropertyByValue($value)) {
  1040. throw new OCSException('', 101);
  1041. }
  1042. $mailCollection->addPropertyWithDefaults($value);
  1043. $this->accountManager->updateAccount($userAccount);
  1044. } else {
  1045. throw new OCSException('', 101);
  1046. }
  1047. break;
  1048. case IAccountManager::PROPERTY_PHONE:
  1049. case IAccountManager::PROPERTY_ADDRESS:
  1050. case IAccountManager::PROPERTY_WEBSITE:
  1051. case IAccountManager::PROPERTY_TWITTER:
  1052. case IAccountManager::PROPERTY_FEDIVERSE:
  1053. case IAccountManager::PROPERTY_ORGANISATION:
  1054. case IAccountManager::PROPERTY_ROLE:
  1055. case IAccountManager::PROPERTY_HEADLINE:
  1056. case IAccountManager::PROPERTY_BIOGRAPHY:
  1057. case IAccountManager::PROPERTY_BIRTHDATE:
  1058. case IAccountManager::PROPERTY_PRONOUNS:
  1059. $userAccount = $this->accountManager->getAccount($targetUser);
  1060. try {
  1061. $userProperty = $userAccount->getProperty($key);
  1062. if ($userProperty->getValue() !== $value) {
  1063. try {
  1064. $userProperty->setValue($value);
  1065. if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
  1066. $this->knownUserService->deleteByContactUserId($targetUser->getUID());
  1067. }
  1068. } catch (InvalidArgumentException $e) {
  1069. throw new OCSException('Invalid ' . $e->getMessage(), 101);
  1070. }
  1071. }
  1072. } catch (PropertyDoesNotExistException $e) {
  1073. $userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED);
  1074. }
  1075. try {
  1076. $this->accountManager->updateAccount($userAccount);
  1077. } catch (InvalidArgumentException $e) {
  1078. throw new OCSException('Invalid ' . $e->getMessage(), 101);
  1079. }
  1080. break;
  1081. case IAccountManager::PROPERTY_PROFILE_ENABLED:
  1082. $userAccount = $this->accountManager->getAccount($targetUser);
  1083. try {
  1084. $userProperty = $userAccount->getProperty($key);
  1085. if ($userProperty->getValue() !== $value) {
  1086. $userProperty->setValue($value);
  1087. }
  1088. } catch (PropertyDoesNotExistException $e) {
  1089. $userAccount->setProperty($key, $value, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
  1090. }
  1091. $this->accountManager->updateAccount($userAccount);
  1092. break;
  1093. case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
  1094. case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
  1095. case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
  1096. case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
  1097. case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
  1098. case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
  1099. case IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX:
  1100. case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
  1101. case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
  1102. case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
  1103. case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
  1104. case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
  1105. case IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX:
  1106. case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
  1107. case IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX:
  1108. $propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
  1109. $userAccount = $this->accountManager->getAccount($targetUser);
  1110. $userProperty = $userAccount->getProperty($propertyName);
  1111. if ($userProperty->getScope() !== $value) {
  1112. try {
  1113. $userProperty->setScope($value);
  1114. $this->accountManager->updateAccount($userAccount);
  1115. } catch (InvalidArgumentException $e) {
  1116. throw new OCSException('Invalid ' . $e->getMessage(), 101);
  1117. }
  1118. }
  1119. break;
  1120. default:
  1121. throw new OCSException('', 113);
  1122. }
  1123. return new DataResponse();
  1124. }
  1125. /**
  1126. * Wipe all devices of a user
  1127. *
  1128. * @param string $userId ID of the user
  1129. *
  1130. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1131. *
  1132. * @throws OCSException
  1133. *
  1134. * 200: Wiped all user devices successfully
  1135. */
  1136. #[PasswordConfirmationRequired]
  1137. #[NoAdminRequired]
  1138. public function wipeUserDevices(string $userId): DataResponse {
  1139. /** @var IUser $currentLoggedInUser */
  1140. $currentLoggedInUser = $this->userSession->getUser();
  1141. $targetUser = $this->userManager->get($userId);
  1142. if ($targetUser === null) {
  1143. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1144. }
  1145. if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
  1146. throw new OCSException('', 101);
  1147. }
  1148. // If not permitted
  1149. $subAdminManager = $this->groupManager->getSubAdmin();
  1150. $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
  1151. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
  1152. if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
  1153. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1154. }
  1155. $this->remoteWipe->markAllTokensForWipe($targetUser);
  1156. return new DataResponse();
  1157. }
  1158. /**
  1159. * Delete a user
  1160. *
  1161. * @param string $userId ID of the user
  1162. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1163. * @throws OCSException
  1164. *
  1165. * 200: User deleted successfully
  1166. */
  1167. #[PasswordConfirmationRequired]
  1168. #[NoAdminRequired]
  1169. public function deleteUser(string $userId): DataResponse {
  1170. $currentLoggedInUser = $this->userSession->getUser();
  1171. $targetUser = $this->userManager->get($userId);
  1172. if ($targetUser === null) {
  1173. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1174. }
  1175. if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
  1176. throw new OCSException('', 101);
  1177. }
  1178. // If not permitted
  1179. $subAdminManager = $this->groupManager->getSubAdmin();
  1180. $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
  1181. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
  1182. if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
  1183. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1184. }
  1185. // Go ahead with the delete
  1186. if ($targetUser->delete()) {
  1187. return new DataResponse();
  1188. } else {
  1189. throw new OCSException('', 101);
  1190. }
  1191. }
  1192. /**
  1193. * Disable a user
  1194. *
  1195. * @param string $userId ID of the user
  1196. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1197. * @throws OCSException
  1198. *
  1199. * 200: User disabled successfully
  1200. */
  1201. #[PasswordConfirmationRequired]
  1202. #[NoAdminRequired]
  1203. public function disableUser(string $userId): DataResponse {
  1204. return $this->setEnabled($userId, false);
  1205. }
  1206. /**
  1207. * Enable a user
  1208. *
  1209. * @param string $userId ID of the user
  1210. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1211. * @throws OCSException
  1212. *
  1213. * 200: User enabled successfully
  1214. */
  1215. #[PasswordConfirmationRequired]
  1216. #[NoAdminRequired]
  1217. public function enableUser(string $userId): DataResponse {
  1218. return $this->setEnabled($userId, true);
  1219. }
  1220. /**
  1221. * @param string $userId
  1222. * @param bool $value
  1223. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1224. * @throws OCSException
  1225. */
  1226. private function setEnabled(string $userId, bool $value): DataResponse {
  1227. $currentLoggedInUser = $this->userSession->getUser();
  1228. $targetUser = $this->userManager->get($userId);
  1229. if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
  1230. throw new OCSException('', 101);
  1231. }
  1232. // If not permitted
  1233. $subAdminManager = $this->groupManager->getSubAdmin();
  1234. $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
  1235. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
  1236. if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
  1237. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1238. }
  1239. // enable/disable the user now
  1240. $targetUser->setEnabled($value);
  1241. return new DataResponse();
  1242. }
  1243. /**
  1244. * @NoSubAdminRequired
  1245. *
  1246. * Get a list of groups the user belongs to
  1247. *
  1248. * @param string $userId ID of the user
  1249. * @return DataResponse<Http::STATUS_OK, array{groups: list<string>}, array{}>
  1250. * @throws OCSException
  1251. *
  1252. * 200: Users groups returned
  1253. */
  1254. #[NoAdminRequired]
  1255. public function getUsersGroups(string $userId): DataResponse {
  1256. $loggedInUser = $this->userSession->getUser();
  1257. $targetUser = $this->userManager->get($userId);
  1258. if ($targetUser === null) {
  1259. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1260. }
  1261. $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
  1262. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
  1263. if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
  1264. // Self lookup or admin lookup
  1265. return new DataResponse([
  1266. 'groups' => $this->groupManager->getUserGroupIds($targetUser)
  1267. ]);
  1268. } else {
  1269. $subAdminManager = $this->groupManager->getSubAdmin();
  1270. // Looking up someone else
  1271. if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
  1272. // Return the group that the method caller is subadmin of for the user in question
  1273. $groups = array_values(array_intersect(
  1274. array_map(static fn (IGroup $group) => $group->getGID(), $subAdminManager->getSubAdminsGroups($loggedInUser)),
  1275. $this->groupManager->getUserGroupIds($targetUser)
  1276. ));
  1277. return new DataResponse(['groups' => $groups]);
  1278. } else {
  1279. // Not permitted
  1280. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1281. }
  1282. }
  1283. }
  1284. /**
  1285. * Add a user to a group
  1286. *
  1287. * @param string $userId ID of the user
  1288. * @param string $groupid ID of the group
  1289. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1290. * @throws OCSException
  1291. *
  1292. * 200: User added to group successfully
  1293. */
  1294. #[PasswordConfirmationRequired]
  1295. #[NoAdminRequired]
  1296. public function addToGroup(string $userId, string $groupid = ''): DataResponse {
  1297. if ($groupid === '') {
  1298. throw new OCSException('', 101);
  1299. }
  1300. $group = $this->groupManager->get($groupid);
  1301. $targetUser = $this->userManager->get($userId);
  1302. if ($group === null) {
  1303. throw new OCSException('', 102);
  1304. }
  1305. if ($targetUser === null) {
  1306. throw new OCSException('', 103);
  1307. }
  1308. // If they're not an admin, check they are a subadmin of the group in question
  1309. $loggedInUser = $this->userSession->getUser();
  1310. $subAdminManager = $this->groupManager->getSubAdmin();
  1311. $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
  1312. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
  1313. if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
  1314. throw new OCSException('', 104);
  1315. }
  1316. // Add user to group
  1317. $group->addUser($targetUser);
  1318. return new DataResponse();
  1319. }
  1320. /**
  1321. * Remove a user from a group
  1322. *
  1323. * @param string $userId ID of the user
  1324. * @param string $groupid ID of the group
  1325. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1326. * @throws OCSException
  1327. *
  1328. * 200: User removed from group successfully
  1329. */
  1330. #[PasswordConfirmationRequired]
  1331. #[NoAdminRequired]
  1332. public function removeFromGroup(string $userId, string $groupid): DataResponse {
  1333. $loggedInUser = $this->userSession->getUser();
  1334. if ($groupid === null || trim($groupid) === '') {
  1335. throw new OCSException('', 101);
  1336. }
  1337. $group = $this->groupManager->get($groupid);
  1338. if ($group === null) {
  1339. throw new OCSException('', 102);
  1340. }
  1341. $targetUser = $this->userManager->get($userId);
  1342. if ($targetUser === null) {
  1343. throw new OCSException('', 103);
  1344. }
  1345. // If they're not an admin, check they are a subadmin of the group in question
  1346. $subAdminManager = $this->groupManager->getSubAdmin();
  1347. $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
  1348. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
  1349. if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
  1350. throw new OCSException('', 104);
  1351. }
  1352. // Check they aren't removing themselves from 'admin' or their 'subadmin; group
  1353. if ($targetUser->getUID() === $loggedInUser->getUID()) {
  1354. if ($isAdmin || $isDelegatedAdmin) {
  1355. if ($group->getGID() === 'admin') {
  1356. throw new OCSException($this->l10n->t('Cannot remove yourself from the admin group'), 105);
  1357. }
  1358. } else {
  1359. // Not an admin, so the user must be a subadmin of this group, but that is not allowed.
  1360. throw new OCSException($this->l10n->t('Cannot remove yourself from this group as you are a sub-admin'), 105);
  1361. }
  1362. } elseif (!($isAdmin || $isDelegatedAdmin)) {
  1363. /** @var IGroup[] $subAdminGroups */
  1364. $subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
  1365. $subAdminGroups = array_map(function (IGroup $subAdminGroup) {
  1366. return $subAdminGroup->getGID();
  1367. }, $subAdminGroups);
  1368. $userGroups = $this->groupManager->getUserGroupIds($targetUser);
  1369. $userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
  1370. if (count($userSubAdminGroups) <= 1) {
  1371. // Subadmin must not be able to remove a user from all their subadmin groups.
  1372. throw new OCSException($this->l10n->t('Not viable to remove user from the last group you are sub-admin of'), 105);
  1373. }
  1374. }
  1375. // Remove user from group
  1376. $group->removeUser($targetUser);
  1377. return new DataResponse();
  1378. }
  1379. /**
  1380. * Make a user a subadmin of a group
  1381. *
  1382. * @param string $userId ID of the user
  1383. * @param string $groupid ID of the group
  1384. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1385. * @throws OCSException
  1386. *
  1387. * 200: User added as group subadmin successfully
  1388. */
  1389. #[AuthorizedAdminSetting(settings:Users::class)]
  1390. #[PasswordConfirmationRequired]
  1391. public function addSubAdmin(string $userId, string $groupid): DataResponse {
  1392. $group = $this->groupManager->get($groupid);
  1393. $user = $this->userManager->get($userId);
  1394. // Check if the user exists
  1395. if ($user === null) {
  1396. throw new OCSException($this->l10n->t('User does not exist'), 101);
  1397. }
  1398. // Check if group exists
  1399. if ($group === null) {
  1400. throw new OCSException($this->l10n->t('Group does not exist'), 102);
  1401. }
  1402. // Check if trying to make subadmin of admin group
  1403. if ($group->getGID() === 'admin') {
  1404. throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
  1405. }
  1406. $subAdminManager = $this->groupManager->getSubAdmin();
  1407. // We cannot be subadmin twice
  1408. if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
  1409. return new DataResponse();
  1410. }
  1411. // Go
  1412. $subAdminManager->createSubAdmin($user, $group);
  1413. return new DataResponse();
  1414. }
  1415. /**
  1416. * Remove a user from the subadmins of a group
  1417. *
  1418. * @param string $userId ID of the user
  1419. * @param string $groupid ID of the group
  1420. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1421. * @throws OCSException
  1422. *
  1423. * 200: User removed as group subadmin successfully
  1424. */
  1425. #[AuthorizedAdminSetting(settings:Users::class)]
  1426. #[PasswordConfirmationRequired]
  1427. public function removeSubAdmin(string $userId, string $groupid): DataResponse {
  1428. $group = $this->groupManager->get($groupid);
  1429. $user = $this->userManager->get($userId);
  1430. $subAdminManager = $this->groupManager->getSubAdmin();
  1431. // Check if the user exists
  1432. if ($user === null) {
  1433. throw new OCSException($this->l10n->t('User does not exist'), 101);
  1434. }
  1435. // Check if the group exists
  1436. if ($group === null) {
  1437. throw new OCSException($this->l10n->t('Group does not exist'), 101);
  1438. }
  1439. // Check if they are a subadmin of this said group
  1440. if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
  1441. throw new OCSException($this->l10n->t('User is not a sub-admin of this group'), 102);
  1442. }
  1443. // Go
  1444. $subAdminManager->deleteSubAdmin($user, $group);
  1445. return new DataResponse();
  1446. }
  1447. /**
  1448. * Get the groups a user is a subadmin of
  1449. *
  1450. * @param string $userId ID if the user
  1451. * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
  1452. * @throws OCSException
  1453. *
  1454. * 200: User subadmin groups returned
  1455. */
  1456. #[AuthorizedAdminSetting(settings:Users::class)]
  1457. public function getUserSubAdminGroups(string $userId): DataResponse {
  1458. $groups = $this->getUserSubAdminGroupsData($userId);
  1459. return new DataResponse($groups);
  1460. }
  1461. /**
  1462. * Resend the welcome message
  1463. *
  1464. * @param string $userId ID if the user
  1465. * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
  1466. * @throws OCSException
  1467. *
  1468. * 200: Resent welcome message successfully
  1469. */
  1470. #[PasswordConfirmationRequired]
  1471. #[NoAdminRequired]
  1472. public function resendWelcomeMessage(string $userId): DataResponse {
  1473. $currentLoggedInUser = $this->userSession->getUser();
  1474. $targetUser = $this->userManager->get($userId);
  1475. if ($targetUser === null) {
  1476. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1477. }
  1478. // Check if admin / subadmin
  1479. $subAdminManager = $this->groupManager->getSubAdmin();
  1480. $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
  1481. $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
  1482. if (
  1483. !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
  1484. && !($isAdmin || $isDelegatedAdmin)
  1485. ) {
  1486. // No rights
  1487. throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
  1488. }
  1489. $email = $targetUser->getEMailAddress();
  1490. if ($email === '' || $email === null) {
  1491. throw new OCSException($this->l10n->t('Email address not available'), 101);
  1492. }
  1493. try {
  1494. if ($this->config->getUserValue($targetUser->getUID(), 'core', 'lostpassword')) {
  1495. $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, true);
  1496. } else {
  1497. $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
  1498. }
  1499. $this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
  1500. } catch (\Exception $e) {
  1501. $this->logger->error(
  1502. "Can't send new user mail to $email",
  1503. [
  1504. 'app' => 'settings',
  1505. 'exception' => $e,
  1506. ]
  1507. );
  1508. throw new OCSException($this->l10n->t('Sending email failed'), 102);
  1509. }
  1510. return new DataResponse();
  1511. }
  1512. }