24 changed files with 555 additions and 19 deletions
-
24app/Entities/Projects/FeaturePresenter.php
-
10app/Entities/Projects/FeaturesRepository.php
-
2app/Entities/Projects/ProjectsRepository.php
-
22app/Entities/Projects/Task.php
-
35app/Entities/Projects/TasksRepository.php
-
20app/Http/Controllers/Projects/FeaturesController.php
-
52app/Http/Controllers/Projects/TasksController.php
-
34app/Http/Requests/Tasks/CreateRequest.php
-
34app/Http/Requests/Tasks/DeleteRequest.php
-
35app/Http/Requests/Tasks/UpdateRequest.php
-
8app/Http/routes/projects.php
-
4app/Providers/AuthServiceProvider.php
-
13database/factories/ModelFactory.php
-
3public/assets/css/app.css
-
2public/assets/css/app.css.map
-
1resources/assets/sass/app.scss
-
1resources/lang/id/feature.php
-
22resources/lang/id/task.php
-
6resources/views/features/partials/breadcrumb.blade.php
-
5resources/views/features/partials/feature-show.blade.php
-
103resources/views/features/partials/feature-tasks.blade.php
-
8resources/views/features/show.blade.php
-
15resources/views/projects/features.blade.php
-
115tests/ManageTasksTest.php
@ -0,0 +1,24 @@ |
|||
<?php |
|||
|
|||
namespace App\Entities\Projects; |
|||
|
|||
use Laracasts\Presenter\Presenter; |
|||
|
|||
class FeaturePresenter extends Presenter |
|||
{ |
|||
public function workerNameAndEmail() |
|||
{ |
|||
return $this->worker_id ? $this->worker->name . ' (' . $this->worker->email . ')' : '-'; |
|||
} |
|||
|
|||
public function projectLink() |
|||
{ |
|||
return link_to_route('projects.show', $this->project->name, [$this->project_id]); |
|||
} |
|||
|
|||
public function projectFeaturesLink() |
|||
{ |
|||
return link_to_route('projects.features', trans('project.features'), [$this->project_id]); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
namespace App\Entities\Projects; |
|||
|
|||
use App\Entities\Projects\TaskPresenter; |
|||
use App\Entities\Users\User; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use Laracasts\Presenter\PresentableTrait; |
|||
|
|||
class Task extends Model { |
|||
|
|||
use PresentableTrait; |
|||
|
|||
protected $presenter = TaskPresenter::class; |
|||
protected $guarded = ['id','created_at','updated_at']; |
|||
|
|||
public function feature() |
|||
{ |
|||
return $this->belongsTo(Feature::class, 'project_id'); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<?php |
|||
|
|||
namespace App\Entities\Projects; |
|||
|
|||
use App\Entities\BaseRepository; |
|||
use App\Entities\Projects\Feature; |
|||
|
|||
/** |
|||
* Tasks Repository Class |
|||
*/ |
|||
class TasksRepository extends BaseRepository |
|||
{ |
|||
protected $model; |
|||
|
|||
public function __construct(Task $model) |
|||
{ |
|||
parent::__construct($model); |
|||
} |
|||
|
|||
public function requireFeatureById($featureId) |
|||
{ |
|||
return Feature::findOrFail($featureId); |
|||
} |
|||
|
|||
public function createTask($taskData, $featureId) |
|||
{ |
|||
$taskData['feature_id'] = $featureId; |
|||
return $this->storeArray($taskData); |
|||
} |
|||
|
|||
public function getTasksByFeatureId($featureId) |
|||
{ |
|||
return Task::whereTaskId($featureId)->get(); |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Controllers\Projects; |
|||
|
|||
use App\Http\Requests\Tasks\CreateRequest; |
|||
use App\Http\Requests\Tasks\UpdateRequest; |
|||
use App\Http\Requests\Tasks\DeleteRequest; |
|||
use App\Http\Controllers\Controller; |
|||
use App\Entities\Projects\TasksRepository; |
|||
|
|||
use Illuminate\Http\Request; |
|||
|
|||
class TasksController extends Controller { |
|||
|
|||
private $repo; |
|||
|
|||
public function __construct(TasksRepository $repo) |
|||
{ |
|||
$this->repo = $repo; |
|||
} |
|||
|
|||
public function store(CreateRequest $req, $featureId) |
|||
{ |
|||
$feature = $this->repo->createTask($req->except('_token'), $featureId); |
|||
flash()->success(trans('task.created')); |
|||
return redirect()->route('features.show', $featureId); |
|||
} |
|||
|
|||
public function update(UpdateRequest $req, $taskId) |
|||
{ |
|||
$task = $this->repo->update($req->except(['_method','_token']), $taskId); |
|||
flash()->success(trans('task.updated')); |
|||
return redirect()->route('features.show', $task->feature_id); |
|||
} |
|||
|
|||
public function destroy(DeleteRequest $req, $taskId) |
|||
{ |
|||
$task = $this->repo->requireById($taskId); |
|||
$featureId = $task->feature_id; |
|||
|
|||
if ($taskId == $req->get('task_id')) |
|||
{ |
|||
$task->delete(); |
|||
flash()->success(trans('task.deleted')); |
|||
} |
|||
else |
|||
flash()->error(trans('task.undeleted')); |
|||
|
|||
return redirect()->route('features.show', $featureId); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Requests\Tasks; |
|||
|
|||
use App\Entities\Projects\Feature; |
|||
use App\Http\Requests\Request; |
|||
|
|||
class CreateRequest extends Request { |
|||
|
|||
/** |
|||
* Determine if the user is authorized to make this request. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function authorize() |
|||
{ |
|||
$feature = Feature::findOrFail($this->segment(2)); |
|||
return auth()->user()->can('manage_feature', $feature); |
|||
} |
|||
|
|||
/** |
|||
* Get the validation rules that apply to the request. |
|||
* |
|||
* @return array |
|||
*/ |
|||
public function rules() |
|||
{ |
|||
return [ |
|||
'name' => 'required|max:60', |
|||
'description' => 'max:255' |
|||
]; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Requests\Tasks; |
|||
|
|||
use App\Entities\Projects\Feature; |
|||
use App\Http\Requests\Request; |
|||
|
|||
class DeleteRequest extends Request { |
|||
|
|||
/** |
|||
* Determine if the user is authorized to make this request. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function authorize() |
|||
{ |
|||
$feature = Feature::findOrFail($this->get('feature_id')); |
|||
return auth()->user()->can('manage_feature', $feature); |
|||
} |
|||
|
|||
/** |
|||
* Get the validation rules that apply to the request. |
|||
* |
|||
* @return array |
|||
*/ |
|||
public function rules() |
|||
{ |
|||
return [ |
|||
'task_id' => 'required', |
|||
'feature_id' => 'required', |
|||
]; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Requests\Tasks; |
|||
|
|||
use App\Entities\Projects\Feature; |
|||
use App\Http\Requests\Request; |
|||
|
|||
class UpdateRequest extends Request { |
|||
|
|||
/** |
|||
* Determine if the user is authorized to make this request. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function authorize() |
|||
{ |
|||
$feature = Feature::findOrFail($this->get('feature_id')); |
|||
return auth()->user()->can('manage_feature', $feature); |
|||
} |
|||
|
|||
/** |
|||
* Get the validation rules that apply to the request. |
|||
* |
|||
* @return array |
|||
*/ |
|||
public function rules() |
|||
{ |
|||
return [ |
|||
'name' => 'required|max:60', |
|||
'description' => 'max:255', |
|||
'progress' => 'required|numeric|max:100', |
|||
]; |
|||
} |
|||
|
|||
} |
|||
2
public/assets/css/app.css.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
return [ |
|||
'task' => 'Task', |
|||
'tasks' => 'Daftar Task', |
|||
'name' => 'Nama Task', |
|||
'create' => 'Input Task Baru', |
|||
'created' => 'Input Task baru telah berhasil.', |
|||
'show' => 'Detail Task', |
|||
'edit' => 'Edit Task', |
|||
'update' => 'Update Task', |
|||
'updated' => 'Update data Task telah berhasil.', |
|||
'delete' => 'Hapus Task', |
|||
'deleted' => 'Hapus data Task telah berhasil.', |
|||
'undeleted' => 'Data Task gagal dihapus.', |
|||
'search' => 'Cari Task', |
|||
'found' => 'Task ditemukan', |
|||
'not_found' => 'Task tidak ditemukan', |
|||
'progress' => 'Progress', |
|||
'empty' => 'Belum ada Task', |
|||
'back_to_index' => 'Kembali ke daftar Task', |
|||
]; |
|||
@ -0,0 +1,6 @@ |
|||
<ul class="breadcrumb hidden-print"> |
|||
<li>{{ link_to_route('projects.index',trans('project.projects')) }}</li> |
|||
<li>{{ $feature->present()->projectLink }}</li> |
|||
<li>{{ $feature->present()->projectFeaturesLink }}</li> |
|||
<li class="active">{{ isset($title) ? $title : $feature->name }}</li> |
|||
</ul> |
|||
@ -0,0 +1,103 @@ |
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"><h3 class="panel-title">{{ trans('feature.tasks') }}</h3></div> |
|||
<table class="table table-condensed"> |
|||
<thead> |
|||
<th>{{ trans('app.table_no') }}</th> |
|||
<th>{{ trans('task.name') }}</th> |
|||
<th>{{ trans('app.description') }}</th> |
|||
<th class="text-center">{{ trans('task.progress') }}</th> |
|||
<th>{{ trans('app.action') }}</th> |
|||
</thead> |
|||
<tbody> |
|||
@forelse($feature->tasks as $key => $task) |
|||
<tr> |
|||
<td>{{ 1 + $key }}</td> |
|||
<td>{{ $task->name }}</td> |
|||
<td>{{ $task->description }}</td> |
|||
<td class="text-center">{{ $task->progress }} %</td> |
|||
<td> |
|||
{{ link_to_route('features.show', trans('task.edit'), [ |
|||
$feature->id, |
|||
'action' => 'task_edit', |
|||
'task_id' => $task->id |
|||
],['class' => 'btn btn-warning btn-xs']) }} |
|||
{{ link_to_route('features.show', trans('task.delete'), [ |
|||
$feature->id, |
|||
'action' => 'task_delete', |
|||
'task_id' => $task->id |
|||
],['class' => 'btn btn-danger btn-xs']) }} |
|||
</td> |
|||
</tr> |
|||
@empty |
|||
<tr><td colspan="5">{{ trans('task.empty') }}</td></tr> |
|||
@endforelse |
|||
</tbody> |
|||
<tfoot> |
|||
<tr> |
|||
<th class="text-right" colspan="3">Total</th> |
|||
<th class="text-center">{{ formatDecimal($feature->tasks->avg('progress')) }} %</th> |
|||
<th></th> |
|||
</tr> |
|||
</tfoot> |
|||
</table> |
|||
</div> |
|||
@if (Request::has('action') == false) |
|||
{!! Form::open(['route' => ['tasks.store', $feature->id]])!!} |
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.create') }}</h3></div> |
|||
<div class="panel-body"> |
|||
<div class="row"> |
|||
<div class="col-sm-4"> |
|||
{!! FormField::text('name') !!} |
|||
</div> |
|||
<div class="col-sm-8"> |
|||
{!! FormField::text('description') !!} |
|||
</div> |
|||
</div> |
|||
{!! Form::submit(trans('task.create'), ['class' => 'btn btn-primary']) !!} |
|||
{!! Form::close() !!} |
|||
</div> |
|||
</div> |
|||
@endif |
|||
@if (Request::get('action') == 'task_edit' && $editableTask) |
|||
{!! Form::model($editableTask, ['route' => ['tasks.update', $editableTask->id],'method' =>'patch'])!!} |
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.edit') }}</h3></div> |
|||
<div class="panel-body"> |
|||
<div class="row"> |
|||
<div class="col-sm-4"> |
|||
{!! FormField::text('name') !!} |
|||
</div> |
|||
<div class="col-sm-6"> |
|||
{!! FormField::text('description') !!} |
|||
</div> |
|||
<div class="col-sm-2"> |
|||
{!! FormField::text('progress', ['addon' => ['after' => '%']]) !!} |
|||
</div> |
|||
</div> |
|||
{!! Form::hidden('feature_id', $editableTask->feature_id) !!} |
|||
{!! Form::submit(trans('task.update'), ['class' => 'btn btn-warning']) !!} |
|||
{!! link_to_route('features.show', trans('app.cancel'), [$feature->id], ['class' => 'btn btn-default']) !!} |
|||
{!! Form::close() !!} |
|||
</div> |
|||
</div> |
|||
@endif |
|||
@if (Request::get('action') == 'task_delete' && $editableTask) |
|||
<div class="panel panel-default"> |
|||
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.delete') }}</h3></div> |
|||
<div class="panel-body"> |
|||
{{ trans('app.delete_confirm') }} |
|||
{!! link_to_route('features.show', trans('app.cancel'), [$feature->id], ['class' => 'btn btn-default']) !!} |
|||
<div class="pull-right"> |
|||
{!! FormField::delete([ |
|||
'route'=>['tasks.destroy',$task->id]], |
|||
trans('app.delete_confirm_button'), |
|||
['class'=>'btn btn-danger'], |
|||
[ |
|||
'task_id' => $task->id, |
|||
'feature_id' => $task->feature_id, |
|||
]) !!} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@endif |
|||
@ -0,0 +1,115 @@ |
|||
<?php |
|||
|
|||
use App\Entities\Projects\Feature; |
|||
use App\Entities\Projects\Project; |
|||
use App\Entities\Projects\Task; |
|||
use App\Entities\Users\User; |
|||
use Illuminate\Foundation\Testing\DatabaseMigrations; |
|||
use Illuminate\Foundation\Testing\DatabaseTransactions; |
|||
use Illuminate\Foundation\Testing\WithoutMiddleware; |
|||
|
|||
class ManageTasksTest extends TestCase |
|||
{ |
|||
use DatabaseTransactions; |
|||
|
|||
/** @test */ |
|||
public function admin_can_entry_task() |
|||
{ |
|||
$user = factory(User::class)->create(); |
|||
$user->assignRole('admin'); |
|||
$this->actingAs($user); |
|||
|
|||
$feature = factory(Feature::class)->create(['worker_id' => $user->id]); |
|||
$this->visit('features/' . $feature->id); |
|||
$this->seePageIs('features/' . $feature->id); |
|||
$this->see(trans('feature.tasks')); |
|||
$this->see(trans('task.create')); |
|||
|
|||
// Fill Form
|
|||
$this->type('Nama Task Baru','name'); |
|||
$this->type('Ipsam magnam laboriosam distinctio officia facere sapiente eius corporis','description'); |
|||
$this->press(trans('task.create')); |
|||
|
|||
$this->seePageIs('features/' . $feature->id); |
|||
$this->see(trans('task.created')); |
|||
$this->seeInDatabase('tasks', [ |
|||
'name' => 'Nama Task Baru', |
|||
'progress' => 0, |
|||
'feature_id' => $feature->id |
|||
]); |
|||
} |
|||
|
|||
/** @test */ |
|||
public function admin_can_edit_task_data() |
|||
{ |
|||
$user = factory(User::class)->create(); |
|||
$user->assignRole('admin'); |
|||
$user->assignRole('worker'); |
|||
$this->actingAs($user); |
|||
|
|||
$feature = factory(Feature::class)->create(['worker_id' => $user->id]); |
|||
|
|||
$task = factory(Task::class)->create(['feature_id' => $feature->id]); |
|||
|
|||
$this->visit('features/' . $feature->id); |
|||
$this->click(trans('task.edit')); |
|||
$this->seePageIs('features/' . $feature->id . '?action=task_edit&task_id=' . $task->id); |
|||
$this->see(trans('task.edit')); |
|||
$this->see(trans('task.update')); |
|||
|
|||
// Fill Form
|
|||
$this->type('Nama Task Edit','name'); |
|||
$this->type(77,'progress'); |
|||
$this->press(trans('task.update')); |
|||
|
|||
$this->seePageIs('features/' . $feature->id); |
|||
$this->see(trans('task.updated')); |
|||
$this->seeInDatabase('tasks', [ |
|||
'name' => 'Nama Task Edit', |
|||
'progress' => 77, |
|||
'feature_id' => $feature->id |
|||
]); |
|||
} |
|||
|
|||
/** @test */ |
|||
public function admin_can_delete_a_task() |
|||
{ |
|||
$user = factory(User::class)->create(); |
|||
$user->assignRole('admin'); |
|||
$user->assignRole('worker'); |
|||
$this->actingAs($user); |
|||
|
|||
$feature = factory(Feature::class)->create(['worker_id' => $user->id]); |
|||
|
|||
$task = factory(Task::class)->create(['feature_id' => $feature->id]); |
|||
|
|||
$this->visit('features/' . $feature->id); |
|||
$this->click(trans('task.delete')); |
|||
$this->see(trans('app.delete_confirm_button')); |
|||
$this->press(trans('app.delete_confirm_button')); |
|||
$this->seePageIs('features/' . $feature->id); |
|||
$this->see(trans('task.deleted')); |
|||
} |
|||
|
|||
/** @test */ |
|||
public function admin_can_see_all_tasks() |
|||
{ |
|||
$user = factory(User::class)->create(); |
|||
$user->assignRole('admin'); |
|||
$user->assignRole('worker'); |
|||
$this->actingAs($user); |
|||
|
|||
$feature = factory(Feature::class)->create(['worker_id' => $user->id]); |
|||
|
|||
$tasks = factory(Task::class, 10)->create(['feature_id' => $feature->id]); |
|||
$this->assertEquals(10, $tasks->count()); |
|||
|
|||
$this->visit('features/' . $feature->id); |
|||
$this->see($tasks[1]->name); |
|||
$this->see($tasks[1]->progress); |
|||
$this->see($tasks[1]->description); |
|||
$this->see($tasks[9]->name); |
|||
$this->see($tasks[9]->progress); |
|||
$this->see($tasks[9]->description); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue