Browse Source

Effected requested changes for PR#43

pull/43/head
Damilola Olowookere 7 years ago
parent
commit
34291f1b89
  1. 2
      .env.example
  2. 202
      app/Entities/Projects/Job.php
  3. 6
      app/Entities/Projects/JobsRepository.php
  4. 158
      app/Http/Controllers/Auth/LoginController.php
  5. 300
      app/Http/Controllers/JobsController.php
  6. 254
      app/Http/Controllers/Projects/FilesController.php
  7. 6
      app/Http/Requests/Jobs/CreateRequest.php
  8. 6
      app/Http/Requests/Jobs/UpdateRequest.php
  9. 6
      app/Http/Requests/Projects/CreateRequest.php
  10. 6
      app/Http/Requests/Projects/UpdateRequest.php
  11. 6
      app/Http/Requests/Tasks/CreateRequest.php
  12. 6
      app/Http/Requests/Tasks/UpdateRequest.php
  13. 6
      app/Services/Option.php
  14. 2
      composer.json
  15. 518
      composer.lock
  16. 2
      config/app.php
  17. 0
      public/.htaccess
  18. 0
      public/assets/.gitignore
  19. 0
      public/assets/css/.gitignore
  20. 0
      public/assets/css/app.css
  21. 0
      public/assets/css/bootstrap-theme.min.css
  22. 0
      public/assets/css/bootstrap.min.css
  23. 0
      public/assets/css/font-awesome.min.css
  24. 0
      public/assets/css/plugins/dataTables.bootstrap.css
  25. 0
      public/assets/css/plugins/fullcalendar.min.css
  26. 0
      public/assets/css/plugins/fullcalendar.print.css
  27. 0
      public/assets/css/plugins/jquery-ui.min.css
  28. 0
      public/assets/css/plugins/jquery.datetimepicker.css
  29. 0
      public/assets/css/plugins/metisMenu/metisMenu.css
  30. 0
      public/assets/css/plugins/metisMenu/metisMenu.min.css
  31. 0
      public/assets/css/plugins/morris.css
  32. 0
      public/assets/css/plugins/rangeslider.css
  33. 0
      public/assets/css/plugins/select2.min.css
  34. 0
      public/assets/css/plugins/social-buttons.css
  35. 0
      public/assets/css/plugins/timeline.css
  36. 0
      public/assets/css/sb-admin-2.css
  37. 0
      public/assets/fonts/FontAwesome.otf
  38. 0
      public/assets/fonts/fontawesome-webfont.eot
  39. 0
      public/assets/fonts/fontawesome-webfont.svg
  40. 0
      public/assets/fonts/fontawesome-webfont.ttf
  41. 0
      public/assets/fonts/fontawesome-webfont.woff
  42. 0
      public/assets/fonts/fontawesome-webfont.woff2
  43. 0
      public/assets/imgs/.gitignore
  44. 0
      public/assets/imgs/default-logo.png
  45. 0
      public/assets/imgs/icon_user_1.png
  46. 0
      public/assets/imgs/icon_user_2.png
  47. 0
      public/assets/js/.gitignore
  48. 0
      public/assets/js/app.js
  49. 0
      public/assets/js/bootstrap.min.js
  50. 0
      public/assets/js/jquery.js
  51. 0
      public/assets/js/plugins/autoNumeric.min.js
  52. 0
      public/assets/js/plugins/fullcalendar.min.js
  53. 0
      public/assets/js/plugins/gcal.js
  54. 0
      public/assets/js/plugins/jquery-ui.min.js
  55. 0
      public/assets/js/plugins/jquery.datetimepicker.js
  56. 0
      public/assets/js/plugins/metisMenu/metisMenu.js
  57. 0
      public/assets/js/plugins/metisMenu/metisMenu.min.js
  58. 0
      public/assets/js/plugins/moment.min.js
  59. 0
      public/assets/js/plugins/morris/morris-data.js
  60. 0
      public/assets/js/plugins/morris/morris.min.js
  61. 0
      public/assets/js/plugins/morris/raphael.min.js
  62. 0
      public/assets/js/plugins/noty.js
  63. 0
      public/assets/js/plugins/rangeslider.min.js
  64. 0
      public/assets/js/plugins/select2.min.js
  65. 0
      public/assets/js/plugins/sortable.min.js
  66. 0
      public/assets/js/plugins/vue-resource.min.js
  67. 0
      public/assets/js/plugins/vue.min.js
  68. 0
      public/assets/js/sb-admin-2.js
  69. 0
      public/favicon.ico
  70. 0
      public/index.php
  71. 0
      public/mix-manifest.json
  72. 0
      public/robots.txt
  73. 0
      public/screenshots/pmo-dashboard-01.jpg
  74. 0
      public/screenshots/pmo-install-free-pmo.jpg
  75. 0
      public/screenshots/pmo-job-tasks-01.jpg
  76. 0
      public/screenshots/pmo-project-detail-01.jpg
  77. 0
      public/screenshots/pmo-project-jobs-01.jpg
  78. 0
      public/screenshots/pmo-testing-01.jpg
  79. 0
      public/screenshots/pmo-yearly-report-01.jpg
  80. 0
      public/web.config
  81. 68
      resources/lang/de/auth.php
  82. 94
      resources/lang/de/job.php
  83. 68
      resources/lang/en/auth.php
  84. 96
      resources/lang/en/job.php
  85. 68
      resources/lang/id/auth.php
  86. 96
      resources/lang/id/job.php
  87. 14
      resources/views/layouts/app.blade.php
  88. 2
      resources/views/layouts/partials/lang-switcher.blade.php
  89. 2
      routes/web.php
  90. 198
      routes/web/projects.php
  91. 11
      tests/Unit/Services/SiteOptionTest.php

2
.env.example

@ -8,6 +8,8 @@ APP_URL=http://localhost
LOG_CHANNEL=stack
APP_TIMEZONE=Asia/Makassar
DESCRIPTION_CHAR_LEN=0
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=homestead

202
app/Entities/Projects/Job.php

@ -2,8 +2,8 @@
namespace App\Entities\Projects;
use App\Entities\Users\User;
use DB;
use App\Entities\Users\User;
use Illuminate\Database\Eloquent\Model;
use Laracasts\Presenter\PresentableTrait;
use Spatie\MediaLibrary\HasMedia\HasMedia;
@ -16,116 +16,116 @@ use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
*/
class Job extends Model implements HasMedia
{
use PresentableTrait;
use HasMediaTrait;
use PresentableTrait;
use HasMediaTrait;
/**
* @var \App\Entities\Projects\JobPresenter
*/
protected $presenter = JobPresenter::class;
/**
* @var \App\Entities\Projects\JobPresenter
*/
protected $presenter = JobPresenter::class;
/**
* @var array
*/
protected $guarded = ['id', 'created_at', 'updated_at'];
/**
* @var array
*/
protected $guarded = ['id', 'created_at', 'updated_at'];
/**
* Show job name with link to job detail.
*
* @return Illuminate\Support\HtmlString
*/
public function nameLink()
{
return link_to_route('jobs.show', $this->name, [$this->id], [
'title' => __(
'app.show_detail_title',
['name' => $this->name, 'type' => __('job.job')]
),
]);
}
/**
* Show job name with link to job detail.
*
* @return Illuminate\Support\HtmlString
*/
public function nameLink()
{
return link_to_route('jobs.show', $this->name, [$this->id], [
'title' => __(
'app.show_detail_title',
['name' => $this->name, 'type' => __('job.job')]
),
]);
}
/**
* Job belongs to a Project relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function project()
{
return $this->belongsTo(Project::class, 'project_id');
}
/**
* Job belongs to a Project relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function project()
{
return $this->belongsTo(Project::class, 'project_id');
}
/**
* Job belongs to a Worker relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function worker()
{
return $this->belongsTo(User::class, 'worker_id');
}
/**
* Job belongs to a Worker relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function worker()
{
return $this->belongsTo(User::class, 'worker_id');
}
/**
* Job has many Tasks relation ordered by position.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function tasks()
{
return $this->hasMany(Task::class)->orderBy('position');
}
/**
* Job has many Tasks relation ordered by position.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function tasks()
{
return $this->hasMany(Task::class)->orderBy('position');
}
/**
* Job has many comments relation.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
/**
* Job has many comments relation.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
/**
* Get the job type.
*
* @return string
*/
public function type()
{
return $this->type_id == 1 ? __('job.main') : __('job.additional');
}
/**
* Get the job type.
*
* @return string
*/
public function type()
{
return $this->type_id == 1 ? __('job.main') : __('job.additional');
}
/**
* Add progress attribute on Job model.
*
* @return int
*/
public function getProgressAttribute()
{
return $this->tasks->isEmpty() ? 0 : $this->tasks->avg('progress');
}
/**
* Add progress attribute on Job model.
*
* @return int
*/
public function getProgressAttribute()
{
return $this->tasks->isEmpty() ? 0 : $this->tasks->avg('progress');
}
/**
* Add receiveable_earning attribute on Job model.
*
* @return float
*/
public function getReceiveableEarningAttribute()
{
return $this->price * ($this->progress / 100);
}
/**
* Add receiveable_earning attribute on Job model.
*
* @return float
*/
public function getReceiveableEarningAttribute()
{
return $this->price * ($this->progress / 100);
}
/**
* Delete the model from the database.
*
* @return bool|null
*/
public function delete()
{
DB::beginTransaction();
$this->tasks()->delete();
$this->comments()->delete();
DB::commit();
/**
* Delete the model from the database.
*
* @return bool|null
*/
public function delete()
{
DB::beginTransaction();
$this->tasks()->delete();
$this->comments()->delete();
DB::commit();
return parent::delete();
}
return parent::delete();
}
}

