Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
41.46% |
34 / 82 |
|
16.67% |
3 / 18 |
CRAP | |
0.00% |
0 / 1 |
| BaseController | |
41.46% |
34 / 82 |
|
16.67% |
3 / 18 |
280.71 | |
0.00% |
0 / 1 |
| sendResponse | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
| sendError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| createUser | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| updateUserPassword | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
| getLoggedInUserId | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
| __validateJson | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
4 | |||
| __validateContentTypeApplicationJson | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| createPaginationFromOrm | |
83.33% |
10 / 12 |
|
0.00% |
0 / 1 |
3.04 | |||
| saltHash | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| __validateSaltHash | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| __dateMidnightZeroOne | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| __dateMidnightZeroZero | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| __dateElevenFiftyNine | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| __getAllDates | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
| __validYYYYMMDDFormat | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| __validateDateTime | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| __validateAndExtractPaginationData | |
75.00% |
6 / 8 |
|
0.00% |
0 / 1 |
5.39 | |||
| __getMe | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace App\Http\Controllers\api; |
| 4 | |
| 5 | use Illuminate\Http\Request; |
| 6 | use Illuminate\Http\JsonResponse; |
| 7 | use App\Http\Controllers\Controller as Controller; |
| 8 | use Validator; |
| 9 | use App\Models\User; |
| 10 | use App\Models\Role; |
| 11 | |
| 12 | class BaseController extends Controller |
| 13 | { |
| 14 | /** |
| 15 | * success response method. |
| 16 | * |
| 17 | * @param Int $status The HTTP status code of the response, ie 200 |
| 18 | * @param Mixed $data The data object to return under 'data' |
| 19 | * @param Array $hateoas An array of HATEOAS data, optional |
| 20 | * @return JsonResponse |
| 21 | */ |
| 22 | public function sendResponse(int $status, $data, array $hateoas = array()):JsonResponse |
| 23 | { |
| 24 | $response = [ |
| 25 | 'data' => $data, |
| 26 | ]; |
| 27 | |
| 28 | if (count($hateoas) > 0) { |
| 29 | $response['links'] = $hateoas; |
| 30 | } |
| 31 | |
| 32 | return response()->json($response, $status); |
| 33 | } // sendResponse |
| 34 | |
| 35 | |
| 36 | /** |
| 37 | * return error response. |
| 38 | * |
| 39 | * @param Int $status |
| 40 | * @param Mixed $error |
| 41 | * @param Mixed $details |
| 42 | * @return JsonResponse |
| 43 | */ |
| 44 | public function sendError(int $status, $error, $details=null):JsonResponse |
| 45 | { |
| 46 | $response = [ |
| 47 | 'error' => $error, |
| 48 | 'details' => $details, |
| 49 | ]; |
| 50 | |
| 51 | return response()->json($response, $status); |
| 52 | } // sendError |
| 53 | |
| 54 | |
| 55 | /** |
| 56 | * Creates a login user of a given role |
| 57 | * |
| 58 | * @param Array $userData ["name", "email", "password", "c_password"] |
| 59 | * @param Int $roleId |
| 60 | * @return Int The user id |
| 61 | */ |
| 62 | protected function createUser(array $userData, Int $roleId = 2):Int |
| 63 | { |
| 64 | $userData['password'] = bcrypt($userData['password']); |
| 65 | |
| 66 | // did you run php artisan passport:install? |
| 67 | try { |
| 68 | $user = User::create($userData); |
| 69 | //$user->createToken('MyApp')->accessToken; |
| 70 | //$user->role_id = $roleId; |
| 71 | $user->save(); |
| 72 | return $user->id; |
| 73 | } |
| 74 | // catch duplicate entry |
| 75 | catch (\Illuminate\Database\QueryException $e) { |
| 76 | return -1; |
| 77 | } |
| 78 | } // createUser |
| 79 | |
| 80 | |
| 81 | /** |
| 82 | * Updates the login password for a user. Used with putCustomersCorporateContact. |
| 83 | * |
| 84 | * @param string $password |
| 85 | * @return Boolean |
| 86 | */ |
| 87 | protected function updateUserPassword(string $email, string $password) |
| 88 | { |
| 89 | $enc = bcrypt($password); |
| 90 | |
| 91 | // did you run php artisan passport:install? |
| 92 | try { |
| 93 | /** |
| 94 | * Update user login account |
| 95 | */ |
| 96 | $user = User::where('email', $email)->first(); |
| 97 | if (!$user) { |
| 98 | return false; |
| 99 | } |
| 100 | $user->password = $enc; |
| 101 | $user->save(); |
| 102 | return true; |
| 103 | } |
| 104 | // catch any errors |
| 105 | catch (\Illuminate\Database\QueryException $e) { |
| 106 | return false; |
| 107 | } |
| 108 | } // updateUserPassword |
| 109 | |
| 110 | |
| 111 | /** |
| 112 | * Tests if the role of the logged-in user is the same as the role passed as arg |
| 113 | * |
| 114 | * Modified: also returns true if the user is 'admin' |
| 115 | * |
| 116 | * Roles are stored as env constants in .env where they are mapped to the name in the `roles` table. |
| 117 | * |
| 118 | * @param String $role The role of the user, ie 'installer', 'lead_manager' or 'admin' |
| 119 | * @return bool |
| 120 | * @author gbh |
| 121 | protected function permissionsEqual(string $role):bool |
| 122 | { |
| 123 | $role_id = Role::where('name', config('app.roles.'.$role))->get()->pluck('id')[0]; // @not-phpstan-ignore-line |
| 124 | $admin_id = Role::where('name', config('app.roles.admin'))->get()->pluck('id')[0]; // @not-phpstan-ignore-line |
| 125 | return (auth()->guard('api')->user()->role_id == $role_id || auth()->guard('api')->user()->role_id == $admin_id); |
| 126 | } |
| 127 | */ |
| 128 | |
| 129 | |
| 130 | /** |
| 131 | * Tests if the role of the logged-in user is exactly the same as role arg, excluding admin. |
| 132 | * |
| 133 | * Roles are stored as env constants in .env where they are mapped to the name in the `roles` table. |
| 134 | * |
| 135 | * @param String $role The role of the user, ie 'installer', 'lead_manager' or 'admin' |
| 136 | * @return bool |
| 137 | * @author arn |
| 138 | protected function permissionsExactly(string $role):bool |
| 139 | { |
| 140 | $role_id = Role::where('name', config('app.roles.'.$role))->get()->pluck('id')[0]; // @not-phpstan-ignore-line |
| 141 | return auth()->guard('api')->user()->role_id == $role_id; |
| 142 | } |
| 143 | */ |
| 144 | |
| 145 | |
| 146 | /** |
| 147 | * Tests if the role of the logged-in user is the same or greater than the role passed as arg |
| 148 | * |
| 149 | * Roles are stored as env constants in .env where they are mapped to the name in the `roles` table. |
| 150 | * |
| 151 | * @param String $role The role of the user, ie 'employee', 'support' or 'admin' |
| 152 | * @return bool |
| 153 | * @author gbh |
| 154 | protected function permissionsAtLeast(string $role) |
| 155 | { |
| 156 | $role_id = Role::where('name', config('app.roles.'.$role))->get()->pluck('id')[0]; // @not-phpstan-ignore-line |
| 157 | return (int)auth()->guard('api')->user()->role_id >= $role_id; |
| 158 | } |
| 159 | */ |
| 160 | |
| 161 | /** |
| 162 | * Get user id of logged-in user. |
| 163 | * |
| 164 | * @return Mixed Int user_id or false |
| 165 | * @author arn |
| 166 | */ |
| 167 | protected function getLoggedInUserId() |
| 168 | { |
| 169 | $currentUser = auth()->guard('api')->user(); |
| 170 | |
| 171 | /** |
| 172 | * If authenticated user is not found, do not authenticate. |
| 173 | */ |
| 174 | if (!$currentUser) { |
| 175 | return false; |
| 176 | } |
| 177 | |
| 178 | return $currentUser->id; |
| 179 | } // getLoggedInUserId |
| 180 | |
| 181 | |
| 182 | /** |
| 183 | * Validates a json string against a set of Laravel validation rules. |
| 184 | * |
| 185 | * @note Only flat json at this point |
| 186 | * |
| 187 | * @param Array $rules The Laravel validator ruleset to validate against |
| 188 | * @param Request $request The request object laravel injects into the controller |
| 189 | * @return mixed `boolean` true on success, `Array` on failure |
| 190 | */ |
| 191 | protected function __validateJson(array $rules, Request $request) |
| 192 | { |
| 193 | $requestContent = $request->getContent(); |
| 194 | $data = json_decode($requestContent, true); |
| 195 | $data = $data ? $data : []; |
| 196 | $validator = Validator::make($data, $rules); |
| 197 | |
| 198 | if ($validator->passes()) { |
| 199 | return true; |
| 200 | } else { |
| 201 | $errors = $validator->errors(); |
| 202 | $errorArray = []; |
| 203 | foreach ($errors->getMessages() as $key => $message) { |
| 204 | $errorArray[$key] = $message; |
| 205 | } |
| 206 | return $errorArray; |
| 207 | } |
| 208 | } //validateJson |
| 209 | |
| 210 | |
| 211 | /** |
| 212 | * Returns true if the header for Content-Type is 'application/json' |
| 213 | * |
| 214 | * @param Request $request |
| 215 | * @return bool |
| 216 | */ |
| 217 | protected function __validateContentTypeApplicationJson(Request $request):bool |
| 218 | { |
| 219 | return strtolower($request->headers->get('Content-Type')) == "application/json"; |
| 220 | } // validateContentTypeApplicationJson |
| 221 | |
| 222 | |
| 223 | /** |
| 224 | * Makes a nice hateoas array from LengthAwarePaginator collection |
| 225 | * |
| 226 | * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginationCollection The return collection from Model::paginate() |
| 227 | * @return Array |
| 228 | */ |
| 229 | protected function createPaginationFromOrm(\Illuminate\Contracts\Pagination\LengthAwarePaginator $paginationCollection) |
| 230 | { |
| 231 | $hateoas = []; |
| 232 | if ($paginationCollection->hasMorePages()) { |
| 233 | $hateoas['next_page'] = $paginationCollection->nextPageUrl(). |
| 234 | "&size=". |
| 235 | $paginationCollection->count(); |
| 236 | } |
| 237 | if ($paginationCollection->previousPageUrl()) { |
| 238 | $hateoas['previous_page'] = $paginationCollection->previousPageUrl(). |
| 239 | "&size=". |
| 240 | $paginationCollection->count(); |
| 241 | } |
| 242 | $hateoas['has_more'] = $paginationCollection->hasMorePages(); |
| 243 | $hateoas['current_page'] = $paginationCollection->currentPage(); |
| 244 | $hateoas['last_page'] = $paginationCollection->lastPage(); |
| 245 | $hateoas['current_size'] = $paginationCollection->perPage(); |
| 246 | |
| 247 | return $hateoas; |
| 248 | } // createPaginationFromOrm |
| 249 | |
| 250 | |
| 251 | /** |
| 252 | * Hashes a value with our configured secret_salt |
| 253 | * |
| 254 | * @param String $toHash The value to hash |
| 255 | * @return String |
| 256 | */ |
| 257 | protected function saltHash(String $toHash):String |
| 258 | { |
| 259 | return md5($toHash.config('app.secret_salt')); |
| 260 | } // saltHash |
| 261 | |
| 262 | |
| 263 | /** |
| 264 | * Tests if the hash $hash is valid for the value $value |
| 265 | * |
| 266 | * @param String $value |
| 267 | * @param String $hash |
| 268 | * @return boolean |
| 269 | */ |
| 270 | protected function __validateSaltHash(String $value, String $hash):bool |
| 271 | { |
| 272 | return md5($value.config('app.secret_salt')) == $hash; |
| 273 | } // validateSaltHash |
| 274 | |
| 275 | |
| 276 | |
| 277 | /** |
| 278 | * Sets the time of a date string to midnight plus one second. |
| 279 | * |
| 280 | * eg. '2020-02-23 13:45:23' => '2020-02-23 00:00:01' |
| 281 | * |
| 282 | * @param String $date |
| 283 | * @return String |
| 284 | */ |
| 285 | protected function __dateMidnightZeroOne(String $date):String |
| 286 | { |
| 287 | $dateObj = new \DateTime($date); |
| 288 | $dateObj->setTime(00, 00, 01); |
| 289 | return $dateObj->format('Y-m-d H:i:s'); |
| 290 | } |
| 291 | |
| 292 | /** |
| 293 | * Sets the time of a date string to midnight |
| 294 | * |
| 295 | * eg. '2020-02-23 13:45:23' => '2020-02-23 00:00:00' |
| 296 | * |
| 297 | * @param String $date |
| 298 | * @return String |
| 299 | */ |
| 300 | protected function __dateMidnightZeroZero(String $date):String |
| 301 | { |
| 302 | $dateObj = new \DateTime($date); |
| 303 | $dateObj->setTime(00, 00, 00); |
| 304 | return $dateObj->format('Y-m-d H:i:s'); |
| 305 | } |
| 306 | |
| 307 | |
| 308 | /** |
| 309 | * Sets the time of a date string to 11:59:59 |
| 310 | * |
| 311 | * eg. '2020-02-23 13:45:23' => '2020-02-23 23:59:59' |
| 312 | * |
| 313 | * @param String $date |
| 314 | * @return String |
| 315 | */ |
| 316 | protected function __dateElevenFiftyNine(String $date):String |
| 317 | { |
| 318 | $dateObj = new \DateTime($date); |
| 319 | $dateObj->setTime(23, 59, 59); |
| 320 | return $dateObj->format('Y-m-d H:i:s'); |
| 321 | } |
| 322 | |
| 323 | |
| 324 | /** |
| 325 | * Get an array of all dates as YYYY-MM-DD between start date and end date |
| 326 | * |
| 327 | * @param String $startdate |
| 328 | * @param String $enddate |
| 329 | * @return Array |
| 330 | */ |
| 331 | protected function __getAllDates(String $startdate, String $enddate):array |
| 332 | { |
| 333 | $begin = new \DateTime($startdate); |
| 334 | $end = new \DateTime($enddate); |
| 335 | $end = $end->modify('+1 day'); |
| 336 | $interval = new \DateInterval('P1D'); |
| 337 | $daterange = new \DatePeriod($begin, $interval, $end); |
| 338 | |
| 339 | $returnableDateRange = []; |
| 340 | foreach ($daterange as $d) { |
| 341 | $returnableDateRange[] = $d->format("Y-m-d"); |
| 342 | } |
| 343 | |
| 344 | return $returnableDateRange; |
| 345 | } // __getAllDates |
| 346 | |
| 347 | |
| 348 | /** |
| 349 | * Validates that a string is in yyyy-mm-dd format |
| 350 | * |
| 351 | * @param String $date The string to validate |
| 352 | * @return boolean |
| 353 | */ |
| 354 | public function __validYYYYMMDDFormat($date):bool |
| 355 | { |
| 356 | $format = 'Y-m-d'; |
| 357 | $d = \DateTime::createFromFormat($format, $date); |
| 358 | return $d && $d->format($format) == $date; |
| 359 | } // __validYYYYMMDDFormat |
| 360 | |
| 361 | |
| 362 | /** |
| 363 | * Validates that a string is in yyyy-mm-dd h:i:s format |
| 364 | */ |
| 365 | public function __validateDateTime(String $date, String $format = 'Y-m-d H:i:s'):bool |
| 366 | { |
| 367 | $d = \DateTime::createFromFormat($format, $date); |
| 368 | return $d && $d->format($format) == $date; |
| 369 | } // __validateDateTime |
| 370 | |
| 371 | |
| 372 | /** |
| 373 | * Validate pagination query string in a request. |
| 374 | * This will return the object [ 'page' => A, 'size' => B ] on a valid request, |
| 375 | * or an error response on failure. |
| 376 | * |
| 377 | * @return Mixed |
| 378 | */ |
| 379 | protected function __validateAndExtractPaginationData(Request $request):array |
| 380 | { |
| 381 | $page = $request->query('page') !== null ? (int)$request->query('page') : config('app.pagination.default_page_number'); |
| 382 | $size = $request->query('size') !== null ? (int)$request->query('size') : config('app.pagination.default_page_size'); |
| 383 | |
| 384 | if ($page < 1) { |
| 385 | $page = 1; |
| 386 | } |
| 387 | |
| 388 | if ($size < 1) { |
| 389 | $size = 1; |
| 390 | } |
| 391 | |
| 392 | $request->page = $page; |
| 393 | |
| 394 | return [ |
| 395 | 'page' => $page, |
| 396 | 'size' => $size |
| 397 | ]; |
| 398 | } // __validateAndExtractPaginationData |
| 399 | |
| 400 | |
| 401 | /** |
| 402 | * Selects and returns the current session user |
| 403 | * |
| 404 | * @return User |
| 405 | */ |
| 406 | protected function __getMe():User |
| 407 | { |
| 408 | $user = User::whereMe()->first(); |
| 409 | return $user; |
| 410 | } |
| 411 | } // BaseController |