diff --git a/app/Http/Requests/Task/StoreTaskRequest.php b/app/Http/Requests/Task/StoreTaskRequest.php index 52d331d3ab92..1a71b17f60ff 100644 --- a/app/Http/Requests/Task/StoreTaskRequest.php +++ b/app/Http/Requests/Task/StoreTaskRequest.php @@ -54,7 +54,13 @@ class StoreTaskRequest extends Request $rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.$user->company()->id.',is_deleted,0'; } - $rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) { + $rules['time_log'] = ['bail',function ($attribute, $values, $fail) { + + if(!is_array(json_decode($values, true))) { + $fail('The '.$attribute.' must be a valid array.'); + return; + } + foreach ($values as $k) { if (!is_int($k[0]) || !is_int($k[1])) { $fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.'); @@ -110,6 +116,10 @@ class StoreTaskRequest extends Request } } + if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}'){ + $input['time_log'] = json_encode([]); + } + $this->replace($input); } } diff --git a/app/Http/Requests/Task/UpdateTaskRequest.php b/app/Http/Requests/Task/UpdateTaskRequest.php index 7107df9fe63f..141fefed78b1 100644 --- a/app/Http/Requests/Task/UpdateTaskRequest.php +++ b/app/Http/Requests/Task/UpdateTaskRequest.php @@ -35,26 +35,38 @@ class UpdateTaskRequest extends Request return false; } - return auth()->user()->can('edit', $this->task); + /** @var \App\Models\User $user */ + $user = auth()->user(); + + return $user->can('edit', $this->task); } public function rules() { + /** @var \App\Models\User $user */ + $user = auth()->user(); + $rules = []; if (isset($this->number)) { - $rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id)->ignore($this->task->id); + $rules['number'] = Rule::unique('tasks')->where('company_id', $user->company()->id)->ignore($this->task->id); } if (isset($this->client_id)) { - $rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + $rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.$user->company()->id.',is_deleted,0'; } if (isset($this->project_id)) { - $rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + $rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.$user->company()->id.',is_deleted,0'; } - $rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) { + $rules['time_log'] = ['bail', function ($attribute, $values, $fail) { + + if(!is_array(json_decode($values, true))) { + $fail('The '.$attribute.' must be a valid array.'); + return; + } + foreach ($values as $k) { if (!is_int($k[0]) || !is_int($k[1])) { $fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.'); @@ -113,6 +125,10 @@ class UpdateTaskRequest extends Request } + if(!isset($input['time_log']) || empty($input['time_log']) || $input['time_log'] == '{}') { + $input['time_log'] = json_encode([]); + } + $this->replace($input); } diff --git a/app/Models/Task.php b/app/Models/Task.php index 083e8094e401..ec0cf54a8afb 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -241,7 +241,7 @@ class Task extends BaseModel public function processLogs() { return - collect($this->timelog)->map(function ($log){ + collect($this->time_log)->map(function ($log){ $parent_entity = $this->client ?? $this->company; diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index e614703cfe88..7b541447e518 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -136,7 +136,7 @@ class TemplateService /** * Initialized a set of HTMLEngine variables * - * @param array | Collection $data + * @param array | \Illuminate\Support\Collection $data * @return self */ private function processVariables($data): self @@ -209,7 +209,7 @@ class TemplateService /** * Process data variables * - * @param array | Collection $data + * @param array | \Illuminate\Support\Collection $data * @return self */ public function processData($data): self @@ -392,7 +392,7 @@ class TemplateService * Pre Processes the Data Blocks into * Twig consumables * - * @param array | Collection $data + * @param array | \Illuminate\Support\Collection $data * @return array */ private function preProcessDataBlocks($data): array @@ -421,7 +421,7 @@ class TemplateService /** * Process Invoices into consumable form for Twig templates * - * @param array | Collection $invoices + * @param array | \Illuminate\Support\Collection $invoices * @return array */ public function processInvoices($invoices): array @@ -506,7 +506,7 @@ class TemplateService * Pads Line Items with raw and formatted content * * @param array $items - * @param mixed $client + * @param Client $client * @return array */ public function padLineItems(array $items, Client $client): array @@ -698,7 +698,7 @@ class TemplateService * Pushes credits through the appropriate transformer * and builds any required relationships * - * @param array | Collection $credits + * @param array | \Illuminate\Support\Collection $credits * @return array */ public function processCredits($credits): array @@ -775,7 +775,7 @@ class TemplateService /** * Pushes payments through the appropriate transformer * - * @param array | Collection $payments + * @param array | \Illuminate\Support\Collection $payments * @return array */ public function processPayments($payments): array @@ -832,7 +832,7 @@ class TemplateService /** * @todo refactor * - * @param array | Collection $projects + * @param array | \Illuminate\Support\Collection $projects * @return array */ public function processProjects($projects): array @@ -900,7 +900,7 @@ class TemplateService /** * Set Company * - * @param mixed $company + * @param Company $company * @return self */ public function setCompany(Company $company): self @@ -955,7 +955,6 @@ class TemplateService }) ->map(function ($stack){ $node = $this->document->getElementById($stack); - nlog(['stack' => $stack, 'labels' => $node->getAttribute('labels')]); return ['stack' => $stack, 'labels' => $node->getAttribute('labels')]; }) ->each(function ($stack) { @@ -976,7 +975,7 @@ class TemplateService { match($stack['stack']) { - 'entity-details' => $this->entityDetails($stack['labels'] == 'true'), + 'entity-details' => $this->entityDetails(), 'client-details' => $this->clientDetails($stack['labels'] == 'true'), 'vendor-details' => $this->vendorDetails($stack['labels'] == 'true'), 'company-details' => $this->companyDetails($stack['labels'] == 'true'), @@ -1010,11 +1009,11 @@ class TemplateService }); })->toArray(); - nlog($company_details); + // nlog($company_details); $company_details = $include_labels ? $this->labelledFieldStack($company_details, 'company_details-') : $company_details; - nlog($company_details); + // nlog($company_details); $this->updateElementProperties('company-details', $company_details); diff --git a/tests/Feature/TaskApiTest.php b/tests/Feature/TaskApiTest.php index 2d7d9e4363fe..065632ea9c82 100644 --- a/tests/Feature/TaskApiTest.php +++ b/tests/Feature/TaskApiTest.php @@ -104,6 +104,90 @@ class TaskApiTest extends TestCase } } + public function testEmptyTimeLogArray() + { + + $data = [ + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'description' => 'Test Task', + 'time_log' => null, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/tasks", $data); + + $response->assertStatus(200); + + $data = [ + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'description' => 'Test Task', + 'time_log' => '', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/tasks", $data); + + $response->assertStatus(200); + + $data = [ + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'description' => 'Test Task', + 'time_log' => '[]', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/tasks", $data); + + $response->assertStatus(200); + + $data = [ + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'description' => 'Test Task', + 'time_log' => '{}', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/tasks", $data); + + $response->assertStatus(200); + } + + public function testFaultyTimeLogArray() + { + + $data = [ + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'description' => 'Test Task', + 'time_log' => 'ABBA is the best band in the world', + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/tasks", $data); + + $response->assertStatus(422); + + } + public function testTaskClientRateSet() { $settings = ClientSettings::defaults(); @@ -262,6 +346,45 @@ class TaskApiTest extends TestCase $response->assertStatus(200); + $task->time_log = 'A very strange place'; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray()); + + $response->assertStatus(422); + + $task->time_log = null; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray()); + + $response->assertStatus(200); + + $task->time_log = ''; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray()); + + $response->assertStatus(200); + + + $task->time_log = '{}'; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true", $task->toArray()); + + $response->assertStatus(200); + + + } public function testStoppingTaskWithDescription() diff --git a/tests/Feature/Template/TemplateTest.php b/tests/Feature/Template/TemplateTest.php index a9ac8ff19805..0b6b34621b02 100644 --- a/tests/Feature/Template/TemplateTest.php +++ b/tests/Feature/Template/TemplateTest.php @@ -191,8 +191,10 @@ class TemplateTest extends TestCase 'client_id' => $this->client->id, ]); + $data['projects'][] = $p; + $ts = new TemplateService(); - $ts->processData($data['projects'][$p]); + $ts->processData($data); $this->assertNotNull($ts); }