6
app/Entities/Projects/JobsRepository.php

@ -82,13 +82,13 @@ class JobsRepository extends BaseRepository
}
$jobData['price'] = str_replace('.', '', $jobData['price']);
$jobData = collect( $jobData);
$jobData = collect($jobData);
$job = $this->requireById($jobId);
if($jobData->has('files')){
if ($jobData->has('files')) {
foreach ($jobData->get('files') as $file) {
$path = $file->getPathName();
if(is_file($path)){
if (is_file($path)) {
$job->addMedia($path)->toMediaCollection();
}
}

158
app/Http/Controllers/Auth/LoginController.php

@ -2,88 +2,88 @@
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (\Auth::attempt($credentials, $request->has('remember'))) {
return redirect($this->redirectTo);
} else {
return $this->sendFailedLoginResponse($request);
}
}
/**
* Send the response after the user was authenticated.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
flash(trans('auth.welcome', ['name' => $request->user()->name]));
return $this->authenticated($request, $this->guard()->user())
?: redirect()->intended($this->redirectPath());
}
/**
* Log the user out of the application.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->flush();
$request->session()->regenerate();
flash(trans('auth.logged_out'), 'success');
return redirect(route('auth.login'));
}
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (\Auth::attempt($credentials, $request->has('remember'))) {
return redirect($this->redirectTo);
} else {
return $this->sendFailedLoginResponse($request);
}
}
/**
* Send the response after the user was authenticated.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
flash(trans('auth.welcome', ['name' => $request->user()->name]));
return $this->authenticated($request, $this->guard()->user())
?: redirect()->intended($this->redirectPath());
}
/**
* Log the user out of the application.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->flush();
$request->session()->regenerate();
flash(trans('auth.logged_out'), 'success');
return redirect(route('auth.login'));
}
}

300
app/Http/Controllers/JobsController.php

@ -2,13 +2,13 @@
namespace App\Http\Controllers;
use App\Entities\Projects\Comment;
use Illuminate\Http\Request;
use App\Entities\Projects\Job;
use App\Entities\Projects\JobsRepository;
use App\Entities\Projects\Comment;
use App\Entities\Projects\Project;
use App\Entities\Projects\JobsRepository;
use App\Http\Requests\Jobs\DeleteRequest;
use App\Http\Requests\Jobs\UpdateRequest;
use Illuminate\Http\Request;
/**
* Jobs Controller.
@ -17,151 +17,151 @@ use Illuminate\Http\Request;
*/
class JobsController extends Controller
{
/**
* @var \App\Entities\Projects\JobsRepository
*/
private $repo;
/**
* Create new Jobs Controller.
*
* @param \App\Entities\Projects\JobsRepository $repo
*/
public function __construct(JobsRepository $repo)
{
$this->repo = $repo;
}
/**
* Show unfinished job list.
*
* @return \Illuminate\View\View
*/
public function index()
{
$user = auth()->user();
if ($user->hasRole('admin')) {
$projects = Project::whereIn('status_id', [2, 3])->pluck('name', 'id');
} else {
$projects = $user->projects()
->whereIn('status_id', [2, 3])
->pluck('projects.name', 'projects.id');
}
$jobs = $this->repo->getUnfinishedJobs($user, request('project_id'));
return view('jobs.unfinished', compact('jobs', 'projects'));
}
/**
* Show a job detail.
*
* @param \Illuminate\Http\Request $request
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function show(Request $request, Job $job)
{
$this->authorize('view', $job);
$editableTask = null;
$editableComment = null;
$comments = $job->comments()->with('creator')->latest()->paginate();
if ($request->get('action') == 'task_edit' && $request->has('task_id')) {
$editableTask = $this->repo->requireTaskById($request->get('task_id'));
}
if ($request->get('action') == 'task_delete' && $request->has('task_id')) {
$editableTask = $this->repo->requireTaskById($request->get('task_id'));
}
if (request('action') == 'comment-edit' && request('comment_id') != null) {
$editableComment = Comment::find(request('comment_id'));
}
return view('jobs.show', compact('job', 'editableTask', 'comments', 'editableComment'));
}
/**
* Show a job edit form.
*
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function edit(Job $job)
{
$files = $job->getMedia();
$this->authorize('view', $job);
$workers = $this->repo->getWorkersList();
return view('jobs.edit', compact('job', 'workers', 'files'));
}
/**
* Update a job on database.
*
* @param \App\Http\Requests\Jobs\UpdateRequest $request
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\Routing\Redirector
*/
public function update(UpdateRequest $request, Job $job)
{
$job = $this->repo->update($request->except(['_method', '_token']), $job->id);
flash(trans('job.updated'), 'success');
return redirect()->route('jobs.show', $job);
}
/**
* Show job delete confirmation page.
*
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function delete(Job $job)
{
return view('jobs.delete', compact('job'));
}
/**
* Show job delete confirmation page.
*
* @param \App\Http\Requests\Jobs\DeleteRequest $request
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function destroy(DeleteRequest $request, Job $job)
{
$projectId = $job->project_id;
if ($job->id == $request->get('job_id')) {
$job->tasks()->delete();
$job->delete();
flash(trans('job.deleted'), 'success');
} else {
flash(trans('job.undeleted'), 'danger');
}
return redirect()->route('projects.jobs.index', $projectId);
}
/**
* Reorder job task position.
*
* @param \Illuminate\Http\Request $request
* @param \App\Entities\Projects\Job $job
* @return string|null
*/
public function tasksReorder(Request $request, Job $job)
{
if ($request->expectsJson()) {
$data = $this->repo->tasksReorder($request->get('postData'));
return 'oke';
}
}
/**
* @var \App\Entities\Projects\JobsRepository
*/
private $repo;
/**
* Create new Jobs Controller.
*
* @param \App\Entities\Projects\JobsRepository $repo
*/
public function __construct(JobsRepository $repo)
{
$this->repo = $repo;
}
/**
* Show unfinished job list.
*
* @return \Illuminate\View\View
*/
public function index()
{
$user = auth()->user();
if ($user->hasRole('admin')) {
$projects = Project::whereIn('status_id', [2, 3])->pluck('name', 'id');
} else {
$projects = $user->projects()
->whereIn('status_id', [2, 3])
->pluck('projects.name', 'projects.id');
}
$jobs = $this->repo->getUnfinishedJobs($user, request('project_id'));
return view('jobs.unfinished', compact('jobs', 'projects'));
}
/**
* Show a job detail.
*
* @param \Illuminate\Http\Request $request
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function show(Request $request, Job $job)
{
$this->authorize('view', $job);
$editableTask = null;
$editableComment = null;
$comments = $job->comments()->with('creator')->latest()->paginate();
if ($request->get('action') == 'task_edit' && $request->has('task_id')) {
$editableTask = $this->repo->requireTaskById($request->get('task_id'));
}
if ($request->get('action') == 'task_delete' && $request->has('task_id')) {
$editableTask = $this->repo->requireTaskById($request->get('task_id'));
}
if (request('action') == 'comment-edit' && request('comment_id') != null) {
$editableComment = Comment::find(request('comment_id'));
}
return view('jobs.show', compact('job', 'editableTask', 'comments', 'editableComment'));
}
/**
* Show a job edit form.
*
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function edit(Job $job)
{
$files = $job->getMedia();
$this->authorize('view', $job);
$workers = $this->repo->getWorkersList();
return view('jobs.edit', compact('job', 'workers', 'files'));
}
/**
* Update a job on database.
*
* @param \App\Http\Requests\Jobs\UpdateRequest $request
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\Routing\Redirector
*/
public function update(UpdateRequest $request, Job $job)
{
$job = $this->repo->update($request->except(['_method', '_token']), $job->id);
flash(trans('job.updated'), 'success');
return redirect()->route('jobs.show', $job);
}
/**
* Show job delete confirmation page.
*
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function delete(Job $job)
{
return view('jobs.delete', compact('job'));
}
/**
* Show job delete confirmation page.
*
* @param \App\Http\Requests\Jobs\DeleteRequest $request
* @param \App\Entities\Projects\Job $job
* @return \Illuminate\View\View
*/
public function destroy(DeleteRequest $request, Job $job)
{
$projectId = $job->project_id;
if ($job->id == $request->get('job_id')) {
$job->tasks()->delete();
$job->delete();
flash(trans('job.deleted'), 'success');
} else {
flash(trans('job.undeleted'), 'danger');
}
return redirect()->route('projects.jobs.index', $projectId);
}
/**
* Reorder job task position.
*
* @param \Illuminate\Http\Request $request
* @param \App\Entities\Projects\Job $job
* @return string|null
*/
public function tasksReorder(Request $request, Job $job)
{
if ($request->expectsJson()) {
$data = $this->repo->tasksReorder($request->get('postData'));
return 'oke';
}
}
}

254
app/Http/Controllers/Projects/FilesController.php

@ -2,10 +2,10 @@
namespace App\Http\Controllers\Projects;
use App\Entities\Projects\File;
use App\Http\Controllers\Controller;
use File as FileSystem;
use Illuminate\Http\Request;
use App\Entities\Projects\File;
use App\Http\Controllers\Controller;
/**
* Project Files Controller.
@ -14,130 +14,128 @@ use Illuminate\Http\Request;
*/
class FilesController extends Controller
{
private $fileableTypes = [
'projects' => 'App\Entities\Projects\Project',
];
public function index(Request $request, $fileableId)
{
$editableFile = null;
$fileableType = $request->segment(1); // projects, jobs
$modelName = $this->getModelName($fileableType);
$modelShortName = $this->getModelShortName($modelName);
$model = $modelName::findOrFail($fileableId);
$files = $model->files;
if (in_array($request->get('action'), ['edit', 'delete']) && $request->has('id')) {
$editableFile = File::find($request->get('id'));
}
return view($fileableType . '.files', [$modelShortName => $model, 'files' => $files, 'editableFile' => $editableFile]);
}
public function create(Request $request, $fileableId)
{
$this->validate($request, [
'fileable_type' => 'required',
'file' => 'required|file|max:10000',
'title' => 'required|max:60',
'description' => 'nullable|max:255',
]);
$fileableType = array_search($request->get('fileable_type'), $this->fileableTypes);
if ($fileableType) {
$file = $this->proccessPhotoUpload($request->except('_token'), $fileableType, $fileableId);
if ($file->exists) {
flash('Upload file berhasil.', 'success');
} else {
flash('Upload file gagal, coba kembali.', 'danger');
}
} else {
flash('Upload file gagal, coba kembali.', 'danger');
}
return back();
}
public function show($fileId)
{
$file = File::find($fileId);
if ($file && file_exists(storage_path('app/public/files/' . $file->filename))) {
$extension = FileSystem::extension('public/files/' . $file->filename);
return response()->download(storage_path('app/public/files/' . $file->filename), $file->title . '.' . $extension);
}
flash(__('file.not_found'), 'danger');
if (\URL::previous() != \URL::current()) {
return back();
}
return redirect()->home();
}
public function update(Request $request, File $file)
{
$file->title = $request->get('title');
$file->description = $request->get('description');
$file->save();
flash(__('file.updated'), 'success');
return redirect()->route($file->fileable_type . '.files', $file->fileable_id);
}
public function destroy(Request $request, File $file)
{
$file->delete();
flash(__('file.deleted'), 'warning');
return redirect()->route($file->fileable_type . '.files', $file->fileable_id);
}
private function proccessPhotoUpload($data, $fileableType, $fileableId)
{
$file = $data['file'];
$fileName = $file->hashName();
$fileData['fileable_id'] = $fileableId;
$fileData['fileable_type'] = $fileableType;
$fileData['filename'] = $fileName;
$fileData['title'] = $data['title'];
$fileData['description'] = $data['description'];
\DB::beginTransaction();
$file->store('public/files');
$file = File::create($fileData);
\DB::commit();
return $file;
}
public function getModelName($fileableType)
{
return isset($this->fileableTypes[$fileableType]) ? $this->fileableTypes[$fileableType] : false;
}
public function getModelShortName($modelName)
{
return strtolower((new \ReflectionClass($modelName))->getShortName());
}
public function showAttachment(Request $request, \App\Entities\Projects\Job $job, $media_id)
{
$files = $job->getMedia();
foreach ($files as $file) {
if ($file->id == $media_id) {
return \Response::file($file->getPath());
}
}
return back()->withErrors(['media not found']);
}
private $fileableTypes = [
'projects' => 'App\Entities\Projects\Project',
];
public function index(Request $request, $fileableId)
{
$editableFile = null;
$fileableType = $request->segment(1); // projects, jobs
$modelName = $this->getModelName($fileableType);
$modelShortName = $this->getModelShortName($modelName);
$model = $modelName::findOrFail($fileableId);
$files = $model->files;
if (in_array($request->get('action'), ['edit', 'delete']) && $request->has('id')) {
$editableFile = File::find($request->get('id'));
}
return view($fileableType.'.files', [$modelShortName => $model, 'files' => $files, 'editableFile' => $editableFile]);
}
public function create(Request $request, $fileableId)
{
$this->validate($request, [
'fileable_type' => 'required',
'file' => 'required|file|max:10000',
'title' => 'required|max:60',
'description' => 'nullable|max:255',
]);
$fileableType = array_search($request->get('fileable_type'), $this->fileableTypes);
if ($fileableType) {
$file = $this->proccessPhotoUpload($request->except('_token'), $fileableType, $fileableId);
if ($file->exists) {
flash('Upload file berhasil.', 'success');
} else {
flash('Upload file gagal, coba kembali.', 'danger');
}
} else {
flash('Upload file gagal, coba kembali.', 'danger');
}
return back();
}
public function show($fileId)
{
$file = File::find($fileId);
if ($file && file_exists(storage_path('app/public/files/'.$file->filename))) {
$extension = FileSystem::extension('public/files/'.$file->filename);
return response()->download(storage_path('app/public/files/'.$file->filename), $file->title.'.'.$extension);
}
flash(__('file.not_found'), 'danger');
if (\URL::previous() != \URL::current()) {
return back();
}
return redirect()->home();
}
public function update(Request $request, File $file)
{
$file->title = $request->get('title');
$file->description = $request->get('description');
$file->save();
flash(__('file.updated'), 'success');
return redirect()->route($file->fileable_type.'.files', $file->fileable_id);
}
public function destroy(Request $request, File $file)
{
$file->delete();
flash(__('file.deleted'), 'warning');
return redirect()->route($file->fileable_type.'.files', $file->fileable_id);
}
private function proccessPhotoUpload($data, $fileableType, $fileableId)
{
$file = $data['file'];
$fileName = $file->hashName();
$fileData['fileable_id'] = $fileableId;
$fileData['fileable_type'] = $fileableType;
$fileData['filename'] = $fileName;
$fileData['title'] = $data['title'];
$fileData['description'] = $data['description'];
\DB::beginTransaction();
$file->store('public/files');
$file = File::create($fileData);
\DB::commit();
return $file;
}
public function getModelName($fileableType)
{
return isset($this->fileableTypes[$fileableType]) ? $this->fileableTypes[$fileableType] : false;
}
public function getModelShortName($modelName)
{
return strtolower((new \ReflectionClass($modelName))->getShortName());
}
public function showAttachment(Request $request, \App\Entities\Projects\Job $job, $media_id)
{
$files = $job->getMedia();
foreach ($files as $file) {
if ($file->id == $media_id) {
return \Response::file($file->getPath());
}
}
return back()->withErrors(['media not found']);
}
}

6
app/Http/Requests/Jobs/CreateRequest.php

@ -39,9 +39,9 @@ class CreateRequest extends Request
//achieved using environmental variable.
//A value of zero (0) will mean "no limit"
$char_len_job_description = intval(env('CHAR_LEN_JOB_DESCRIPTION', 255));
if ($char_len_job_description > 0) {
$rules['description'] = "max:$char_len_job_description";
$charLenJobDescription = intval(env('DESCRIPTION_CHAR_LEN', 255));
if ($charLenJobDescription > 0) {
$rules['description'] = "max:$charLenJobDescription";
}
return $rules;

6
app/Http/Requests/Jobs/UpdateRequest.php

@ -37,9 +37,9 @@ class UpdateRequest extends Request
//achieved using environmental variable.
//A value of zero (0) will mean "no limit"
$char_len_job_description = intval(env('CHAR_LEN_JOB_DESCRIPTION', 255));
if ($char_len_job_description > 0) {
$rules['description'] = "max:$char_len_job_description";
$charLenJobDescription = intval(env('DESCRIPTION_CHAR_LEN', 255));
if ($charLenJobDescription > 0) {
$rules['description'] = "max:$charLenJobDescription";
}
return $rules;

6
app/Http/Requests/Projects/CreateRequest.php

@ -37,9 +37,9 @@ class CreateRequest extends Request
//achieved using environmental variable.
//A value of zero (0) will mean "no limit"
$char_len_project_description = intval(env('CHAR_LEN_PROJECT_DESCRIPTION', 255));
if ($char_len_project_description > 0) {
$rules['description'] = "max:$char_len_project_description";
$charLenProjectDescription = intval(env('DESCRIPTION_CHAR_LEN', 255));
if ($charLenProjectDescription > 0) {
$rules['description'] = "max:$charLenProjectDescription";
}
return $rules;

6
app/Http/Requests/Projects/UpdateRequest.php

@ -42,9 +42,9 @@ class UpdateRequest extends Request
//achieved using environmental variable.
//A value of zero (0) will mean "no limit"
$char_len_project_description = intval(env('CHAR_LEN_PROJECT_DESCRIPTION', 255));
if ($char_len_project_description > 0) {
$rules['description'] = "max:$char_len_project_description";
$charLenProjectDescription = intval(env('DESCRIPTION_CHAR_LEN', 255));
if ($charLenProjectDescription > 0) {
$rules['description'] = "max:$charLenProjectDescription";
}
return $rules;

6
app/Http/Requests/Tasks/CreateRequest.php

@ -33,9 +33,9 @@ class CreateRequest extends Request
//achieved using environmental variable.
//A value of zero (0) will mean "no limit"
$char_len_task_description = intval(env('CHAR_LEN_TASK_DESCRIPTION', 255));
if ($char_len_task_description > 0) {
$rules['description'] = "max:$char_len_task_description";
$charLenTaskDescription = intval(env('DESCRIPTION_CHAR_LEN', 255));
if ($charLenTaskDescription > 0) {
$rules['description'] = "max:$charLenTaskDescription";
}
return $rules;

6
app/Http/Requests/Tasks/UpdateRequest.php

@ -35,9 +35,9 @@ class UpdateRequest extends Request
//achieved using environmental variable.
//A value of zero (0) will mean "no limit"
$char_len_task_description = intval(env('CHAR_LEN_TASK_DESCRIPTION', 255));
if ($char_len_task_description > 0) {
$rules['description'] = "max:$char_len_task_description";
$charLenTaskDescription = intval(env('DESCRIPTION_CHAR_LEN', 255));
if ($charLenTaskDescription > 0) {
$rules['description'] = "max:$charLenTaskDescription";
}
return $rules;

6
app/Services/Option.php

@ -49,8 +49,12 @@ class Option
*
* @return string The option value.
*/
public function set($key, string $value)
public function set($key, ?string $value)
{
if (is_null($value)) {
$value = '';
}
$option = $this->option->where('key', $key)->first();
if ($option) {

2
composer.json

@ -7,7 +7,6 @@
"require": {
"php": "^7.1.3",
"backup-manager/laravel": "^1.2",
"doctrine/dbal": "^2.9",
"fideloper/proxy": "^4.0",
"laracasts/presenter": "^0.2.1",
"laravel/framework": "5.7.*",
@ -19,6 +18,7 @@
"require-dev": {
"barryvdh/laravel-debugbar": "^3.1",
"doctrine/dbal": "^2.9",
"fzaninotto/faker": "^1.4",
"johnkary/phpunit-speedtrap": "^3.0",
"luthfi/simple-crud-generator": "1.2.*",

518
composer.lock

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "2c79006b0c9b9c41306539d5f580fb9f",
"content-hash": "eff47d81730132ae7bb2e5121935ea8c",
"packages": [
{
"name": "backup-manager/backup-manager",
@ -139,237 +139,6 @@
"time": "2018-06-18T09:20:25+00:00"
},
{
"name": "doctrine/cache",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "d768d58baee9a4862ca783840eca1b9add7a7f57"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/d768d58baee9a4862ca783840eca1b9add7a7f57",
"reference": "d768d58baee9a4862ca783840eca1b9add7a7f57",
"shasum": ""
},
"require": {
"php": "~7.1"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"alcaeus/mongo-php-adapter": "^1.1",
"doctrine/coding-standard": "^4.0",
"mongodb/mongodb": "^1.1",
"phpunit/phpunit": "^7.0",
"predis/predis": "~1.0"
},
"suggest": {
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Caching library offering an object-oriented API for many cache backends",
"homepage": "https://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
],
"time": "2018-08-21T18:01:43+00:00"
},
{
"name": "doctrine/dbal",
"version": "v2.9.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9",
"reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9",
"shasum": ""
},
"require": {
"doctrine/cache": "^1.0",
"doctrine/event-manager": "^1.0",
"ext-pdo": "*",
"php": "^7.1"
},
"require-dev": {
"doctrine/coding-standard": "^5.0",
"jetbrains/phpstorm-stubs": "^2018.1.2",
"phpstan/phpstan": "^0.10.1",
"phpunit/phpunit": "^7.4",
"symfony/console": "^2.0.5|^3.0|^4.0",
"symfony/phpunit-bridge": "^3.4.5|^4.0.5"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.9.x-dev",
"dev-develop": "3.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
"keywords": [
"abstraction",
"database",
"dbal",
"mysql",
"persistence",
"pgsql",
"php",
"queryobject"
],
"time": "2018-12-31T03:27:51+00:00"
},
{
"name": "doctrine/event-manager",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/event-manager.git",
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3",
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"conflict": {
"doctrine/common": "<2.9@dev"
},
"require-dev": {
"doctrine/coding-standard": "^4.0",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "Doctrine Event Manager component",
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
"keywords": [
"event",
"eventdispatcher",
"eventmanager"
],
"time": "2018-06-11T11:59:03+00:00"
},
{
"name": "doctrine/inflector",
"version": "v1.3.0",
"source": {
@ -825,33 +594,37 @@
},
{
"name": "guzzlehttp/psr7",
"version": "1.5.2",
"version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "9f83dded91781a01c63574e387eaa769be769115"
"reference": "239400de7a173fe9901b9ac7c06497751f00727a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115",
"reference": "9f83dded91781a01c63574e387eaa769be769115",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a",
"reference": "239400de7a173fe9901b9ac7c06497751f00727a",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0",
"ralouphie/getallheaders": "^2.0.5"
"ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"ext-zlib": "*",
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
},
"suggest": {
"zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.5-dev"
"dev-master": "1.6-dev"
}
},
"autoload": {
@ -888,7 +661,7 @@
"uri",
"url"
],
"time": "2018-12-04T20:46:45+00:00"
"time": "2019-07-01T23:21:34+00:00"
},
{
"name": "intervention/image",
@ -2454,24 +2227,24 @@
},
{
"name": "ralouphie/getallheaders",
"version": "2.0.5",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa"
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
"reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
"php": ">=5.3"
"php": ">=5.6"
},
"require-dev": {
"phpunit/phpunit": "~3.7.0",
"satooshi/php-coveralls": ">=1.0"
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^5 || ^6.5"
},
"type": "library",
"autoload": {
@ -2490,7 +2263,7 @@
}
],
"description": "A polyfill for getallheaders.",
"time": "2016-02-11T07:05:27+00:00"
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "ramsey/uuid",
@ -2854,16 +2627,16 @@
},
{
"name": "spatie/laravel-medialibrary",
"version": "7.6.0",
"version": "7.6.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-medialibrary.git",
"reference": "6ffb8a41e60f024abd35ff47e08628354d6efd0e"
"reference": "ba5437eb92c537530538d68cb29181233d257fa0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/6ffb8a41e60f024abd35ff47e08628354d6efd0e",
"reference": "6ffb8a41e60f024abd35ff47e08628354d6efd0e",
"url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/ba5437eb92c537530538d68cb29181233d257fa0",
"reference": "ba5437eb92c537530538d68cb29181233d257fa0",
"shasum": ""
},
"require": {
@ -2933,7 +2706,7 @@
"media",
"spatie"
],
"time": "2019-02-27T09:31:55+00:00"
"time": "2019-07-04T11:01:02+00:00"
},
{
"name": "spatie/pdf-to-image",
@ -4638,6 +4411,237 @@
"time": "2019-03-25T09:39:08+00:00"
},
{
"name": "doctrine/cache",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "d768d58baee9a4862ca783840eca1b9add7a7f57"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/d768d58baee9a4862ca783840eca1b9add7a7f57",
"reference": "d768d58baee9a4862ca783840eca1b9add7a7f57",
"shasum": ""
},
"require": {
"php": "~7.1"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"alcaeus/mongo-php-adapter": "^1.1",
"doctrine/coding-standard": "^4.0",
"mongodb/mongodb": "^1.1",
"phpunit/phpunit": "^7.0",
"predis/predis": "~1.0"
},
"suggest": {
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Caching library offering an object-oriented API for many cache backends",
"homepage": "https://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
],
"time": "2018-08-21T18:01:43+00:00"
},
{
"name": "doctrine/dbal",
"version": "v2.9.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9",
"reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9",
"shasum": ""
},
"require": {
"doctrine/cache": "^1.0",
"doctrine/event-manager": "^1.0",
"ext-pdo": "*",
"php": "^7.1"
},
"require-dev": {
"doctrine/coding-standard": "^5.0",
"jetbrains/phpstorm-stubs": "^2018.1.2",
"phpstan/phpstan": "^0.10.1",
"phpunit/phpunit": "^7.4",
"symfony/console": "^2.0.5|^3.0|^4.0",
"symfony/phpunit-bridge": "^3.4.5|^4.0.5"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.9.x-dev",
"dev-develop": "3.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
"keywords": [
"abstraction",
"database",
"dbal",
"mysql",
"persistence",
"pgsql",
"php",
"queryobject"
],
"time": "2018-12-31T03:27:51+00:00"
},
{
"name": "doctrine/event-manager",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/event-manager.git",
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3",
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"conflict": {
"doctrine/common": "<2.9@dev"
},
"require-dev": {
"doctrine/coding-standard": "^4.0",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "Doctrine Event Manager component",
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
"keywords": [
"event",
"eventdispatcher",
"eventmanager"
],
"time": "2018-06-11T11:59:03+00:00"
},
{
"name": "doctrine/instantiator",
"version": "1.2.0",
"source": {
@ -5651,16 +5655,16 @@
},
{
"name": "phpunit/php-token-stream",
"version": "3.0.1",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18"
"reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18",
"reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c",
"reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c",
"shasum": ""
},
"require": {
@ -5696,7 +5700,7 @@
"keywords": [
"tokenizer"
],
"time": "2018-10-30T05:52:18+00:00"
"time": "2019-07-08T05:24:54+00:00"
},
{
"name": "phpunit/phpunit",

2
config/app.php

@ -13,7 +13,7 @@ return [
|
*/
'name' => 'Anchis & Kolbins',
'name' => 'FREE PMO',
/*
|--------------------------------------------------------------------------

0
public/.htaccess

0
public/assets/.gitignore

0
public/assets/css/.gitignore

0
public/assets/css/app.css

0
public/assets/css/bootstrap-theme.min.css

0
public/assets/css/bootstrap.min.css

0
public/assets/css/font-awesome.min.css

0
public/assets/css/plugins/dataTables.bootstrap.css

0
public/assets/css/plugins/fullcalendar.min.css

0
public/assets/css/plugins/fullcalendar.print.css

0
public/assets/css/plugins/jquery-ui.min.css

0
public/assets/css/plugins/jquery.datetimepicker.css

0
public/assets/css/plugins/metisMenu/metisMenu.css

0
public/assets/css/plugins/metisMenu/metisMenu.min.css

0
public/assets/css/plugins/morris.css

0
public/assets/css/plugins/rangeslider.css

0
public/assets/css/plugins/select2.min.css

0
public/assets/css/plugins/social-buttons.css

0
public/assets/css/plugins/timeline.css

0
public/assets/css/sb-admin-2.css

0
public/assets/fonts/FontAwesome.otf

0
public/assets/fonts/fontawesome-webfont.eot

0
public/assets/fonts/fontawesome-webfont.svg

0
public/assets/fonts/fontawesome-webfont.ttf

0
public/assets/fonts/fontawesome-webfont.woff

0
public/assets/fonts/fontawesome-webfont.woff2

0
public/assets/imgs/.gitignore

0
public/assets/imgs/default-logo.png

Before

Width: 200  |  Height: 200  |  Size: 22 KiB

After

Width: 200  |  Height: 200  |  Size: 22 KiB

0
public/assets/imgs/icon_user_1.png

Before

Width: 280  |  Height: 280  |  Size: 10 KiB

After

Width: 280  |  Height: 280  |  Size: 10 KiB

0
public/assets/imgs/icon_user_2.png

Before

Width: 280  |  Height: 280  |  Size: 11 KiB

After

Width: 280  |  Height: 280  |  Size: 11 KiB

0
public/assets/js/.gitignore

0
public/assets/js/app.js

0
public/assets/js/bootstrap.min.js

0
public/assets/js/jquery.js

0
public/assets/js/plugins/autoNumeric.min.js

0
public/assets/js/plugins/fullcalendar.min.js

0
public/assets/js/plugins/gcal.js

0
public/assets/js/plugins/jquery-ui.min.js

0
public/assets/js/plugins/jquery.datetimepicker.js

0
public/assets/js/plugins/metisMenu/metisMenu.js

0
public/assets/js/plugins/metisMenu/metisMenu.min.js

0
public/assets/js/plugins/moment.min.js

0
public/assets/js/plugins/morris/morris-data.js

0
public/assets/js/plugins/morris/morris.min.js

0
public/assets/js/plugins/morris/raphael.min.js

0
public/assets/js/plugins/noty.js

0
public/assets/js/plugins/rangeslider.min.js

0
public/assets/js/plugins/select2.min.js

0
public/assets/js/plugins/sortable.min.js

0
public/assets/js/plugins/vue-resource.min.js

0
public/assets/js/plugins/vue.min.js

0
public/assets/js/sb-admin-2.js

0
public/favicon.ico

0
public/index.php

0
public/mix-manifest.json

0
public/robots.txt

0
public/screenshots/pmo-dashboard-01.jpg

Before

Width: 1000  |  Height: 478  |  Size: 61 KiB

After

Width: 1000  |  Height: 478  |  Size: 61 KiB

0
public/screenshots/pmo-install-free-pmo.jpg

Before

Width: 610  |  Height: 640  |  Size: 49 KiB

After

Width: 610  |  Height: 640  |  Size: 49 KiB

0
public/screenshots/pmo-job-tasks-01.jpg

Before

Width: 1000  |  Height: 578  |  Size: 81 KiB

After

Width: 1000  |  Height: 578  |  Size: 81 KiB

0
public/screenshots/pmo-project-detail-01.jpg

Before

Width: 1000  |  Height: 478  |  Size: 64 KiB

After

Width: 1000  |  Height: 478  |  Size: 64 KiB

0
public/screenshots/pmo-project-jobs-01.jpg

Before

Width: 1000  |  Height: 560  |  Size: 78 KiB

After

Width: 1000  |  Height: 560  |  Size: 78 KiB

0
public/screenshots/pmo-testing-01.jpg

Before

Width: 658  |  Height: 355  |  Size: 36 KiB

After

Width: 658  |  Height: 355  |  Size: 36 KiB

0
public/screenshots/pmo-yearly-report-01.jpg

Before

Width: 1000  |  Height: 819  |  Size: 97 KiB

After

Width: 1000  |  Height: 819  |  Size: 97 KiB

0
public/web.config

68
resources/lang/de/auth.php

@ -1,43 +1,43 @@
<?php
return [
// Profile
'profile' => 'Mein Profil',
'profile_edit' => 'Mein Profil bearbeiten',
'update_profile' => 'Profil aktualisieren',
'profile_updated' => 'Profil wurde aktualisiert.',
// Profile
'profile' => 'Mein Profil',
'profile_edit' => 'Mein Profil bearbeiten',
'update_profile' => 'Profil aktualisieren',
'profile_updated' => 'Profil wurde aktualisiert.',
// Registration
'register' => 'Neuen Account anlegen',
'need_account' => 'Account benötigt?',
'have_an_account' => 'Ich habe bereits einen Account',
// Registration
'register' => 'Neuen Account anlegen',
'need_account' => 'Account benötigt?',
'have_an_account' => 'Ich habe bereits einen Account',
// Login & Logout
'login' => 'Login',
'welcome' => 'Willkommen :name.',
'failed' => 'Diese Zugangsdaten passen nicht zu unseren Daten.',
'throttle' => 'Zu viele Login Versuche. Bitte probiere es erneut in :seconds Sekunden.',
'logout' => 'Logout',
'logged_out' => 'Sie haben sich ausgeloggt.',
'remember_me' => 'Erinnere dich an mich',
// Login & Logout
'login' => 'Login',
'welcome' => 'Willkommen :name.',
'failed' => 'Diese Zugangsdaten passen nicht zu unseren Daten.',
'throttle' => 'Zu viele Login Versuche. Bitte probiere es erneut in :seconds Sekunden.',
'logout' => 'Logout',
'logged_out' => 'Sie haben sich ausgeloggt.',
'remember_me' => 'Erinnere dich an mich',
// Password
'change_password' => 'Passwort ändern',
'password_changed' => 'Ihr Passwort wurde geändert',
'forgot_password' => 'Passwort vergessen?',
'reset_password' => 'Password zurücksetzen',
'send_reset_password_link' => 'Sende Passwort Reset Link',
'old_password_failed' => 'Altes Passwort stimmt nicht überein!',
'reset_password_hint' => 'Bitte setzen Sie Ihr Passwort zurück, indem Sie dieses Formular ausfüllen',
// Password
'change_password' => 'Passwort ändern',
'password_changed' => 'Ihr Passwort wurde geändert',
'forgot_password' => 'Passwort vergessen?',
'reset_password' => 'Password zurücksetzen',
'send_reset_password_link' => 'Sende Passwort Reset Link',
'old_password_failed' => 'Altes Passwort stimmt nicht überein!',
'reset_password_hint' => 'Bitte setzen Sie Ihr Passwort zurück, indem Sie dieses Formular ausfüllen',
// Attributes
'email' => 'E-Mail',
'password' => 'Passwort',
'password_confirmation' => 'Passwort bestätigen',
'old_password' => 'Altes Passwort',
'new_password' => 'Neues Passwort',
'new_password_confirmation' => 'Neues Passwort bestätigen',
// Attributes
'email' => 'E-Mail',
'password' => 'Passwort',
'password_confirmation' => 'Passwort bestätigen',
'old_password' => 'Altes Passwort',
'new_password' => 'Neues Passwort',
'new_password_confirmation' => 'Neues Passwort bestätigen',
// Authorization
'unauthorized_access' => 'Sie können nicht auf die Seite :url zugreifen.',
// Authorization
'unauthorized_access' => 'Sie können nicht auf die Seite :url zugreifen.',
];

94
resources/lang/de/job.php

@ -1,54 +1,54 @@
<?php
return [
// Labels
'job' => 'Beschäftigung',
'list' => 'Beschäftigungsliste',
'on_progress' => 'in Arbeit',
'detail' => 'Beschäftigungsdetails',
'search' => 'Beschäftigung suchen',
'found' => 'Beschäftigung gefunden.',
'not_found' => 'Beschäftigung nicht gefunden.',
'tasks' => 'Aufgabenliste',
'price_total' => 'Beschäftigungsgesamtpreis',
'tasks_count' => 'Beschäftigungsanzahl',
'empty' => 'Beschäftigungsliste ist leer.',
'back_to_index' => 'zurück zur Beschäftigungsliste',
'starts' => 'Starts',
'ends' => 'Ends',
'target' => 'Target',
'actual' => 'Actual',
'duration' => 'Duration',
// Labels
'job' => 'Beschäftigung',
'list' => 'Beschäftigungsliste',
'on_progress' => 'in Arbeit',
'detail' => 'Beschäftigungsdetails',
'search' => 'Beschäftigung suchen',
'found' => 'Beschäftigung gefunden.',
'not_found' => 'Beschäftigung nicht gefunden.',
'tasks' => 'Aufgabenliste',
'price_total' => 'Beschäftigungsgesamtpreis',
'tasks_count' => 'Beschäftigungsanzahl',
'empty' => 'Beschäftigungsliste ist leer.',
'back_to_index' => 'zurück zur Beschäftigungsliste',
'starts' => 'Starts',
'ends' => 'Ends',
'target' => 'Target',
'actual' => 'Actual',
'duration' => 'Duration',
// Actions
'create' => 'Neue Beschäftigung anlegen',
'add' => 'Beschäftigung hinzufügen',
'created' => 'Neue Beschäftigung wurde angelegt.',
'show' => 'Beschäftigungsdetails anzeigen',
'edit' => 'Beschäftigung bearbeiten',
'update' => 'Beschäftigung aktualisieren',
'updated' => 'Beschäftigungsdetails wurden aktualisiert.',
'delete' => 'Beschäftigung löschen',
'deleted' => 'Beschäftigung wurde gelöscht.',
'undeleted' => 'Beschäftigung nicht gelöscht.',
'add_from_other_project' => 'Beschäftigung von einem anderen Projekt hinzufügen',
'select_project' => 'ein Projekt auswählen.',
'sort_tasks' => 'sortiere Aufgabenpriorität',
// Actions
'create' => 'Neue Beschäftigung anlegen',
'add' => 'Beschäftigung hinzufügen',
'created' => 'Neue Beschäftigung wurde angelegt.',
'show' => 'Beschäftigungsdetails anzeigen',
'edit' => 'Beschäftigung bearbeiten',
'update' => 'Beschäftigung aktualisieren',
'updated' => 'Beschäftigungsdetails wurden aktualisiert.',
'delete' => 'Beschäftigung löschen',
'deleted' => 'Beschäftigung wurde gelöscht.',
'undeleted' => 'Beschäftigung nicht gelöscht.',
'add_from_other_project' => 'Beschäftigung von einem anderen Projekt hinzufügen',
'select_project' => 'ein Projekt auswählen.',
'sort_tasks' => 'sortiere Aufgabenpriorität',
// Attributes
'name' => 'Beschäftigungsname',
'description' => 'Beschreibung',
'progress' => 'Fortschritt',
'worker' => 'Bearbeiter',
'price' => 'Preis',
'type' => 'Beschäftigungstyp',
'target_start_date' => 'Target Start Date',
'target_end_date' => 'Target End Date',
'actual_start_date' => 'Actual Start Date',
'actual_end_date' => 'Actual End Date',
'files' => 'An diesen Job angehängte Dateien',
// Attributes
'name' => 'Beschäftigungsname',
'description' => 'Beschreibung',
'progress' => 'Fortschritt',
'worker' => 'Bearbeiter',
'price' => 'Preis',
'type' => 'Beschäftigungstyp',
'target_start_date' => 'Target Start Date',
'target_end_date' => 'Target End Date',
'actual_start_date' => 'Actual Start Date',
'actual_end_date' => 'Actual End Date',
'files' => 'An diesen Job angehängte Dateien',
// Types
'main' => 'Haupt',
'additional' => 'Zusätzlich',
// Types
'main' => 'Haupt',
'additional' => 'Zusätzlich',
];

68
resources/lang/en/auth.php

@ -1,43 +1,43 @@
<?php
return [
// Profile
'profile' => 'My Profile',
'profile_edit' => 'Edit My Profile',
'update_profile' => 'Update Profile',
'profile_updated' => 'Profile has been updated.',
// Profile
'profile' => 'My Profile',
'profile_edit' => 'Edit My Profile',
'update_profile' => 'Update Profile',
'profile_updated' => 'Profile has been updated.',
// Registration
'register' => 'Create new Account',
'need_account' => 'Need an Account?',
'have_an_account' => 'I have an Account',
// Registration
'register' => 'Create new Account',
'need_account' => 'Need an Account?',
'have_an_account' => 'I have an Account',
// Login & Logout
'login' => 'Login',
'welcome' => 'Welcome :name.',
'failed' => 'These credentials do not match our records.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
'logout' => 'Logout',
'logged_out' => 'You have logged out.',
'remember_me' => 'Remember me',
// Login & Logout
'login' => 'Login',
'welcome' => 'Welcome :name.',
'failed' => 'These credentials do not match our records.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
'logout' => 'Logout',
'logged_out' => 'You have logged out.',
'remember_me' => 'Remember me',
// Password
'change_password' => 'Change Password',
'password_changed' => 'Your password has been changed.',
'forgot_password' => 'Forgot Password?',
'reset_password' => 'Reset Password',
'send_reset_password_link' => 'Send reset password link',
'old_password_failed' => 'Old password does not match!',
'reset_password_hint' => 'Please reset your password by filling out this form',
// Password
'change_password' => 'Change Password',
'password_changed' => 'Your password has been changed.',
'forgot_password' => 'Forgot Password?',
'reset_password' => 'Reset Password',
'send_reset_password_link' => 'Send reset password link',
'old_password_failed' => 'Old password does not match!',
'reset_password_hint' => 'Please reset your password by filling out this form',
// Attributes
'email' => 'Email',
'password' => 'Password',
'password_confirmation' => 'Confirm Password',
'old_password' => 'Old Password',
'new_password' => 'New Password',
'new_password_confirmation' => 'Confirm new Password',
// Attributes
'email' => 'Email',
'password' => 'Password',
'password_confirmation' => 'Confirm Password',
'old_password' => 'Old Password',
'new_password' => 'New Password',
'new_password_confirmation' => 'Confirm new Password',
// Authorization
'unauthorized_access' => 'You cannot access :url page.',
// Authorization
'unauthorized_access' => 'You cannot access :url page.',
];

96
resources/lang/en/job.php

@ -1,56 +1,56 @@
<?php
return [
// Labels
'job' => 'Job',
'list' => 'Job List',
'on_progress' => 'Job on Progress',
'detail' => 'Job Detail',
'search' => 'Ssearch Job',
'found' => 'Job found.',
'not_found' => 'Job not found.',
'tasks' => 'Task List',
'price_total' => 'Job Price Total',
'tasks_count' => 'Tasks Count',
'empty' => 'Job list is empty.',
'back_to_index' => 'Back to Job List',
'starts' => 'Starts',
'ends' => 'Ends',
'target' => 'Target',
'actual' => 'Actual',
'duration' => 'Duration',
// Labels
'job' => 'Job',
'list' => 'Job List',
'on_progress' => 'Job on Progress',
'detail' => 'Job Detail',
'search' => 'Ssearch Job',
'found' => 'Job found.',
'not_found' => 'Job not found.',
'tasks' => 'Task List',
'price_total' => 'Job Price Total',
'tasks_count' => 'Tasks Count',
'empty' => 'Job list is empty.',
'back_to_index' => 'Back to Job List',
'starts' => 'Starts',
'ends' => 'Ends',
'target' => 'Target',
'actual' => 'Actual',
'duration' => 'Duration',
// Actions
'create' => 'Create new Job',
'add' => 'Add Jobs',
'created' => 'New Job has been created.',
'show' => 'View Job Detail',
'edit' => 'Edit Job',
'update' => 'Update Job',
'updated' => 'Job data has been updated.',
'delete' => 'Delete Job',
'deleted' => 'Job has been deleted.',
'undeleted' => 'Job not deleted.',
'add_from_other_project' => 'Add Job from another Project',
'select_project' => 'Select a project.',
'sort_tasks' => 'Sort Task Priority',
// Actions
'create' => 'Create new Job',
'add' => 'Add Jobs',
'created' => 'New Job has been created.',
'show' => 'View Job Detail',
'edit' => 'Edit Job',
'update' => 'Update Job',
'updated' => 'Job data has been updated.',
'delete' => 'Delete Job',
'deleted' => 'Job has been deleted.',
'undeleted' => 'Job not deleted.',
'add_from_other_project' => 'Add Job from another Project',
'select_project' => 'Select a project.',
'sort_tasks' => 'Sort Task Priority',
'created_from_other_project' => 'Job has been added from other Project.',
'created_from_other_project' => 'Job has been added from other Project.',
// Attributes
'name' => 'Job Name',
'description' => 'Description',
'progress' => 'Progress',
'worker' => 'Worker',
'price' => 'Price',
'type' => 'Job Type',
'target_start_date' => 'Target Start Date',
'target_end_date' => 'Target End Date',
'actual_start_date' => 'Actual Start Date',
'actual_end_date' => 'Actual End Date',
'files' => 'Files attached to this job',
// Attributes
'name' => 'Job Name',
'description' => 'Description',
'progress' => 'Progress',
'worker' => 'Worker',
'price' => 'Price',
'type' => 'Job Type',
'target_start_date' => 'Target Start Date',
'target_end_date' => 'Target End Date',
'actual_start_date' => 'Actual Start Date',
'actual_end_date' => 'Actual End Date',
'files' => 'Files attached to this job',
// Types
'main' => 'Main',
'additional' => 'Additional',
// Types
'main' => 'Main',
'additional' => 'Additional',
];

68
resources/lang/id/auth.php

@ -1,43 +1,43 @@
<?php
return [
// Profile
'profile' => 'Profil Saya',
'profile_edit' => 'Edit Profil Saya',
'update_profile' => 'Update Profil',
'profile_updated' => 'Profil sudah diupdate.',
// Profile
'profile' => 'Profil Saya',
'profile_edit' => 'Edit Profil Saya',
'update_profile' => 'Update Profil',
'profile_updated' => 'Profil sudah diupdate.',
// Registration
'register' => 'Buat Akun Baru',
'need_account' => 'Belum punya Akun?',
'have_an_account' => 'Saya sudah punya Akun',
// Registration
'register' => 'Buat Akun Baru',
'need_account' => 'Belum punya Akun?',
'have_an_account' => 'Saya sudah punya Akun',
// Login & Logout
'login' => 'Login',
'welcome' => 'Selamat datang kembali :name.',
'failed' => 'Identitas tersebut tidak cocok dengan data kami.',
'throttle' => 'Terlalu banyak usaha masuk. Silahkan coba lagi dalam :seconds detik.',
'logout' => 'Keluar',
'logged_out' => 'Anda telah logout.',
'remember_me' => 'Ingat saya',
// Login & Logout
'login' => 'Login',
'welcome' => 'Selamat datang kembali :name.',
'failed' => 'Identitas tersebut tidak cocok dengan data kami.',
'throttle' => 'Terlalu banyak usaha masuk. Silahkan coba lagi dalam :seconds detik.',
'logout' => 'Keluar',
'logged_out' => 'Anda telah logout.',
'remember_me' => 'Ingat saya',
// Password
'change_password' => 'Ganti Password',
'password_changed' => 'Password berhasil diubah.',
'forgot_password' => 'Lupa Password?',
'reset_password' => 'Reset Password',
'send_reset_password_link' => 'Kirim Link Reset Password',
'old_password_failed' => 'Password lama tidak cocok!',
'reset_password_hint' => 'Silakan melakukan reset password dengan mengisi form berikut',
// Password
'change_password' => 'Ganti Password',
'password_changed' => 'Password berhasil diubah.',
'forgot_password' => 'Lupa Password?',
'reset_password' => 'Reset Password',
'send_reset_password_link' => 'Kirim Link Reset Password',
'old_password_failed' => 'Password lama tidak cocok!',
'reset_password_hint' => 'Silakan melakukan reset password dengan mengisi form berikut',
// Attributes
'email' => 'Email',
'password' => 'Password',
'password_confirmation' => 'Ulangi Password',
'old_password' => 'Password Lama',
'new_password' => 'Password Baru',
'new_password_confirmation' => 'Ulangi Password Baru',
// Attributes
'email' => 'Email',
'password' => 'Password',
'password_confirmation' => 'Ulangi Password',
'old_password' => 'Password Lama',
'new_password' => 'Password Baru',
'new_password_confirmation' => 'Ulangi Password Baru',
// Authorization
'unauthorized_access' => 'Anda tidak dapat mengakses halaman :url.',
// Authorization
'unauthorized_access' => 'Anda tidak dapat mengakses halaman :url.',
];

96
resources/lang/id/job.php

@ -1,56 +1,56 @@
<?php
return [
// Labels
'job' => 'Job',
'list' => 'Daftar Job',
'on_progress' => 'Job on Progress',
'detail' => 'Detail Job',
'search' => 'Cari Job',
'found' => 'Job ditemukan',
'not_found' => 'Job tidak ditemukan',
'tasks' => 'Daftar Task',
'price_total' => 'Nilai Job Total',
'tasks_count' => 'Jumlah Task',
'empty' => 'Belum ada Job',
'back_to_index' => 'Kembali ke daftar Job',
'starts' => 'Mulai',
'ends' => 'Selesai',
'target' => 'Target',
'actual' => 'Aktual',
'duration' => 'Durasi',
// Labels
'job' => 'Job',
'list' => 'Daftar Job',
'on_progress' => 'Job on Progress',
'detail' => 'Detail Job',
'search' => 'Cari Job',
'found' => 'Job ditemukan',
'not_found' => 'Job tidak ditemukan',
'tasks' => 'Daftar Task',
'price_total' => 'Nilai Job Total',
'tasks_count' => 'Jumlah Task',
'empty' => 'Belum ada Job',
'back_to_index' => 'Kembali ke daftar Job',
'starts' => 'Mulai',
'ends' => 'Selesai',
'target' => 'Target',
'actual' => 'Aktual',
'duration' => 'Durasi',
// Actions
'create' => 'Input Job Baru',
'add' => 'Tambahkan Job',
'created' => 'Input Job baru telah berhasil.',
'show' => 'Detail Job',
'edit' => 'Edit Job',
'update' => 'Update Job',
'updated' => 'Update data Job telah berhasil.',
'delete' => 'Hapus Job',
'deleted' => 'Hapus data Job telah berhasil.',
'undeleted' => 'Data Job gagal dihapus.',
'add_from_other_project' => 'Tambah Job dari Project Lain',
'select_project' => 'Pilih salah satu project.',
'sort_tasks' => 'Urutkan Prioritas Task',
// Actions
'create' => 'Input Job Baru',
'add' => 'Tambahkan Job',
'created' => 'Input Job baru telah berhasil.',
'show' => 'Detail Job',
'edit' => 'Edit Job',
'update' => 'Update Job',
'updated' => 'Update data Job telah berhasil.',
'delete' => 'Hapus Job',
'deleted' => 'Hapus data Job telah berhasil.',
'undeleted' => 'Data Job gagal dihapus.',
'add_from_other_project' => 'Tambah Job dari Project Lain',
'select_project' => 'Pilih salah satu project.',
'sort_tasks' => 'Urutkan Prioritas Task',
'created_from_other_project' => 'Berhasil tambah job dari Project lain.',
'created_from_other_project' => 'Berhasil tambah job dari Project lain.',
// Attributes
'name' => 'Nama Job',
'description' => 'Deskripsi',
'progress' => 'Progress',
'worker' => 'Pekerja',
'price' => 'Biaya Pengerjaan',
'type' => 'Jenis Job',
'target_start_date' => 'Target Tgl Mulai',
'target_end_date' => 'Target Tgl Selesai',
'actual_start_date' => 'Tgl Mulai Aktual',
'actual_end_date' => 'Tgl Selesai Aktual',
'files' => 'File terlampir pada pekerjaan ini',
// Attributes
'name' => 'Nama Job',
'description' => 'Deskripsi',
'progress' => 'Progress',
'worker' => 'Pekerja',
'price' => 'Biaya Pengerjaan',
'type' => 'Jenis Job',
'target_start_date' => 'Target Tgl Mulai',
'target_end_date' => 'Target Tgl Selesai',
'actual_start_date' => 'Tgl Mulai Aktual',
'actual_end_date' => 'Tgl Selesai Aktual',
'files' => 'File terlampir pada pekerjaan ini',
// Types
'main' => 'Utama',
'additional' => 'Tambahan',
// Types
'main' => 'Utama',
'additional' => 'Tambahan',
];

14
resources/views/layouts/app.blade.php

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="x-csrf-token" content="{{ csrf_token() }}">
@ -15,12 +16,12 @@
{!! Html::style('assets/css/sb-admin-2.min.css') !!}
<style>
.sidebar {
margin-top: 0px;
}
.sidebar {
margin-top: 0px;
}
</style>
</head>
<body>
<div id="wrapper">
@ -46,7 +47,7 @@
{!! Html::script(url('assets/js/sb-admin-2.js')) !!}
<script type="text/javascript">
(function() {
(function() {
$("div.alert.notifier, div.alert.add-cart-notifier").delay(5000).slideUp('slow');
$.ajaxSetup({
headers: {
@ -69,4 +70,5 @@
@yield('script')
</body>
</html>
</html>

2
resources/views/layouts/partials/lang-switcher.blade.php

@ -1,5 +1,5 @@
<div class="text-center" style="border-bottom: 1px solid #e7e7e7; padding: 90px 10px 0px 0px">
{{-- {{ trans('lang.lang') }} : --}}
{{ trans('lang.lang') }} :
@foreach (['en', 'id', 'de'] as $langKey)
{{-- @break --}}

2
routes/web.php

@ -1,7 +1,5 @@
<?php
//upload table issues
require __DIR__.'/web/pages.php';
require __DIR__.'/web/users.php';
require __DIR__.'/web/references.php';

198
routes/web/projects.php

@ -1,109 +1,109 @@
<?php
Route::group(['middleware' => ['auth'], 'namespace' => 'Projects'], function () {
/*
* Projects Routes
*/
Route::get('projects/{project}/delete', ['as' => 'projects.delete', 'uses' => 'ProjectsController@delete']);
Route::get('projects/{project}/subscriptions', ['as' => 'projects.subscriptions', 'uses' => 'ProjectsController@subscriptions']);
Route::patch('projects/{project}/status-update', ['as' => 'projects.status-update', 'uses' => 'ProjectsController@statusUpdate']);
Route::resource('projects', 'ProjectsController');
/*
* Project Payments Routes
*/
Route::get('projects/{project}/payments', ['as' => 'projects.payments', 'uses' => 'ProjectsController@payments']);
/*
* Project Fees Routes
*/
Route::get('projects/{project}/fees/create', ['as' => 'projects.fees.create', 'uses' => 'FeesController@create']);
Route::post('projects/{project}/fees/store', ['as' => 'projects.fees.store', 'uses' => 'FeesController@store']);
/*
* Project Invoices Routes
*/
Route::get('projects/{project}/invoices', ['as' => 'projects.invoices', 'uses' => 'InvoicesController@index']);
/*
* Project Jobs Routes
*/
Route::get('projects/{project}/jobs-export/{type?}', ['as' => 'projects.jobs-export', 'uses' => 'JobsController@jobsExport']);
Route::get('projects/{project}/job-progress-export/{type?}', ['as' => 'projects.job-progress-export', 'uses' => 'JobsController@jobProgressExport']);
Route::get('projects/{project}/jobs/create', ['as' => 'projects.jobs.create', 'uses' => 'JobsController@create']);
Route::post('projects/{project}/jobs', ['as' => 'projects.jobs.store', 'uses' => 'JobsController@store']);
Route::get('projects/{project}/jobs/add-from-other-project', ['as' => 'projects.jobs.add-from-other-project', 'uses' => 'JobsController@addFromOtherProject']);
Route::post('projects/{project}/jobs/store-from-other-project', ['as' => 'projects.jobs.store-from-other-project', 'uses' => 'JobsController@storeFromOtherProject']);
Route::get('projects/{project}/jobs', ['as' => 'projects.jobs.index', 'uses' => 'JobsController@index']);
Route::post('projects/{project}/jobs-reorder', ['as' => 'projects.jobs-reorder', 'uses' => 'ProjectsController@jobsReorder']);
/*
* Project Comments Routes
*/
Route::get('projects/{project}/comments', 'CommentsController@index')->name('projects.comments.index');
Route::post('projects/{project}/comments', 'CommentsController@store')->name('projects.comments.store');
Route::patch('projects/{project}/comments/{comment}', 'CommentsController@update')->name('projects.comments.update');
Route::delete('projects/{project}/comments/{comment}', 'CommentsController@destroy')->name('projects.comments.destroy');
/*
* Project Issues Routes
*/
Route::get('projects/{project}/issues', 'IssueController@index')->name('projects.issues.index');
Route::get('projects/{project}/issues/create', 'IssueController@create')->name('projects.issues.create');
Route::post('projects/{project}/issues', 'IssueController@store')->name('projects.issues.store');
Route::get('projects/{project}/issues/{issue}', 'IssueController@show')->name('projects.issues.show');
Route::get('projects/{project}/issues/{issue}/edit', 'IssueController@edit')->name('projects.issues.edit');
Route::patch('projects/{project}/issues/{issue}', 'IssueController@update')->name('projects.issues.update');
Route::delete('projects/{project}/issues/{issue}', 'IssueController@destroy')->name('projects.issues.destroy');
/*
* Tasks Routes
*/
Route::get('jobs/{job}/tasks/create', ['as' => 'tasks.create', 'uses' => 'TasksController@create']);
Route::post('jobs/{job}/tasks', ['as' => 'tasks.store', 'uses' => 'TasksController@store']);
Route::patch('tasks/{task}', ['as' => 'tasks.update', 'uses' => 'TasksController@update']);
Route::delete('tasks/{task}', ['as' => 'tasks.destroy', 'uses' => 'TasksController@destroy']);
Route::post('tasks/{task}/set-as-job', ['as' => 'tasks.set-as-job', 'uses' => 'TasksController@setAsJob']);
/*
* Files Routes
*/
Route::get('projects/{project}/files', ['as' => 'projects.files', 'uses' => 'FilesController@index']);
Route::post('files/{fileable}', ['as' => 'files.upload', 'uses' => 'FilesController@create']);
Route::get('files/{file}', ['as' => 'files.download', 'uses' => 'FilesController@show']);
Route::patch('files/{file}', ['as' => 'files.update', 'uses' => 'FilesController@update']);
Route::delete('files/{file}', ['as' => 'files.destroy', 'uses' => 'FilesController@destroy']);
/**
* Job file attachments
*/
Route::get('files/show/{job}/{media_id}', 'FilesController@showAttachment')->name('show-job-file');
/*
* Projects Routes
*/
Route::get('projects/{project}/delete', ['as' => 'projects.delete', 'uses' => 'ProjectsController@delete']);
Route::get('projects/{project}/subscriptions', ['as' => 'projects.subscriptions', 'uses' => 'ProjectsController@subscriptions']);
Route::patch('projects/{project}/status-update', ['as' => 'projects.status-update', 'uses' => 'ProjectsController@statusUpdate']);
Route::resource('projects', 'ProjectsController');
/*
* Project Payments Routes
*/
Route::get('projects/{project}/payments', ['as' => 'projects.payments', 'uses' => 'ProjectsController@payments']);
/*
* Project Fees Routes
*/
Route::get('projects/{project}/fees/create', ['as' => 'projects.fees.create', 'uses' => 'FeesController@create']);
Route::post('projects/{project}/fees/store', ['as' => 'projects.fees.store', 'uses' => 'FeesController@store']);
/*
* Project Invoices Routes
*/
Route::get('projects/{project}/invoices', ['as' => 'projects.invoices', 'uses' => 'InvoicesController@index']);
/*
* Project Jobs Routes
*/
Route::get('projects/{project}/jobs-export/{type?}', ['as' => 'projects.jobs-export', 'uses' => 'JobsController@jobsExport']);
Route::get('projects/{project}/job-progress-export/{type?}', ['as' => 'projects.job-progress-export', 'uses' => 'JobsController@jobProgressExport']);
Route::get('projects/{project}/jobs/create', ['as' => 'projects.jobs.create', 'uses' => 'JobsController@create']);
Route::post('projects/{project}/jobs', ['as' => 'projects.jobs.store', 'uses' => 'JobsController@store']);
Route::get('projects/{project}/jobs/add-from-other-project', ['as' => 'projects.jobs.add-from-other-project', 'uses' => 'JobsController@addFromOtherProject']);
Route::post('projects/{project}/jobs/store-from-other-project', ['as' => 'projects.jobs.store-from-other-project', 'uses' => 'JobsController@storeFromOtherProject']);
Route::get('projects/{project}/jobs', ['as' => 'projects.jobs.index', 'uses' => 'JobsController@index']);
Route::post('projects/{project}/jobs-reorder', ['as' => 'projects.jobs-reorder', 'uses' => 'ProjectsController@jobsReorder']);
/*
* Project Comments Routes
*/
Route::get('projects/{project}/comments', 'CommentsController@index')->name('projects.comments.index');
Route::post('projects/{project}/comments', 'CommentsController@store')->name('projects.comments.store');
Route::patch('projects/{project}/comments/{comment}', 'CommentsController@update')->name('projects.comments.update');
Route::delete('projects/{project}/comments/{comment}', 'CommentsController@destroy')->name('projects.comments.destroy');
/*
* Project Issues Routes
*/
Route::get('projects/{project}/issues', 'IssueController@index')->name('projects.issues.index');
Route::get('projects/{project}/issues/create', 'IssueController@create')->name('projects.issues.create');
Route::post('projects/{project}/issues', 'IssueController@store')->name('projects.issues.store');
Route::get('projects/{project}/issues/{issue}', 'IssueController@show')->name('projects.issues.show');
Route::get('projects/{project}/issues/{issue}/edit', 'IssueController@edit')->name('projects.issues.edit');
Route::patch('projects/{project}/issues/{issue}', 'IssueController@update')->name('projects.issues.update');
Route::delete('projects/{project}/issues/{issue}', 'IssueController@destroy')->name('projects.issues.destroy');
/*
* Tasks Routes
*/
Route::get('jobs/{job}/tasks/create', ['as' => 'tasks.create', 'uses' => 'TasksController@create']);
Route::post('jobs/{job}/tasks', ['as' => 'tasks.store', 'uses' => 'TasksController@store']);
Route::patch('tasks/{task}', ['as' => 'tasks.update', 'uses' => 'TasksController@update']);
Route::delete('tasks/{task}', ['as' => 'tasks.destroy', 'uses' => 'TasksController@destroy']);
Route::post('tasks/{task}/set-as-job', ['as' => 'tasks.set-as-job', 'uses' => 'TasksController@setAsJob']);
/*
* Files Routes
*/
Route::get('projects/{project}/files', ['as' => 'projects.files', 'uses' => 'FilesController@index']);
Route::post('files/{fileable}', ['as' => 'files.upload', 'uses' => 'FilesController@create']);
Route::get('files/{file}', ['as' => 'files.download', 'uses' => 'FilesController@show']);
Route::patch('files/{file}', ['as' => 'files.update', 'uses' => 'FilesController@update']);
Route::delete('files/{file}', ['as' => 'files.destroy', 'uses' => 'FilesController@destroy']);
/*
* Job file attachments
*/
Route::get('files/show/{job}/{media_id}', 'FilesController@showAttachment')->name('show-job-file');
});
Route::group(['middleware' => ['auth']], function () {
/*
* Jobs Routes
*/
Route::get('jobs', ['as' => 'jobs.index', 'uses' => 'JobsController@index']);
Route::get('jobs/{job}', ['as' => 'jobs.show', 'uses' => 'JobsController@show']);
/*
* Job Actions Routes
*/
Route::get('jobs/{job}/edit', ['as' => 'jobs.edit', 'uses' => 'JobsController@edit']);
Route::patch('jobs/{job}', ['as' => 'jobs.update', 'uses' => 'JobsController@update']);
Route::get('jobs/{job}/delete', ['as' => 'jobs.delete', 'uses' => 'JobsController@delete']);
Route::delete('jobs/{job}', ['as' => 'jobs.destroy', 'uses' => 'JobsController@destroy']);
Route::post('jobs/{id}/tasks-reorder', ['as' => 'jobs.tasks-reorder', 'uses' => 'JobsController@tasksReorder']);
/*
* Project Comments Routes
*/
Route::get('jobs/{job}/comments', 'Jobs\CommentsController@index')->name('jobs.comments.index');
Route::post('jobs/{job}/comments', 'Jobs\CommentsController@store')->name('jobs.comments.store');
Route::patch('jobs/{job}/comments/{comment}', 'Jobs\CommentsController@update')->name('jobs.comments.update');
Route::delete('jobs/{job}/comments/{comment}', 'Jobs\CommentsController@destroy')->name('jobs.comments.destroy');
/*
* Jobs Routes
*/
Route::get('jobs', ['as' => 'jobs.index', 'uses' => 'JobsController@index']);
Route::get('jobs/{job}', ['as' => 'jobs.show', 'uses' => 'JobsController@show']);
/*
* Job Actions Routes
*/
Route::get('jobs/{job}/edit', ['as' => 'jobs.edit', 'uses' => 'JobsController@edit']);
Route::patch('jobs/{job}', ['as' => 'jobs.update', 'uses' => 'JobsController@update']);
Route::get('jobs/{job}/delete', ['as' => 'jobs.delete', 'uses' => 'JobsController@delete']);
Route::delete('jobs/{job}', ['as' => 'jobs.destroy', 'uses' => 'JobsController@destroy']);
Route::post('jobs/{id}/tasks-reorder', ['as' => 'jobs.tasks-reorder', 'uses' => 'JobsController@tasksReorder']);
/*
* Project Comments Routes
*/
Route::get('jobs/{job}/comments', 'Jobs\CommentsController@index')->name('jobs.comments.index');
Route::post('jobs/{job}/comments', 'Jobs\CommentsController@store')->name('jobs.comments.store');
Route::patch('jobs/{job}/comments/{comment}', 'Jobs\CommentsController@update')->name('jobs.comments.update');
Route::delete('jobs/{job}/comments/{comment}', 'Jobs\CommentsController@destroy')->name('jobs.comments.destroy');
});
/*

11
tests/Unit/Services/SiteOptionTest.php

@ -22,6 +22,17 @@ class SiteOptionTest extends TestCase
}
/** @test */
public function option_value_null_must_be_converted_to_empty_string()
{
Option::set('testing_key', null);
$this->seeInDatabase('site_options', [
'key' => 'testing_key',
'value' => '',
]);
}
/** @test */
public function option_can_be_get()
{
\DB::table('site_options')->insert([

Loading…
Cancel
Save