Test Failed
Pull Request — master (#80)
by Maximo
05:40
created

UsersInviteController   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Test Coverage

Coverage 79.05%

Importance

Changes 0
Metric Value
eloc 105
dl 0
loc 222
ccs 83
cts 105
cp 0.7905
rs 10
c 0
b 0
f 0
wmc 20

5 Methods

Rating   Name   Duplication   Size   Complexity  
A onConstruct() 0 12 2
A insertInvite() 0 42 5
A getByHash() 0 12 2
B processUserInvite() 0 86 8
A sendInviteEmail() 0 20 3
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\Roles;
10
use Phalcon\Security\Random;
11
use Phalcon\Validation;
12
use Phalcon\Validation\Validator\PresenceOf;
13
use Phalcon\Validation\Validator\StringLength;
14
use Gewaer\Exception\UnprocessableEntityHttpException;
15
use Gewaer\Exception\NotFoundHttpException;
16
use Gewaer\Exception\ServerErrorHttpException;
17
use Phalcon\Http\Response;
18
use Exception;
19
use Gewaer\Exception\ModelException;
20
use Gewaer\Traits\AuthTrait;
21
22
/**
23
 * Class LanguagesController.
24
 * @property Users $userData
25
 * @property Request $request
26
 * @property Config $config
27
 * @property Apps $app
28
 * @property Mail $mail
29
 * @property Auth $auth
30
 * @property Payload $payload
31
 * @property Exp $exp
32
 * @property JWT $jwt
33
 * @package Gewaer\Api\Controllers
34
 *
35
 */
36
class UsersInviteController extends BaseController
37
{
38
    use AuthTrait;
39
40
    /*
41
     * fields we accept to create
42
     *
43
     * @var array
44
     */
45
    protected $createFields = ['invite_hash', 'companies_id', 'role_id', 'app_id', 'email'];
46
47
    /*
48
     * fields we accept to create
49
     *
50
     * @var array
51
     */
52
    protected $updateFields = ['invite_hash', 'companies_id', 'role_id', 'app_id', 'email'];
53
54
    /**
55
     * set objects.
56
     *
57
     * @return void
58
     */
59 4
    public function onConstruct()
60
    {
61 4
        $this->model = new UsersInvite();
62
        $additionaFields = [
63 4
            ['is_deleted', ':', '0'],
64
        ];
65
66 4
        if ($this->di->has('userData')) {
67 4
            $additionaFields[] = ['companies_id', ':', $this->userData->currentCompanyId()];
68
        }
69
        
70 4
        $this->additionalSearchFields = $additionaFields;
71 4
    }
72
73
    /**
74
     * Get users invite by hash.
75
     * @param string $hash
76
     * @return Response
77
     */
78 1
    public function getByHash(string $hash):Response
79
    {
80 1
        $userInvite = $this->model::findFirst([
81 1
            'conditions' => 'invite_hash =  ?0 and is_deleted = 0',
82 1
            'bind' => [$hash]
83
        ]);
84
85 1
        if (!is_object($userInvite)) {
86
            throw new NotFoundHttpException('Users Invite not found');
87
        }
88
89 1
        return $this->response($userInvite);
90
    }
91
92
    /**
93
     * Sets up invitation information for a would be user.
94
     * @return Response
95
     */
96 4
    public function insertInvite(): Response
97
    {
98 4
        $request = $this->request->getPost();
99 4
        $random = new Random();
100
101 4
        $validation = new Validation();
102 4
        $validation->add('email', new PresenceOf(['message' => _('The email is required.')]));
103 4
        $validation->add('role_id', new PresenceOf(['message' => _('The role is required.')]));
104
105
        //validate this form for password
106 4
        $messages = $validation->validate($this->request->getPost());
107 4
        if (count($messages)) {
108
            foreach ($messages as $message) {
109
                throw new ServerErrorHttpException((string)$message);
110
            }
111
        }
112
113
        //Check if user was already was invited to current company and return message
114 4
        $invitedUser = $this->model::findFirst([
115 4
            'conditions' => 'email = ?0 and companies_id = ?1 and role_id = ?2',
116 4
            'bind' => [$request['email'], $this->userData->default_company, $request['role_id']]
117
        ]);
118
119 4
        if (is_object($invitedUser)) {
120
            throw new ModelException('User already invited to this company and added with this role');
121
        }
122
123
        //Save data to users_invite table and generate a hash for the invite
124 4
        $userInvite = $this->model;
125 4
        $userInvite->companies_id = $this->userData->default_company;
126 4
        $userInvite->app_id = $this->app->getId();
127 4
        $userInvite->role_id = Roles::existsById((int)$request['role_id'])->id;
128 4
        $userInvite->email = $request['email'];
129 4
        $userInvite->invite_hash = $random->base58();
130 4
        $userInvite->created_at = date('Y-m-d H:m:s');
131
132 4
        if (!$userInvite->save()) {
133
            throw new UnprocessableEntityHttpException((string) current($userInvite->getMessages()));
134
        }
135
136 4
        $this->sendInviteEmail($request['email'], $userInvite->invite_hash);
137 4
        return $this->response($userInvite);
138
    }
139
140
    /**
141
     * Send users invite email.
142
     * @param string $email
143
     * @return void
144
     */
145 4
    private function sendInviteEmail(string $email, string $hash): void
146
    {
147 4
        $userExists = Users::findFirst([
148 4
            'conditions' => 'email = ?0 and is_deleted = 0',
149 4
            'bind' => [$email]
150
        ]);
151
152 4
        $invitationUrl = $this->config->app->frontEndUrl . '/users/invites/' . $hash;
153
154 4
        if (is_object($userExists)) {
155
            $invitationUrl = $this->config->app->frontEndUrl . '/users/link/' . $hash;
156
        }
157
158 4
        if (!defined('API_TESTS')) {
159
            $subject = _('You have been invited!');
160
            $this->mail
161
            ->to($email)
162
            ->subject($subject)
163
            ->content($invitationUrl)
164
            ->sendNow();
165
        }
166 4
    }
167
168
    /**
169
     * Add invited user to our system.
170
     * @return Response
171
     */
172 2
    public function processUserInvite(string $hash): Response
173
    {
174 2
        $request = $this->request->getPost();
175 2
        $password = ltrim(trim($request['password']));
176
177 2
        if (empty($request)) {
178
            $request = $this->request->getJsonRawBody(true);
179
        }
180
181
        //Ok let validate user password
182 2
        $validation = new Validation();
183 2
        $validation->add('password', new PresenceOf(['message' => _('The password is required.')]));
184
185 2
        $validation->add(
186 2
            'password',
187 2
            new StringLength([
188 2
                'min' => 8,
189 2
                'messageMinimum' => _('Password is too short. Minimum 8 characters.'),
190
            ])
191
        );
192
193
        //validate this form for password
194 2
        $messages = $validation->validate($request);
195 2
        if (count($messages)) {
196
            foreach ($messages as $message) {
197
                throw new ServerErrorHttpException((string)$message);
198
            }
199
        }
200
201
        //Lets find users_invite by hash on our database
202 2
        $usersInvite = $this->model::findFirst([
203 2
            'conditions' => 'invite_hash = ?0 and is_deleted = 0',
204 2
            'bind' => [$hash]
205
        ]);
206
207 2
        if (!is_object($usersInvite)) {
208
            throw new NotFoundHttpException('Users Invite not found');
209
        }
210
211
        //Check if user already exists
212 2
        $userExists = Users::findFirst([
213 2
            'conditions' => 'email = ?0 and is_deleted = 0',
214 2
            'bind' => [$usersInvite->email]
215
        ]);
216
217 2
        if (is_object($userExists)) {
218 1
            $newUser = $this->userData->defaultCompany->associate($userExists, $this->userData->defaultCompany);
219 1
            $this->app->associate($userExists, $this->userData->defaultCompany);
220
        } else {
221 2
            $newUser = new Users();
222 2
            $newUser->firstname = $request['firstname'];
223 2
            $newUser->lastname = $request['lastname'];
224 2
            $newUser->displayname = $request['displayname'];
225 2
            $newUser->password = $password;
226 2
            $newUser->email = $usersInvite->email;
227 2
            $newUser->user_active = 1;
228 2
            $newUser->roles_id = $usersInvite->role_id;
229 2
            $newUser->created_at = date('Y-m-d H:m:s');
230 2
            $newUser->default_company = $usersInvite->companies_id;
231 2
            $newUser->default_company_branch = $usersInvite->company->branch->getId();
232
233
            try {
234 2
                $this->db->begin();
235
236
                //signup
237 2
                $newUser->signup();
238
239 2
                $this->db->commit();
240
            } catch (Exception $e) {
241
                $this->db->rollback();
242
243
                throw new UnprocessableEntityHttpException($e->getMessage());
244
            }
245
        }
246
247
        //Lets login the new user
248 2
        $authInfo = $this->loginUsers($usersInvite->email, $password);
249
250 2
        if (!defined('API_TESTS')) {
251
            $usersInvite->is_deleted = 1;
252
            $usersInvite->update();
253
254
            return $this->response($authInfo);
255
        }
256
257 2
        return $this->response($newUser);
258
    }
259
}
260