1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Libraries;
7
8use App\Exceptions\ValidationException;
9use App\Models\Count;
10use App\Models\User;
11use Carbon\Carbon;
12use Datadog;
13use Exception;
14
15class UserRegistration
16{
17 private $group;
18 private $user;
19
20 public function __construct($params)
21 {
22 $group = $params['group'] ?? 'default';
23 unset($params['group']);
24 $this->group = app('groups')->byIdentifier($group);
25 $params['group_id'] = $this->group->getKey();
26
27 $this->user = new User(array_merge([
28 'user_permissions' => '',
29 'user_interests' => '',
30 'user_occ' => '',
31 'user_sig' => '',
32 'user_regdate' => Carbon::now(),
33 'user_lastvisit' => Carbon::now(),
34 ], $params));
35 }
36
37 public function assertValid()
38 {
39 if (!$this->validateAttributes()) {
40 throw new ValidationException($this->user()->validationErrors());
41 }
42
43 $this->assertValidation(UsernameValidation::validateUsername($this->user->username));
44 $this->assertValidation(UsernameValidation::validateAvailability($this->user->username));
45 $this->assertValidation(UsernameValidation::validateUsersOfUsername($this->user->username));
46
47 if (!$this->user->isValid()) {
48 throw new ValidationException($this->user()->validationErrors());
49 }
50 }
51
52 public function save()
53 {
54 $this->assertValid();
55
56 try {
57 $this->user->getConnection()->transaction(function () {
58 User::findAndRenameUserForInactive($this->user->username);
59 if (!$this->user->save()) {
60 // probably failed because of validation
61 throw new ValidationException($this->user->validationErrors());
62 }
63
64 $this->user->setDefaultGroup($this->group);
65
66 Count::totalUsers()->incrementInstance('count');
67 Datadog::increment('osu.new_account_registrations', 1, ['source' => 'osu-web']);
68 });
69 } catch (Exception $e) {
70 if (is_sql_unique_exception($e)) {
71 $this->user->validationErrors()->add('username', '.unknown_duplicate');
72 throw new ValidationException($this->user->validationErrors(), $e);
73 }
74
75 throw $e;
76 }
77 }
78
79 public function user()
80 {
81 return $this->user;
82 }
83
84 private function assertValidation($errors)
85 {
86 $this->user()->validationErrors()->merge($errors);
87
88 if ($this->user()->validationErrors()->isAny()) {
89 throw new ValidationException($this->user->validationErrors());
90 }
91 }
92
93 private function validateAttributes()
94 {
95 $isValid = true;
96
97 foreach (['username', 'user_email'] as $attribute) {
98 if (!present($this->user->$attribute)) {
99 $this->user->validationErrors()->add($attribute, 'required');
100 $isValid = false;
101 }
102 }
103
104 if (!present($this->user->password) && !present($this->user->user_password)) {
105 $this->user->validationErrors()->add('password', 'required');
106 $isValid = false;
107 }
108
109 return $isValid;
110 }
111}