Passed
Pull Request — master (#37)
by Rafael
03:52
created

UsersInviteController   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Test Coverage

Coverage 81.97%

Importance

Changes 0
Metric Value
eloc 123
dl 0
loc 252
ccs 100
cts 122
cp 0.8197
rs 10
c 0
b 0
f 0
wmc 21

5 Methods

Rating   Name   Duplication   Size   Complexity  
A onConstruct() 0 6 1
A getByHash() 0 12 2
B insertInvite() 0 64 7
A loginInvitedUser() 0 28 2
B processUserInvite() 0 94 9
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gewaer\Api\Controllers;
6
7
use Gewaer\Models\UsersInvite;
8
use Gewaer\Models\Users;
9
use Gewaer\Models\UsersAssociatedCompany;
10
use Gewaer\Models\Roles;
11
use Phalcon\Security\Random;
12
use Phalcon\Validation;
13
use Phalcon\Validation\Validator\PresenceOf;
14
use Phalcon\Validation\Validator\StringLength;
15
use Gewaer\Exception\UnprocessableEntityHttpException;
16
use Gewaer\Exception\NotFoundHttpException;
17
use Gewaer\Exception\ServerErrorHttpException;
18
use Phalcon\Http\Response;
19
use Exception;
20
use Baka\Auth\Models\Sessions;
21
use Gewaer\Exception\ModelException;
22
23
/**
24
 * Class LanguagesController
25
 * @property Users $userData
26
 * @property Request $request
27
 * @property Config $config
28
 * @property Apps $app
29
 * @property Mail $mail
30
 * @property Auth $auth
31
 * @package Gewaer\Api\Controllers
32
 *
33
 */
34
class UsersInviteController extends BaseController
35
{
36
    /*
37
     * fields we accept to create
38
     *
39
     * @var array
40
     */
41
    protected $createFields = ['invite_hash', 'companies_id', 'role_id', 'app_id', 'email'];
42
43
    /*
44
     * fields we accept to create
45
     *
46
     * @var array
47
     */
48
    protected $updateFields = ['invite_hash', 'companies_id', 'role_id', 'app_id', 'email'];
49
50
    /**
51
     * set objects
52
     *
53
     * @return void
54
     */
55 4
    public function onConstruct()
56
    {
57 4
        $this->model = new UsersInvite();
58 4
        $this->additionalSearchFields = [
59 4
            ['is_deleted', ':', '0'],
60 4
            ['companies_id', ':', $this->userData->currentCompanyId()],
61
        ];
62 4
    }
63
64
    /**
65
     * Get users invite by hash
66
     * @param string $hash
67
     * @return Response
68
     */
69 1
    public function getByHash(string $hash):Response
70
    {
71 1
        $userInvite = $this->model::findFirst([
72 1
            'conditions' => 'invite_hash =  ?0 and is_deleted = 0',
73 1
            'bind' => [$hash]
74
        ]);
75
76 1
        if (!is_object($userInvite)) {
77
            throw new NotFoundHttpException('Users Invite not found');
78
        }
79
80 1
        return $this->response($userInvite);
81
    }
82
83
    /**
84
     * Sets up invitation information for a would be user
85
     * @return Response
86
     */
87 4
    public function insertInvite(): Response
88
    {
89 4
        $request = $this->request->getPost();
90 4
        $random = new Random();
91
92 4
        $validation = new Validation();
93 4
        $validation->add('email', new PresenceOf(['message' => _('The email is required.')]));
94 4
        $validation->add('role_id', new PresenceOf(['message' => _('The role is required.')]));
95
96
        //validate this form for password
97 4
        $messages = $validation->validate($this->request->getPost());
98 4
        if (count($messages)) {
99
            foreach ($messages as $message) {
100
                throw new ServerErrorHttpException((string)$message);
101
            }
102
        }
103
104
        //Check if user was already was invited to current company and return message
105 4
        $invitedUser = $this->model::findFirst([
106 4
            'conditions' => 'email = ?0 and companies_id = ?1 and role_id = ?2',
107 4
            'bind' => [$request['email'], $this->userData->default_company, $request['role_id']]
108
        ]);
109
110 4
        if (is_object($invitedUser)) {
111
            throw new ModelException('User already invited to this company and added with this role');
112
        }
113
114
        //Save data to users_invite table and generate a hash for the invite
115 4
        $userInvite = $this->model;
116 4
        $userInvite->companies_id = $this->userData->default_company;
117 4
        $userInvite->app_id = $this->app->getId();
118 4
        $userInvite->role_id = Roles::getById((int)$request['role_id'])->id;
119 4
        $userInvite->email = $request['email'];
120 4
        $userInvite->invite_hash = $random->base58();
121 4
        $userInvite->created_at = date('Y-m-d H:m:s');
122
123 4
        if (!$userInvite->save()) {
124
            throw new UnprocessableEntityHttpException((string) current($userInvite->getMessages()));
125
        }
126
127
        //Check whether user exists or not
128 4
        $userExists = Users::findFirst([
129 4
            'conditions' => 'email = ?0 and is_deleted = 0',
130 4
            'bind' => [$request['email']]
131
        ]);
132
133 4
        $invitationUrl = $this->config->app->frontEndUrl . '/users/invites/' . $userInvite->invite_hash;
134
135 4
        if (is_object($userExists)) {
136
            $invitationUrl = $this->config->app->frontEndUrl . '/users/link/' . $userInvite->invite_hash;
137
        }
138
139
        // Lets send the mail
140
141 4
        if (!defined('API_TESTS')) {
142
            $subject = _('You have been invited!');
143
            $this->mail
144
            ->to($userInvite->email)
145
            ->subject($subject)
146
            ->content($invitationUrl)
147
            ->sendNow();
148
        }
149
150 4
        return $this->response($userInvite);
151
    }
152
153
    /**
154
     * Add invited user to our system
155
     * @return Response
156
     */
157 2
    public function processUserInvite(string $hash): Response
158
    {
159 2
        $request = $this->request->getPost();
160 2
        $password = ltrim(trim($request['password']));
161
162 2
        if (empty($request)) {
163
            $request = $this->request->getJsonRawBody(true);
164
        }
165
166
        //Ok let validate user password
167 2
        $validation = new Validation();
168 2
        $validation->add('password', new PresenceOf(['message' => _('The password is required.')]));
169
170 2
        $validation->add(
171 2
            'password',
172 2
            new StringLength([
173 2
                'min' => 8,
174 2
                'messageMinimum' => _('Password is too short. Minimum 8 characters.'),
175
            ])
176
        );
177
178
        //validate this form for password
179 2
        $messages = $validation->validate($request);
180 2
        if (count($messages)) {
181
            foreach ($messages as $message) {
182
                throw new ServerErrorHttpException((string)$message);
183
            }
184
        }
185
186
        //Lets find users_invite by hash on our database
187 2
        $usersInvite = $this->model::findFirst([
188 2
                'conditions' => 'invite_hash = ?0 and is_deleted = 0',
189 2
                'bind' => [$hash]
190
            ]);
191
192 2
        if (!is_object($usersInvite)) {
193
            throw new NotFoundHttpException('Users Invite not found');
194
        }
195
196
        //Check if user already exists
197 2
        $userExists = Users::findFirst([
198 2
            'conditions' => 'email = ?0 and is_deleted = 0',
199 2
            'bind' => [$usersInvite->email]
200
        ]);
201
202 2
        if (is_object($userExists)) {
203 1
            $newUser = new UsersAssociatedCompany;
204 1
            $newUser->users_id = $userExists->id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $userExists->id of type Phalcon\Mvc\Model\Resultset or Phalcon\Mvc\Phalcon\Mvc\Model is incompatible with the declared type integer of property $users_id.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
205 1
            $newUser->companies_id = $userExists->default_company;
0 ignored issues
show
Documentation Bug introduced by
It seems like $userExists->default_company of type Phalcon\Mvc\Model\Resultset or Phalcon\Mvc\Phalcon\Mvc\Model is incompatible with the declared type integer of property $companies_id.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
206 1
            $newUser->identify_id = $userExists->roles_id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $userExists->roles_id can also be of type Phalcon\Mvc\Model\Resultset. However, the property $identify_id is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
207 1
            $newUser->user_active = 1;
208 1
            $newUser->user_role = Roles::getById((int)$userExists->roles_id)->name;
209
210 1
            if (!$newUser->save()) {
211 1
                throw new UnprocessableEntityHttpException((string) current($newUser->getMessages()));
212
            }
213
        } else {
214 2
            $newUser = new Users();
215 2
            $newUser->firstname = $request['firstname'];
216 2
            $newUser->lastname = $request['lastname'];
217 2
            $newUser->displayname = $request['displayname'];
218 2
            $newUser->password = $password;
219 2
            $newUser->email = $usersInvite->email;
220 2
            $newUser->user_active = 1;
221 2
            $newUser->roles_id = $usersInvite->role_id;
222 2
            $newUser->created_at = date('Y-m-d H:m:s');
223 2
            $newUser->default_company = $usersInvite->companies_id;
224 2
            $newUser->default_company_branch = $usersInvite->company->branch->getId();
225
226
            try {
227 2
                $this->db->begin();
228
229
                //signup
230 2
                $newUser->signup();
231
232 2
                $this->db->commit();
233
            } catch (Exception $e) {
234
                $this->db->rollback();
235
236
                throw new UnprocessableEntityHttpException($e->getMessage());
237
            }
238
        }
239
240
        //Lets login the new user
241 2
        $authInfo = $this->loginInvitedUser($usersInvite->email, $password);
242
243 2
        if (!defined('API_TESTS')) {
244
            $usersInvite->is_deleted = 1;
245
            $usersInvite->update();
246
247
            return $this->response($authInfo);
248
        }
249
250 2
        return $this->response($newUser);
251
    }
252
253
    /**
254
     * Login invited user
255
     * @param string
256
     * @return array
257
     */
258 2
    public function loginInvitedUser(string $email, string $password): array
259
    {
260 2
        $userIp = !defined('API_TESTS') ? $this->request->getClientAddress() : '127.0.0.1';
261
262 2
        $random = new \Phalcon\Security\Random();
263
264 2
        $userData = Users::login($email, $password, 1, 0, $userIp);
265
266 2
        $sessionId = $random->uuid();
267
268
        //save in user logs
269
        $payload = [
270 2
            'sessionId' => $sessionId,
271 2
            'email' => $userData->getEmail(),
272 2
            'iat' => time(),
273
        ];
274
275 2
        $token = $this->auth->make($payload);
276
277
        //start session
278 2
        $session = new Sessions();
279 2
        $session->start($userData, $sessionId, $token, $userIp, 1);
280
281
        return [
282 2
            'token' => $token,
283 2
            'time' => date('Y-m-d H:i:s'),
284 2
            'expires' => date('Y-m-d H:i:s', time() + $this->config->jwt->payload->exp),
285 2
            'id' => $userData->getId(),
286
        ];
287
    }
288
}
289