+ * Create a new basic instance of user with the given pre-validated data.
+ *
+ * @param array{name: string, email: string, password: ?string, external_auth_id: ?string, language: ?string, roles: ?array} $data
+ */
+ public function createWithoutActivity(array $data, bool $emailConfirmed = false): User
+ {
+ $user = new User();
+ $user->name = $data['name'];
+ $user->email = $data['email'];
+ $user->password = bcrypt(empty($data['password']) ? Str::random(32) : $data['password']);
+ $user->email_confirmed = $emailConfirmed;
+ $user->external_auth_id = $data['external_auth_id'] ?? '';
+
+ $user->refreshSlug();
+ $user->save();
+
+ if (!empty($data['language'])) {
+ setting()->putUser($user, 'language', $data['language']);
+ }
+
+ if (isset($data['roles'])) {
+ $this->setUserRoles($user, $data['roles']);
+ }
+
+ $this->downloadAndAssignUserAvatar($user);
+
+ return $user;
+ }
+
+ /**
+ * As per "createWithoutActivity" but records a "create" activity.
+ *
+ * @param array{name: string, email: string, password: ?string, external_auth_id: ?string, language: ?string, roles: ?array} $data
+ */
+ public function create(array $data, bool $sendInvite = false): User
+ {
+ $user = $this->createWithoutActivity($data, true);
+
+ if ($sendInvite) {
+ $this->inviteService->sendInvitation($user);
+ }
+
+ Activity::add(ActivityType::USER_CREATE, $user);
+
+ return $user;
+ }
+
+ /**
+ * Update the given user with the given data.
+ *
+ * @param array{name: ?string, email: ?string, external_auth_id: ?string, password: ?string, roles: ?array<int>, language: ?string} $data
+ *
+ * @throws UserUpdateException