refactor: replace custom CRM with Monica fork
Some checks failed
Build & Push Monica Image to Gitea Registry / build-and-push (push) Failing after 9s
Some checks failed
Build & Push Monica Image to Gitea Registry / build-and-push (push) Failing after 9s
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Account\Activity;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Account\Activity\ActivityTypeCategory\CreateActivityTypeCategory;
|
||||
use App\Services\Account\Activity\ActivityTypeCategory\UpdateActivityTypeCategory;
|
||||
use App\Services\Account\Activity\ActivityTypeCategory\DestroyActivityTypeCategory;
|
||||
use App\Http\Resources\Activity\ActivityTypeCategory as ActivityTypeCategoryResource;
|
||||
|
||||
class ActivityTypeCategoriesController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get all the activity type categories.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$activityTypeCategoriesData = collect([]);
|
||||
$activityTypeCategories = auth()->user()->account->activityTypeCategories;
|
||||
|
||||
foreach ($activityTypeCategories as $activityTypeCategory) {
|
||||
$activityTypesData = collect([]);
|
||||
$activityTypes = $activityTypeCategory->activityTypes;
|
||||
|
||||
foreach ($activityTypes as $activityType) {
|
||||
$dataActivityType = [
|
||||
'id' => $activityType->id,
|
||||
'name' => $activityType->name,
|
||||
];
|
||||
$activityTypesData->push($dataActivityType);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $activityTypeCategory->id,
|
||||
'name' => $activityTypeCategory->name,
|
||||
'activityTypes' => $activityTypesData,
|
||||
];
|
||||
$activityTypeCategoriesData->push($data);
|
||||
}
|
||||
|
||||
return $activityTypeCategoriesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ActivityTypeCategoryResource
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$type = app(CreateActivityTypeCategory::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'name' => $request->input('name'),
|
||||
'translation_key' => $request->input('translation_key'),
|
||||
]);
|
||||
|
||||
return new ActivityTypeCategoryResource($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeCategoryId
|
||||
* @return ActivityTypeCategoryResource
|
||||
*/
|
||||
public function update(Request $request, $activityTypeCategoryId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_category_id' => $activityTypeCategoryId,
|
||||
'name' => $request->input('name'),
|
||||
'translation_key' => $request->input('translation_key'),
|
||||
];
|
||||
|
||||
$type = app(UpdateActivityTypeCategory::class)->execute($data);
|
||||
|
||||
return new ActivityTypeCategoryResource($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeCategoryId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $activityTypeCategoryId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_category_id' => $activityTypeCategoryId,
|
||||
];
|
||||
|
||||
try {
|
||||
app(DestroyActivityTypeCategory::class)->execute($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($activityTypeCategoryId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Account\Activity;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Account\Activity\ActivityType\CreateActivityType;
|
||||
use App\Services\Account\Activity\ActivityType\UpdateActivityType;
|
||||
use App\Services\Account\Activity\ActivityType\DestroyActivityType;
|
||||
use App\Http\Resources\Activity\ActivityType as ActivityTypeResource;
|
||||
|
||||
class ActivityTypesController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Store an activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ActivityTypeResource
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$type = app(CreateActivityType::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_category_id' => $request->input('activity_type_category_id'),
|
||||
'name' => $request->input('name'),
|
||||
'translation_key' => $request->input('translation_key'),
|
||||
]);
|
||||
|
||||
return new ActivityTypeResource($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an activity type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeId
|
||||
* @return ActivityTypeResource
|
||||
*/
|
||||
public function update(Request $request, $activityTypeId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_id' => $activityTypeId,
|
||||
'activity_type_category_id' => $request->input('activity_type_category_id'),
|
||||
'name' => $request->input('name'),
|
||||
'translation_key' => $request->input('translation_key'),
|
||||
];
|
||||
|
||||
$type = app(UpdateActivityType::class)->execute($data);
|
||||
|
||||
return new ActivityTypeResource($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the activity type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $activityTypeId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_id' => $activityTypeId,
|
||||
];
|
||||
|
||||
try {
|
||||
app(DestroyActivityType::class)->execute($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($activityTypeId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Account\LifeEvent;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
|
||||
class LifeEventCategoriesController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get all the life event categories.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$lifeEventCategoriesData = collect([]);
|
||||
$lifeEventCategories = auth()->user()->account->lifeEventCategories;
|
||||
|
||||
foreach ($lifeEventCategories as $lifeEventCategory) {
|
||||
$lifeEventTypesData = collect([]);
|
||||
$lifeEventTypes = $lifeEventCategory->lifeEventTypes;
|
||||
|
||||
foreach ($lifeEventTypes as $lifeEventType) {
|
||||
$dataLifeEventType = [
|
||||
'id' => $lifeEventType->id,
|
||||
'name' => $lifeEventType->name,
|
||||
'default_life_event_type_key' => $lifeEventType->default_life_event_type_key,
|
||||
];
|
||||
$lifeEventTypesData->push($dataLifeEventType);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $lifeEventCategory->id,
|
||||
'name' => $lifeEventCategory->name,
|
||||
'default_life_event_category_key' => $lifeEventCategory->default_life_event_category_key,
|
||||
'lifeEventTypes' => $lifeEventTypesData,
|
||||
];
|
||||
$lifeEventCategoriesData->push($data);
|
||||
}
|
||||
|
||||
return $lifeEventCategoriesData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Account\LifeEvent;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Account\LifeEvent\LifeEventType\CreateLifeEventType;
|
||||
use App\Services\Account\LifeEvent\LifeEventType\UpdateLifeEventType;
|
||||
use App\Services\Account\LifeEvent\LifeEventType\DestroyLifeEventType;
|
||||
use App\Http\Resources\LifeEvent\LifeEventType as LifeEventTypeResource;
|
||||
|
||||
class LifeEventTypesController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Store a life event type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return LifeEventTypeResource
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$type = app(CreateLifeEventType::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'life_event_category_id' => $request->input('life_event_category_id'),
|
||||
'name' => $request->input('name'),
|
||||
]);
|
||||
|
||||
return new LifeEventTypeResource($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a life event type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $liveEventTypeId
|
||||
* @return LifeEventTypeResource
|
||||
*/
|
||||
public function update(Request $request, $liveEventTypeId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'life_event_type_id' => $liveEventTypeId,
|
||||
'life_event_category_id' => $request->input('life_event_category_id'),
|
||||
'name' => $request->input('name'),
|
||||
];
|
||||
|
||||
$type = app(UpdateLifeEventType::class)->execute($data);
|
||||
|
||||
return new LifeEventTypeResource($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the life event type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $lifeEventTypeId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $lifeEventTypeId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'life_event_type_id' => $lifeEventTypeId,
|
||||
];
|
||||
|
||||
try {
|
||||
app(DestroyLifeEventType::class)->execute($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($lifeEventTypeId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account\Activity;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Models\Account\ActivityTypeCategory;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Services\Account\Activity\ActivityTypeCategory\CreateActivityTypeCategory;
|
||||
use App\Services\Account\Activity\ActivityTypeCategory\UpdateActivityTypeCategory;
|
||||
use App\Services\Account\Activity\ActivityTypeCategory\DestroyActivityTypeCategory;
|
||||
use App\Http\Resources\Activity\ActivityTypeCategory as ActivityTypeCategoryResource;
|
||||
|
||||
class ApiActivityTypeCategoryController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of activity type categories.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$activityTypeCategories = auth()->user()->account->activityTypeCategories()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ActivityTypeCategoryResource::collection($activityTypeCategories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeCategoryId
|
||||
* @return ActivityTypeCategoryResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $activityTypeCategoryId)
|
||||
{
|
||||
try {
|
||||
$activityTypeCategory = ActivityTypeCategory::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $activityTypeCategoryId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ActivityTypeCategoryResource($activityTypeCategory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ActivityTypeCategoryResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$activityTypeCategory = app(CreateActivityTypeCategory::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ActivityTypeCategoryResource($activityTypeCategory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeCategoryId
|
||||
* @return ActivityTypeCategoryResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $activityTypeCategoryId)
|
||||
{
|
||||
try {
|
||||
$activityTypeCategory = app(UpdateActivityTypeCategory::class)->execute(
|
||||
$request->except(['account_id', 'activity_type_category_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_category_id' => $activityTypeCategoryId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ActivityTypeCategoryResource($activityTypeCategory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an activity type category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $activityTypeCategoryId)
|
||||
{
|
||||
try {
|
||||
app(DestroyActivityTypeCategory::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_category_id' => $activityTypeCategoryId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($activityTypeCategoryId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account\Activity;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Account\ActivityType;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Services\Account\Activity\ActivityType\CreateActivityType;
|
||||
use App\Services\Account\Activity\ActivityType\UpdateActivityType;
|
||||
use App\Services\Account\Activity\ActivityType\DestroyActivityType;
|
||||
use App\Http\Resources\Activity\ActivityType as ActivityTypeResource;
|
||||
|
||||
class ApiActivityTypeController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of activity types.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$activityTypes = auth()->user()->account->activityTypes()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ActivityTypeResource::collection($activityTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given activity type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ActivityTypeResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $activityTypeId)
|
||||
{
|
||||
try {
|
||||
$activityType = ActivityType::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $activityTypeId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ActivityTypeResource($activityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the activity type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ActivityTypeResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$activityType = app(CreateActivityType::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ActivityTypeResource($activityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the activity type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeId
|
||||
* @return ActivityTypeResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $activityTypeId)
|
||||
{
|
||||
try {
|
||||
$activityType = app(UpdateActivityType::class)->execute(
|
||||
$request->except(['account_id', 'activity_type_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_id' => $activityTypeId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ActivityTypeResource($activityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an activity type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityTypeId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $activityTypeId)
|
||||
{
|
||||
try {
|
||||
app(DestroyActivityType::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_type_id' => $activityTypeId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($activityTypeId);
|
||||
}
|
||||
}
|
||||
135
app/Http/Controllers/Api/Account/ApiCompanyController.php
Normal file
135
app/Http/Controllers/Api/Account/ApiCompanyController.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Account\Company;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Account\Company\CreateCompany;
|
||||
use App\Services\Account\Company\UpdateCompany;
|
||||
use App\Services\Account\Company\DestroyCompany;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Company\Company as CompanyResource;
|
||||
|
||||
class ApiCompanyController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of companies.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$companies = auth()->user()->account->companies()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return CompanyResource::collection($companies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given company.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return CompanyResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $companyId)
|
||||
{
|
||||
try {
|
||||
$company = Company::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $companyId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new CompanyResource($company);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the company.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return CompanyResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$company = app(CreateCompany::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new CompanyResource($company);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a company.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $companyId
|
||||
* @return CompanyResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $companyId)
|
||||
{
|
||||
try {
|
||||
$company = app(UpdateCompany::class)->execute(
|
||||
$request->except(['account_id', 'company_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'company_id' => $companyId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new CompanyResource($company);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a company.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $companyId)
|
||||
{
|
||||
try {
|
||||
app(DestroyCompany::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'company_id' => $companyId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($companyId);
|
||||
}
|
||||
}
|
||||
134
app/Http/Controllers/Api/Account/ApiGenderController.php
Normal file
134
app/Http/Controllers/Api/Account/ApiGenderController.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Gender;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Services\Account\Gender\CreateGender;
|
||||
use App\Services\Account\Gender\UpdateGender;
|
||||
use App\Services\Account\Gender\DestroyGender;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Http\Resources\Gender\Gender as GenderResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiGenderController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of genders.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$genders = auth()->user()->account->genders()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return GenderResource::collection($genders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given gender.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return GenderResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $genderId)
|
||||
{
|
||||
try {
|
||||
$gender = Gender::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $genderId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new GenderResource($gender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the gender.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return GenderResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$gender = app(CreateGender::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new GenderResource($gender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a gender.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $genderId
|
||||
* @return GenderResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $genderId)
|
||||
{
|
||||
try {
|
||||
$gender = app(UpdateGender::class)->execute(
|
||||
$request->except(['account_id', 'gender_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'gender_id' => $genderId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new GenderResource($gender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gender.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $genderId)
|
||||
{
|
||||
try {
|
||||
app(DestroyGender::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'gender_id' => $genderId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($genderId);
|
||||
}
|
||||
}
|
||||
134
app/Http/Controllers/Api/Account/ApiPlaceController.php
Normal file
134
app/Http/Controllers/Api/Account/ApiPlaceController.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Account\Place;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Services\Account\Place\CreatePlace;
|
||||
use App\Services\Account\Place\UpdatePlace;
|
||||
use App\Services\Account\Place\DestroyPlace;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Http\Resources\Place\Place as PlaceResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiPlaceController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of places.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$places = auth()->user()->account->places()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return PlaceResource::collection($places);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given place.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return PlaceResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $placeId)
|
||||
{
|
||||
try {
|
||||
$place = Place::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $placeId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new PlaceResource($place);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the place.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return PlaceResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$place = app(CreatePlace::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new PlaceResource($place);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a place.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $placeId
|
||||
* @return PlaceResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $placeId)
|
||||
{
|
||||
try {
|
||||
$place = app(UpdatePlace::class)->execute(
|
||||
$request->except(['account_id', 'place_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'place_id' => $placeId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new PlaceResource($place);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a place.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $placeId)
|
||||
{
|
||||
try {
|
||||
app(DestroyPlace::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'place_id' => $placeId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($placeId);
|
||||
}
|
||||
}
|
||||
148
app/Http/Controllers/Api/Account/ApiUserController.php
Normal file
148
app/Http/Controllers/Api/Account/ApiUserController.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use App\Models\User\User;
|
||||
use App\Helpers\DateHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Settings\Term;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Services\User\AcceptPolicy;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Account\User\User as UserResource;
|
||||
use App\Http\Resources\Settings\Compliance\Compliance as ComplianceResource;
|
||||
|
||||
class ApiUserController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the detail of the authenticated user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return UserResource
|
||||
*/
|
||||
public function show(Request $request): UserResource
|
||||
{
|
||||
return new UserResource(auth()->user());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of a specific term for the user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $termId
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function get(Request $request, $termId)
|
||||
{
|
||||
try {
|
||||
$term = Term::findOrFail($termId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$termUser = DB::table('term_user')->where('user_id', auth()->user()->id)
|
||||
->where('account_id', auth()->user()->account_id)
|
||||
->where('term_id', $term->id)
|
||||
->first();
|
||||
|
||||
if ($termUser) {
|
||||
$data = [
|
||||
'signed' => true,
|
||||
'signed_date' => DateHelper::getTimestamp($termUser->created_at),
|
||||
'ip_address' => $termUser->ip_address,
|
||||
'user' => new UserResource(auth()->user()),
|
||||
'term' => new ComplianceResource($term),
|
||||
];
|
||||
} else {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return $this->respond([
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the policies ever signed by the authenticated user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getSignedPolicies(Request $request)
|
||||
{
|
||||
$terms = collect();
|
||||
$termsForUser = DB::table('term_user')
|
||||
->where('user_id', auth()->user()->id)
|
||||
->get();
|
||||
|
||||
if ($termsForUser->count() == 0) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
foreach ($termsForUser as $termUser) {
|
||||
$term = Term::findOrFail($termUser->term_id);
|
||||
|
||||
$terms->push([
|
||||
'signed' => true,
|
||||
'signed_date' => DateHelper::getTimestamp($termUser->created_at),
|
||||
'ip_address' => $termUser->ip_address,
|
||||
'user' => new UserResource(auth()->user()),
|
||||
'term' => new ComplianceResource($term),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->respond([
|
||||
'data' => $terms,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the latest policy for the authenticated user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function set(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'ip_address' => 'required',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
try {
|
||||
$term = app(AcceptPolicy::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
'ip_address' => $request->input('ip_address'),
|
||||
]);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
try {
|
||||
$termUser = DB::table('term_user')->where('user_id', auth()->user()->id)
|
||||
->where('account_id', auth()->user()->account_id)
|
||||
->where('term_id', $term->id)
|
||||
->first();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respond([
|
||||
'data' => [
|
||||
'signed' => true,
|
||||
'signed_date' => DateHelper::getTimestamp($termUser->created_at),
|
||||
'ip_address' => $termUser->ip_address,
|
||||
'user' => new UserResource(auth()->user()),
|
||||
'term' => new ComplianceResource($term),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
161
app/Http/Controllers/Api/ApiActivitiesController.php
Normal file
161
app/Http/Controllers/Api/ApiActivitiesController.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Account\Activity;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Services\Account\Activity\Activity\CreateActivity;
|
||||
use App\Services\Account\Activity\Activity\UpdateActivity;
|
||||
use App\Services\Account\Activity\Activity\DestroyActivity;
|
||||
use App\Http\Resources\Activity\Activity as ActivityResource;
|
||||
|
||||
class ApiActivitiesController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of activities.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$activities = auth()->user()->account->activities()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ActivityResource::collection($activities)->additional(['meta' => [
|
||||
'statistics' => AccountHelper::getYearlyActivitiesStatistics(auth()->user()->account),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given activity.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ActivityResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $activityId)
|
||||
{
|
||||
try {
|
||||
$activity = Activity::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($activityId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ActivityResource($activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the activity.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ActivityResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$activity = app(CreateActivity::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ActivityResource($activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the activity.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $activityId
|
||||
* @return ActivityResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $activityId)
|
||||
{
|
||||
try {
|
||||
$activity = app(UpdateActivity::class)->execute(
|
||||
$request->except(['account_id', 'activity_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_id' => $activityId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ActivityResource($activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an activity.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $activityId)
|
||||
{
|
||||
try {
|
||||
app(DestroyActivity::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_id' => $activityId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($activityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of activities for the given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function activities(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($contactId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
$activities = $contact->activities()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ActivityResource::collection($activities)->additional(['meta' => [
|
||||
'statistics' => AccountHelper::getYearlyActivitiesStatistics(auth()->user()->account),
|
||||
]]);
|
||||
}
|
||||
}
|
||||
260
app/Http/Controllers/Api/ApiContactController.php
Normal file
260
app/Http/Controllers/Api/ApiContactController.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\SearchHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Jobs\UpdateLastConsultedDate;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Contact\CreateContact;
|
||||
use App\Services\Contact\Contact\UpdateContact;
|
||||
use App\Services\Contact\Contact\DestroyContact;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use App\Services\Contact\Contact\UpdateWorkInformation;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Contact\Contact as ContactResource;
|
||||
use App\Services\Contact\Contact\UpdateContactIntroduction;
|
||||
use App\Services\Contact\Contact\UpdateContactFoodPreferences;
|
||||
|
||||
class ApiContactController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Instantiate a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('limitations')->only('setMe');
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of the contacts.
|
||||
* We will only retrieve the contacts that are "real", not the partials
|
||||
* ones.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResource|JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($request->input('query')) {
|
||||
$needle = rawurldecode($request->input('query'));
|
||||
|
||||
try {
|
||||
$contacts = SearchHelper::searchContacts(
|
||||
$needle,
|
||||
$this->sort,
|
||||
$this->sortDirection
|
||||
)
|
||||
->real()
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ContactResource::collection($contacts)->additional([
|
||||
'meta' => [
|
||||
'query' => $needle,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
$contacts = auth()->user()->account->contacts()
|
||||
->real()
|
||||
->active()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ContactResource::collection($contacts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return ContactResource|JsonResponse
|
||||
*/
|
||||
public function show(Request $request, int $id)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $id)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
UpdateLastConsultedDate::dispatch($contact);
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ContactResource|JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$contact = app(CreateContact::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ContactResource|JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = app(UpdateContact::class)->execute(
|
||||
$request->except(['account_id', 'contact_id'])
|
||||
+
|
||||
[
|
||||
'contact_id' => $contactId,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $contactId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contactId,
|
||||
];
|
||||
DestroyContact::dispatch($data);
|
||||
|
||||
return $this->respondObjectDeleted($contactId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the contact career.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return ContactResource|JsonResponse
|
||||
*/
|
||||
public function updateWork(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = app(UpdateWorkInformation::class)->execute(
|
||||
$request->except(['account_id', 'contact_id'])
|
||||
+ [
|
||||
'contact_id' => $contactId,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the contact food preferences.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return ContactResource|JsonResponse
|
||||
*/
|
||||
public function updateFoodPreferences(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = app(UpdateContactFoodPreferences::class)->execute(
|
||||
$request->except(['account_id', 'contact_id'])
|
||||
+ [
|
||||
'contact_id' => $contactId,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set how you met the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return ContactResource|JsonResponse
|
||||
*/
|
||||
public function updateIntroduction(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = app(UpdateContactIntroduction::class)->execute(
|
||||
$request->except(['account_id', 'contact_id'])
|
||||
+ [
|
||||
'contact_id' => $contactId,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
}
|
||||
140
app/Http/Controllers/Api/ApiContactFieldController.php
Normal file
140
app/Http/Controllers/Api/ApiContactFieldController.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\ContactField;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Services\Contact\ContactField\CreateContactField;
|
||||
use App\Services\Contact\ContactField\UpdateContactField;
|
||||
use App\Services\Contact\ContactField\DestroyContactField;
|
||||
use App\Http\Resources\ContactField\ContactField as ContactFieldResource;
|
||||
|
||||
class ApiContactFieldController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the detail of a given contactField.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactFieldId
|
||||
* @return ContactFieldResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $contactFieldId)
|
||||
{
|
||||
try {
|
||||
$contactField = ContactField::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($contactFieldId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ContactFieldResource($contactField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the contactField.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ContactFieldResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$contactField = app(CreateContactField::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactFieldResource($contactField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the contactField.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactFieldId
|
||||
* @return ContactFieldResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $contactFieldId)
|
||||
{
|
||||
try {
|
||||
$contactField = app(UpdateContactField::class)->execute(
|
||||
$request->except(['account_id', 'address_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_field_id' => $contactFieldId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactFieldResource($contactField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a contactField.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactFieldId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $contactFieldId)
|
||||
{
|
||||
try {
|
||||
app(DestroyContactField::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_field_id' => $contactFieldId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($contactFieldId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of contact fields for the given contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function contactFields(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$contactFields = $contact->contactFields()
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return ContactFieldResource::collection($contactFields);
|
||||
}
|
||||
}
|
||||
129
app/Http/Controllers/Api/ApiContactTagController.php
Normal file
129
app/Http/Controllers/Api/ApiContactTagController.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Contact\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Services\Contact\Tag\DetachTag;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Services\Contact\Tag\AssociateTag;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Contact\Contact as ContactResource;
|
||||
|
||||
class ApiContactTagController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Associate one or more tags to the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
*/
|
||||
public function setTags(Request $request, $contactId)
|
||||
{
|
||||
$contact = $this->validateTag($request, $contactId);
|
||||
if (! $contact instanceof Contact) {
|
||||
return $contact;
|
||||
}
|
||||
|
||||
$tags = collect($request->input('tags'))
|
||||
->filter(function ($tag) {
|
||||
return ! empty($tag);
|
||||
});
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
app(AssociateTag::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'name' => $tag,
|
||||
]);
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all the tags associated with the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
*/
|
||||
public function unsetTags(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$contactTags = $contact->tags()->get();
|
||||
|
||||
foreach ($contactTags as $tag) {
|
||||
app(DetachTag::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'tag_id' => $tag->id,
|
||||
]);
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove one or more specific tags associated with the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
*/
|
||||
public function unsetTag(Request $request, $contactId)
|
||||
{
|
||||
$contact = $this->validateTag($request, $contactId);
|
||||
if (! $contact instanceof Contact) {
|
||||
return $contact;
|
||||
}
|
||||
|
||||
$tags = collect($request->input('tags'))
|
||||
->filter(function ($tag) {
|
||||
return ! empty($tag);
|
||||
});
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
app(DetachTag::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'tag_id' => $tag,
|
||||
]);
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request for update tag.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return mixed
|
||||
*/
|
||||
private function validateTag(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($contactId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'tags' => 'required|array',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
return $contact;
|
||||
}
|
||||
}
|
||||
207
app/Http/Controllers/Api/ApiController.php
Normal file
207
app/Http/Controllers/Api/ApiController.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use function Safe\json_decode;
|
||||
use App\Models\Account\ApiUsage;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
|
||||
class ApiController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $limitPerPage = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sort = 'created_at';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $withParameter = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sortDirection = 'asc';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(function ($request, $next) {
|
||||
(new ApiUsage)->log($request);
|
||||
|
||||
if ($request->has('sort')) {
|
||||
$this->setSortCriteria($request->input('sort'));
|
||||
|
||||
// It has a sort criteria, but is it a valid one?
|
||||
if (empty($this->getSortCriteria())) {
|
||||
return $this->setHTTPStatusCode(400)
|
||||
->setErrorCode(39)
|
||||
->respondWithError();
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->has('limit')) {
|
||||
if ($request->input('limit') > config('api.max_limit_per_page')) {
|
||||
return $this->setHTTPStatusCode(400)
|
||||
->setErrorCode(30)
|
||||
->respondWithError();
|
||||
}
|
||||
|
||||
$this->setLimitPerPage($request->input('limit'));
|
||||
}
|
||||
|
||||
if ($request->has('with')) {
|
||||
$this->setWithParameter($request->input('with'));
|
||||
}
|
||||
|
||||
// make sure the JSON is well formatted if the call sends a JSON
|
||||
// if the call contains a JSON, the call must not be a GET or
|
||||
// a DELETE
|
||||
// TODO: there is probably a much better way to do that
|
||||
try {
|
||||
if ($request->method() != 'GET' && $request->method() != 'DELETE'
|
||||
&& is_null(json_decode($request->getContent()))) {
|
||||
return $this->setHTTPStatusCode(400)
|
||||
->setErrorCode(37)
|
||||
->respondWithError();
|
||||
}
|
||||
} catch (\Safe\Exceptions\JsonException $e) {
|
||||
// no error
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Default request to the API.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function success()
|
||||
{
|
||||
return $this->respond([
|
||||
'success' => [
|
||||
'message' => 'Welcome to Monica',
|
||||
],
|
||||
'links' => [
|
||||
'activities_url' => route('api.activities'),
|
||||
'addresses_url' => route('api.addresses'),
|
||||
'calls_url' => route('api.calls'),
|
||||
'contacts_url' => route('api.contacts'),
|
||||
'conversations_url' => route('api.conversations'),
|
||||
'countries_url' => route('api.countries'),
|
||||
'currencies_url' => route('api.currencies'),
|
||||
'documents_url' => route('api.documents'),
|
||||
'journal_url' => route('api.journal'),
|
||||
'notes_url' => route('api.notes'),
|
||||
'relationships_url' => route('api.relationships', ['contact' => ':contactId']),
|
||||
'reminders_url' => route('api.reminders'),
|
||||
'statistics_url' => route('api.statistics'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getWithParameter()
|
||||
{
|
||||
return $this->withParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $with
|
||||
* @return self
|
||||
*/
|
||||
public function setWithParameter($with)
|
||||
{
|
||||
$this->withParameter = $with;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLimitPerPage()
|
||||
{
|
||||
return $this->limitPerPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @return self
|
||||
*/
|
||||
public function setLimitPerPage($limit)
|
||||
{
|
||||
$this->limitPerPage = $limit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sort direction parameter.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSortDirection()
|
||||
{
|
||||
return $this->sortDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSortCriteria()
|
||||
{
|
||||
return $this->sort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $criteria
|
||||
* @return self
|
||||
*/
|
||||
public function setSortCriteria($criteria)
|
||||
{
|
||||
$acceptedCriteria = [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'-created_at',
|
||||
'-updated_at',
|
||||
'completed_at',
|
||||
'-completed_at',
|
||||
'called_at',
|
||||
'-called_at',
|
||||
'favorited_at',
|
||||
'-favorited_at',
|
||||
];
|
||||
|
||||
if (in_array($criteria, $acceptedCriteria)) {
|
||||
$this->setSQLOrderByQuery($criteria);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->sort = '';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set both the column and order necessary to perform an orderBy.
|
||||
*/
|
||||
public function setSQLOrderByQuery($criteria)
|
||||
{
|
||||
$this->sortDirection = $criteria[0] == '-' ? 'desc' : 'asc';
|
||||
$this->sort = ltrim($criteria, '-');
|
||||
}
|
||||
}
|
||||
191
app/Http/Controllers/Api/ApiDebtController.php
Normal file
191
app/Http/Controllers/Api/ApiDebtController.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Contact\Debt;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Resources\Debt\Debt as DebtResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiDebtController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of debts.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$debts = auth()->user()->account->debts()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return DebtResource::collection($debts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given debt.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return DebtResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $debtId)
|
||||
{
|
||||
try {
|
||||
$debt = Debt::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $debtId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new DebtResource($debt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the debt.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return DebtResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$debt = Debt::create(
|
||||
$request->except(['account_id'])
|
||||
+ ['account_id' => auth()->user()->account_id]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new DebtResource($debt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the debt.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $debtId
|
||||
* @return DebtResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $debtId)
|
||||
{
|
||||
try {
|
||||
$debt = Debt::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $debtId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$debt->update($request->only(['in_debt', 'status', 'amount', 'reason', 'contact_id']));
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new DebtResource($debt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request for update.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|true
|
||||
*/
|
||||
private function validateUpdate(Request $request)
|
||||
{
|
||||
// Validates basic fields to create the entry
|
||||
$validator = Validator::make($request->all(), [
|
||||
'in_debt' => [
|
||||
'required',
|
||||
'string',
|
||||
Rule::in(['yes', 'no']),
|
||||
],
|
||||
'status' => [
|
||||
'required',
|
||||
'string',
|
||||
Rule::in(['inprogress', 'completed']),
|
||||
],
|
||||
'amount' => 'required|numeric',
|
||||
'reason' => 'string|max:1000000|nullable',
|
||||
'contact_id' => 'required|integer',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
try {
|
||||
Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $request->input('contact_id'))
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a debt.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $debtId)
|
||||
{
|
||||
try {
|
||||
$debt = Debt::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $debtId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$debt->delete();
|
||||
|
||||
return $this->respondObjectDeleted($debt->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of debts for the given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function debts(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$debts = $contact->debts()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return DebtResource::collection($debts);
|
||||
}
|
||||
}
|
||||
174
app/Http/Controllers/Api/ApiGiftController.php
Normal file
174
app/Http/Controllers/Api/ApiGiftController.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Contact\Gift;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Services\Contact\Gift\CreateGift;
|
||||
use App\Services\Contact\Gift\UpdateGift;
|
||||
use App\Services\Contact\Gift\DestroyGift;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Http\Resources\Gift\Gift as GiftResource;
|
||||
use App\Services\Contact\Gift\AssociatePhotoToGift;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiGiftController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of gifts.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$gifts = auth()->user()->account->gifts()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return GiftResource::collection($gifts);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$gift = Gift::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($id);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new GiftResource($gift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$gift = app(CreateGift::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+ ['account_id' => auth()->user()->account_id]
|
||||
);
|
||||
|
||||
return new GiftResource($gift);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $giftId
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $giftId)
|
||||
{
|
||||
try {
|
||||
$gift = app(UpdateGift::class)->execute(
|
||||
$request->except(['account_id', 'gift_id'])
|
||||
+ [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'gift_id' => $giftId,
|
||||
]
|
||||
);
|
||||
|
||||
return new GiftResource($gift);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a photo to the gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $giftId
|
||||
* @param int $photoId
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function associate(Request $request, $giftId, $photoId)
|
||||
{
|
||||
try {
|
||||
$gift = app(AssociatePhotoToGift::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'gift_id' => $giftId,
|
||||
'photo_id' => $photoId,
|
||||
]);
|
||||
|
||||
return new GiftResource($gift);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $giftId)
|
||||
{
|
||||
try {
|
||||
app(DestroyGift::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'gift_id' => $giftId,
|
||||
]);
|
||||
|
||||
return $this->respondObjectDeleted($giftId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of gifts for the given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function gifts(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($contactId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
$gifts = $contact->gifts()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return GiftResource::collection($gifts);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
148
app/Http/Controllers/Api/ApiJournalController.php
Normal file
148
app/Http/Controllers/Api/ApiJournalController.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Journal\Entry;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Resources\Journal\Entry as JournalResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiJournalController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of journal entries.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$entries = auth()->user()->account->entries()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return JournalResource::collection($entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given journal entry.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JournalResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $entryId)
|
||||
{
|
||||
try {
|
||||
$entry = Entry::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $entryId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new JournalResource($entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the call.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JournalResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$entry = Entry::create(
|
||||
$request->except(['account_id'])
|
||||
+ ['account_id' => auth()->user()->account_id]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new JournalResource($entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the note.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $entryId
|
||||
* @return JournalResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $entryId)
|
||||
{
|
||||
try {
|
||||
$entry = Entry::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $entryId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$entry->update($request->only(['title', 'post']));
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new JournalResource($entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request for update.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|true
|
||||
*/
|
||||
private function validateUpdate(Request $request)
|
||||
{
|
||||
// Validates basic fields to create the entry
|
||||
$validator = Validator::make($request->all(), [
|
||||
'title' => 'required|max:255',
|
||||
'post' => 'required|max:1000000',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a journal entry.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $entryId)
|
||||
{
|
||||
try {
|
||||
$entry = Entry::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $entryId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$entry->delete();
|
||||
|
||||
return $this->respondObjectDeleted($entry->id);
|
||||
}
|
||||
}
|
||||
66
app/Http/Controllers/Api/ApiMeController.php
Normal file
66
app/Http/Controllers/Api/ApiMeController.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Services\Contact\Contact\SetMeContact;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Contact\DeleteMeContact;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiMeController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Instantiate a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('limitations')->only('store');
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a contact as 'me'.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$data = [
|
||||
'contact_id' => $request->input('contact_id'),
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
];
|
||||
|
||||
try {
|
||||
app(SetMeContact::class)->execute($data);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return $this->respond(['true']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes contact as 'me' association.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
];
|
||||
|
||||
app(DeleteMeContact::class)->execute($data);
|
||||
|
||||
return $this->respond(['true']);
|
||||
}
|
||||
}
|
||||
192
app/Http/Controllers/Api/ApiNoteController.php
Normal file
192
app/Http/Controllers/Api/ApiNoteController.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Contact\Note;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Resources\Note\Note as NoteResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiNoteController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of notes.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$notes = auth()->user()->account->notes()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return NoteResource::collection($notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given note.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return NoteResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$note = Note::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $id)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new NoteResource($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the note.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return NoteResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$note = Note::create(
|
||||
$request->except(['account_id'])
|
||||
+ ['account_id' => auth()->user()->account_id]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
if ($request->input('is_favorited')) {
|
||||
$note->favorited_at = now();
|
||||
$note->save();
|
||||
}
|
||||
|
||||
return new NoteResource($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the note.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $noteId
|
||||
* @return NoteResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $noteId)
|
||||
{
|
||||
try {
|
||||
$note = Note::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $noteId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$note->update($request->only(['body', 'contact_id', 'is_favorited']));
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
if ($request->input('is_favorited')) {
|
||||
$note->favorited_at = now();
|
||||
} else {
|
||||
$note->favorited_at = null;
|
||||
}
|
||||
$note->save();
|
||||
|
||||
return new NoteResource($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request for update.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|true
|
||||
*/
|
||||
private function validateUpdate(Request $request)
|
||||
{
|
||||
// Validates basic fields to create the entry
|
||||
$validator = Validator::make($request->all(), [
|
||||
'body' => 'required|max:100000',
|
||||
'contact_id' => 'required|integer',
|
||||
'is_favorited' => 'boolean',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
try {
|
||||
Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $request->input('contact_id'))
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a note.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $noteId)
|
||||
{
|
||||
try {
|
||||
$note = Note::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $noteId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$note->delete();
|
||||
|
||||
return $this->respondObjectDeleted($note->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of notes for the given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function notes(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$notes = $contact->notes()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return NoteResource::collection($notes);
|
||||
}
|
||||
}
|
||||
182
app/Http/Controllers/Api/ApiPetController.php
Normal file
182
app/Http/Controllers/Api/ApiPetController.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Contact\Pet;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Resources\Pet\Pet as PetResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiPetController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of pet.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$pets = Pet::where('account_id', auth()->user()->account_id)
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return PetResource::collection($pets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given pet.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return PetResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$pet = Pet::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $id)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new PetResource($pet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the pet.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return PetResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$pet = Pet::create(
|
||||
$request->except(['account_id'])
|
||||
+ ['account_id' => auth()->user()->account_id]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new PetResource($pet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the pet.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $petId
|
||||
* @return PetResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $petId)
|
||||
{
|
||||
try {
|
||||
$pet = Pet::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $petId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$pet->update($request->only(['pet_category_id', 'contact_id', 'name']));
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new PetResource($pet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request for update.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|true
|
||||
*/
|
||||
private function validateUpdate(Request $request)
|
||||
{
|
||||
// Validates basic fields to create the entry
|
||||
$validator = Validator::make($request->all(), [
|
||||
'pet_category_id' => 'integer|required|exists:pet_categories,id',
|
||||
'contact_id' => 'required|integer',
|
||||
'name' => 'max:255',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
try {
|
||||
Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $request->input('contact_id'))
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a pet.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $petId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $petId)
|
||||
{
|
||||
try {
|
||||
$pet = Pet::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $petId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$pet->delete();
|
||||
|
||||
return $this->respondObjectDeleted($pet->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of pets for the given contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function pets(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$pets = $contact->pets()
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return PetResource::collection($pets);
|
||||
}
|
||||
}
|
||||
124
app/Http/Controllers/Api/ApiRelationshipController.php
Normal file
124
app/Http/Controllers/Api/ApiRelationshipController.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Relationship\Relationship;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Services\Contact\Relationship\CreateRelationship;
|
||||
use App\Services\Contact\Relationship\UpdateRelationship;
|
||||
use App\Services\Contact\Relationship\DestroyRelationship;
|
||||
use App\Http\Resources\Relationship\Relationship as RelationshipResource;
|
||||
|
||||
class ApiRelationshipController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get all of relationships of a contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$relationships = Relationship::where('account_id', auth()->user()->account_id)
|
||||
->where('contact_is', $contactId)
|
||||
->get();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return RelationshipResource::collection($relationships);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given relationship.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return RelationshipResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$relationship = Relationship::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($id);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new RelationshipResource($relationship);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new relationship.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return RelationshipResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$relationship = app(CreateRelationship::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_is' => $request->input('contact_is'),
|
||||
'of_contact' => $request->input('of_contact'),
|
||||
'relationship_type_id' => $request->input('relationship_type_id'),
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return new RelationshipResource($relationship);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing relationship.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|RelationshipResource
|
||||
*/
|
||||
public function update(Request $request, $relationshipId)
|
||||
{
|
||||
try {
|
||||
$relationship = app(UpdateRelationship::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'relationship_id' => $relationshipId,
|
||||
'relationship_type_id' => $request->input('relationship_type_id'),
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
$relationship->refresh();
|
||||
|
||||
return new RelationshipResource($relationship);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a relationship.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $relationshipId)
|
||||
{
|
||||
try {
|
||||
app(DestroyRelationship::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'relationship_id' => $relationshipId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($relationshipId);
|
||||
}
|
||||
}
|
||||
47
app/Http/Controllers/Api/ApiRelationshipTypeController.php
Normal file
47
app/Http/Controllers/Api/ApiRelationshipTypeController.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Relationship\RelationshipType;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\RelationshipType\RelationshipType as RelationshipTypeResource;
|
||||
|
||||
class ApiRelationshipTypeController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get all relationship types in an instance.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$relationshipTypes = auth()->user()->account->relationshipTypes()
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return RelationshipTypeResource::collection($relationshipTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given relationship type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return RelationshipTypeResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$relationshipType = RelationshipType::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($id);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new RelationshipTypeResource($relationshipType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Relationship\RelationshipTypeGroup;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\RelationshipTypeGroup\RelationshipTypeGroup as RelationshipTypeGroupResource;
|
||||
|
||||
class ApiRelationshipTypeGroupController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Account ID column name.
|
||||
*/
|
||||
const ACCOUNT_ID = 'account_id';
|
||||
|
||||
/**
|
||||
* Get all relationship type groups in an instance.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$relationshipTypeGroups = auth()->user()->account->relationshipTypeGroups()
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return RelationshipTypeGroupResource::collection($relationshipTypeGroups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given relationship type group.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return RelationshipTypeGroupResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$relationshipTypeGroup = RelationshipTypeGroup::where(static::ACCOUNT_ID, auth()->user()->account_id)
|
||||
->where('id', $id)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new RelationshipTypeGroupResource($relationshipTypeGroup);
|
||||
}
|
||||
}
|
||||
182
app/Http/Controllers/Api/ApiReminderController.php
Normal file
182
app/Http/Controllers/Api/ApiReminderController.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\Reminder;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Reminder\CreateReminder;
|
||||
use App\Services\Contact\Reminder\UpdateReminder;
|
||||
use App\Services\Contact\Reminder\DestroyReminder;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Reminder\Reminder as ReminderResource;
|
||||
use App\Http\Resources\Reminder\ReminderOutbox as ReminderOutboxResource;
|
||||
|
||||
class ApiReminderController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of reminders.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$reminders = auth()->user()->account->reminders()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ReminderResource::collection($reminders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given reminder.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ReminderResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $reminderId)
|
||||
{
|
||||
try {
|
||||
$reminder = Reminder::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $reminderId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ReminderResource($reminder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the reminder.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ReminderResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$reminder = app(CreateReminder::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ReminderResource($reminder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the reminder.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $reminderId
|
||||
* @return ReminderResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $reminderId)
|
||||
{
|
||||
try {
|
||||
$reminder = app(UpdateReminder::class)->execute(
|
||||
$request->except(['account_id', 'reminder_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'reminder_id' => $reminderId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ReminderResource($reminder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a reminder.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $reminderId)
|
||||
{
|
||||
try {
|
||||
app(DestroyReminder::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'reminder_id' => $reminderId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($reminderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of reminders for the given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function reminders(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$reminders = $contact->reminders()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return ReminderResource::collection($reminders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reminders for the month given in parameter.
|
||||
* - 0 means current month
|
||||
* - 1 means month+1
|
||||
* - 2 means month+2...
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $month
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function upcoming(Request $request, int $month = 0)
|
||||
{
|
||||
try {
|
||||
$reminders = AccountHelper::getUpcomingRemindersForMonth(
|
||||
auth()->user()->account,
|
||||
$month
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ReminderOutboxResource::collection($reminders);
|
||||
}
|
||||
}
|
||||
157
app/Http/Controllers/Api/ApiTagController.php
Normal file
157
app/Http/Controllers/Api/ApiTagController.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Contact\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Services\Contact\Tag\CreateTag;
|
||||
use App\Services\Contact\Tag\UpdateTag;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Services\Contact\Tag\DestroyTag;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\Http\Resources\Tag\Tag as TagResource;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use App\Http\Resources\Contact\ContactWithContactFields as ContactWithContactFieldsResource;
|
||||
|
||||
class ApiTagController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of the contacts.
|
||||
* We will only retrieve the contacts that are "real", not the partials
|
||||
* ones.
|
||||
*
|
||||
* @return AnonymousResourceCollection|JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$tags = auth()->user()->account->tags()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return TagResource::collection($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given tag.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return TagResource|JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$tag = Tag::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $id)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new TagResource($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the tag.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return TagResource|JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$tag = app(CreateTag::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return new TagResource($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tag.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return TagResource|JsonResponse
|
||||
*/
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
try {
|
||||
$tag = app(UpdateTag::class)->execute(
|
||||
$request->except(['account_id', 'tag_id'])
|
||||
+
|
||||
[
|
||||
'tag_id' => $id,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return new TagResource($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a tag.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
app(DestroyTag::class)->execute([
|
||||
'tag_id' => $id,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all the contacts for a given tag.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $tagId
|
||||
* @return JsonResponse|AnonymousResourceCollection
|
||||
*/
|
||||
public function contacts(Request $request, int $tagId)
|
||||
{
|
||||
try {
|
||||
$contacts = auth()->user()->account->contacts()
|
||||
->real()
|
||||
->active()
|
||||
->whereHas('tags', function (Builder $query) use ($tagId) {
|
||||
$query->where('id', $tagId);
|
||||
})
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ContactWithContactFieldsResource::collection($contacts);
|
||||
}
|
||||
}
|
||||
149
app/Http/Controllers/Api/ApiTaskController.php
Normal file
149
app/Http/Controllers/Api/ApiTaskController.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Contact\Task;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Services\Task\CreateTask;
|
||||
use App\Services\Task\UpdateTask;
|
||||
use App\Services\Task\DestroyTask;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Http\Resources\Task\Task as TaskResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiTaskController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of task.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$tasks = auth()->user()->account->tasks()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return TaskResource::collection($tasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given task.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return TaskResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $taskId)
|
||||
{
|
||||
try {
|
||||
$task = Task::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $taskId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new TaskResource($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the task.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return TaskResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$task = app(CreateTask::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => ($request->input('contact_id') == '' ? null : $request->input('contact_id')),
|
||||
'title' => $request->input('title'),
|
||||
'description' => ($request->input('description') == '' ? null : $request->input('description')),
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return new TaskResource($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the task.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $taskId
|
||||
* @return TaskResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $taskId)
|
||||
{
|
||||
try {
|
||||
$task = app(UpdateTask::class)->execute(
|
||||
$request->except(['account_id', 'task_id'])
|
||||
+
|
||||
[
|
||||
'task_id' => $taskId,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return new TaskResource($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a task.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $taskId)
|
||||
{
|
||||
try {
|
||||
app(DestroyTask::class)->execute([
|
||||
'task_id' => $taskId,
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of tasks for the given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function tasks(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$tasks = $contact->tasks()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return TaskResource::collection($tasks);
|
||||
}
|
||||
}
|
||||
212
app/Http/Controllers/Api/Auth/OAuthController.php
Normal file
212
app/Http/Controllers/Api/Auth/OAuthController.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Models\User\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use function Safe\json_decode;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Traits\JsonRespondController;
|
||||
use Illuminate\Contracts\Http\Kernel;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Barryvdh\Debugbar\Facades\Debugbar;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Contracts\Encryption\Encrypter;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OAuthController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* The encrypter implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Encryption\Encrypter
|
||||
*/
|
||||
protected $encrypter;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Encrypter $encrypter)
|
||||
{
|
||||
$this->encrypter = $encrypter;
|
||||
|
||||
if (config('app.debug')) {
|
||||
Debugbar::disable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a log in form for oauth accessToken.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$request->session()->flush();
|
||||
|
||||
return view('auth.oauthlogin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in a user and returns an accessToken.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response|null
|
||||
*/
|
||||
public function login(Request $request): ?Response
|
||||
{
|
||||
$isvalid = $this->validateRequest($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
$email = $request->input('email');
|
||||
$password = $request->input('password');
|
||||
|
||||
if (Auth::attempt(['email' => $email, 'password' => $password])) {
|
||||
// The user is active, not suspended, and exists.
|
||||
|
||||
$request->session()->put('oauth', true);
|
||||
$request->session()->put('email', $email);
|
||||
$request->session()->put('password', $this->encrypter->encrypt($password));
|
||||
|
||||
$this->fixRequest($request);
|
||||
|
||||
// add intendedUrl for WebAuthn
|
||||
Redirect::setIntendedUrl(route('oauth.verify'));
|
||||
|
||||
return Route::respondWithRoute('oauth.verify');
|
||||
}
|
||||
|
||||
return $this->respondUnauthorized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix request parameters.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
private function fixRequest(Request $request)
|
||||
{
|
||||
$request->setMethod('GET');
|
||||
$cookie = $request->cookies->get(config('session.cookie'));
|
||||
$request->cookies->set(config('session.cookie'), $this->encrypter->encrypt($cookie));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|true
|
||||
*/
|
||||
private function validateRequest(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'email' => 'email|required',
|
||||
'password' => 'required',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
// Check if email exists. If not respond with an Unauthorized, this way a hacker
|
||||
// doesn't know if the login email exist or not, or if the password is wrong
|
||||
$count = User::where('email', $request->input('email'))->count();
|
||||
if ($count === 0) {
|
||||
return $this->respondUnauthorized();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in a user and returns an accessToken.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function verify(Request $request): JsonResponse
|
||||
{
|
||||
$response = $this->handleVerify($request);
|
||||
|
||||
Auth::logout();
|
||||
$request->session()->flush();
|
||||
|
||||
return $response ?: $this->respondUnauthorized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the verify request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|null
|
||||
*/
|
||||
private function handleVerify(Request $request): ?JsonResponse
|
||||
{
|
||||
if (! $request->session()->has('email') || ! $request->session()->has('password')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$request->query->set('email', $request->session()->pull('email'));
|
||||
$request->query->set('password', $this->encrypter->decrypt($request->session()->pull('password')));
|
||||
|
||||
$isvalid = $this->validateRequest($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$token = $this->proxy([
|
||||
'username' => $request->input('email'),
|
||||
'password' => $request->input('password'),
|
||||
'grantType' => 'password',
|
||||
]);
|
||||
|
||||
return $this->respond($token);
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy a request to the OAuth server.
|
||||
*
|
||||
* @param array $data the data to send to the server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Safe\Exceptions\JsonException
|
||||
*/
|
||||
private function proxy(array $data = []): array
|
||||
{
|
||||
$url = App::runningUnitTests() ? Str::of(config('app.url'))->ltrim('/').'/oauth/token' : route('passport.token');
|
||||
/** @var \Illuminate\Http\Response */
|
||||
$response = app(Kernel::class)->handle(Request::create($url, 'POST', [
|
||||
'grant_type' => $data['grantType'],
|
||||
'client_id' => config('passport.password_grant_client.id'),
|
||||
'client_secret' => config('passport.password_grant_client.secret'),
|
||||
'username' => $data['username'],
|
||||
'password' => $data['password'],
|
||||
'scope' => '',
|
||||
]));
|
||||
|
||||
$data = json_decode($response->content());
|
||||
|
||||
return [
|
||||
'access_token' => $data->access_token,
|
||||
'expires_in' => $data->expires_in,
|
||||
];
|
||||
}
|
||||
}
|
||||
156
app/Http/Controllers/Api/Contact/ApiAddressController.php
Normal file
156
app/Http/Controllers/Api/Contact/ApiAddressController.php
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Address;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Address\CreateAddress;
|
||||
use App\Services\Contact\Address\UpdateAddress;
|
||||
use App\Services\Contact\Address\DestroyAddress;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Address\Address as AddressResource;
|
||||
|
||||
class ApiAddressController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of addresses.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$addresses = auth()->user()->account->addresses()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return AddressResource::collection($addresses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given address.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return AddressResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$address = Address::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $id)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new AddressResource($address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the address.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return AddressResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$address = app(CreateAddress::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new AddressResource($address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the address.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $addressId
|
||||
* @return AddressResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $addressId)
|
||||
{
|
||||
try {
|
||||
$address = app(UpdateAddress::class)->execute(
|
||||
$request->except(['account_id', 'address_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'address_id' => $addressId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new AddressResource($address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an address.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $addressId)
|
||||
{
|
||||
try {
|
||||
app(DestroyAddress::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'address_id' => $addressId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($addressId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of addresses for the given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function addresses(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$addresses = $contact->addresses()
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return AddressResource::collection($addresses);
|
||||
}
|
||||
}
|
||||
42
app/Http/Controllers/Api/Contact/ApiAuditLogController.php
Normal file
42
app/Http/Controllers/Api/Contact/ApiAuditLogController.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\AuditLog\AuditLog as AuditLogResource;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
|
||||
class ApiAuditLogController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of the audit logs for the given contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return JsonResponse|AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request, int $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
$logs = $contact->logs()
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return AuditLogResource::collection($logs);
|
||||
}
|
||||
}
|
||||
43
app/Http/Controllers/Api/Contact/ApiAvatarController.php
Normal file
43
app/Http/Controllers/Api/Contact/ApiAvatarController.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Services\Contact\Avatar\UpdateAvatar;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Contact\Contact as ContactResource;
|
||||
|
||||
class ApiAvatarController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Update a contact's avatar.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return ContactResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = app(UpdateAvatar::class)->execute(
|
||||
$request->except(['account_id', 'contact_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contactId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ContactResource($contact);
|
||||
}
|
||||
}
|
||||
162
app/Http/Controllers/Api/Contact/ApiCallController.php
Normal file
162
app/Http/Controllers/Api/Contact/ApiCallController.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use App\Models\Contact\Call;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Services\Contact\Call\CreateCall;
|
||||
use App\Services\Contact\Call\UpdateCall;
|
||||
use App\Services\Contact\Call\DestroyCall;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Http\Resources\Call\Call as CallResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiCallController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of calls.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$calls = auth()->user()->account->calls()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return CallResource::collection($calls)->additional(['meta' => [
|
||||
'statistics' => AccountHelper::getYearlyCallStatistics(auth()->user()->account),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given call.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return CallResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $callId)
|
||||
{
|
||||
try {
|
||||
$call = Call::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $callId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new CallResource($call);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the call.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return CallResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$call = app(CreateCall::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new CallResource($call);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a call.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $callId
|
||||
* @return CallResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $callId)
|
||||
{
|
||||
try {
|
||||
$call = app(UpdateCall::class)->execute(
|
||||
$request->except(['account_id', 'call_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'call_id' => $callId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new CallResource($call);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a call.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $callId)
|
||||
{
|
||||
try {
|
||||
app(DestroyCall::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'call_id' => $callId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($callId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of calls for a given contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function calls(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$calls = $contact->calls()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return CallResource::collection($calls)->additional(['meta' => [
|
||||
'statistics' => AccountHelper::getYearlyCallStatistics(auth()->user()->account),
|
||||
]]);
|
||||
}
|
||||
}
|
||||
162
app/Http/Controllers/Api/Contact/ApiConversationController.php
Normal file
162
app/Http/Controllers/Api/Contact/ApiConversationController.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\Conversation;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Services\Contact\Conversation\CreateConversation;
|
||||
use App\Services\Contact\Conversation\UpdateConversation;
|
||||
use App\Services\Contact\Conversation\DestroyConversation;
|
||||
use App\Http\Resources\Conversation\Conversation as ConversationResource;
|
||||
|
||||
class ApiConversationController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of conversations.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$conversations = auth()->user()->account->conversations()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ConversationResource::collection($conversations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of conversations for a specific contact.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function conversations(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
Contact::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
$conversations = auth()->user()->account->conversations()
|
||||
->where('contact_id', $contactId)
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return ConversationResource::collection($conversations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ConversationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $conversationId)
|
||||
{
|
||||
try {
|
||||
$conversation = Conversation::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($conversationId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ConversationResource($conversation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ConversationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$conversation = app(CreateConversation::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ConversationResource($conversation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $conversationId
|
||||
* @return ConversationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $conversationId)
|
||||
{
|
||||
try {
|
||||
$conversation = app(UpdateConversation::class)->execute(
|
||||
$request->except(['account_id', 'conversation_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversationId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ConversationResource($conversation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $conversationId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $conversationId)
|
||||
{
|
||||
try {
|
||||
app(DestroyConversation::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversationId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($conversationId);
|
||||
}
|
||||
}
|
||||
146
app/Http/Controllers/Api/Contact/ApiDocumentController.php
Normal file
146
app/Http/Controllers/Api/Contact/ApiDocumentController.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\Document;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Document\UploadDocument;
|
||||
use App\Services\Contact\Document\DestroyDocument;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Document\Document as DocumentResource;
|
||||
|
||||
class ApiDocumentController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Instantiate a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('limitations')->only('store');
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of documents.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$documents = auth()->user()->account->documents()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return DocumentResource::collection($documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of documents for a specific contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function contact(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
Contact::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($contactId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
$documents = auth()->user()->account->documents()
|
||||
->where('contact_id', $contactId)
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return DocumentResource::collection($documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given document.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $documentId
|
||||
* @return DocumentResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $documentId)
|
||||
{
|
||||
try {
|
||||
$document = Document::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($documentId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new DocumentResource($document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a document.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return DocumentResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$document = app(UploadDocument::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new DocumentResource($document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a document.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $documentId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $documentId)
|
||||
{
|
||||
try {
|
||||
app(DestroyDocument::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'document_id' => $documentId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($documentId);
|
||||
}
|
||||
}
|
||||
121
app/Http/Controllers/Api/Contact/ApiLifeEventController.php
Normal file
121
app/Http/Controllers/Api/Contact/ApiLifeEventController.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\LifeEvent;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\LifeEvent\CreateLifeEvent;
|
||||
use App\Services\Contact\LifeEvent\UpdateLifeEvent;
|
||||
use App\Services\Contact\LifeEvent\DestroyLifeEvent;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\LifeEvent\LifeEvent as LifeEventResource;
|
||||
|
||||
class ApiLifeEventController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of life events.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$lifeEvents = auth()->user()->account->lifeEvents()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return LifeEventResource::collection($lifeEvents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given life event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return LifeEventResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $lifeEventId)
|
||||
{
|
||||
try {
|
||||
$lifeEvent = LifeEvent::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($lifeEventId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new LifeEventResource($lifeEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the life event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return LifeEventResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$lifeEvent = app(CreateLifeEvent::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return new LifeEventResource($lifeEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the life event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $lifeEventId
|
||||
* @return LifeEventResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $lifeEventId)
|
||||
{
|
||||
try {
|
||||
$lifeEvent = app(UpdateLifeEvent::class)->execute(
|
||||
$request->except(['account_id', 'life_event_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'life_event_id' => $lifeEventId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
}
|
||||
|
||||
return new LifeEventResource($lifeEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the life event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $lifeEventId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $lifeEventId)
|
||||
{
|
||||
try {
|
||||
app(DestroyLifeEvent::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'life_event_id' => $lifeEventId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($lifeEventId);
|
||||
}
|
||||
}
|
||||
126
app/Http/Controllers/Api/Contact/ApiMessageController.php
Normal file
126
app/Http/Controllers/Api/Contact/ApiMessageController.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Message;
|
||||
use App\Models\Contact\Conversation;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Conversation\UpdateMessage;
|
||||
use App\Services\Contact\Conversation\DestroyMessage;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Services\Contact\Conversation\AddMessageToConversation;
|
||||
use App\Http\Resources\Conversation\Conversation as ConversationResource;
|
||||
|
||||
class ApiMessageController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Store the message.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ConversationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request, int $conversationId)
|
||||
{
|
||||
try {
|
||||
$conversation = Conversation::findOrFail($conversationId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
app(AddMessageToConversation::class)->execute(
|
||||
$request->except(['account_id', 'conversation_id', 'contact_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversation->id,
|
||||
'contact_id' => $conversation->contact_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ConversationResource($conversation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the message.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $conversationId
|
||||
* @param int $messageId
|
||||
* @return ConversationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, int $conversationId, int $messageId)
|
||||
{
|
||||
try {
|
||||
$conversation = Conversation::findOrFail($conversationId);
|
||||
$message = Message::findOrFail($messageId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
app(UpdateMessage::class)->execute(
|
||||
$request->except(['account_id', 'conversation_id', 'message_id', 'contact_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversationId,
|
||||
'message_id' => $message->id,
|
||||
'contact_id' => $conversation->contact_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new ConversationResource($conversation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the message.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $conversationId
|
||||
* @param int $messageId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $conversationId, int $messageId)
|
||||
{
|
||||
try {
|
||||
Conversation::findOrFail($conversationId);
|
||||
Message::findOrFail($messageId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
app(DestroyMessage::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversationId,
|
||||
'message_id' => $messageId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($messageId);
|
||||
}
|
||||
}
|
||||
134
app/Http/Controllers/Api/Contact/ApiOccupationController.php
Normal file
134
app/Http/Controllers/Api/Contact/ApiOccupationController.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Occupation;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Occupation\CreateOccupation;
|
||||
use App\Services\Contact\Occupation\UpdateOccupation;
|
||||
use App\Services\Contact\Occupation\DestroyOccupation;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Occupation\Occupation as OccupationResource;
|
||||
|
||||
class ApiOccupationController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of occupations.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$occupations = auth()->user()->account->occupations()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return OccupationResource::collection($occupations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given occupation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return OccupationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $occupationId)
|
||||
{
|
||||
try {
|
||||
$occupation = Occupation::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $occupationId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new OccupationResource($occupation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the occupation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return OccupationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$occupation = app(CreateOccupation::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new OccupationResource($occupation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an occupation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $occupationId
|
||||
* @return OccupationResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $occupationId)
|
||||
{
|
||||
try {
|
||||
$occupation = app(UpdateOccupation::class)->execute(
|
||||
$request->except(['account_id', 'occupation_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'occupation_id' => $occupationId,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new OccupationResource($occupation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an occupation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $occupationId)
|
||||
{
|
||||
try {
|
||||
app(DestroyOccupation::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'occupation_id' => $occupationId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($occupationId);
|
||||
}
|
||||
}
|
||||
134
app/Http/Controllers/Api/Contact/ApiPhotoController.php
Normal file
134
app/Http/Controllers/Api/Contact/ApiPhotoController.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Contact;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Account\Photo;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Services\Account\Photo\UploadPhoto;
|
||||
use App\Services\Account\Photo\DestroyPhoto;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Http\Resources\Photo\Photo as PhotoResource;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class ApiPhotoController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of photos.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$photos = auth()->user()->account->photos()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return PhotoResource::collection($photos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of photos for a specific contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactId
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function contact(Request $request, $contactId)
|
||||
{
|
||||
try {
|
||||
$contact = Contact::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($contactId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
$photos = $contact->photos()
|
||||
->orderBy($this->sort, $this->sortDirection)
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return PhotoResource::collection($photos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given photo.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $photoId
|
||||
* @return PhotoResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $photoId)
|
||||
{
|
||||
try {
|
||||
$photo = Photo::where('account_id', auth()->user()->account_id)
|
||||
->findOrFail($photoId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new PhotoResource($photo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a photo.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return PhotoResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$photo = app(UploadPhoto::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return new PhotoResource($photo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a photo.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $photoId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, int $photoId)
|
||||
{
|
||||
try {
|
||||
app(DestroyPhoto::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'photo_id' => $photoId,
|
||||
]);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
} catch (ValidationException $e) {
|
||||
return $this->respondValidatorFailed($e->validator);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($photoId);
|
||||
}
|
||||
}
|
||||
29
app/Http/Controllers/Api/Misc/ApiCountryController.php
Normal file
29
app/Http/Controllers/Api/Misc/ApiCountryController.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Misc;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\CountriesHelper;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Http\Resources\Country\Country as CountryResource;
|
||||
|
||||
class ApiCountryController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of countries.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$key = 'countries.'.App::getLocale();
|
||||
|
||||
$countries = Cache::rememberForever($key, function () {
|
||||
return CountriesHelper::getAll();
|
||||
});
|
||||
|
||||
return CountryResource::collection($countries);
|
||||
}
|
||||
}
|
||||
31
app/Http/Controllers/Api/Settings/ApiAuditLogController.php
Normal file
31
app/Http/Controllers/Api/Settings/ApiAuditLogController.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Http\Resources\AuditLog\AuditLog as AuditLogResource;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
|
||||
class ApiAuditLogController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of the audit logs.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse|AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$logs = auth()->user()->account->auditLogs()
|
||||
->paginate($this->getLimitPerPage());
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondInvalidQuery();
|
||||
}
|
||||
|
||||
return AuditLogResource::collection($logs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Settings\Term;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Settings\Compliance\Compliance as ComplianceResource;
|
||||
|
||||
class ApiComplianceController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of terms and privacy policies.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$terms = Term::orderBy('term_version', 'desc')->paginate($this->getLimitPerPage());
|
||||
|
||||
return ComplianceResource::collection($terms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given term.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ComplianceResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $termId)
|
||||
{
|
||||
try {
|
||||
$term = Term::where('id', $termId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ComplianceResource($term);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Database\QueryException;
|
||||
use App\Models\Contact\ContactFieldType;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Settings\ContactFieldType\ContactFieldType as ContactFieldTypeResource;
|
||||
|
||||
class ApiContactFieldTypeController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of contact field types.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$contactFieldTypes = auth()->user()->account->contactFieldTypes()
|
||||
->paginate($this->getLimitPerPage());
|
||||
|
||||
return ContactFieldTypeResource::collection($contactFieldTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given contact field type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ContactFieldTypeResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $contactFieldTypeId)
|
||||
{
|
||||
try {
|
||||
$contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactFieldTypeId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new ContactFieldTypeResource($contactFieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the contactfieldtype.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ContactFieldTypeResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
try {
|
||||
$contactFieldType = ContactFieldType::create(
|
||||
$request->except(['account_id'])
|
||||
+ ['account_id' => auth()->user()->account_id]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new ContactFieldTypeResource($contactFieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the contact field type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $contactFieldTypeId
|
||||
* @return ContactFieldTypeResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, $contactFieldTypeId)
|
||||
{
|
||||
try {
|
||||
$contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactFieldTypeId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$isvalid = $this->validateUpdate($request);
|
||||
if ($isvalid !== true) {
|
||||
return $isvalid;
|
||||
}
|
||||
|
||||
// Update the contactfieldtype itself
|
||||
try {
|
||||
$contactFieldType->update(
|
||||
$request->only([
|
||||
'name',
|
||||
'fontawesome_icon',
|
||||
'protocol',
|
||||
'delible',
|
||||
'type',
|
||||
])
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
return $this->respondNotTheRightParameters();
|
||||
}
|
||||
|
||||
return new ContactFieldTypeResource($contactFieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the request for update.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|true
|
||||
*/
|
||||
private function validateUpdate(Request $request)
|
||||
{
|
||||
// Validates basic fields to create the entry
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|max:255',
|
||||
'fontawesome_icon' => 'nullable|max:255',
|
||||
'protocol' => 'nullable|max:255',
|
||||
'delible' => 'integer',
|
||||
'type' => 'nullable|max:255',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $this->respondValidatorFailed($validator);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an contactfieldtype.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, $contactFieldTypeId)
|
||||
{
|
||||
try {
|
||||
$contactFieldType = ContactFieldType::where('account_id', auth()->user()->account_id)
|
||||
->where('id', $contactFieldTypeId)
|
||||
->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$contactFields = auth()->user()->account->contactFields
|
||||
->where('contact_field_type_id', $contactFieldTypeId);
|
||||
|
||||
foreach ($contactFields as $contactField) {
|
||||
$contactField->delete();
|
||||
}
|
||||
|
||||
$contactFieldType->delete();
|
||||
|
||||
return $this->respondObjectDeleted($contactFieldType->id);
|
||||
}
|
||||
}
|
||||
41
app/Http/Controllers/Api/Settings/ApiCurrencyController.php
Normal file
41
app/Http/Controllers/Api/Settings/ApiCurrencyController.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Settings;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Settings\Currency;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use App\Http\Resources\Settings\Currency\Currency as CurrencyResource;
|
||||
|
||||
class ApiCurrencyController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of currencies.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$currencies = Currency::paginate($this->getLimitPerPage());
|
||||
|
||||
return CurrencyResource::collection($currencies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given currency.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return CurrencyResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $currencyId)
|
||||
{
|
||||
try {
|
||||
$currency = Currency::findOrFail($currencyId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return new CurrencyResource($currency);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Statistics;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Instance\Instance;
|
||||
use App\Models\Instance\Statistic;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
|
||||
class ApiStatisticsController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Get the list of general, public statistics.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if (config('monica.allow_statistics_through_public_api_access') == false) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
// Collecting statistics
|
||||
$statistic = Statistic::orderBy('created_at', 'desc')->first();
|
||||
$instance = Instance::first();
|
||||
|
||||
// Get the date of the monday of last week
|
||||
$dateMondayLastWeek = now()->subDays(7);
|
||||
$dateMondayLastWeek = $dateMondayLastWeek->startOfWeek();
|
||||
|
||||
// Get the date of the sunday of last week
|
||||
$dateSundayLastWeek = now()->subDays(7);
|
||||
$dateSundayLastWeek = $dateSundayLastWeek->endOfWeek();
|
||||
|
||||
// Get the number of users last monday
|
||||
$instanceLastMonday = Statistic::whereDate('created_at', '=', $dateMondayLastWeek->toDateString())->first();
|
||||
$instanceLastSunday = Statistic::whereDate('created_at', '=', $dateSundayLastWeek->toDateString())->first();
|
||||
|
||||
$numberNewUsers = 0;
|
||||
if ($instanceLastMonday && $instanceLastSunday) {
|
||||
$numberNewUsers = $instanceLastSunday->number_of_users - $instanceLastMonday->number_of_users;
|
||||
}
|
||||
|
||||
$statistics = collect();
|
||||
$statistics->push([
|
||||
'instance_creation_date' => DateHelper::getTimestamp($instance->created_at),
|
||||
'number_of_contacts' => ($statistic ? $statistic->number_of_contacts : 0),
|
||||
'number_of_users' => ($statistic ? $statistic->number_of_users : 0),
|
||||
'number_of_activities' => ($statistic ? $statistic->number_of_activities : 0),
|
||||
'number_of_reminders' => ($statistic ? $statistic->number_of_reminders : 0),
|
||||
'number_of_new_users_last_week' => $numberNewUsers,
|
||||
]);
|
||||
|
||||
return $statistics;
|
||||
}
|
||||
}
|
||||
118
app/Http/Controllers/Auth/EmailChangeController.php
Normal file
118
app/Http/Controllers/Auth/EmailChangeController.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Models\User\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Services\User\EmailChange;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Http\Requests\EmailChangeRequest;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
|
||||
class EmailChangeController extends Controller
|
||||
{
|
||||
use AuthenticatesUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after login / registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/settings/emailchange2';
|
||||
|
||||
/**
|
||||
* Show the application's login form.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
public function showLoginFormSpecial(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
if ($user &&
|
||||
$user instanceof User &&
|
||||
! $user->hasVerifiedEmail()) {
|
||||
return view('auth.emailchange1')
|
||||
->with('email', $user->email);
|
||||
}
|
||||
|
||||
return redirect()->route('login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
return view('auth.emailchange2')
|
||||
->with('email', $user->email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change user email.
|
||||
*
|
||||
* @param EmailChangeRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function save(EmailChangeRequest $request)
|
||||
{
|
||||
$response = $this->validateAndEmailChange($request);
|
||||
|
||||
return $response == 'auth.email_changed'
|
||||
? $this->sendChangedResponse($response)
|
||||
: $this->sendChangedFailedResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a password change request and update password of the user.
|
||||
*
|
||||
* @param EmailChangeRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
protected function validateAndEmailChange(EmailChangeRequest $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
app(EmailChange::class)->execute([
|
||||
'account_id' => $user->account_id,
|
||||
'email' => $request->input('newmail'),
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
|
||||
// Logout the user
|
||||
Auth::guard()->logout();
|
||||
$request->session()->invalidate();
|
||||
|
||||
return 'auth.email_changed';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a successful password changed.
|
||||
*
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function sendChangedResponse($response)
|
||||
{
|
||||
return redirect()->route('login')
|
||||
->with('status', trans($response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a failed password.
|
||||
*
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function sendChangedFailedResponse($response)
|
||||
{
|
||||
return redirect()->route('login')
|
||||
->withErrors(trans($response));
|
||||
}
|
||||
}
|
||||
22
app/Http/Controllers/Auth/ForgotPasswordController.php
Normal file
22
app/Http/Controllers/Auth/ForgotPasswordController.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset emails and
|
||||
| includes a trait which assists in sending these notifications from
|
||||
| your application to your users. Feel free to explore this trait.
|
||||
|
|
||||
*/
|
||||
|
||||
use SendsPasswordResetEmails;
|
||||
}
|
||||
150
app/Http/Controllers/Auth/InvitationController.php
Normal file
150
app/Http/Controllers/Auth/InvitationController.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\RequestHelper;
|
||||
use App\Jobs\SendNewUserAlert;
|
||||
use App\Services\User\CreateUser;
|
||||
use App\Models\Account\Invitation;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Foundation\Auth\RedirectsUsers;
|
||||
use Illuminate\Validation\Rules\Password as PasswordRules;
|
||||
|
||||
class InvitationController extends Controller
|
||||
{
|
||||
use RedirectsUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after login / registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/dashboard';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param string $key
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function show($key)
|
||||
{
|
||||
if (Auth::check()) {
|
||||
return redirect()->route('loginRedirect');
|
||||
}
|
||||
|
||||
$invitation = Invitation::where('invitation_key', $key)
|
||||
->firstOrFail();
|
||||
|
||||
return view('settings.users.accept')
|
||||
->withKey($key)
|
||||
->withEmail($invitation->email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
protected function validator(array $data)
|
||||
{
|
||||
return Validator::make($data, [
|
||||
'last_name' => 'required|max:255',
|
||||
'first_name' => 'required|max:255',
|
||||
'email' => 'required|email|max:255|unique:users',
|
||||
'email_security' => 'required',
|
||||
'password' => ['required', 'confirmed', PasswordRules::defaults()],
|
||||
'policy' => 'required',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the specified resource.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $key
|
||||
* @return null|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(Request $request, $key)
|
||||
{
|
||||
$this->validator($request->all())->validate();
|
||||
|
||||
$invitation = Invitation::where('invitation_key', $key)
|
||||
->firstOrFail();
|
||||
|
||||
// as a security measure, make sure that the new user provides the email
|
||||
// of the person who has invited him/her.
|
||||
if ($request->input('email_security') != $invitation->invitedBy->email) {
|
||||
return redirect()->back()->withErrors(trans('settings.users_error_email_not_similar'))->withInput();
|
||||
}
|
||||
|
||||
event(new Registered($user = $this->create($request->all(), $invitation)));
|
||||
|
||||
$invitation->delete();
|
||||
|
||||
/** @var \Illuminate\Contracts\Auth\StatefulGuard */
|
||||
$guard = Auth::guard();
|
||||
$guard->login($user);
|
||||
|
||||
$this->registered($request, $user);
|
||||
|
||||
return redirect($this->redirectPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @param array $data
|
||||
* @param mixed $invitation
|
||||
* @return \App\Models\User\User
|
||||
*/
|
||||
protected function create(array $data, $invitation)
|
||||
{
|
||||
$user = app(CreateUser::class)->execute([
|
||||
'account_id' => $invitation->account_id,
|
||||
'first_name' => $data['first_name'],
|
||||
'last_name' => $data['last_name'],
|
||||
'email' => $data['email'],
|
||||
'password' => $data['password'],
|
||||
'locale' => $invitation->invitedBy->locale,
|
||||
'ip_address' => RequestHelper::ip(),
|
||||
]);
|
||||
$user->invited_by_user_id = $invitation->invited_by_user_id;
|
||||
$user->save();
|
||||
|
||||
// send me an alert
|
||||
SendNewUserAlert::dispatch($user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user has been registered.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param mixed $user
|
||||
* @return void
|
||||
*/
|
||||
protected function registered(Request $request, $user)
|
||||
{
|
||||
if (! config('monica.signup_double_optin')) {
|
||||
// if signup_double_optin is disabled, skip the confirm email part
|
||||
$user->markEmailAsVerified();
|
||||
}
|
||||
}
|
||||
}
|
||||
50
app/Http/Controllers/Auth/LoginController.php
Normal file
50
app/Http/Controllers/Auth/LoginController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Helpers\InstanceHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
|
||||
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 / registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/dashboard';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest', ['except' => 'logout']);
|
||||
}
|
||||
|
||||
public function showLoginOrRegister()
|
||||
{
|
||||
$first = ! InstanceHelper::hasAtLeastOneAccount();
|
||||
if ($first) {
|
||||
return redirect()->route('register');
|
||||
}
|
||||
|
||||
return $this->showLoginForm();
|
||||
}
|
||||
}
|
||||
157
app/Http/Controllers/Auth/PasswordChangeController.php
Normal file
157
app/Http/Controllers/Auth/PasswordChangeController.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Models\User\User;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use App\Http\Requests\PasswordChangeRequest;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Foundation\Auth\RedirectsUsers;
|
||||
use Illuminate\Contracts\Auth\CanResetPassword;
|
||||
|
||||
class PasswordChangeController extends Controller
|
||||
{
|
||||
use RedirectsUsers;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/settings/security';
|
||||
|
||||
/**
|
||||
* Get useful parameters from request.
|
||||
*
|
||||
* @param \App\Http\Requests\PasswordChangeRequest $request
|
||||
* @return array
|
||||
*/
|
||||
protected function credentials(PasswordChangeRequest $request)
|
||||
{
|
||||
return $request->only(
|
||||
'password_current', 'password', 'password_confirmation'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change user password.
|
||||
*
|
||||
* @param \App\Http\Requests\PasswordChangeRequest $request
|
||||
*/
|
||||
public function passwordChange(PasswordChangeRequest $request)
|
||||
{
|
||||
$credentials = $this->credentials($request);
|
||||
|
||||
$response = $this->validateAndPasswordChange($credentials);
|
||||
|
||||
return $response === 'passwords.changed'
|
||||
? $this->sendChangedResponse($response)
|
||||
: $this->sendChangedFailedResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a password change request and update password of the user.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return string|Authenticatable
|
||||
*/
|
||||
protected function validateAndPasswordChange($credentials)
|
||||
{
|
||||
$user = $this->validateChange($credentials);
|
||||
if (! $user instanceof CanResetPassword) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
if ($user instanceof User) {
|
||||
$this->setNewPassword($user, $credentials['password']);
|
||||
}
|
||||
|
||||
return 'passwords.changed';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a password change request with the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return string|Authenticatable
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
protected function validateChange(array $credentials)
|
||||
{
|
||||
if (is_null($user = $this->getUser($credentials))) {
|
||||
return 'passwords.invalid';
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user with the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return null|Authenticatable
|
||||
*/
|
||||
protected function getUser(array $credentials): ?Authenticatable
|
||||
{
|
||||
/** @var User */
|
||||
$user = Auth::user();
|
||||
|
||||
// Using current email from user, and current password sent with the request to authenticate the user
|
||||
if (! Auth::attempt([
|
||||
'email' => $user->getEmailForPasswordReset(),
|
||||
'password' => $credentials['password_current'],
|
||||
])) {
|
||||
// authentication fails
|
||||
return null;
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new password if all validation has passed.
|
||||
*
|
||||
* @param User $user
|
||||
* @param string $password
|
||||
* @return void
|
||||
*/
|
||||
protected function setNewPassword($user, $password)
|
||||
{
|
||||
$user->password = Hash::make($password);
|
||||
|
||||
$user->setRememberToken(Str::random(60));
|
||||
|
||||
$user->save();
|
||||
|
||||
event(new PasswordReset($user));
|
||||
|
||||
Auth::guard()->login($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a successful password change.
|
||||
*
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function sendChangedResponse($response)
|
||||
{
|
||||
return redirect($this->redirectPath())
|
||||
->with('status', trans($response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a failed password change.
|
||||
*
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function sendChangedFailedResponse($response)
|
||||
{
|
||||
return redirect($this->redirectPath())
|
||||
->withErrors(['password' => trans($response)]);
|
||||
}
|
||||
}
|
||||
69
app/Http/Controllers/Auth/RecoveryLoginController.php
Normal file
69
app/Http/Controllers/Auth/RecoveryLoginController.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Events\RecoveryLogin;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Foundation\Auth\RedirectsUsers;
|
||||
|
||||
class RecoveryLoginController extends Controller
|
||||
{
|
||||
use RedirectsUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after login / registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/dashboard';
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function get(Request $request)
|
||||
{
|
||||
return view('auth.recovery.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate recovery login.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
Validator::make($request->all(), [
|
||||
'recovery' => 'required',
|
||||
])->validate();
|
||||
|
||||
$user = auth()->user();
|
||||
$recovery = $request->input('recovery');
|
||||
|
||||
if ($user instanceof \App\Models\User\User &&
|
||||
$user->recoveryChallenge($recovery)) {
|
||||
$this->fireLoginEvent($user);
|
||||
} else {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
return redirect($this->redirectPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire the login event.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return void
|
||||
*/
|
||||
protected function fireLoginEvent($user)
|
||||
{
|
||||
Event::dispatch(new RecoveryLogin($user));
|
||||
}
|
||||
}
|
||||
140
app/Http/Controllers/Auth/RegisterController.php
Normal file
140
app/Http/Controllers/Auth/RegisterController.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Models\User\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\LocaleHelper;
|
||||
use App\Helpers\RequestHelper;
|
||||
use App\Jobs\SendNewUserAlert;
|
||||
use App\Helpers\InstanceHelper;
|
||||
use App\Models\Account\Account;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Validation\Rules\Password as PasswordRules;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles the registration of new users as well as their
|
||||
| validation and creation. By default this controller uses a trait to
|
||||
| provide this functionality without requiring any additional code.
|
||||
|
|
||||
*/
|
||||
|
||||
use RegistersUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after login / registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/dashboard';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application registration form.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showRegistrationForm(Request $request)
|
||||
{
|
||||
$first = ! InstanceHelper::hasAtLeastOneAccount();
|
||||
if (config('monica.disable_signup') == 'true' && ! $first) {
|
||||
abort(403, trans('auth.signup_disabled'));
|
||||
}
|
||||
|
||||
return view('auth.register')
|
||||
->withFirst($first)
|
||||
->withLocales(LocaleHelper::getLocaleList()->sortByCollator('lang'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
protected function validator(array $data)
|
||||
{
|
||||
return Validator::make($data, [
|
||||
'last_name' => 'required|max:255',
|
||||
'first_name' => 'required|max:255',
|
||||
'email' => 'required|email|max:255|unique:users',
|
||||
'password' => ['required', 'confirmed', PasswordRules::defaults()],
|
||||
'policy' => 'required',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @param array $data
|
||||
* @return User|null
|
||||
*/
|
||||
protected function create(array $data): ?User
|
||||
{
|
||||
$first = ! InstanceHelper::hasAtLeastOneAccount();
|
||||
if (config('monica.disable_signup') == 'true' && ! $first) {
|
||||
abort(403, trans('auth.signup_disabled'));
|
||||
}
|
||||
|
||||
try {
|
||||
$account = Account::createDefault(
|
||||
$data['first_name'],
|
||||
$data['last_name'],
|
||||
$data['email'],
|
||||
$data['password'],
|
||||
RequestHelper::ip(),
|
||||
$data['lang']
|
||||
);
|
||||
/** @var User */
|
||||
$user = $account->users()->first();
|
||||
|
||||
if (! $first) {
|
||||
// send me an alert
|
||||
SendNewUserAlert::dispatch($user);
|
||||
}
|
||||
|
||||
return $user;
|
||||
} catch (\Exception $e) {
|
||||
Log::error($e);
|
||||
|
||||
abort(500, trans('auth.signup_error'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The user has been registered.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param mixed $user
|
||||
* @return mixed
|
||||
*/
|
||||
protected function registered(Request $request, $user)
|
||||
{
|
||||
if (! is_null($user)) {
|
||||
/** @var int $count */
|
||||
$count = Account::count();
|
||||
if (! config('monica.signup_double_optin') || $count == 1) {
|
||||
// if signup_double_optin is disabled, skip the confirm email part
|
||||
$user->markEmailAsVerified();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
app/Http/Controllers/Auth/ResetPasswordController.php
Normal file
42
app/Http/Controllers/Auth/ResetPasswordController.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Validation\Rules\Password as PasswordRules;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset requests
|
||||
| and uses a simple trait to include this behavior. You're free to
|
||||
| explore this trait and override any methods you wish to tweak.
|
||||
|
|
||||
*/
|
||||
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/dashboard';
|
||||
|
||||
/**
|
||||
* Get the password reset validation rules.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function rules()
|
||||
{
|
||||
return [
|
||||
'token' => 'required',
|
||||
'email' => 'required|email',
|
||||
'password' => ['required', 'confirmed', PasswordRules::defaults()],
|
||||
];
|
||||
}
|
||||
}
|
||||
35
app/Http/Controllers/Auth/Validate2faController.php
Normal file
35
app/Http/Controllers/Auth/Validate2faController.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use PragmaRX\Google2FALaravel\Facade as Google2FA;
|
||||
|
||||
class Validate2faController extends Controller
|
||||
{
|
||||
/**
|
||||
* Redirect the user after 2fa form has been submitted.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\Http\JsonResponse|\Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($request->session()->get('oauth')) {
|
||||
return Route::respondWithRoute('oauth.verify');
|
||||
}
|
||||
if ($request->has('url')) {
|
||||
return redirect(urldecode($request->input('url')));
|
||||
}
|
||||
|
||||
return redirect()->route('login');
|
||||
}
|
||||
|
||||
public static function loginCallback()
|
||||
{
|
||||
app('pragmarx.google2fa')->setStateless(false);
|
||||
Google2FA::login();
|
||||
}
|
||||
}
|
||||
41
app/Http/Controllers/Auth/VerificationController.php
Normal file
41
app/Http/Controllers/Auth/VerificationController.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\VerifiesEmails;
|
||||
|
||||
class VerificationController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Email Verification Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling email verification for any
|
||||
| user that recently registered with the application. Emails may also
|
||||
| be re-sent if the user didn't receive the original email message.
|
||||
|
|
||||
*/
|
||||
|
||||
use VerifiesEmails;
|
||||
|
||||
/**
|
||||
* Where to redirect users after verification.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/dashboard';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
$this->middleware('signed')->only('verify');
|
||||
$this->middleware('throttle:6,1')->only('verify', 'resend');
|
||||
}
|
||||
}
|
||||
22
app/Http/Controllers/ChangelogController.php
Normal file
22
app/Http/Controllers/ChangelogController.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\InstanceHelper;
|
||||
|
||||
class ChangelogController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$changelogs = InstanceHelper::getChangelogEntries();
|
||||
|
||||
return view('changelog.index')->withChangelogs($changelogs);
|
||||
}
|
||||
}
|
||||
38
app/Http/Controllers/ComplianceController.php
Normal file
38
app/Http/Controllers/ComplianceController.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Services\User\AcceptPolicy;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
|
||||
class ComplianceController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View|Factory
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
return view('compliance.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
app(AcceptPolicy::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
'ip_address' => \Request::ip(),
|
||||
]);
|
||||
|
||||
return redirect()->route('dashboard.index');
|
||||
}
|
||||
}
|
||||
207
app/Http/Controllers/Contacts/ActivitiesController.php
Normal file
207
app/Http/Controllers/Contacts/ActivitiesController.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Account\Activity;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Account\ActivityType;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Account\Activity\Activity\CreateActivity;
|
||||
use App\Services\Account\Activity\Activity\UpdateActivity;
|
||||
use App\Services\Account\Activity\Activity\DestroyActivity;
|
||||
use App\Services\Account\Activity\ActivityStatisticService;
|
||||
use App\Http\Resources\Activity\Activity as ActivityResource;
|
||||
|
||||
class ActivitiesController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get the list of activities.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
||||
*/
|
||||
public function index(Request $request, Contact $contact)
|
||||
{
|
||||
$activities = $contact->activities()
|
||||
->orderBy('happened_at', 'desc')
|
||||
->limit(10)
|
||||
->get();
|
||||
|
||||
return ActivityResource::collection($activities)->additional(['meta' => [
|
||||
'statistics' => AccountHelper::getYearlyActivitiesStatistics($contact->account),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of contacts available to associate the activity with
|
||||
* participants.
|
||||
* We could have chosen to query `/people` to get the full list of contacts
|
||||
* but some accounts have thousands of contacts. Thus for performance
|
||||
* purposes we have to create our own collection containing just the
|
||||
* necessary information.
|
||||
* Also we need to filter out the current contact from the list.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return Collection
|
||||
*/
|
||||
public function contacts(Request $request, Contact $contact)
|
||||
{
|
||||
return auth()->user()->account->contacts
|
||||
->filter(function ($c) use ($contact) {
|
||||
return $contact->id !== $c->id;
|
||||
})
|
||||
->map(function (Contact $c): array {
|
||||
return [
|
||||
'id' => $c->id,
|
||||
'name' => $c->name,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of activity categories.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Collection
|
||||
*/
|
||||
public function categories(Request $request)
|
||||
{
|
||||
$categories = auth()->user()->account->activityTypeCategories;
|
||||
|
||||
$array = collect([]);
|
||||
foreach ($categories as $category) {
|
||||
$types = ActivityType::where('activity_type_category_id', $category->id)->get();
|
||||
|
||||
$typeCollection = collect([]);
|
||||
foreach ($types as $type) {
|
||||
$typeCollection->push([
|
||||
'id' => $type->id,
|
||||
'name' => $type->name,
|
||||
]);
|
||||
}
|
||||
|
||||
$array->push([
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
'types' => $typeCollection,
|
||||
]);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the summary of activities for a given contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function summary(Request $request, Contact $contact)
|
||||
{
|
||||
// get the year of the most recent activity done with the contact
|
||||
$year = $contact->activities->sortByDesc('happened_at')
|
||||
->first()
|
||||
->happened_at
|
||||
->year;
|
||||
|
||||
return redirect()->route('people.activities.year', [$contact, $year]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the activities for this contact for a specific year.
|
||||
*/
|
||||
public function year(ActivityStatisticService $activityStatisticService, Contact $contact, int $year)
|
||||
{
|
||||
$startDate = Carbon::create($year, 1, 1);
|
||||
$endDate = Carbon::create($year, 12, 31);
|
||||
|
||||
$activitiesLastTwelveMonths = $activityStatisticService
|
||||
->activitiesWithContactInTimeRange($contact, now()->subMonths(12), now())
|
||||
->count();
|
||||
|
||||
$uniqueActivityTypes = $activityStatisticService
|
||||
->uniqueActivityTypesInTimeRange($contact, $startDate, $endDate);
|
||||
|
||||
$activitiesPerYear = $activityStatisticService->activitiesPerYearWithContact($contact);
|
||||
|
||||
$activitiesPerMonthForYear = $activityStatisticService
|
||||
->activitiesPerMonthForYear($contact, $year)
|
||||
->sortByDesc('month');
|
||||
|
||||
return view('people.activities.year')
|
||||
->withTotalActivities($contact->activities->count())
|
||||
->withActivitiesLastTwelveMonths($activitiesLastTwelveMonths)
|
||||
->withUniqueActivityTypes($uniqueActivityTypes)
|
||||
->withActivitiesPerYear($activitiesPerYear)
|
||||
->withActivitiesPerMonthForYear($activitiesPerMonthForYear)
|
||||
->withYear($year)
|
||||
->withContact($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the activity.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Support\Responsable
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$activity = app(CreateActivity::class)->execute(
|
||||
$request->except(['account_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
|
||||
return new ActivityResource($activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the activity.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Activity $activity
|
||||
* @return \Illuminate\Contracts\Support\Responsable
|
||||
*/
|
||||
public function update(Request $request, Activity $activity)
|
||||
{
|
||||
$activity = app(UpdateActivity::class)->execute(
|
||||
$request->except(['account_id', 'activity_id'])
|
||||
+
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_id' => $activity->id,
|
||||
]
|
||||
);
|
||||
|
||||
return new ActivityResource($activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an activity.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Activity $activity
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Activity $activity)
|
||||
{
|
||||
app(DestroyActivity::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'activity_id' => $activity->id,
|
||||
]);
|
||||
|
||||
return $this->respondObjectDeleted($activity->id);
|
||||
}
|
||||
}
|
||||
144
app/Http/Controllers/Contacts/AddressesController.php
Normal file
144
app/Http/Controllers/Contacts/AddressesController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Address;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Helpers\CountriesHelper;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Services\Contact\Address\CreateAddress;
|
||||
use App\Services\Contact\Address\UpdateAddress;
|
||||
use App\Services\Contact\Address\DestroyAddress;
|
||||
|
||||
class AddressesController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get all the addresses for this contact.
|
||||
*/
|
||||
public function index(Contact $contact)
|
||||
{
|
||||
$addresses = collect([]);
|
||||
|
||||
foreach ($contact->addresses as $address) {
|
||||
$addresses->push($this->addressObject($address));
|
||||
}
|
||||
|
||||
return $addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the countries.
|
||||
*/
|
||||
public function getCountries()
|
||||
{
|
||||
$key = 'countries.'.App::getLocale();
|
||||
|
||||
$countries = Cache::rememberForever($key, function () {
|
||||
return CountriesHelper::getAll();
|
||||
});
|
||||
|
||||
return response()->json($countries->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the address.
|
||||
*/
|
||||
public function store(Request $request, Contact $contact)
|
||||
{
|
||||
$datas = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
] + $request->only([
|
||||
'name',
|
||||
'country',
|
||||
'street',
|
||||
'city',
|
||||
'province',
|
||||
'postal_code',
|
||||
'latitude',
|
||||
'longitude',
|
||||
]);
|
||||
|
||||
$address = app(CreateAddress::class)->execute($datas);
|
||||
|
||||
return $this->setHTTPStatusCode(201)
|
||||
->respond($this->addressObject($address));
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the contact field.
|
||||
*/
|
||||
public function edit(Request $request, Contact $contact, Address $address)
|
||||
{
|
||||
$datas = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'address_id' => $address->id,
|
||||
] + $request->only([
|
||||
'name',
|
||||
'country',
|
||||
'street',
|
||||
'city',
|
||||
'province',
|
||||
'postal_code',
|
||||
'latitude',
|
||||
'longitude',
|
||||
]);
|
||||
|
||||
$address = app(UpdateAddress::class)->execute($datas);
|
||||
|
||||
return $this->respond($this->addressObject($address));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the address.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Address $address
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact, Address $address)
|
||||
{
|
||||
$datas = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'address_id' => $address->id,
|
||||
];
|
||||
|
||||
if (app(DestroyAddress::class)->execute($datas)) {
|
||||
return $this->respondObjectDeleted($address->id);
|
||||
}
|
||||
|
||||
return $this->setHTTPStatusCode(400)
|
||||
->setErrorCode(32)
|
||||
->respondWithError();
|
||||
}
|
||||
|
||||
private function addressObject($address)
|
||||
{
|
||||
$place = $address->place;
|
||||
|
||||
return [
|
||||
'id' => $address->id,
|
||||
'name' => $address->name,
|
||||
'googleMapAddress' => $place->getGoogleMapAddress(),
|
||||
'googleMapAddressLatitude' => $place->getGoogleMapsAddressWithLatitude(),
|
||||
'address' => $place->getAddressAsString(),
|
||||
'country' => $place->country,
|
||||
'country_name' => $place->country_name,
|
||||
'street' => $place->street,
|
||||
'city' => $place->city,
|
||||
'province' => $place->province,
|
||||
'postal_code' => $place->postal_code,
|
||||
'latitude' => $place->latitude,
|
||||
'longitude' => $place->longitude,
|
||||
'edit' => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
92
app/Http/Controllers/Contacts/AvatarController.php
Normal file
92
app/Http/Controllers/Contacts/AvatarController.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Services\Account\Photo\UploadPhoto;
|
||||
use App\Services\Contact\Avatar\UpdateAvatar;
|
||||
|
||||
class AvatarController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the Edit avatar screen.
|
||||
*/
|
||||
public function edit(Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
return view('people.avatar.edit')
|
||||
->withContact($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the avatar of the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
*/
|
||||
public function update(Request $request, Contact $contact)
|
||||
{
|
||||
// update the avatar
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'source' => $request->input('avatar'),
|
||||
];
|
||||
|
||||
switch ($request->input('avatar')) {
|
||||
case 'upload':
|
||||
// if it's a new photo, we need to upload it
|
||||
$validator = Validator::make($request->all(), [
|
||||
'file' => 'image|max:'.config('monica.max_upload_size'),
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($validator);
|
||||
}
|
||||
|
||||
$photo = app(UploadPhoto::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'photo' => $request->photo,
|
||||
]);
|
||||
|
||||
$data['photo_id'] = $photo->id;
|
||||
$data['source'] = 'photo';
|
||||
break;
|
||||
case 'photo':
|
||||
$data['photo_id'] = $contact->avatar_photo_id;
|
||||
break;
|
||||
}
|
||||
|
||||
app(UpdateAvatar::class)->execute($data);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.information_edit_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given photo as avatar.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param int $photoId
|
||||
*/
|
||||
public function photo(Request $request, Contact $contact, $photoId)
|
||||
{
|
||||
// update the avatar
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'source' => 'photo',
|
||||
'photo_id' => $photoId,
|
||||
];
|
||||
|
||||
return app(UpdateAvatar::class)->execute($data);
|
||||
}
|
||||
}
|
||||
111
app/Http/Controllers/Contacts/CallsController.php
Normal file
111
app/Http/Controllers/Contacts/CallsController.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use App\Models\Contact\Call;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Contact\Call\CreateCall;
|
||||
use App\Services\Contact\Call\UpdateCall;
|
||||
use App\Services\Contact\Call\DestroyCall;
|
||||
use App\Http\Resources\Call\Call as CallResource;
|
||||
|
||||
class CallsController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Display the list of calls.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request, Contact $contact)
|
||||
{
|
||||
$calls = $contact->calls()->get();
|
||||
|
||||
return CallResource::collection($calls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the timestamp of the last phone contact.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function lastCalled(Contact $contact): JsonResponse
|
||||
{
|
||||
$lastTalkedTo = $contact->last_talked_to;
|
||||
|
||||
if ($lastTalkedTo !== null) {
|
||||
$lastTalkedTo = DateHelper::getShortDate($contact->last_talked_to);
|
||||
}
|
||||
|
||||
return $this->respond([
|
||||
'last_talked_to' => $lastTalkedTo,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a call.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return Call
|
||||
*/
|
||||
public function store(Request $request, Contact $contact)
|
||||
{
|
||||
return app(CreateCall::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'content' => $request->input('content'),
|
||||
'called_at' => $request->input('called_at'),
|
||||
'contact_called' => $request->input('contact_called'),
|
||||
'emotions' => $request->input('emotions'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a call.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Call $call
|
||||
* @return Call
|
||||
*/
|
||||
public function update(Request $request, Contact $contact, Call $call)
|
||||
{
|
||||
return app(UpdateCall::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'call_id' => $call->id,
|
||||
'content' => $request->input('content'),
|
||||
'called_at' => $request->input('called_at'),
|
||||
'contact_called' => $request->input('contact_called'),
|
||||
'emotions' => $request->input('emotions'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the call.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Call $call
|
||||
* @return null|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact, Call $call): ?JsonResponse
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'call_id' => $call->id,
|
||||
];
|
||||
|
||||
if (app(DestroyCall::class)->execute($data)) {
|
||||
return $this->respondObjectDeleted($call->id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
26
app/Http/Controllers/Contacts/ContactAuditLogController.php
Normal file
26
app/Http/Controllers/Contacts/ContactAuditLogController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Helpers\AuditLogHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ContactAuditLogController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the page listing all the audit logs.
|
||||
*/
|
||||
public function index(Contact $contact)
|
||||
{
|
||||
$logs = $contact->logs()
|
||||
->with('author')
|
||||
->orderBy('created_at', 'desc')
|
||||
->paginate(15);
|
||||
|
||||
return view('people.auditlogs.index')
|
||||
->withContact($contact)
|
||||
->withLogsCollection(AuditLogHelper::getCollectionOfAudits($logs))
|
||||
->withLogsPagination($logs);
|
||||
}
|
||||
}
|
||||
92
app/Http/Controllers/Contacts/ContactFieldsController.php
Normal file
92
app/Http/Controllers/Contacts/ContactFieldsController.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Contact\ContactField;
|
||||
use App\Jobs\Avatars\GetAvatarsFromInternet;
|
||||
use App\Http\Requests\People\ContactFieldsRequest;
|
||||
|
||||
class ContactFieldsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get all the contact information for this contact.
|
||||
*/
|
||||
public function getContactFields(Contact $contact)
|
||||
{
|
||||
$contactInformationData = collect([]);
|
||||
|
||||
foreach ($contact->contactFields as $contactField) {
|
||||
$data = [
|
||||
'id' => $contactField->id,
|
||||
'data' => $contactField->data,
|
||||
'name' => $contactField->contactFieldType->name,
|
||||
'fontawesome_icon' => (is_null($contactField->contactFieldType->fontawesome_icon) ? null : $contactField->contactFieldType->fontawesome_icon),
|
||||
'protocol' => (is_null($contactField->contactFieldType->protocol) ? null : $contactField->contactFieldType->protocol),
|
||||
'contact_field_type_id' => $contactField->contact_field_type_id,
|
||||
'edit' => false,
|
||||
];
|
||||
$contactInformationData->push($data);
|
||||
}
|
||||
|
||||
return $contactInformationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the contact field types.
|
||||
*
|
||||
* @param Contact $contact
|
||||
*/
|
||||
public function getContactFieldTypes(Contact $contact)
|
||||
{
|
||||
return auth()->user()->account->contactFieldTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the contact field.
|
||||
*/
|
||||
public function storeContactField(ContactFieldsRequest $request, Contact $contact)
|
||||
{
|
||||
$contactField = $contact->contactFields()->create(
|
||||
$request->only([
|
||||
'contact_field_type_id',
|
||||
'data',
|
||||
])
|
||||
+ [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
|
||||
GetAvatarsFromInternet::dispatch($contact);
|
||||
|
||||
return $contactField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the contact field.
|
||||
*/
|
||||
public function editContactField(ContactFieldsRequest $request, Contact $contact, ContactField $contactField)
|
||||
{
|
||||
$contactField->update(
|
||||
$request->only([
|
||||
'contact_field_type_id',
|
||||
'data',
|
||||
])
|
||||
+ [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
|
||||
GetAvatarsFromInternet::dispatch($contact);
|
||||
|
||||
return $contactField;
|
||||
}
|
||||
|
||||
public function destroyContactField(Contact $contact, ContactField $contactField)
|
||||
{
|
||||
$contactField->delete();
|
||||
|
||||
GetAvatarsFromInternet::dispatch($contact);
|
||||
}
|
||||
}
|
||||
289
app/Http/Controllers/Contacts/ConversationsController.php
Normal file
289
app/Http/Controllers/Contacts/ConversationsController.php
Normal file
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Contact\Conversation;
|
||||
use App\Traits\JsonRespondController;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Conversation\DestroyMessage;
|
||||
use App\Services\Contact\Conversation\CreateConversation;
|
||||
use App\Services\Contact\Conversation\UpdateConversation;
|
||||
use App\Services\Contact\Conversation\DestroyConversation;
|
||||
use App\Services\Contact\Conversation\AddMessageToConversation;
|
||||
|
||||
class ConversationsController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Display the Create conversation page.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create(Request $request, Contact $contact)
|
||||
{
|
||||
return view('people.conversations.new')
|
||||
->withContact($contact)
|
||||
->withContactFieldTypes(auth()->user()->account->contactFieldTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of conversations.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return Collection
|
||||
*/
|
||||
public function index(Request $request, Contact $contact)
|
||||
{
|
||||
$conversationsCollection = collect([]);
|
||||
$conversations = $contact->conversations()->get();
|
||||
|
||||
foreach ($conversations as $conversation) {
|
||||
$message = $conversation->messages->last();
|
||||
$data = [
|
||||
'id' => $conversation->id,
|
||||
'message_count' => $conversation->messages->count(),
|
||||
'contact_field_type' => $conversation->contactFieldType->name,
|
||||
'icon' => $conversation->contactFieldType->fontawesome_icon,
|
||||
'content' => ! is_null($message) ? mb_strimwidth($message->content, 0, 50, '…') : '',
|
||||
'happened_at' => DateHelper::getShortDate($conversation->happened_at),
|
||||
'route' => route('people.conversations.edit', [$contact, $conversation]),
|
||||
];
|
||||
$conversationsCollection->push($data);
|
||||
}
|
||||
|
||||
return $conversationsCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(Request $request, Contact $contact)
|
||||
{
|
||||
$data = $this->validateAndGetDatas($request);
|
||||
|
||||
if ($data instanceof \Illuminate\Contracts\Validation\Validator) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($data);
|
||||
}
|
||||
|
||||
$date = $data['happened_at'];
|
||||
$data['contact_id'] = $contact->id;
|
||||
|
||||
// create the conversation
|
||||
try {
|
||||
$conversation = app(CreateConversation::class)->execute($data);
|
||||
} catch (ValidationException $e) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($e->validator);
|
||||
} catch (\Exception $e) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors(trans('app.error_save'));
|
||||
}
|
||||
|
||||
// add the messages to the conversation
|
||||
$result = $this->updateMessages($request, $conversation, $date);
|
||||
if ($result !== true) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($result);
|
||||
}
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.conversation_add_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a specific conversation.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Request $request, Contact $contact, Conversation $conversation)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
// preparing the messages for the Vue component
|
||||
$messages = collect([]);
|
||||
foreach ($conversation->messages as $message) {
|
||||
$messages->push([
|
||||
'uid' => $message->id,
|
||||
'content' => $message->content,
|
||||
'author' => ($message->written_by_me ? 'me' : 'other'),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('people.conversations.edit')
|
||||
->withContact($contact)
|
||||
->withConversation($conversation)
|
||||
->withMessages($messages)
|
||||
->withContactFieldTypes(auth()->user()->account->contactFieldTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Conversation $conversation
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Request $request, Contact $contact, Conversation $conversation)
|
||||
{
|
||||
$data = $this->validateAndGetDatas($request);
|
||||
|
||||
if ($data instanceof \Illuminate\Contracts\Validation\Validator) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($data);
|
||||
}
|
||||
|
||||
$date = $data['happened_at'];
|
||||
$data['conversation_id'] = $conversation->id;
|
||||
|
||||
// update the conversation
|
||||
try {
|
||||
$conversation = app(UpdateConversation::class)->execute($data);
|
||||
} catch (ValidationException $e) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($e->validator);
|
||||
} catch (\Exception $e) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors(trans('app.error_save'));
|
||||
}
|
||||
|
||||
// delete all current messages
|
||||
foreach ($conversation->messages as $message) {
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversation->id,
|
||||
'message_id' => $message->id,
|
||||
];
|
||||
app(DestroyMessage::class)->execute($data);
|
||||
}
|
||||
|
||||
// and create all new ones
|
||||
$result = $this->updateMessages($request, $conversation, $date);
|
||||
if ($result !== true) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($result);
|
||||
}
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.conversation_edit_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate datas and get an array for create or update a conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array|\Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
private function validateAndGetDatas(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'conversationDateRadio' => 'required',
|
||||
'conversationDate' => 'required_unless:conversationDateRadio,today,yesterday',
|
||||
'messages' => 'required',
|
||||
'contactFieldTypeId' => 'required|integer|exists:contact_field_types,id',
|
||||
], [
|
||||
'messages.required' => trans('people.conversation_add_error'),
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $validator;
|
||||
}
|
||||
|
||||
// find out what the date is
|
||||
$chosenDate = $request->input('conversationDateRadio');
|
||||
if ($chosenDate == 'today') {
|
||||
$date = DateHelper::getDate(now($request->user()->timezone));
|
||||
} elseif ($chosenDate == 'yesterday') {
|
||||
$date = DateHelper::getDate(now($request->user()->timezone)->subDay());
|
||||
} else {
|
||||
$date = $request->input('conversationDate');
|
||||
}
|
||||
|
||||
return [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'happened_at' => $date,
|
||||
'contact_field_type_id' => $request->input('contactFieldTypeId'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update messages for conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Conversation $conversation
|
||||
* @param string $date
|
||||
* @return bool|string|\Illuminate\Contracts\Validation\Validator
|
||||
* @psalm-return bool|array|string|\Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
private function updateMessages(Request $request, Conversation $conversation, string $date)
|
||||
{
|
||||
$messages = explode(',', $request->input('messages'));
|
||||
foreach ($messages as $messageId) {
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversation->id,
|
||||
'contact_id' => $conversation->contact_id,
|
||||
'written_at' => $date,
|
||||
'written_by_me' => ($request->input('who_wrote_'.$messageId) === 'me'),
|
||||
'content' => $request->input('content_'.$messageId),
|
||||
];
|
||||
|
||||
try {
|
||||
app(AddMessageToConversation::class)->execute($data);
|
||||
} catch (ValidationException $e) {
|
||||
return $e->validator;
|
||||
} catch (\Exception $e) {
|
||||
return trans('app.error_save');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the conversation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Conversation $conversation
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact, Conversation $conversation)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'conversation_id' => $conversation->id,
|
||||
];
|
||||
|
||||
try {
|
||||
app(DestroyConversation::class)->execute($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.conversation_delete_success'));
|
||||
}
|
||||
}
|
||||
139
app/Http/Controllers/Contacts/DebtController.php
Normal file
139
app/Http/Controllers/Contacts/DebtController.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Models\Contact\Debt;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\People\DebtRequest;
|
||||
|
||||
class DebtController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Contact $contact)
|
||||
{
|
||||
return view('people.debt.index')
|
||||
->withContact($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create(Contact $contact)
|
||||
{
|
||||
return view('people.debt.add')
|
||||
->withContact($contact)
|
||||
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account))
|
||||
->withDebt(new Debt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param DebtRequest $request
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(DebtRequest $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$contact->debts()->create(
|
||||
$request->only([
|
||||
'in_debt',
|
||||
'amount',
|
||||
'reason',
|
||||
])
|
||||
+ [
|
||||
'account_id' => $contact->account_id,
|
||||
'status' => 'inprogress',
|
||||
]
|
||||
);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.debt_add_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Debt $debt
|
||||
* @return void
|
||||
*/
|
||||
public function show(Contact $contact, Debt $debt): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Debt $debt
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Contact $contact, Debt $debt)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
return view('people.debt.edit')
|
||||
->withContact($contact)
|
||||
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account))
|
||||
->withDebt($debt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param DebtRequest $request
|
||||
* @param Contact $contact
|
||||
* @param Debt $debt
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(DebtRequest $request, Contact $contact, Debt $debt)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$debt->update(
|
||||
$request->only([
|
||||
'in_debt',
|
||||
'amount',
|
||||
'reason',
|
||||
])
|
||||
+ [
|
||||
'account_id' => $contact->account_id,
|
||||
'status' => 'inprogress',
|
||||
]
|
||||
);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.debt_edit_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Debt $debt
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Contact $contact, Debt $debt)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$debt->delete();
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.debt_delete_success'));
|
||||
}
|
||||
}
|
||||
85
app/Http/Controllers/Contacts/DocumentsController.php
Normal file
85
app/Http/Controllers/Contacts/DocumentsController.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\Document;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Contact\Document\UploadDocument;
|
||||
use App\Services\Contact\Document\DestroyDocument;
|
||||
use App\Http\Resources\Document\Document as DocumentResource;
|
||||
|
||||
class DocumentsController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Instantiate a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('limitations')->only('store');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of documents.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request, Contact $contact)
|
||||
{
|
||||
$documents = $contact->documents()->get();
|
||||
|
||||
return DocumentResource::collection($documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the document.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return Document
|
||||
*/
|
||||
public function store(Request $request, Contact $contact): Document
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
return app(UploadDocument::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'document' => $request->document,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the document.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Document $document
|
||||
* @return null|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact, Document $document): ?JsonResponse
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'document_id' => $document->id,
|
||||
];
|
||||
|
||||
try {
|
||||
if (app(DestroyDocument::class)->execute($data)) {
|
||||
return $this->respondObjectDeleted($document->id);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
124
app/Http/Controllers/Contacts/GiftController.php
Normal file
124
app/Http/Controllers/Contacts/GiftController.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Models\Contact\Gift;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Account\Photo;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Contact\Gift\CreateGift;
|
||||
use App\Services\Contact\Gift\UpdateGift;
|
||||
use App\Services\Contact\Gift\DestroyGift;
|
||||
use App\Http\Resources\Gift\Gift as GiftResource;
|
||||
use App\Services\Contact\Gift\AssociatePhotoToGift;
|
||||
|
||||
class GiftController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get the list of gifts for the given contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request, Contact $contact)
|
||||
{
|
||||
$gifts = $contact->gifts()
|
||||
->orderBy('created_at', 'asc')
|
||||
->paginate();
|
||||
|
||||
return GiftResource::collection($gifts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detail of a given gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Gift $gift
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, Contact $contact, Gift $gift)
|
||||
{
|
||||
return new GiftResource($gift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request, Contact $contact)
|
||||
{
|
||||
$gift = app(CreateGift::class)->execute(
|
||||
$request->except(['account_id', 'contact_id']) +
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
]
|
||||
);
|
||||
|
||||
return new GiftResource($gift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Gift $gift
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, Contact $contact, Gift $gift)
|
||||
{
|
||||
$gift = app(UpdateGift::class)->execute(
|
||||
$request->except(['account_id', 'contact_id', 'gift_id']) +
|
||||
[
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'gift_id' => $gift->id,
|
||||
]
|
||||
);
|
||||
|
||||
return new GiftResource($gift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a photo to the gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Gift $gift
|
||||
* @param Photo $photo
|
||||
* @return GiftResource|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function associate(Request $request, Contact $contact, Gift $gift, Photo $photo)
|
||||
{
|
||||
$gift = app(AssociatePhotoToGift::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'gift_id' => $gift->id,
|
||||
'photo_id' => $photo->id,
|
||||
]);
|
||||
|
||||
return new GiftResource($gift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a gift.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Gift $gift
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact, Gift $gift)
|
||||
{
|
||||
app(DestroyGift::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'gift_id' => $gift->id,
|
||||
]);
|
||||
|
||||
return $this->respondObjectDeleted($gift->id);
|
||||
}
|
||||
}
|
||||
69
app/Http/Controllers/Contacts/IntroductionsController.php
Normal file
69
app/Http/Controllers/Contacts/IntroductionsController.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Contact\Contact\UpdateContactIntroduction;
|
||||
use App\Http\Resources\Contact\ContactShort as ContactResource;
|
||||
|
||||
class IntroductionsController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$contacts = $contact->siblingContacts()
|
||||
->real()
|
||||
->active()
|
||||
->orderByUserPreference()
|
||||
->paginate(20);
|
||||
|
||||
$introducer = $contact->getIntroducer();
|
||||
if ($introducer !== null) {
|
||||
$introducer = new ContactResource($introducer);
|
||||
}
|
||||
|
||||
return view('people.introductions.edit')
|
||||
->withContact($contact)
|
||||
->withContacts(ContactResource::collection($contacts))
|
||||
->withIntroducer($introducer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(Request $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$contact = app(UpdateContactIntroduction::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'met_through_contact_id' => $request->input('metThroughId'),
|
||||
'general_information' => $request->input('first_met_additional_info'),
|
||||
'is_date_known' => $request->input('is_first_met_date_known') == 'known',
|
||||
'day' => $request->input('first_met_day'),
|
||||
'month' => $request->input('first_met_month'),
|
||||
'year' => $request->input('first_met_year'),
|
||||
'add_reminder' => $request->addReminder == 'on',
|
||||
]);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.introductions_update_success'));
|
||||
}
|
||||
}
|
||||
138
app/Http/Controllers/Contacts/LifeEventsController.php
Normal file
138
app/Http/Controllers/Contacts/LifeEventsController.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\LifeEvent;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Models\Contact\LifeEventCategory;
|
||||
use App\Services\Contact\LifeEvent\CreateLifeEvent;
|
||||
use App\Services\Contact\LifeEvent\DestroyLifeEvent;
|
||||
use App\Http\Resources\LifeEvent\LifeEventType as LifeEventTypeResource;
|
||||
use App\Http\Resources\LifeEvent\LifeEventCategory as LifeEventCategoryResource;
|
||||
|
||||
class LifeEventsController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get the list of life event categories.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
||||
*/
|
||||
public function categories(Request $request)
|
||||
{
|
||||
$lifeEventCategories = auth()->user()->account->lifeEventCategories;
|
||||
|
||||
return LifeEventCategoryResource::collection($lifeEventCategories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of life event types for a given life event category.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $lifeEventCategoryId
|
||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
||||
*/
|
||||
public function types(Request $request, int $lifeEventCategoryId)
|
||||
{
|
||||
$lifeEventCategory = LifeEventCategory::findOrFail($lifeEventCategoryId);
|
||||
$lifeEventTypes = $lifeEventCategory->lifeEventTypes;
|
||||
|
||||
return LifeEventTypeResource::collection($lifeEventTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of life events.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return Collection
|
||||
*/
|
||||
public function index(Request $request, Contact $contact)
|
||||
{
|
||||
$lifeEventsCollection = collect([]);
|
||||
$lifeEvents = $contact->lifeEvents()->get();
|
||||
|
||||
foreach ($lifeEvents as $lifeEvent) {
|
||||
$data = [
|
||||
'id' => $lifeEvent->id,
|
||||
'life_event_type' => $lifeEvent->lifeEventType->name,
|
||||
'default_life_event_type_key' => $lifeEvent->lifeEventType->default_life_event_type_key,
|
||||
'life_event_type_name' => $lifeEvent->lifeEventType->name,
|
||||
'name' => $lifeEvent->name,
|
||||
'note' => $lifeEvent->note,
|
||||
'happened_at' => DateHelper::getShortDate($lifeEvent->happened_at),
|
||||
];
|
||||
$lifeEventsCollection->push($data);
|
||||
}
|
||||
|
||||
return $lifeEventsCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the life event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return LifeEvent|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(Request $request, Contact $contact)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'life_event_type_id' => $request->input('life_event_type_id'),
|
||||
'happened_at' => $request->input('happened_at'),
|
||||
'name' => $request->input('name'),
|
||||
'note' => $request->input('note'),
|
||||
'has_reminder' => $request->input('has_reminder'),
|
||||
'happened_at_month_unknown' => $request->input('happened_at_month_unknown'),
|
||||
'happened_at_day_unknown' => $request->input('happened_at_day_unknown'),
|
||||
];
|
||||
|
||||
// create the conversation
|
||||
try {
|
||||
$lifeEvent = app(CreateLifeEvent::class)->execute($data);
|
||||
} catch (\Exception $e) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors(trans('app.error_save'));
|
||||
}
|
||||
|
||||
return $lifeEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the life event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param LifeEvent $lifeEvent
|
||||
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Request $request, LifeEvent $lifeEvent)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'life_event_id' => $lifeEvent->id,
|
||||
];
|
||||
|
||||
try {
|
||||
app(DestroyLifeEvent::class)->execute($data);
|
||||
} catch (\Exception $e) {
|
||||
// We have to redirect with HTTP status 303 or the browser will issue a
|
||||
// DELETE request to the new location. This may result in deleting other
|
||||
// resources as well. Refer to Github issue #2415
|
||||
return back(303)
|
||||
->withInput()
|
||||
->withErrors(trans('app.error_save'));
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($lifeEvent->id);
|
||||
}
|
||||
}
|
||||
101
app/Http/Controllers/Contacts/NotesController.php
Normal file
101
app/Http/Controllers/Contacts/NotesController.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use App\Models\Contact\Note;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\People\NotesRequest;
|
||||
use App\Http\Requests\People\NoteToggleRequest;
|
||||
|
||||
class NotesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get all the tasks of this contact.
|
||||
*/
|
||||
public function index(Contact $contact)
|
||||
{
|
||||
$notesCollection = collect([]);
|
||||
$notes = $contact->notes()->latest()->get();
|
||||
|
||||
foreach ($notes as $note) {
|
||||
$data = [
|
||||
'id' => $note->id,
|
||||
'body' => $note->body,
|
||||
'is_favorited' => $note->is_favorited,
|
||||
'favorited_at' => $note->favorited_at,
|
||||
'favorited_at_short' => $note->favorited_at ? DateHelper::getShortDate($note->favorited_at) : null,
|
||||
'created_at' => $note->created_at,
|
||||
'created_at_short' => DateHelper::getShortDate($note->created_at),
|
||||
'edit' => false,
|
||||
];
|
||||
$notesCollection->push($data);
|
||||
}
|
||||
|
||||
return $notesCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the task.
|
||||
*/
|
||||
public function store(NotesRequest $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
return $contact->notes()->create([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'body' => $request->input('body'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function toggle(NoteToggleRequest $request, Contact $contact, Note $note)
|
||||
{
|
||||
// check if the state of the note has changed
|
||||
if ($note->is_favorited) {
|
||||
$note->favorited_at = null;
|
||||
$note->is_favorited = false;
|
||||
} else {
|
||||
$note->is_favorited = true;
|
||||
$note->favorited_at = now();
|
||||
}
|
||||
|
||||
$note->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param NotesRequest $request
|
||||
* @param Contact $contact
|
||||
* @param Note $note
|
||||
* @return Note
|
||||
*/
|
||||
public function update(NotesRequest $request, Contact $contact, Note $note): Note
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$note->update(
|
||||
$request->only([
|
||||
'body',
|
||||
])
|
||||
+ ['account_id' => $contact->account_id]
|
||||
);
|
||||
|
||||
return $note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Note $note
|
||||
* @return void
|
||||
*/
|
||||
public function destroy(Contact $contact, Note $note): void
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$note->delete();
|
||||
}
|
||||
}
|
||||
114
app/Http/Controllers/Contacts/PetsController.php
Normal file
114
app/Http/Controllers/Contacts/PetsController.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Models\Contact\Pet;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\PetCategory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\People\PetsRequest;
|
||||
|
||||
class PetsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get all the pet categories.
|
||||
*/
|
||||
public function getPetCategories()
|
||||
{
|
||||
$petCategoriesData = collect([]);
|
||||
|
||||
$petCategories = PetCategory::all();
|
||||
|
||||
foreach ($petCategories as $petCategory) {
|
||||
$data = [
|
||||
'id' => $petCategory->id,
|
||||
'name' => $petCategory->name,
|
||||
'edit' => false,
|
||||
];
|
||||
$petCategoriesData->push($data);
|
||||
}
|
||||
|
||||
return $petCategoriesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the pets for this contact.
|
||||
*
|
||||
* @param Contact $contact
|
||||
*/
|
||||
public function index(Contact $contact)
|
||||
{
|
||||
$petsCollection = collect([]);
|
||||
$pets = $contact->pets;
|
||||
|
||||
foreach ($pets as $pet) {
|
||||
$data = [
|
||||
'id' => $pet->id,
|
||||
'name' => $pet->name,
|
||||
'pet_category_id' => $pet->pet_category_id,
|
||||
'category_name' => $pet->petCategory->name,
|
||||
'edit' => false,
|
||||
];
|
||||
$petsCollection->push($data);
|
||||
}
|
||||
|
||||
return $petsCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the pet.
|
||||
*/
|
||||
public function store(PetsRequest $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$pet = $contact->pets()->create(
|
||||
$request->only([
|
||||
'pet_category_id',
|
||||
'name',
|
||||
])
|
||||
+ [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
|
||||
return [
|
||||
'id' => $pet->id,
|
||||
'name' => $pet->name,
|
||||
'pet_category_id' => $pet->pet_category_id,
|
||||
'category_name' => $pet->petCategory->name,
|
||||
'edit' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the pet.
|
||||
*/
|
||||
public function update(PetsRequest $request, Contact $contact, Pet $pet)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$pet->update(
|
||||
$request->only([
|
||||
'pet_category_id',
|
||||
'name',
|
||||
])
|
||||
+ [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
|
||||
return [
|
||||
'id' => $pet->id,
|
||||
'name' => $pet->name,
|
||||
'pet_category_id' => $pet->pet_category_id,
|
||||
'category_name' => $pet->petCategory->name,
|
||||
'edit' => false,
|
||||
];
|
||||
}
|
||||
|
||||
public function destroy(Contact $contact, Pet $pet)
|
||||
{
|
||||
$pet->delete();
|
||||
}
|
||||
}
|
||||
84
app/Http/Controllers/Contacts/PhotosController.php
Normal file
84
app/Http/Controllers/Contacts/PhotosController.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Account\Photo;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Account\Photo\UploadPhoto;
|
||||
use App\Services\Account\Photo\DestroyPhoto;
|
||||
use App\Services\Contact\Avatar\UpdateAvatar;
|
||||
use App\Http\Resources\Photo\Photo as PhotoResource;
|
||||
|
||||
class PhotosController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Display the list of photos.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request, Contact $contact)
|
||||
{
|
||||
$photos = $contact->photos()->orderBy('created_at', 'desc')->get();
|
||||
|
||||
return PhotoResource::collection($photos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the Photo.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return PhotoResource
|
||||
*/
|
||||
public function store(Request $request, Contact $contact): PhotoResource
|
||||
{
|
||||
$photo = app(UploadPhoto::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'photo' => $request->photo,
|
||||
]);
|
||||
|
||||
return new PhotoResource($photo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the Photo.
|
||||
* Also, if this photo was the current avatar of the contact, change the
|
||||
* avatar to the default one.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Photo $photo
|
||||
* @return null|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact, Photo $photo)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'photo_id' => $photo->id,
|
||||
];
|
||||
|
||||
try {
|
||||
app(DestroyPhoto::class)->execute($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
if ($contact->avatar_source == 'photo'
|
||||
&& $contact->avatar_photo_id == $photo->id) {
|
||||
app(UpdateAvatar::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'source' => 'adorable',
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->respondObjectDeleted($photo->id);
|
||||
}
|
||||
}
|
||||
270
app/Http/Controllers/Contacts/RelationshipsController.php
Normal file
270
app/Http/Controllers/Contacts/RelationshipsController.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use App\Helpers\DateHelper;
|
||||
use App\Helpers\FormHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\GenderHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use App\Models\Relationship\Relationship;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Services\Contact\Contact\CreateContact;
|
||||
use App\Services\Contact\Contact\UpdateContact;
|
||||
use App\Services\Contact\Relationship\CreateRelationship;
|
||||
use App\Services\Contact\Relationship\UpdateRelationship;
|
||||
use App\Services\Contact\Relationship\DestroyRelationship;
|
||||
use App\Http\Resources\Contact\ContactShort as ContactResource;
|
||||
|
||||
class RelationshipsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the Create relationship page.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return View
|
||||
*/
|
||||
public function create(Request $request, Contact $contact)
|
||||
{
|
||||
$existingContacts = Contact::search('', Auth::user()->account_id, 'updated_at')
|
||||
->whereNotIn('id', [$contact->id])
|
||||
->paginate(20);
|
||||
|
||||
return view('people.relationship.new')
|
||||
->withContact($contact)
|
||||
->withPartner(new Contact)
|
||||
->withGenders(GenderHelper::getGendersInput())
|
||||
->withRelationshipTypes($this->getRelationshipTypesList($contact))
|
||||
->withDefaultGender(auth()->user()->account->default_gender_id)
|
||||
->withDays(DateHelper::getListOfDays())
|
||||
->withMonths(DateHelper::getListOfMonths())
|
||||
->withBirthdate(now(DateHelper::getTimezone())->toDateString())
|
||||
->withExistingContacts(ContactResource::collection($existingContacts))
|
||||
->withType($request->input('type'))
|
||||
->withFormNameOrder(FormHelper::getNameOrderForForms(auth()->user()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function store(Request $request, Contact $contact)
|
||||
{
|
||||
// case of linking to an existing contact
|
||||
if ($request->input('relationship_type') == 'existing') {
|
||||
$partnerId = $request->input('existing_contact_id');
|
||||
} else {
|
||||
|
||||
// case of creating a new contact
|
||||
$datas = $this->validateAndGetDatas($request);
|
||||
|
||||
if ($datas instanceof \Illuminate\Contracts\Validation\Validator) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($datas);
|
||||
}
|
||||
|
||||
$partner = app(CreateContact::class)->execute($datas);
|
||||
$partnerId = $partner->id;
|
||||
}
|
||||
|
||||
app(CreateRelationship::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_is' => $contact->id,
|
||||
'of_contact' => $partnerId,
|
||||
'relationship_type_id' => $request->input('relationship_type_id'),
|
||||
]);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.relationship_form_add_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Relationship $relationship
|
||||
* @return View
|
||||
*/
|
||||
public function edit(Contact $contact, Relationship $relationship)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$otherContact = $relationship->ofContact;
|
||||
|
||||
$now = now();
|
||||
$age = (string) (! is_null($otherContact->birthdate) ? $otherContact->birthdate->getAge() : 0);
|
||||
$birthdate = ! is_null($otherContact->birthdate) ? $otherContact->birthdate->date->toDateString() : $now->toDateString();
|
||||
$day = ! is_null($otherContact->birthdate) ? $otherContact->birthdate->date->day : $now->day;
|
||||
$month = ! is_null($otherContact->birthdate) ? $otherContact->birthdate->date->month : $now->month;
|
||||
|
||||
$hasBirthdayReminder = is_null($otherContact->birthday_reminder_id) ? 0 : 1;
|
||||
|
||||
return view('people.relationship.edit')
|
||||
->withContact($contact)
|
||||
->withPartner($otherContact)
|
||||
->withGenders(auth()->user()->account->genders)
|
||||
->withRelationshipTypes($this->getRelationshipTypesList($contact))
|
||||
->withDays(DateHelper::getListOfDays())
|
||||
->withMonths(DateHelper::getListOfMonths())
|
||||
->withBirthdate($birthdate)
|
||||
->withRelationshipId($relationship->id)
|
||||
->withType($relationship->relationship_type_id)
|
||||
->withBirthdayState($otherContact->getBirthdayState())
|
||||
->withDay($day)
|
||||
->withMonth($month)
|
||||
->withAge($age)
|
||||
->withGenders(GenderHelper::getGendersInput())
|
||||
->withHasBirthdayReminder($hasBirthdayReminder)
|
||||
->withFormNameOrder(FormHelper::getNameOrderForForms(auth()->user()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Relationship $relationship
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function update(Request $request, Contact $contact, Relationship $relationship)
|
||||
{
|
||||
$otherContact = $relationship->ofContact;
|
||||
|
||||
if ($otherContact->is_partial) {
|
||||
$datas = $this->validateAndGetDatas($request);
|
||||
|
||||
if ($datas instanceof \Illuminate\Contracts\Validation\Validator) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($datas);
|
||||
}
|
||||
|
||||
app(UpdateContact::class)->execute($datas + [
|
||||
'contact_id' => $otherContact->id,
|
||||
'author_id' => auth()->user()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
// update the relationship
|
||||
app(UpdateRelationship::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'relationship_id' => $relationship->id,
|
||||
'relationship_type_id' => $request->input('relationship_type_id'),
|
||||
]);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.relationship_form_add_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate datas and get an array for create or update a contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array|\Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
private function validateAndGetDatas(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'first_name' => 'required|max:255',
|
||||
'last_name' => 'max:255',
|
||||
'gender_id' => 'nullable|integer',
|
||||
'birthdayDate' => 'date_format:Y-m-d',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return $validator;
|
||||
}
|
||||
|
||||
// this is really ugly. it should be changed
|
||||
if ($request->input('birthdate') == 'exact') {
|
||||
$birthdate = $request->input('birthdayDate');
|
||||
$birthdate = DateHelper::parseDate($birthdate);
|
||||
$day = $birthdate->day;
|
||||
$month = $birthdate->month;
|
||||
$year = $birthdate->year;
|
||||
} else {
|
||||
$day = $request->input('day');
|
||||
$month = $request->input('month');
|
||||
$year = $request->input('year');
|
||||
}
|
||||
|
||||
return [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
'first_name' => $request->input('first_name'),
|
||||
'last_name' => $request->input('last_name'),
|
||||
'gender_id' => $request->input('gender_id'),
|
||||
'is_birthdate_known' => ! empty($request->input('birthdate')) && $request->input('birthdate') !== 'unknown',
|
||||
'birthdate_day' => $day,
|
||||
'birthdate_month' => $month,
|
||||
'birthdate_year' => $year,
|
||||
'birthdate_is_age_based' => $request->input('birthdate') === 'approximate',
|
||||
'birthdate_age' => $request->input('age'),
|
||||
'birthdate_add_reminder' => ! empty($request->input('addReminder')),
|
||||
'is_partial' => ! $request->input('realContact'),
|
||||
'is_deceased' => false,
|
||||
'is_deceased_date_known' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Relationship $relationship
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function destroy(Contact $contact, Relationship $relationship)
|
||||
{
|
||||
if ($contact->account_id != auth()->user()->account_id) {
|
||||
return redirect()->route('people.index');
|
||||
}
|
||||
|
||||
if ($relationship->account_id != auth()->user()->account_id) {
|
||||
return redirect()->route('people.index');
|
||||
}
|
||||
|
||||
app(DestroyRelationship::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'relationship_id' => $relationship->id,
|
||||
]);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.relationship_form_deletion_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Building the list of relationship types specifically for the dropdown which asks
|
||||
* for an id and a name.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getRelationshipTypesList(Contact $contact)
|
||||
{
|
||||
$relationshipTypes = collect();
|
||||
foreach (auth()->user()->account->relationshipTypes as $relationshipType) {
|
||||
$types = $relationshipTypes->get($relationshipType->relationshipTypeGroup->name, [
|
||||
'name' => trans('app.relationship_type_group_'.$relationshipType->relationshipTypeGroup->name),
|
||||
'options' => [],
|
||||
]);
|
||||
|
||||
$types['options'][] = [
|
||||
'id' => $relationshipType->id,
|
||||
'name' => $relationshipType->getLocalizedName($contact, true),
|
||||
];
|
||||
|
||||
$relationshipTypes->put($relationshipType->relationshipTypeGroup->name, $types);
|
||||
}
|
||||
|
||||
return $relationshipTypes;
|
||||
}
|
||||
}
|
||||
127
app/Http/Controllers/Contacts/RemindersController.php
Normal file
127
app/Http/Controllers/Contacts/RemindersController.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Models\Contact\Reminder;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\Contact\Reminder\CreateReminder;
|
||||
use App\Services\Contact\Reminder\UpdateReminder;
|
||||
use App\Services\Contact\Reminder\DestroyReminder;
|
||||
|
||||
class RemindersController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the form for creating a new reminder.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create(Contact $contact)
|
||||
{
|
||||
return view('people.reminders.add')
|
||||
->withContact($contact)
|
||||
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account))
|
||||
->withReminder(new Reminder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a reminder.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(Request $request, Contact $contact)
|
||||
{
|
||||
$frequency_type = $request->input('frequency_type');
|
||||
if ($frequency_type === 'recurrent') {
|
||||
$frequency_type = $request->input('frequency_number_select');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'initial_date' => $request->input('initial_date'),
|
||||
'frequency_type' => $frequency_type,
|
||||
'frequency_number' => is_null($request->input('frequency_number')) ? 1 : $request->input('frequency_number'),
|
||||
'title' => $request->input('title'),
|
||||
'description' => $request->input('description'),
|
||||
];
|
||||
|
||||
app(CreateReminder::class)->execute($data);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.reminders_create_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @param Reminder $reminder
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Contact $contact, Reminder $reminder)
|
||||
{
|
||||
return view('people.reminders.edit')
|
||||
->withContact($contact)
|
||||
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account))
|
||||
->withReminder($reminder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the reminder.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Reminder $reminder
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Request $request, Contact $contact, Reminder $reminder)
|
||||
{
|
||||
$frequency_type = $request->input('frequency_type');
|
||||
if ($frequency_type === 'recurrent') {
|
||||
$frequency_type = $request->input('frequency_number_select');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'reminder_id' => $reminder->id,
|
||||
'initial_date' => $request->input('initial_date'),
|
||||
'frequency_type' => $frequency_type,
|
||||
'frequency_number' => is_null($request->input('frequency_number')) ? 1 : $request->input('frequency_number'),
|
||||
'title' => $request->input('title'),
|
||||
'description' => $request->input('description'),
|
||||
];
|
||||
|
||||
app(UpdateReminder::class)->execute($data);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.reminders_update_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the reminder.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @param Reminder $reminder
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact, Reminder $reminder)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => $reminder->account_id,
|
||||
'reminder_id' => $reminder->id,
|
||||
];
|
||||
|
||||
app(DestroyReminder::class)->execute($data);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.reminders_delete_success'));
|
||||
}
|
||||
}
|
||||
74
app/Http/Controllers/Contacts/TagsController.php
Normal file
74
app/Http/Controllers/Contacts/TagsController.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\Contact\Tag\DetachTag;
|
||||
use App\Services\Contact\Tag\AssociateTag;
|
||||
use App\Http\Resources\Tag\Tag as TagResource;
|
||||
|
||||
class TagsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get the list of all the tags in the account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$tags = auth()->user()->account->tags()->get();
|
||||
|
||||
return TagResource::collection($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of all the tags for this contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function get(Request $request, Contact $contact)
|
||||
{
|
||||
$tags = $contact->tags()->get();
|
||||
|
||||
return TagResource::collection($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return void
|
||||
*/
|
||||
public function update(Request $request, Contact $contact): void
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$tags = $request->all();
|
||||
|
||||
// detaching all the tags
|
||||
$contactTags = $contact->tags()->get();
|
||||
foreach ($contactTags as $tag) {
|
||||
app(DetachTag::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'tag_id' => $tag->id,
|
||||
]);
|
||||
}
|
||||
|
||||
// attach all the new/updated tags
|
||||
foreach ($tags as $tag) {
|
||||
if (! empty($tag['name'])) {
|
||||
app(AssociateTag::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'name' => $tag['name'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
app/Http/Controllers/Contacts/TasksController.php
Normal file
32
app/Http/Controllers/Contacts/TasksController.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Contacts;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class TasksController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get all the tasks of this contact.
|
||||
*/
|
||||
public function index(Contact $contact)
|
||||
{
|
||||
$tasks = collect([]);
|
||||
|
||||
foreach ($contact->tasks as $task) {
|
||||
$data = [
|
||||
'id' => $task->id,
|
||||
'title' => $task->title,
|
||||
'description' => $task->description,
|
||||
'completed' => $task->completed,
|
||||
'completed_at' => ($task->completed_at) ? DateHelper::getShortDate($task->completed_at) : null,
|
||||
'edit' => false,
|
||||
];
|
||||
$tasks->push($data);
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
}
|
||||
755
app/Http/Controllers/ContactsController.php
Normal file
755
app/Http/Controllers/ContactsController.php
Normal file
@@ -0,0 +1,755 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use App\Helpers\DateHelper;
|
||||
use App\Helpers\FormHelper;
|
||||
use App\Models\Contact\Tag;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\GenderHelper;
|
||||
use App\Helpers\LocaleHelper;
|
||||
use App\Helpers\SearchHelper;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Services\VCard\ExportVCard;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Jobs\UpdateLastConsultedDate;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Barryvdh\Debugbar\Facades\Debugbar;
|
||||
use App\Services\User\UpdateViewPreference;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\Contact\Contact\CreateContact;
|
||||
use App\Services\Contact\Contact\UpdateContact;
|
||||
use App\Services\Contact\Contact\DestroyContact;
|
||||
use App\Services\Contact\Contact\UpdateWorkInformation;
|
||||
use App\Services\Contact\Contact\UpdateContactFoodPreferences;
|
||||
use App\Http\Resources\Contact\ContactSearch as ContactResource;
|
||||
|
||||
class ContactsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View|RedirectResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
return $this->contacts($request, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View|RedirectResponse
|
||||
*/
|
||||
public function archived(Request $request)
|
||||
{
|
||||
return $this->contacts($request, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display contacts.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param bool $active
|
||||
* @return View|RedirectResponse
|
||||
*/
|
||||
private function contacts(Request $request, bool $active)
|
||||
{
|
||||
$user = $request->user();
|
||||
$sort = $request->input('sort') ?? $user->contacts_sort_order;
|
||||
$showDeceased = $request->input('show_dead');
|
||||
|
||||
if ($user->contacts_sort_order !== $sort) {
|
||||
app(UpdateViewPreference::class)->execute([
|
||||
'account_id' => $user->account_id,
|
||||
'user_id' => $user->id,
|
||||
'preference' => $sort,
|
||||
]);
|
||||
}
|
||||
|
||||
$contacts = $user->account->contacts()->real();
|
||||
if ($active) {
|
||||
$archived = (clone $contacts)->notActive();
|
||||
$contacts = (clone $contacts)->active();
|
||||
$nbArchived = $archived->count();
|
||||
} else {
|
||||
$contacts = $contacts->notActive();
|
||||
$nbArchived = $contacts->count();
|
||||
}
|
||||
|
||||
$tagsCount = Tag::contactsCount();
|
||||
$contactsWithoutTagsCount = (clone $contacts)->doesntHave('tags')->count();
|
||||
|
||||
$tags = null;
|
||||
$url = null;
|
||||
$count = 1;
|
||||
|
||||
if ($request->input('tags')) {
|
||||
$tagsInput = $request->input('tags');
|
||||
|
||||
$tags = $tagsCount->filter(function ($tag) use ($tagsInput) {
|
||||
return in_array($tag->name, $tagsInput);
|
||||
});
|
||||
|
||||
$url = $tags->map(function ($tag): string {
|
||||
return 'tags[]='.urlencode($tag->name);
|
||||
})->join('&');
|
||||
|
||||
if ('' !== $url) {
|
||||
$url .= '&';
|
||||
}
|
||||
|
||||
if ($tags->count() === 0) {
|
||||
return redirect()->route('people.index');
|
||||
} else {
|
||||
$contacts = $contacts->tags($tags);
|
||||
}
|
||||
} elseif ($request->input('no_tag')) {
|
||||
$contacts = $contacts->tags('NONE');
|
||||
}
|
||||
|
||||
$contactsCount = (clone $contacts)->alive()->count();
|
||||
$deceasedCount = (clone $contacts)->dead()->count();
|
||||
|
||||
if ($showDeceased === 'true') {
|
||||
$contactsCount += $deceasedCount;
|
||||
}
|
||||
|
||||
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
|
||||
|
||||
return view('people.index')
|
||||
->withAccountHasLimitations($accountHasLimitations)
|
||||
->withHidingDeceased($showDeceased !== 'true')
|
||||
->withDeceasedCount($deceasedCount)
|
||||
->withActive($active)
|
||||
->withContactsCount($contactsCount)
|
||||
->withHasArchived($nbArchived > 0)
|
||||
->withArchivedContacts($nbArchived)
|
||||
->withTags($tags)
|
||||
->withSort($sort)
|
||||
->withTagsCount($tagsCount)
|
||||
->withUrl($url)
|
||||
->withTagCount($count)
|
||||
->withTagLess($request->input('no_tag') ?? false)
|
||||
->with('contactsWithoutTagsCount', $contactsWithoutTagsCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form to add a new contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View|Factory|RedirectResponse
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
return $this->createForm($request, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form in case the contact is missing.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View|Factory|RedirectResponse
|
||||
*/
|
||||
public function missing(Request $request)
|
||||
{
|
||||
return $this->createForm($request, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Add user form unless the contact has limitations.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param bool $isContactMissing
|
||||
* @return View|Factory|RedirectResponse
|
||||
*/
|
||||
private function createForm(Request $request, bool $isContactMissing = false)
|
||||
{
|
||||
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
|
||||
|
||||
if ($accountHasLimitations
|
||||
&& AccountHelper::hasReachedContactLimit(auth()->user()->account)
|
||||
&& ! auth()->user()->account->legacy_free_plan_unlimited_contacts) {
|
||||
return redirect()->route('settings.subscriptions.index');
|
||||
}
|
||||
|
||||
return view('people.create')
|
||||
->withAccountHasLimitations($accountHasLimitations)
|
||||
->withIsContactMissing($isContactMissing)
|
||||
->withGenders(GenderHelper::getGendersInput())
|
||||
->withDefaultGender(auth()->user()->account->default_gender_id)
|
||||
->withFormNameOrder(FormHelper::getNameOrderForForms(auth()->user()))
|
||||
->withFirstName($request->input('first_name'))
|
||||
->withLastName($request->input('last_name'))
|
||||
->withEmail($request->input('email'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$contact = app(CreateContact::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
'first_name' => $request->input('first_name'),
|
||||
'middle_name' => $request->input('middle_name', null),
|
||||
'last_name' => $request->input('last_name', null),
|
||||
'nickname' => $request->input('nickname', null),
|
||||
'email' => $request->input('email', null),
|
||||
'gender_id' => $request->input('gender'),
|
||||
'is_birthdate_known' => false,
|
||||
'is_deceased' => false,
|
||||
'is_deceased_date_known' => false,
|
||||
]);
|
||||
} catch (ValidationException $e) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($e->validator);
|
||||
}
|
||||
|
||||
// Did the user press "Save" or "Submit and add another person"
|
||||
if (! is_null($request->input('save'))) {
|
||||
return redirect()->route('people.show', $contact);
|
||||
} else {
|
||||
return redirect()->route('people.create')
|
||||
->with('status', trans('people.people_add_success', ['name' => $contact->name]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the contact profile.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return View|RedirectResponse
|
||||
*/
|
||||
public function show(Contact $contact)
|
||||
{
|
||||
// make sure we don't display a partial contact
|
||||
if ($contact->is_partial) {
|
||||
$realContact = $contact->getRelatedRealContact();
|
||||
if (is_null($realContact)) {
|
||||
return redirect()->route('people.index')
|
||||
->withErrors(trans('people.people_not_found'));
|
||||
}
|
||||
|
||||
return redirect()->route('people.show', $realContact);
|
||||
}
|
||||
$contact->load(['notes' => function ($query) {
|
||||
$query->orderBy('updated_at', 'desc');
|
||||
}]);
|
||||
|
||||
UpdateLastConsultedDate::dispatch($contact);
|
||||
|
||||
$relationships = $contact->relationships;
|
||||
// get love relationship type
|
||||
$loveRelationships = $relationships->filter(function ($item) {
|
||||
$item->relationshipTypeLocalized = $item->relationshipType->getLocalizedName(null, false, $item->ofContact->gender->type ?? null);
|
||||
|
||||
return $item->relationshipType->relationshipTypeGroup->name == 'love';
|
||||
});
|
||||
$loveRelationships->sortByCollator('relationshipTypeLocalized');
|
||||
|
||||
// get family relationship type
|
||||
$familyRelationships = $relationships->filter(function ($item) {
|
||||
$item->relationshipTypeLocalized = $item->relationshipType->getLocalizedName(null, false, $item->ofContact->gender->type ?? null);
|
||||
|
||||
return $item->relationshipType->relationshipTypeGroup->name == 'family';
|
||||
});
|
||||
$familyRelationships->sortByCollator('relationshipTypeLocalized');
|
||||
|
||||
// get friend relationship type
|
||||
$friendRelationships = $relationships->filter(function ($item) {
|
||||
$item->relationshipTypeLocalized = $item->relationshipType->getLocalizedName(null, false, $item->ofContact->gender->type ?? null);
|
||||
|
||||
return $item->relationshipType->relationshipTypeGroup->name == 'friend';
|
||||
});
|
||||
$friendRelationships->sortByCollator('relationshipTypeLocalized');
|
||||
|
||||
// get work relationship type
|
||||
$workRelationships = $relationships->filter(function ($item) {
|
||||
$item->relationshipTypeLocalized = $item->relationshipType->getLocalizedName(null, false, $item->ofContact->gender->type ?? null);
|
||||
|
||||
return $item->relationshipType->relationshipTypeGroup->name == 'work';
|
||||
});
|
||||
$workRelationships->sortByCollator('relationshipTypeLocalized');
|
||||
|
||||
// reminders
|
||||
$reminders = $contact->reminders()->active()->get();
|
||||
$relevantRemindersFromRelatedContacts = $contact->getBirthdayRemindersAboutRelatedContacts();
|
||||
$reminders = $reminders->merge($relevantRemindersFromRelatedContacts);
|
||||
// now we need to sort the reminders by next date they will be triggered
|
||||
foreach ($reminders as $reminder) {
|
||||
$next_expected_date = $reminder->calculateNextExpectedDateOnTimezone();
|
||||
$reminder->next_expected_date_human_readable = DateHelper::getShortDate($next_expected_date);
|
||||
$reminder->next_expected_date = DateHelper::getDate($next_expected_date);
|
||||
}
|
||||
$reminders = $reminders->sortBy('next_expected_date');
|
||||
|
||||
// list of active features
|
||||
$modules = $contact->account->modules()->active()->get();
|
||||
|
||||
// add `---` at the top of the dropdowns
|
||||
$days = DateHelper::getListOfDays();
|
||||
$days->prepend([
|
||||
'id' => 0,
|
||||
'name' => '---',
|
||||
]);
|
||||
|
||||
$months = DateHelper::getListOfMonths();
|
||||
$months->prepend([
|
||||
'id' => 0,
|
||||
'name' => '---',
|
||||
]);
|
||||
|
||||
$hasReachedAccountStorageLimit = StorageHelper::hasReachedAccountStorageLimit($contact->account);
|
||||
$accountHasLimitations = AccountHelper::hasLimitations($contact->account);
|
||||
|
||||
return view('people.profile')
|
||||
->withHasReachedAccountStorageLimit($hasReachedAccountStorageLimit)
|
||||
->withAccountHasLimitations($accountHasLimitations)
|
||||
->withLoveRelationships($loveRelationships)
|
||||
->withFamilyRelationships($familyRelationships)
|
||||
->withFriendRelationships($friendRelationships)
|
||||
->withWorkRelationships($workRelationships)
|
||||
->withReminders($reminders)
|
||||
->withModules($modules)
|
||||
->withContact($contact)
|
||||
->withWeather($contact->getWeather())
|
||||
->withDays($days)
|
||||
->withMonths($months)
|
||||
->withYears(DateHelper::getListOfYears());
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the Edit people's view.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return View|RedirectResponse
|
||||
*/
|
||||
public function edit(Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$now = now();
|
||||
$age = (string) (! is_null($contact->birthdate) ? $contact->birthdate->getAge() : 0);
|
||||
$birthdate = ! is_null($contact->birthdate) ? $contact->birthdate->date->toDateString() : $now->toDateString();
|
||||
$deceaseddate = ! is_null($contact->deceasedDate) ? $contact->deceasedDate->date->toDateString() : '';
|
||||
$day = ! is_null($contact->birthdate) ? $contact->birthdate->date->day : $now->day;
|
||||
$month = ! is_null($contact->birthdate) ? $contact->birthdate->date->month : $now->month;
|
||||
|
||||
$hasBirthdayReminder = ! is_null($contact->birthday_reminder_id);
|
||||
$hasDeceasedReminder = ! is_null($contact->deceased_reminder_id);
|
||||
|
||||
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
|
||||
|
||||
return view('people.edit')
|
||||
->withAccountHasLimitations($accountHasLimitations)
|
||||
->withContact($contact)
|
||||
->withDays(DateHelper::getListOfDays())
|
||||
->withMonths(DateHelper::getListOfMonths())
|
||||
->withBirthdayState($contact->getBirthdayState())
|
||||
->withBirthdate($birthdate)
|
||||
->withDeceaseddate($deceaseddate)
|
||||
->withDay($day)
|
||||
->withMonth($month)
|
||||
->withAge($age)
|
||||
->withHasBirthdayReminder($hasBirthdayReminder)
|
||||
->withHasDeceasedReminder($hasDeceasedReminder)
|
||||
->withGenders(GenderHelper::getGendersInput())
|
||||
->withFormNameOrder(FormHelper::getNameOrderForForms(auth()->user()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function update(Request $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
// process birthday dates
|
||||
// TODO: remove this part entirely when we redo this whole SpecialDate
|
||||
// thing
|
||||
if ($request->input('birthdate') == 'exact') {
|
||||
$birthdate = $request->input('birthdayDate');
|
||||
$birthdate = DateHelper::parseDate($birthdate);
|
||||
$day = $birthdate->day;
|
||||
$month = $birthdate->month;
|
||||
$year = $birthdate->year;
|
||||
} else {
|
||||
$day = $request->input('day');
|
||||
$month = $request->input('month');
|
||||
$year = $request->input('year');
|
||||
}
|
||||
$is_deceased_date_known = false;
|
||||
if ($request->input('is_deceased_date_known') === 'true' && $request->input('deceased_date')) {
|
||||
$is_deceased_date_known = true;
|
||||
$deceased_date = $request->input('deceased_date');
|
||||
$deceased_date = DateHelper::parseDate($deceased_date);
|
||||
$deceased_date_day = $deceased_date->day;
|
||||
$deceased_date_month = $deceased_date->month;
|
||||
$deceased_date_year = $deceased_date->year;
|
||||
} else {
|
||||
$deceased_date_day = $deceased_date_month = $deceased_date_year = null;
|
||||
}
|
||||
if (! empty($request->input('is_deceased'))) {
|
||||
//if the contact has died, disable StayInTouch
|
||||
$contact->updateStayInTouchFrequency(0);
|
||||
$contact->setStayInTouchTriggerDate(0);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
'contact_id' => $contact->id,
|
||||
'first_name' => $request->input('firstname'),
|
||||
'middle_name' => $request->input('middlename', null),
|
||||
'last_name' => $request->input('lastname', null),
|
||||
'nickname' => $request->input('nickname', null),
|
||||
'gender_id' => $request->input('gender'),
|
||||
'description' => $request->input('description', null),
|
||||
'is_birthdate_known' => ! empty($request->input('birthdate')) && $request->input('birthdate') !== 'unknown',
|
||||
'birthdate_day' => $day,
|
||||
'birthdate_month' => $month,
|
||||
'birthdate_year' => $year,
|
||||
'birthdate_is_age_based' => $request->input('birthdate') === 'approximate',
|
||||
'birthdate_age' => $request->input('age'),
|
||||
'birthdate_add_reminder' => ! empty($request->input('addReminder')),
|
||||
'is_deceased' => ! empty($request->input('is_deceased')),
|
||||
'is_deceased_date_known' => $is_deceased_date_known,
|
||||
'deceased_date_day' => $deceased_date_day,
|
||||
'deceased_date_month' => $deceased_date_month,
|
||||
'deceased_date_year' => $deceased_date_year,
|
||||
'deceased_date_add_reminder' => ! empty($request->input('add_reminder_deceased')),
|
||||
];
|
||||
|
||||
$contact = app(UpdateContact::class)->execute($data);
|
||||
|
||||
if ($request->file('avatar') != '') {
|
||||
if ($contact->has_avatar) {
|
||||
try {
|
||||
$contact->deleteAvatars();
|
||||
} catch (\Exception $e) {
|
||||
Log::warning(__CLASS__.' update: Failed to delete avatars', [
|
||||
'contact' => $contact,
|
||||
$e,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$contact->has_avatar = true;
|
||||
$contact->avatar_location = config('filesystems.default');
|
||||
$contact->avatar_file_name = $request->file('avatar')->store('avatars', [
|
||||
'disk' => $contact->avatar_location,
|
||||
'visibility' => config('filesystems.default_visibility'),
|
||||
]);
|
||||
$contact->save();
|
||||
}
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.information_edit_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function destroy(Request $request, Contact $contact)
|
||||
{
|
||||
if ($contact->account_id != auth()->user()->account_id) {
|
||||
return redirect()->route('people.index');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
];
|
||||
|
||||
DestroyContact::dispatch($data);
|
||||
|
||||
return redirect()->route('people.index')
|
||||
->with('success', trans('people.people_delete_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Edit work view.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return View|RedirectResponse
|
||||
*/
|
||||
public function editWork(Request $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
return view('people.work.edit')
|
||||
->withContact($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the work information.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function updateWork(Request $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$contact = app(UpdateWorkInformation::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'author_id' => auth()->user()->id,
|
||||
'contact_id' => $contact->id,
|
||||
'job' => $request->input('job'),
|
||||
'company' => $request->input('company'),
|
||||
]);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.work_edit_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Edit food preferences view.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return View|RedirectResponse
|
||||
*/
|
||||
public function editFoodPreferences(Request $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
|
||||
|
||||
return view('people.food-preferences.edit')
|
||||
->withAccountHasLimitations($accountHasLimitations)
|
||||
->withContact($contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the food preferences.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function updateFoodPreferences(Request $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$contact = app(UpdateContactFoodPreferences::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
'food_preferences' => $request->input('food'),
|
||||
]);
|
||||
|
||||
return redirect()->route('people.show', $contact)
|
||||
->with('success', trans('people.food_preferences_add_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search used in the header.
|
||||
*
|
||||
* @param Request $request
|
||||
*/
|
||||
public function search(Request $request)
|
||||
{
|
||||
$needle = $request->needle;
|
||||
|
||||
if ($needle == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$results = SearchHelper::searchContacts($needle, 'created_at')
|
||||
->paginate(20);
|
||||
|
||||
if ($results->total() > 0) {
|
||||
return ContactResource::collection($results);
|
||||
} else {
|
||||
return ['noResults' => trans('people.people_search_no_results')];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the contact as vCard.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function vCard(Contact $contact)
|
||||
{
|
||||
if (config('app.debug') && class_exists('\Barryvdh\Debugbar\Facade')) {
|
||||
Debugbar::disable();
|
||||
}
|
||||
|
||||
$vcard = app(ExportVCard::class)->execute([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
]);
|
||||
|
||||
return response($vcard->serialize())
|
||||
->header('Content-type', 'text/x-vcard')
|
||||
->header('Content-Disposition', 'attachment; filename='.Str::slug($contact->name, '-', LocaleHelper::getLang()).'.vcf');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or change the frequency of which the user wants to stay in touch with
|
||||
* the given contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return array
|
||||
*/
|
||||
public function stayInTouch(Request $request, Contact $contact)
|
||||
{
|
||||
$contact->throwInactive();
|
||||
|
||||
$frequency = intval($request->input('frequency'));
|
||||
$state = $request->input('state');
|
||||
|
||||
if (AccountHelper::hasLimitations(auth()->user()->account)) {
|
||||
throw new \LogicException(trans('people.stay_in_touch_premium'));
|
||||
}
|
||||
|
||||
// if not active, set frequency to 0
|
||||
if (! $state) {
|
||||
$frequency = 0;
|
||||
}
|
||||
$result = $contact->updateStayInTouchFrequency($frequency);
|
||||
|
||||
if (! $result) {
|
||||
throw new \LogicException(trans('people.stay_in_touch_invalid'));
|
||||
}
|
||||
|
||||
$contact->setStayInTouchTriggerDate($frequency);
|
||||
|
||||
return [
|
||||
'frequency' => $frequency,
|
||||
'trigger_date' => $contact->stay_in_touch_trigger_date,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle favorites of a contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return array
|
||||
*/
|
||||
public function favorite(Request $request, Contact $contact)
|
||||
{
|
||||
$bool = (bool) $request->input('toggle');
|
||||
|
||||
$contact->is_starred = $bool;
|
||||
$contact->save();
|
||||
|
||||
return [
|
||||
'is_starred' => $bool,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle archive state of a contact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Contact $contact
|
||||
* @return array
|
||||
*/
|
||||
public function archive(Request $request, Contact $contact)
|
||||
{
|
||||
if (! $contact->is_active
|
||||
&& AccountHelper::hasReachedContactLimit(auth()->user()->account)
|
||||
&& AccountHelper::hasLimitations(auth()->user()->account)
|
||||
&& ! auth()->user()->account->legacy_free_plan_unlimited_contacts) {
|
||||
abort(402);
|
||||
}
|
||||
|
||||
$contact->is_active = ! $contact->is_active;
|
||||
$contact->save();
|
||||
|
||||
return [
|
||||
'is_active' => $contact->is_active,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of contacts.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
$accountId = auth()->user()->account_id;
|
||||
|
||||
$user = $request->user();
|
||||
$sort = $request->input('sort') ?? $user->contacts_sort_order;
|
||||
|
||||
if ($user->contacts_sort_order !== $sort) {
|
||||
app(UpdateViewPreference::class)->execute([
|
||||
'account_id' => $user->account_id,
|
||||
'user_id' => $user->id,
|
||||
'preference' => $sort,
|
||||
]);
|
||||
}
|
||||
|
||||
$tags = null;
|
||||
|
||||
$contacts = $user->account->contacts()->real();
|
||||
|
||||
// filter out archived contacts if necessary
|
||||
if ($request->input('show_archived') != 'true') {
|
||||
$contacts = $contacts->active();
|
||||
} else {
|
||||
$contacts = $contacts->notActive();
|
||||
}
|
||||
|
||||
// filter out deceased if necessary
|
||||
if ($request->input('show_dead') != 'true') {
|
||||
$contacts = $contacts->alive();
|
||||
}
|
||||
|
||||
if ($request->input('tags')) {
|
||||
$tags = Tag::where('account_id', $accountId)
|
||||
->whereIn('name', $request->input('tags'))
|
||||
->get();
|
||||
|
||||
if ($tags->count() > 0) {
|
||||
$contacts = $contacts->tags($tags);
|
||||
}
|
||||
} elseif ($request->input('no_tag')) {
|
||||
// get tag less contacts
|
||||
$contacts = $contacts->tags('NONE');
|
||||
}
|
||||
|
||||
// get the number of contacts per page
|
||||
$perPage = $request->has('perPage') ? $request->input('perPage') : config('monica.number_of_contacts_pagination');
|
||||
|
||||
// search contacts
|
||||
$contacts = $contacts->search($request->input('search') ?? '', $accountId, 'is_starred', 'desc', $sort)
|
||||
->paginate($perPage);
|
||||
|
||||
return [
|
||||
'totalRecords' => $contacts->total(),
|
||||
'contacts' => ContactResource::collection($contacts),
|
||||
];
|
||||
}
|
||||
}
|
||||
13
app/Http/Controllers/Controller.php
Normal file
13
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
}
|
||||
80
app/Http/Controllers/DAV/Auth/AuthBackend.php
Normal file
80
app/Http/Controllers/DAV/Auth/AuthBackend.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Auth;
|
||||
|
||||
use Sabre\HTTP\RequestInterface;
|
||||
use Sabre\HTTP\ResponseInterface;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Sabre\DAV\Auth\Backend\BackendInterface;
|
||||
use App\Http\Controllers\DAV\DAVACL\PrincipalBackend;
|
||||
|
||||
class AuthBackend implements BackendInterface
|
||||
{
|
||||
/**
|
||||
* Authentication Realm.
|
||||
*
|
||||
* The realm is often displayed by browser clients when showing the
|
||||
* authentication dialog.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $realm = 'sabre/dav';
|
||||
|
||||
/**
|
||||
* Sets the authentication realm for this backend.
|
||||
*
|
||||
* @param string $realm
|
||||
* @return void
|
||||
*/
|
||||
public function setRealm($realm)
|
||||
{
|
||||
$this->realm = $realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Laravel authentication.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return array
|
||||
*/
|
||||
public function check(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
if (! Auth::check()) {
|
||||
return [false, 'User is not authenticated'];
|
||||
}
|
||||
|
||||
return [true, PrincipalBackend::getPrincipalUser(Auth::user())];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when a user could not be authenticated, and
|
||||
* authentication was required for the current request.
|
||||
*
|
||||
* This gives you the opportunity to set authentication headers. The 401
|
||||
* status code will already be set.
|
||||
*
|
||||
* In this case of Bearer Auth, this would for example mean that the
|
||||
* following header needs to be set:
|
||||
*
|
||||
* $response->addHeader('WWW-Authenticate', 'Bearer realm=SabreDAV');
|
||||
*
|
||||
* Keep in mind that in the case of multiple authentication backends, other
|
||||
* WWW-Authenticate headers may already have been set, and you'll want to
|
||||
* append your own WWW-Authenticate header instead of overwriting the
|
||||
* existing one.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return void
|
||||
*/
|
||||
public function challenge(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
$auth = new \Sabre\HTTP\Auth\Bearer(
|
||||
$this->realm,
|
||||
$request,
|
||||
$response
|
||||
);
|
||||
$auth->requireLogin();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CalDAV;
|
||||
|
||||
use Sabre\DAV\Server as SabreServer;
|
||||
use Sabre\CalDAV\Plugin as CalDAVPlugin;
|
||||
use Sabre\DAV\Sync\Plugin as DAVSyncPlugin;
|
||||
use App\Http\Controllers\DAV\Backend\IDAVBackend;
|
||||
use App\Http\Controllers\DAV\Backend\SyncDAVBackend;
|
||||
use App\Http\Controllers\DAV\DAVACL\PrincipalBackend;
|
||||
|
||||
abstract class AbstractCalDAVBackend implements ICalDAVBackend, IDAVBackend
|
||||
{
|
||||
use SyncDAVBackend;
|
||||
|
||||
/**
|
||||
* Get description array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
$token = DAVSyncPlugin::SYNCTOKEN_PREFIX.$this->refreshSyncToken(null)->id;
|
||||
|
||||
return [
|
||||
'id' => $this->backendUri(),
|
||||
'uri' => $this->backendUri(),
|
||||
'principaluri' => PrincipalBackend::getPrincipalUser($this->user),
|
||||
'{DAV:}sync-token' => $token,
|
||||
'{'.SabreServer::NS_SABREDAV.'}sync-token' => $token,
|
||||
'{'.CalDAVPlugin::NS_CALENDARSERVER.'}getctag' => $token,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new exported version of the object.
|
||||
*
|
||||
* @param mixed $obj
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function refreshObject($obj): string;
|
||||
}
|
||||
356
app/Http/Controllers/DAV/Backend/CalDAV/CalDAVBackend.php
Normal file
356
app/Http/Controllers/DAV/Backend/CalDAV/CalDAVBackend.php
Normal file
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CalDAV;
|
||||
|
||||
use Sabre\DAV;
|
||||
use App\Traits\WithUser;
|
||||
use Sabre\CalDAV\Backend\SyncSupport;
|
||||
use Sabre\CalDAV\Backend\AbstractBackend;
|
||||
|
||||
class CalDAVBackend extends AbstractBackend implements SyncSupport
|
||||
{
|
||||
use WithUser;
|
||||
|
||||
/**
|
||||
* Set the Calendar backends.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getBackends(): array
|
||||
{
|
||||
return [
|
||||
app(CalDAVBirthdays::class)->init($this->user),
|
||||
app(CalDAVTasks::class)->init($this->user),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the backend for this id.
|
||||
*
|
||||
* @return AbstractCalDAVBackend|null
|
||||
*/
|
||||
private function getBackend($id)
|
||||
{
|
||||
return collect($this->getBackends())->first(function ($backend) use ($id) {
|
||||
return $backend->backendUri() === $id;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of calendars for a principal.
|
||||
*
|
||||
* Every project is an array with the following keys:
|
||||
* * id, a unique id that will be used by other functions to modify the
|
||||
* calendar. This can be the same as the uri or a database key.
|
||||
* * uri, which is the basename of the uri with which the calendar is
|
||||
* accessed.
|
||||
* * principaluri. The owner of the calendar. Almost always the same as
|
||||
* principalUri passed to this method.
|
||||
*
|
||||
* Furthermore it can contain webdav properties in clark notation. A very
|
||||
* common one is '{DAV:}displayname'.
|
||||
*
|
||||
* Many clients also require:
|
||||
* {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
|
||||
* For this property, you can just return an instance of
|
||||
* Sabre\CalDAV\Property\SupportedCalendarComponentSet.
|
||||
*
|
||||
* If you return {http://sabredav.org/ns}read-only and set the value to 1,
|
||||
* ACL will automatically be put in read-only mode.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri)
|
||||
{
|
||||
return array_map(function ($backend) {
|
||||
return $backend->getDescription();
|
||||
}, $this->getBackends());
|
||||
}
|
||||
|
||||
/**
|
||||
* The getChanges method returns all the changes that have happened, since
|
||||
* the specified syncToken in the specified calendar.
|
||||
*
|
||||
* This function should return an array, such as the following:
|
||||
*
|
||||
* [
|
||||
* 'syncToken' => 'The current synctoken',
|
||||
* 'added' => [
|
||||
* 'new.txt',
|
||||
* ],
|
||||
* 'modified' => [
|
||||
* 'modified.txt',
|
||||
* ],
|
||||
* 'deleted' => [
|
||||
* 'foo.php.bak',
|
||||
* 'old.txt'
|
||||
* ]
|
||||
* );
|
||||
*
|
||||
* The returned syncToken property should reflect the *current* syncToken
|
||||
* of the calendar, as reported in the {http://sabredav.org/ns}sync-token
|
||||
* property This is * needed here too, to ensure the operation is atomic.
|
||||
*
|
||||
* If the $syncToken argument is specified as null, this is an initial
|
||||
* sync, and all members should be reported.
|
||||
*
|
||||
* The modified property is an array of nodenames that have changed since
|
||||
* the last token.
|
||||
*
|
||||
* The deleted property is an array with nodenames, that have been deleted
|
||||
* from collection.
|
||||
*
|
||||
* The $syncLevel argument is basically the 'depth' of the report. If it's
|
||||
* 1, you only have to report changes that happened only directly in
|
||||
* immediate descendants. If it's 2, it should also include changes from
|
||||
* the nodes below the child collections. (grandchildren)
|
||||
*
|
||||
* The $limit argument allows a client to specify how many results should
|
||||
* be returned at most. If the limit is not specified, it should be treated
|
||||
* as infinite.
|
||||
*
|
||||
* If the limit (infinite or not) is higher than you're willing to return,
|
||||
* you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
|
||||
*
|
||||
* If the syncToken is expired (due to data cleanup) or unknown, you must
|
||||
* return null.
|
||||
*
|
||||
* The limit is 'suggestive'. You are free to ignore it.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $syncToken
|
||||
* @param int $syncLevel
|
||||
* @param int $limit
|
||||
* @return array
|
||||
*/
|
||||
public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null)
|
||||
{
|
||||
$backend = $this->getBackend($calendarId);
|
||||
if ($backend) {
|
||||
return $backend->getChanges($calendarId, $syncToken);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all calendar objects within a calendar.
|
||||
*
|
||||
* Every item contains an array with the following keys:
|
||||
* * calendardata - The iCalendar-compatible calendar data
|
||||
* * uri - a unique key which will be used to construct the uri. This can
|
||||
* be any arbitrary string, but making sure it ends with '.ics' is a
|
||||
* good idea. This is only the basename, or filename, not the full
|
||||
* path.
|
||||
* * lastmodified - a timestamp of the last modification time
|
||||
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
|
||||
* '"abcdef"')
|
||||
* * size - The size of the calendar objects, in bytes.
|
||||
* * component - optional, a string containing the type of object, such
|
||||
* as 'vevent' or 'vtodo'. If specified, this will be used to populate
|
||||
* the Content-Type header.
|
||||
*
|
||||
* Note that the etag is optional, but it's highly encouraged to return for
|
||||
* speed reasons.
|
||||
*
|
||||
* The calendardata is also optional. If it's not returned
|
||||
* 'getCalendarObject' will be called later, which *is* expected to return
|
||||
* calendardata.
|
||||
*
|
||||
* If neither etag or size are specified, the calendardata will be
|
||||
* used/fetched to determine these numbers. If both are specified the
|
||||
* amount of times this is needed is reduced by a great degree.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObjects($calendarId)
|
||||
{
|
||||
$backend = $this->getBackend($calendarId);
|
||||
if ($backend) {
|
||||
$objs = $backend->getObjects($calendarId);
|
||||
|
||||
return $objs
|
||||
->map(function ($date) use ($backend) {
|
||||
return $backend->prepareData($date);
|
||||
})
|
||||
->filter(function ($event) {
|
||||
return $event !== null;
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* This method must return null if the object did not exist.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array|null
|
||||
*/
|
||||
public function getCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$backend = $this->getBackend($calendarId);
|
||||
if ($backend) {
|
||||
$obj = $backend->getObject($calendarId, $objectUri);
|
||||
|
||||
if ($obj) {
|
||||
return $backend->prepareData($obj);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* It is possible to return an etag from this function, which will be used
|
||||
* in the response to this PUT request. Note that the ETag must be
|
||||
* surrounded by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function createCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
return $this->updateCalendarObject($calendarId, $objectUri, $calendarData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateCalendarObject($calendarId, $objectUri, $calendarData): ?string
|
||||
{
|
||||
$backend = $this->getBackend($calendarId);
|
||||
|
||||
return $backend ?
|
||||
$backend->updateOrCreateCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$backend = $this->getBackend($calendarId);
|
||||
if ($backend) {
|
||||
$backend->deleteCalendarObject($objectUri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar for a principal.
|
||||
*
|
||||
* If the creation was a success, an id must be returned that can be used to
|
||||
* reference this calendar in other methods, such as updateCalendar.
|
||||
*
|
||||
* The id can be any type, including ints, strings, objects or array.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $calendarUri
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function createCalendar($principalUri, $calendarUri, array $properties): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all its objects.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new subscription for a principal.
|
||||
*
|
||||
* If the creation was a success, an id must be returned that can be used to reference
|
||||
* this subscription in other methods, such as updateSubscription.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $uri
|
||||
* @param array $properties
|
||||
* @return mixed
|
||||
*/
|
||||
public function createSubscription($principalUri, $uri, array $properties)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a subscription.
|
||||
*
|
||||
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||
* To do the actual updates, you must tell this object which properties
|
||||
* you're going to process with the handle() method.
|
||||
*
|
||||
* Calling the handle method is like telling the PropPatch object "I
|
||||
* promise I can handle updating this property".
|
||||
*
|
||||
* Read the PropPatch documentation for more info and examples.
|
||||
*
|
||||
* @param mixed $subscriptionId
|
||||
* @param \Sabre\DAV\PropPatch $propPatch
|
||||
* @return void
|
||||
*/
|
||||
public function updateSubscription($subscriptionId, DAV\PropPatch $propPatch)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a subscription.
|
||||
*
|
||||
* @param mixed $subscriptionId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteSubscription($subscriptionId)
|
||||
{
|
||||
}
|
||||
}
|
||||
168
app/Http/Controllers/DAV/Backend/CalDAV/CalDAVBirthdays.php
Normal file
168
app/Http/Controllers/DAV/Backend/CalDAV/CalDAVBirthdays.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CalDAV;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Instance\SpecialDate;
|
||||
use Sabre\DAV\Server as SabreServer;
|
||||
use Sabre\CalDAV\Plugin as CalDAVPlugin;
|
||||
use App\Services\VCalendar\ExportVCalendar;
|
||||
use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
|
||||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
|
||||
|
||||
class CalDAVBirthdays extends AbstractCalDAVBackend
|
||||
{
|
||||
/**
|
||||
* Returns the uri for this backend.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function backendUri()
|
||||
{
|
||||
return 'birthdays';
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return parent::getDescription()
|
||||
+ [
|
||||
'{DAV:}displayname' => trans('app.dav_birthdays'),
|
||||
'{'.SabreServer::NS_SABREDAV.'}read-only' => true,
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}calendar-description' => trans('app.dav_birthdays_description', ['name' => $this->user->name]),
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}calendar-timezone' => $this->user->timezone,
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VEVENT']),
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}schedule-calendar-transp' => new ScheduleCalendarTransp(ScheduleCalendarTransp::TRANSPARENT),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension for Calendar objects.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExtension()
|
||||
{
|
||||
return '.ics';
|
||||
}
|
||||
|
||||
/**
|
||||
* Datas for this date.
|
||||
*
|
||||
* @param mixed $obj
|
||||
* @return array
|
||||
*/
|
||||
public function prepareData($obj)
|
||||
{
|
||||
$calendardata = null;
|
||||
if ($obj instanceof SpecialDate) {
|
||||
try {
|
||||
$calendardata = $this->refreshObject($obj);
|
||||
|
||||
return [
|
||||
'id' => $obj->id,
|
||||
'uri' => $this->encodeUri($obj),
|
||||
'calendardata' => $calendardata,
|
||||
'etag' => '"'.sha1($calendardata).'"',
|
||||
'lastmodified' => $obj->updated_at->timestamp,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
Log::error(__CLASS__.' '.__FUNCTION__.': '.$e->getMessage(), [
|
||||
'calendardata' => $calendardata,
|
||||
$e,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new exported version of the object.
|
||||
*
|
||||
* @param mixed $obj date
|
||||
* @return string
|
||||
*/
|
||||
protected function refreshObject($obj): string
|
||||
{
|
||||
$vcal = app(ExportVCalendar::class)
|
||||
->execute([
|
||||
'account_id' => $this->user->account_id,
|
||||
'special_date_id' => $obj->id,
|
||||
]);
|
||||
|
||||
return $vcal->serialize();
|
||||
}
|
||||
|
||||
private function hasBirthday($contact)
|
||||
{
|
||||
if (! $contact || ! $contact->birthdate) {
|
||||
return false;
|
||||
}
|
||||
$birthdayState = $contact->getBirthdayState();
|
||||
if ($birthdayState != 'almost' && $birthdayState != 'exact') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date for the specific uuid.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @param string $uuid
|
||||
* @return mixed
|
||||
*/
|
||||
public function getObjectUuid($collectionId, $uuid)
|
||||
{
|
||||
return SpecialDate::where([
|
||||
'account_id' => $this->user->account_id,
|
||||
'uuid' => $uuid,
|
||||
])->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of contact's birthdays.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getObjects($collectionId)
|
||||
{
|
||||
// We only return the birthday of default addressBook
|
||||
$contacts = $this->user->account->contacts()
|
||||
->real()
|
||||
->active()
|
||||
->get();
|
||||
|
||||
return $contacts->filter(function ($contact) {
|
||||
return $this->hasBirthday($contact);
|
||||
})
|
||||
->map(function ($contact) {
|
||||
return $contact->birthdate;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of deleted birthdays.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getDeletedObjects($collectionId)
|
||||
{
|
||||
return collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateOrCreateCalendarObject($calendarId, $objectUri, $calendarData): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function deleteCalendarObject($objectUri)
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
}
|
||||
219
app/Http/Controllers/DAV/Backend/CalDAV/CalDAVTasks.php
Normal file
219
app/Http/Controllers/DAV/Backend/CalDAV/CalDAVTasks.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CalDAV;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use App\Models\Contact\Task;
|
||||
use App\Services\Task\DestroyTask;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Services\VCalendar\ExportTask;
|
||||
use App\Services\VCalendar\ImportTask;
|
||||
use Sabre\CalDAV\Plugin as CalDAVPlugin;
|
||||
use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
|
||||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
|
||||
|
||||
class CalDAVTasks extends AbstractCalDAVBackend
|
||||
{
|
||||
/**
|
||||
* Returns the uri for this backend.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function backendUri()
|
||||
{
|
||||
return 'tasks';
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return parent::getDescription()
|
||||
+ [
|
||||
'{DAV:}displayname' => trans('app.dav_tasks'),
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}calendar-description' => trans('app.dav_tasks_description', ['name' => $this->user->name]),
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}calendar-timezone' => $this->user->timezone,
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO']),
|
||||
'{'.CalDAVPlugin::NS_CALDAV.'}schedule-calendar-transp' => new ScheduleCalendarTransp(ScheduleCalendarTransp::TRANSPARENT),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of all tasks.
|
||||
*
|
||||
* @param mixed|null $collectionId
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getObjects($collectionId)
|
||||
{
|
||||
return $this->user->account
|
||||
->tasks()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of deleted tasks.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getDeletedObjects($collectionId)
|
||||
{
|
||||
return collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact for the specific uuid.
|
||||
*
|
||||
* @param mixed|null $collectionId
|
||||
* @param string $uuid
|
||||
* @return mixed
|
||||
*/
|
||||
public function getObjectUuid($collectionId, $uuid)
|
||||
{
|
||||
return Task::where([
|
||||
'account_id' => $this->user->account_id,
|
||||
'uuid' => $uuid,
|
||||
])->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension for Calendar objects.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExtension()
|
||||
{
|
||||
return '.ics';
|
||||
}
|
||||
|
||||
/**
|
||||
* Datas for this task.
|
||||
*
|
||||
* @param mixed $obj
|
||||
* @return array
|
||||
*/
|
||||
public function prepareData($obj)
|
||||
{
|
||||
$calendardata = null;
|
||||
if ($obj instanceof Task) {
|
||||
try {
|
||||
$calendardata = $this->refreshObject($obj);
|
||||
|
||||
return [
|
||||
'id' => $obj->id,
|
||||
'uri' => $this->encodeUri($obj),
|
||||
'calendardata' => $calendardata,
|
||||
'etag' => '"'.sha1($calendardata).'"',
|
||||
'lastmodified' => $obj->updated_at->timestamp,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
Log::error(__CLASS__.' '.__FUNCTION__.': '.$e->getMessage(), [
|
||||
'calendardata' => $calendardata,
|
||||
$e,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new exported version of the object.
|
||||
*
|
||||
* @param mixed $obj task
|
||||
* @return string
|
||||
*/
|
||||
protected function refreshObject($obj): string
|
||||
{
|
||||
$vcal = app(ExportTask::class)
|
||||
->execute([
|
||||
'account_id' => $this->user->account_id,
|
||||
'task_id' => $obj->id,
|
||||
]);
|
||||
|
||||
return $vcal->serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateOrCreateCalendarObject($calendarId, $objectUri, $calendarData): ?string
|
||||
{
|
||||
$task_id = null;
|
||||
if ($objectUri) {
|
||||
$task = $this->getObject($this->backendUri(), $objectUri);
|
||||
|
||||
if ($task) {
|
||||
$task_id = $task->id;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$result = app(ImportTask::class)
|
||||
->execute([
|
||||
'account_id' => $this->user->account_id,
|
||||
'task_id' => $task_id,
|
||||
'entry' => $calendarData,
|
||||
]);
|
||||
|
||||
if (! Arr::has($result, 'error')) {
|
||||
$task = Task::where('account_id', $this->user->account_id)
|
||||
->find($result['task_id']);
|
||||
|
||||
$calendar = $this->prepareData($task);
|
||||
|
||||
return $calendar['etag'];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error(__CLASS__.' '.__FUNCTION__.': '.$e->getMessage(), [
|
||||
'calendarId' => $calendarId,
|
||||
'objectUri' => $objectUri,
|
||||
'calendarData' => $calendarData,
|
||||
$e,
|
||||
]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendarObject($objectUri)
|
||||
{
|
||||
$task = $this->getObject($this->backendUri(), $objectUri);
|
||||
|
||||
if ($task) {
|
||||
try {
|
||||
app(DestroyTask::class)
|
||||
->execute([
|
||||
'account_id' => $this->user->account_id,
|
||||
'task_id' => $task->id,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
Log::error(__CLASS__.' '.__FUNCTION__.': '.$e->getMessage(), [
|
||||
'objectUri' => $objectUri,
|
||||
$e,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
118
app/Http/Controllers/DAV/Backend/CalDAV/ICalDAVBackend.php
Normal file
118
app/Http/Controllers/DAV/Backend/CalDAV/ICalDAVBackend.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CalDAV;
|
||||
|
||||
interface ICalDAVBackend
|
||||
{
|
||||
/**
|
||||
* Returns a list of properties for a principal.
|
||||
*
|
||||
* Every project is an array with the following keys:
|
||||
* * id, a unique id that will be used by other functions to modify the
|
||||
* calendar. This can be the same as the uri or a database key.
|
||||
* * uri, which is the basename of the uri with which the calendar is
|
||||
* accessed.
|
||||
* * principaluri. The owner of the calendar. Almost always the same as
|
||||
* principalUri passed to this method.
|
||||
*
|
||||
* Furthermore it can contain webdav properties in clark notation. A very
|
||||
* common one is '{DAV:}displayname'.
|
||||
*
|
||||
* Many clients also require:
|
||||
* {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
|
||||
* For this property, you can just return an instance of
|
||||
* Sabre\CalDAV\Property\SupportedCalendarComponentSet.
|
||||
*
|
||||
* If you return {http://sabredav.org/ns}read-only and set the value to 1,
|
||||
* ACL will automatically be put in read-only mode.
|
||||
*
|
||||
************************
|
||||
* == From Subscription :
|
||||
* Furthermore, all the subscription info must be returned too:
|
||||
*
|
||||
* 1. {DAV:}displayname
|
||||
* 2. {http://apple.com/ns/ical/}refreshrate
|
||||
* 3. {http://calendarserver.org/ns/}subscribed-strip-todos (omit if todos
|
||||
* should not be stripped).
|
||||
* 4. {http://calendarserver.org/ns/}subscribed-strip-alarms (omit if alarms
|
||||
* should not be stripped).
|
||||
* 5. {http://calendarserver.org/ns/}subscribed-strip-attachments (omit if
|
||||
* attachments should not be stripped).
|
||||
* 6. {http://calendarserver.org/ns/}source (Must be a
|
||||
* Sabre\DAV\Property\Href).
|
||||
* 7. {http://apple.com/ns/ical/}calendar-color
|
||||
* 8. {http://apple.com/ns/ical/}calendar-order
|
||||
* 9. {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
|
||||
* (should just be an instance of
|
||||
* Sabre\CalDAV\Property\SupportedCalendarComponentSet, with a bunch of
|
||||
* default components).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDescription();
|
||||
|
||||
/**
|
||||
* The getChanges method returns all the changes that have happened, since
|
||||
* the specified syncToken in the specified calendar.
|
||||
*
|
||||
* @param string|null $calendarId
|
||||
* @param string $syncToken
|
||||
* @return array
|
||||
*/
|
||||
public function getChanges($calendarId, $syncToken);
|
||||
|
||||
/**
|
||||
* Returns calendar object.
|
||||
*
|
||||
* It returns an array with the following keys:
|
||||
* * calendardata - The iCalendar-compatible calendar data
|
||||
* * uri - a unique key which will be used to construct the uri. This can
|
||||
* be any arbitrary string, but making sure it ends with '.ics' is a
|
||||
* good idea. This is only the basename, or filename, not the full
|
||||
* path.
|
||||
* * lastmodified - a timestamp of the last modification time
|
||||
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
|
||||
* '"abcdef"')
|
||||
* * size - The size of the calendar objects, in bytes.
|
||||
* * component - optional, a string containing the type of object, such
|
||||
* as 'vevent' or 'vtodo'. If specified, this will be used to populate
|
||||
* the Content-Type header.
|
||||
*
|
||||
* Note that the etag is optional, but it's highly encouraged to return for
|
||||
* speed reasons.
|
||||
*
|
||||
* @param mixed $obj
|
||||
* @return array
|
||||
*/
|
||||
public function prepareData($obj);
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param string|null $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateOrCreateCalendarObject($calendarId, $objectUri, $calendarData): ?string;
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* The object uri is only the basename, or filename and not a full path.
|
||||
*
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendarObject($objectUri);
|
||||
}
|
||||
100
app/Http/Controllers/DAV/Backend/CardDAV/AddressBook.php
Normal file
100
app/Http/Controllers/DAV/Backend/CardDAV/AddressBook.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CardDAV;
|
||||
|
||||
use Sabre\CardDAV\AddressBook as BaseAddressBook;
|
||||
|
||||
class AddressBook extends BaseAddressBook
|
||||
{
|
||||
/**
|
||||
* Returns a list of ACE's for this node.
|
||||
*
|
||||
* Each ACE has the following properties:
|
||||
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||
* currently the only supported privileges
|
||||
* * 'principal', a url to the principal who owns the node
|
||||
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||
* be updated.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getACL()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => '{DAV:}owner',
|
||||
'protected' => true,
|
||||
],
|
||||
[
|
||||
'privilege' => '{DAV:}write-content',
|
||||
'principal' => '{DAV:}owner',
|
||||
'protected' => true,
|
||||
],
|
||||
[
|
||||
'privilege' => '{DAV:}bind',
|
||||
'principal' => '{DAV:}owner',
|
||||
'protected' => true,
|
||||
],
|
||||
[
|
||||
'privilege' => '{DAV:}unbind',
|
||||
'principal' => '{DAV:}owner',
|
||||
'protected' => true,
|
||||
],
|
||||
[
|
||||
'privilege' => '{DAV:}write-properties',
|
||||
'principal' => '{DAV:}owner',
|
||||
'protected' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the ACL's for card nodes in this address book.
|
||||
* The result of this method automatically gets passed to the
|
||||
* card nodes in this address book.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildACL()
|
||||
{
|
||||
return $this->getACL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getLastModified(): ?int
|
||||
{
|
||||
$carddavBackend = $this->carddavBackend;
|
||||
if ($carddavBackend instanceof CardDAVBackend) {
|
||||
$date = $carddavBackend->getLastModified(null);
|
||||
if (! is_null($date)) {
|
||||
return (int) $date->timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the current sync-token for this collection.
|
||||
* This can be any string.
|
||||
*
|
||||
* If null is returned from this function, the plugin assumes there's no
|
||||
* sync information available.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSyncToken(): ?string
|
||||
{
|
||||
$carddavBackend = $this->carddavBackend;
|
||||
if ($carddavBackend instanceof CardDAVBackend) {
|
||||
return (string) $carddavBackend->refreshSyncToken(null)->id;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
45
app/Http/Controllers/DAV/Backend/CardDAV/AddressBookHome.php
Normal file
45
app/Http/Controllers/DAV/Backend/CardDAV/AddressBookHome.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CardDAV;
|
||||
|
||||
use Sabre\CardDAV\AddressBookHome as BaseAddressBookHome;
|
||||
|
||||
class AddressBookHome extends BaseAddressBookHome
|
||||
{
|
||||
/**
|
||||
* Returns a list of ACE's for this node.
|
||||
*
|
||||
* Each ACE has the following properties:
|
||||
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||
* currently the only supported privileges
|
||||
* * 'principal', a url to the principal who owns the node
|
||||
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||
* be updated.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getACL()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => '{DAV:}owner',
|
||||
'protected' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of addressbooks.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
$addressBooks = $this->carddavBackend->getAddressBooksForUser($this->principalUri);
|
||||
|
||||
return collect($addressBooks)->map(function (array $addressBook): AddressBook {
|
||||
return new AddressBook($this->carddavBackend, $addressBook);
|
||||
})->toArray();
|
||||
}
|
||||
}
|
||||
51
app/Http/Controllers/DAV/Backend/CardDAV/AddressBookRoot.php
Normal file
51
app/Http/Controllers/DAV/Backend/CardDAV/AddressBookRoot.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CardDAV;
|
||||
|
||||
use Sabre\DAVACL\IACL;
|
||||
use Sabre\DAVACL\ACLTrait;
|
||||
use Sabre\CardDAV\AddressBookRoot as BaseAddressBookRoot;
|
||||
|
||||
class AddressBookRoot extends BaseAddressBookRoot implements IACL
|
||||
{
|
||||
use ACLTrait;
|
||||
|
||||
/**
|
||||
* Returns a list of ACE's for this node.
|
||||
*
|
||||
* Each ACE has the following properties:
|
||||
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||
* currently the only supported privileges
|
||||
* * 'principal', a url to the principal who owns the node
|
||||
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||
* be updated.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getACL()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => '{DAV:}authenticated',
|
||||
'protected' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a node for a principal.
|
||||
*
|
||||
* The passed array contains principal information, and is guaranteed to
|
||||
* at least contain a uri item. Other properties may or may not be
|
||||
* supplied by the authentication backend.
|
||||
*
|
||||
* @param array $principal
|
||||
* @return \Sabre\DAV\INode
|
||||
* @psalm-suppress ParamNameMismatch
|
||||
*/
|
||||
public function getChildForPrincipal(array $principal)
|
||||
{
|
||||
return new AddressBookHome($this->carddavBackend, $principal['uri']);
|
||||
}
|
||||
}
|
||||
486
app/Http/Controllers/DAV/Backend/CardDAV/CardDAVBackend.php
Normal file
486
app/Http/Controllers/DAV/Backend/CardDAV/CardDAVBackend.php
Normal file
@@ -0,0 +1,486 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend\CardDAV;
|
||||
|
||||
use Sabre\DAV;
|
||||
use App\Jobs\Dav\UpdateVCard;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Services\VCard\GetEtag;
|
||||
use App\Models\Account\AddressBook;
|
||||
use App\Services\VCard\ExportVCard;
|
||||
use Illuminate\Support\Facades\Bus;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Sabre\DAV\Server as SabreServer;
|
||||
use Sabre\CardDAV\Backend\SyncSupport;
|
||||
use Sabre\CalDAV\Plugin as CalDAVPlugin;
|
||||
use Sabre\CardDAV\Backend\AbstractBackend;
|
||||
use Sabre\CardDAV\Plugin as CardDAVPlugin;
|
||||
use Sabre\DAV\Sync\Plugin as DAVSyncPlugin;
|
||||
use App\Services\Contact\Contact\SetMeContact;
|
||||
use App\Services\Contact\Contact\DestroyContact;
|
||||
use App\Http\Controllers\DAV\Backend\IDAVBackend;
|
||||
use App\Http\Controllers\DAV\Backend\SyncDAVBackend;
|
||||
use App\Http\Controllers\DAV\DAVACL\PrincipalBackend;
|
||||
use App\Services\DavClient\Utils\Model\ContactUpdateDto;
|
||||
|
||||
class CardDAVBackend extends AbstractBackend implements SyncSupport, IDAVBackend
|
||||
{
|
||||
use SyncDAVBackend;
|
||||
|
||||
/**
|
||||
* Returns the uri for this backend.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function backendUri()
|
||||
{
|
||||
return 'contacts';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of addressbooks for a specific user.
|
||||
*
|
||||
* Every addressbook should have the following properties:
|
||||
* id - an arbitrary unique id
|
||||
* uri - the 'basename' part of the url
|
||||
* principaluri - Same as the passed parameter
|
||||
*
|
||||
* Any additional clark-notation property may be passed besides this. Some
|
||||
* common ones are :
|
||||
* {DAV:}displayname
|
||||
* {urn:ietf:params:xml:ns:carddav}addressbook-description
|
||||
* {http://calendarserver.org/ns/}getctag
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getAddressBooksForUser($principalUri)
|
||||
{
|
||||
$result = [];
|
||||
$result[] = $this->getDefaultAddressBook();
|
||||
|
||||
$addressBooks = AddressBook::where('account_id', $this->user->account_id)
|
||||
->get();
|
||||
|
||||
foreach ($addressBooks as $addressBook) {
|
||||
$result[] = $this->getAddressBookDetails($addressBook);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function getDefaultAddressBook()
|
||||
{
|
||||
$des = $this->getAddressBookDetails(null);
|
||||
|
||||
$me = auth()->user()->me;
|
||||
if ($me) {
|
||||
$des += [
|
||||
'{'.CalDAVPlugin::NS_CALENDARSERVER.'}me-card' => '/'.config('laravelsabre.path').'/addressbooks/'.$this->user->email.'/contacts/'.$this->encodeUri($me),
|
||||
];
|
||||
}
|
||||
|
||||
return $des;
|
||||
}
|
||||
|
||||
private function getAddressBookDetails($addressBook)
|
||||
{
|
||||
$id = $addressBook ? $addressBook->name : $this->backendUri();
|
||||
$token = $this->getCurrentSyncToken($addressBook);
|
||||
|
||||
$des = [
|
||||
'id' => $id,
|
||||
'uri' => $id,
|
||||
'principaluri' => PrincipalBackend::getPrincipalUser($this->user),
|
||||
'{DAV:}displayname' => trans('app.dav_contacts'),
|
||||
'{'.CardDAVPlugin::NS_CARDDAV.'}addressbook-description' => $addressBook ? $addressBook->description : trans('app.dav_contacts_description', ['name' => $this->user->name]),
|
||||
];
|
||||
if ($token) {
|
||||
$des += [
|
||||
'{DAV:}sync-token' => $token->id,
|
||||
'{'.SabreServer::NS_SABREDAV.'}sync-token' => $token->id,
|
||||
'{'.CalDAVPlugin::NS_CALENDARSERVER.'}getctag' => DAVSyncPlugin::SYNCTOKEN_PREFIX.$token->id,
|
||||
];
|
||||
}
|
||||
|
||||
return $des;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension for Calendar objects.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExtension()
|
||||
{
|
||||
return '.vcf';
|
||||
}
|
||||
|
||||
/**
|
||||
* The getChanges method returns all the changes that have happened, since
|
||||
* the specified syncToken in the specified address book.
|
||||
*
|
||||
* This function should return an array, such as the following:
|
||||
*
|
||||
* [
|
||||
* 'syncToken' => 'The current synctoken',
|
||||
* 'added' => [
|
||||
* 'new.txt',
|
||||
* ],
|
||||
* 'modified' => [
|
||||
* 'modified.txt',
|
||||
* ],
|
||||
* 'deleted' => [
|
||||
* 'foo.php.bak',
|
||||
* 'old.txt'
|
||||
* ]
|
||||
* ];
|
||||
*
|
||||
* The returned syncToken property should reflect the *current* syncToken
|
||||
* of the calendar, as reported in the {http://sabredav.org/ns}sync-token
|
||||
* property. This is needed here too, to ensure the operation is atomic.
|
||||
*
|
||||
* If the $syncToken argument is specified as null, this is an initial
|
||||
* sync, and all members should be reported.
|
||||
*
|
||||
* The modified property is an array of nodenames that have changed since
|
||||
* the last token.
|
||||
*
|
||||
* The deleted property is an array with nodenames, that have been deleted
|
||||
* from collection.
|
||||
*
|
||||
* The $syncLevel argument is basically the 'depth' of the report. If it's
|
||||
* 1, you only have to report changes that happened only directly in
|
||||
* immediate descendants. If it's 2, it should also include changes from
|
||||
* the nodes below the child collections. (grandchildren)
|
||||
*
|
||||
* The $limit argument allows a client to specify how many results should
|
||||
* be returned at most. If the limit is not specified, it should be treated
|
||||
* as infinite.
|
||||
*
|
||||
* If the limit (infinite or not) is higher than you're willing to return,
|
||||
* you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
|
||||
*
|
||||
* If the syncToken is expired (due to data cleanup) or unknown, you must
|
||||
* return null.
|
||||
*
|
||||
* The limit is 'suggestive'. You are free to ignore it.
|
||||
*
|
||||
* @param string $addressBookId
|
||||
* @param string $syncToken
|
||||
* @param int $syncLevel
|
||||
* @param int $limit
|
||||
* @return array|null
|
||||
*/
|
||||
public function getChangesForAddressBook($addressBookId, $syncToken, $syncLevel, $limit = null): ?array
|
||||
{
|
||||
return $this->getChanges($addressBookId, $syncToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare datas for this contact.
|
||||
*
|
||||
* @param Contact $contact
|
||||
* @return array
|
||||
*/
|
||||
public function prepareCard($contact): array
|
||||
{
|
||||
$carddata = $contact->vcard;
|
||||
try {
|
||||
if (empty($carddata)) {
|
||||
$carddata = $this->refreshObject($contact);
|
||||
}
|
||||
|
||||
$etag = app(GetEtag::class)->execute([
|
||||
'account_id' => $this->user->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
]);
|
||||
|
||||
return [
|
||||
'contact_id' => $contact->id,
|
||||
'uri' => $this->encodeUri($contact),
|
||||
'carddata' => $carddata,
|
||||
'etag' => $etag,
|
||||
'distant_etag' => $contact->distant_etag,
|
||||
'lastmodified' => $contact->updated_at->timestamp,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
Log::error(__CLASS__.' '.__FUNCTION__.': '.$e->getMessage(), [
|
||||
'carddata' => $carddata,
|
||||
'contact_id' => $contact->id,
|
||||
$e,
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new exported version of the object.
|
||||
*
|
||||
* @param mixed $obj contact
|
||||
* @return string
|
||||
*/
|
||||
protected function refreshObject($obj): string
|
||||
{
|
||||
$vcard = app(ExportVCard::class)
|
||||
->execute([
|
||||
'account_id' => $this->user->account_id,
|
||||
'contact_id' => $obj->id,
|
||||
]);
|
||||
|
||||
return $vcard->serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact for the specific uuid.
|
||||
*
|
||||
* @param mixed|null $collectionId
|
||||
* @param string $uuid
|
||||
* @return Contact
|
||||
*/
|
||||
public function getObjectUuid($collectionId, $uuid)
|
||||
{
|
||||
$addressBook = null;
|
||||
if ($collectionId && $collectionId != $this->backendUri()) {
|
||||
$addressBook = AddressBook::where([
|
||||
'account_id' => $this->user->account_id,
|
||||
'name' => $collectionId,
|
||||
])->first();
|
||||
}
|
||||
|
||||
return Contact::where([
|
||||
'account_id' => $this->user->account_id,
|
||||
'uuid' => $uuid,
|
||||
'address_book_id' => $addressBook ? $addressBook->id : null,
|
||||
])->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of all active contacts.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Illuminate\Support\Collection<array-key, Contact>
|
||||
*/
|
||||
public function getObjects($collectionId)
|
||||
{
|
||||
return $this->user->account->contacts($collectionId)
|
||||
->real()
|
||||
->active()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of deleted contacts.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Illuminate\Support\Collection<array-key, Contact>
|
||||
*/
|
||||
public function getDeletedObjects($collectionId)
|
||||
{
|
||||
return $this->user->account->contacts($collectionId)
|
||||
->onlyTrashed()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all cards for a specific addressbook id.
|
||||
*
|
||||
* This method should return the following properties for each card:
|
||||
* * carddata - raw vcard data
|
||||
* * uri - Some unique url
|
||||
* * lastmodified - A unix timestamp
|
||||
*
|
||||
* It's recommended to also return the following properties:
|
||||
* * etag - A unique etag. This must change every time the card changes.
|
||||
* * size - The size of the card in bytes.
|
||||
*
|
||||
* If these last two properties are provided, less time will be spent
|
||||
* calculating them. If they are specified, you can also ommit carddata.
|
||||
* This may speed up certain requests, especially with large cards.
|
||||
*
|
||||
* @param mixed $addressbookId
|
||||
* @return array
|
||||
*/
|
||||
public function getCards($addressbookId)
|
||||
{
|
||||
$contacts = $this->getObjects($addressbookId);
|
||||
|
||||
return $contacts->map(function ($contact) {
|
||||
return $this->prepareCard($contact);
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific card.
|
||||
*
|
||||
* The same set of properties must be returned as with getCards. The only
|
||||
* exception is that 'carddata' is absolutely required.
|
||||
*
|
||||
* If the card does not exist, you must return false.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getCard($addressBookId, $cardUri)
|
||||
{
|
||||
$contact = $this->getObject($addressBookId, $cardUri);
|
||||
|
||||
if ($contact) {
|
||||
return $this->prepareCard($contact);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new card.
|
||||
*
|
||||
* The addressbook id will be passed as the first argument. This is the
|
||||
* same id as it is returned from the getAddressBooksForUser method.
|
||||
*
|
||||
* The cardUri is a base uri, and doesn't include the full path. The
|
||||
* cardData argument is the vcard body, and is passed as a string.
|
||||
*
|
||||
* It is possible to return an ETag from this method. This ETag is for the
|
||||
* newly created resource, and must be enclosed with double quotes (that
|
||||
* is, the string itself must contain the double quotes).
|
||||
*
|
||||
* You should only return the ETag if you store the carddata as-is. If a
|
||||
* subsequent GET request on the same card does not have the same body,
|
||||
* byte-by-byte and you did return an ETag here, clients tend to get
|
||||
* confused.
|
||||
*
|
||||
* If you don't return an ETag, you can just return null.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $cardData
|
||||
* @return string|null
|
||||
*/
|
||||
public function createCard($addressBookId, $cardUri, $cardData)
|
||||
{
|
||||
return $this->updateCard($addressBookId, $cardUri, $cardData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a card.
|
||||
*
|
||||
* The addressbook id will be passed as the first argument. This is the
|
||||
* same id as it is returned from the getAddressBooksForUser method.
|
||||
*
|
||||
* The cardUri is a base uri, and doesn't include the full path. The
|
||||
* cardData argument is the vcard body, and is passed as a string.
|
||||
*
|
||||
* It is possible to return an ETag from this method. This ETag should
|
||||
* match that of the updated resource, and must be enclosed with double
|
||||
* quotes (that is: the string itself must contain the actual quotes).
|
||||
*
|
||||
* You should only return the ETag if you store the carddata as-is. If a
|
||||
* subsequent GET request on the same card does not have the same body,
|
||||
* byte-by-byte and you did return an ETag here, clients tend to get
|
||||
* confused.
|
||||
*
|
||||
* If you don't return an ETag, you can just return null.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string|resource $cardData
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateCard($addressBookId, $cardUri, $cardData): ?string
|
||||
{
|
||||
$job = new UpdateVCard($this->user, $addressBookId, new ContactUpdateDto($cardUri, null, $cardData));
|
||||
|
||||
Bus::batch([$job])
|
||||
->allowFailures()
|
||||
->dispatch();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a card.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteCard($addressBookId, $cardUri)
|
||||
{
|
||||
$contact = $this->getObject($addressBookId, $cardUri);
|
||||
|
||||
if ($contact) {
|
||||
DestroyContact::dispatch([
|
||||
'account_id' => $contact->account_id,
|
||||
'contact_id' => $contact->id,
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties for an address book.
|
||||
*
|
||||
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||
* To do the actual updates, you must tell this object which properties
|
||||
* you're going to process with the handle() method.
|
||||
*
|
||||
* Calling the handle method is like telling the PropPatch object "I
|
||||
* promise I can handle updating this property".
|
||||
*
|
||||
* Read the PropPatch documentation for more info and examples.
|
||||
*
|
||||
* @param string $addressBookId
|
||||
* @param \Sabre\DAV\PropPatch $propPatch
|
||||
* @return bool|null
|
||||
*/
|
||||
public function updateAddressBook($addressBookId, DAV\PropPatch $propPatch): ?bool
|
||||
{
|
||||
$propPatch->handle('{'.CalDAVPlugin::NS_CALENDARSERVER.'}me-card', function ($props) use ($addressBookId) {
|
||||
$contact = $this->getObject($addressBookId, $props->getHref());
|
||||
|
||||
$data = [
|
||||
'contact_id' => $contact->id,
|
||||
'account_id' => $this->user->account_id,
|
||||
'user_id' => $this->user->id,
|
||||
];
|
||||
|
||||
app(SetMeContact::class)->execute($data);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new address book.
|
||||
*
|
||||
* This method should return the id of the new address book. The id can be
|
||||
* in any format, including ints, strings, arrays or objects.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $url Just the 'basename' of the url.
|
||||
* @param array $properties
|
||||
* @return int|bool
|
||||
*/
|
||||
public function createAddressBook($principalUri, $url, array $properties)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entire addressbook and all its contents.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @return bool|null
|
||||
*/
|
||||
public function deleteAddressBook($addressBookId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
37
app/Http/Controllers/DAV/Backend/IDAVBackend.php
Normal file
37
app/Http/Controllers/DAV/Backend/IDAVBackend.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend;
|
||||
|
||||
interface IDAVBackend
|
||||
{
|
||||
/**
|
||||
* Returns the uri for this backend.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function backendUri();
|
||||
|
||||
/**
|
||||
* Returns the object for the specific uuid.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @param string $uuid
|
||||
* @return mixed
|
||||
*/
|
||||
public function getObjectUuid($collectionId, $uuid);
|
||||
|
||||
/**
|
||||
* Returns the collection of objects.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getObjects($collectionId);
|
||||
|
||||
/**
|
||||
* Returns the extension for this backend.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getExtension();
|
||||
}
|
||||
288
app/Http/Controllers/DAV/Backend/SyncDAVBackend.php
Normal file
288
app/Http/Controllers/DAV/Backend/SyncDAVBackend.php
Normal file
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\Backend;
|
||||
|
||||
use App\Traits\WithUser;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\User\SyncToken;
|
||||
|
||||
trait SyncDAVBackend
|
||||
{
|
||||
use WithUser;
|
||||
|
||||
/**
|
||||
* This method returns a sync-token for this collection.
|
||||
*
|
||||
* If null is returned from this function, the plugin assumes there's no
|
||||
* sync information available.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return SyncToken|null
|
||||
*/
|
||||
public function getCurrentSyncToken($collectionId): ?SyncToken
|
||||
{
|
||||
$tokens = SyncToken::where([
|
||||
'account_id' => $this->user->account_id,
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $collectionId ?? $this->backendUri(),
|
||||
])
|
||||
->orderBy('created_at')
|
||||
->get();
|
||||
|
||||
return $tokens->count() > 0 ? $tokens->last() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or refresh the token if a change happened.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return SyncToken
|
||||
*/
|
||||
public function refreshSyncToken($collectionId): SyncToken
|
||||
{
|
||||
$token = $this->getCurrentSyncToken($collectionId);
|
||||
|
||||
if (! $token || $token->timestamp < $this->getLastModified($collectionId)) {
|
||||
$token = $this->createSyncTokenNow($collectionId);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SyncToken by token id.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @param string $syncToken
|
||||
* @return SyncToken|null
|
||||
*/
|
||||
protected function getSyncToken($collectionId, $syncToken)
|
||||
{
|
||||
/** @var SyncToken|null */
|
||||
return SyncToken::where([
|
||||
'account_id' => $this->user->account_id,
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $collectionId ?? $this->backendUri(),
|
||||
])
|
||||
->find($syncToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a token with now timestamp.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return SyncToken
|
||||
*/
|
||||
private function createSyncTokenNow($collectionId)
|
||||
{
|
||||
return SyncToken::create([
|
||||
'account_id' => $this->user->account_id,
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $collectionId ?? $this->backendUri(),
|
||||
'timestamp' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Carbon\Carbon|null
|
||||
*/
|
||||
public function getLastModified($collectionId)
|
||||
{
|
||||
return $this->getObjects($collectionId)
|
||||
->map(function ($object) {
|
||||
return $object->updated_at;
|
||||
})
|
||||
->max();
|
||||
}
|
||||
|
||||
/**
|
||||
* The getChanges method returns all the changes that have happened, since
|
||||
* the specified syncToken.
|
||||
*
|
||||
* This function should return an array, such as the following:
|
||||
*
|
||||
* [
|
||||
* 'syncToken' => 'The current synctoken',
|
||||
* 'added' => [
|
||||
* 'new.txt',
|
||||
* ],
|
||||
* 'modified' => [
|
||||
* 'modified.txt',
|
||||
* ],
|
||||
* 'deleted' => [
|
||||
* 'foo.php.bak',
|
||||
* 'old.txt'
|
||||
* ]
|
||||
* );
|
||||
*
|
||||
* The returned syncToken property should reflect the *current* syncToken
|
||||
* , as reported in the {http://sabredav.org/ns}sync-token
|
||||
* property This is * needed here too, to ensure the operation is atomic.
|
||||
*
|
||||
* If the $syncToken argument is specified as null, this is an initial
|
||||
* sync, and all members should be reported.
|
||||
*
|
||||
* The modified property is an array of nodenames that have changed since
|
||||
* the last token.
|
||||
*
|
||||
* The deleted property is an array with nodenames, that have been deleted
|
||||
* from collection.
|
||||
*
|
||||
* The $syncLevel argument is basically the 'depth' of the report. If it's
|
||||
* 1, you only have to report changes that happened only directly in
|
||||
* immediate descendants. If it's 2, it should also include changes from
|
||||
* the nodes below the child collections. (grandchildren)
|
||||
*
|
||||
* The $limit argument allows a client to specify how many results should
|
||||
* be returned at most. If the limit is not specified, it should be treated
|
||||
* as infinite.
|
||||
*
|
||||
* If the limit (infinite or not) is higher than you're willing to return,
|
||||
* you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
|
||||
*
|
||||
* If the syncToken is expired (due to data cleanup) or unknown, you must
|
||||
* return null.
|
||||
*
|
||||
* The limit is 'suggestive'. You are free to ignore it.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $syncToken
|
||||
* @return array|null
|
||||
*/
|
||||
public function getChanges($calendarId, $syncToken): ?array
|
||||
{
|
||||
$token = null;
|
||||
$timestamp = null;
|
||||
if (! empty($syncToken)) {
|
||||
$token = $this->getSyncToken($calendarId, $syncToken);
|
||||
|
||||
if (is_null($token)) {
|
||||
// syncToken is not recognized
|
||||
return null;
|
||||
}
|
||||
|
||||
$timestamp = $token->timestamp;
|
||||
}
|
||||
|
||||
$objs = $this->getObjects($calendarId);
|
||||
|
||||
$modified = $objs->filter(function ($obj) use ($timestamp) {
|
||||
return ! is_null($timestamp) &&
|
||||
$obj->updated_at > $timestamp &&
|
||||
$obj->created_at < $timestamp;
|
||||
});
|
||||
$added = $objs->filter(function ($obj) use ($timestamp) {
|
||||
return is_null($timestamp) ||
|
||||
$obj->created_at >= $timestamp;
|
||||
});
|
||||
$deleted = $this->getDeletedObjects($calendarId)
|
||||
->filter(function ($obj) use ($timestamp) {
|
||||
$d = $obj->deleted_at;
|
||||
|
||||
return is_null($timestamp) ||
|
||||
$obj->deleted_at >= $timestamp;
|
||||
});
|
||||
|
||||
return [
|
||||
'syncToken' => $this->refreshSyncToken($calendarId)->id,
|
||||
'added' => $added->map(function ($obj) {
|
||||
return $this->encodeUri($obj);
|
||||
})->values()->toArray(),
|
||||
'modified' => $modified->map(function ($obj) {
|
||||
$this->refreshObject($obj);
|
||||
|
||||
return $this->encodeUri($obj);
|
||||
})->values()->toArray(),
|
||||
'deleted' => $deleted->map(function ($obj) {
|
||||
return $this->encodeUri($obj);
|
||||
})->values()->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function encodeUri($obj): string
|
||||
{
|
||||
if (empty($obj->uuid)) {
|
||||
// refresh model from database
|
||||
$obj->refresh();
|
||||
|
||||
if (empty($obj->uuid)) {
|
||||
// in case uuid is still not set, do it
|
||||
$obj->forceFill([
|
||||
'uuid' => Str::uuid(),
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
|
||||
return urlencode($obj->uuid.$this->getExtension());
|
||||
}
|
||||
|
||||
private function decodeUri($uri): string
|
||||
{
|
||||
return pathinfo(urldecode($uri), PATHINFO_FILENAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact uuid for the specific uri.
|
||||
*
|
||||
* @param string $uri
|
||||
* @return string
|
||||
*/
|
||||
public function getUuid($uri): string
|
||||
{
|
||||
return $this->decodeUri($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact for the specific uri.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @param string $uri
|
||||
* @return mixed
|
||||
*/
|
||||
public function getObject($collectionId, $uri)
|
||||
{
|
||||
try {
|
||||
return $this->getObjectUuid($collectionId, $this->getUuid($uri));
|
||||
} catch (\Exception $e) {
|
||||
// Object not found
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object for the specific uuid.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @param string $uuid
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function getObjectUuid($collectionId, $uuid);
|
||||
|
||||
/**
|
||||
* Returns the collection of objects.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
abstract public function getObjects($collectionId);
|
||||
|
||||
/**
|
||||
* Returns the collection of objects.
|
||||
*
|
||||
* @param string|null $collectionId
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
abstract public function getDeletedObjects($collectionId);
|
||||
|
||||
abstract public function getExtension();
|
||||
|
||||
/**
|
||||
* Get the new exported version of the object.
|
||||
*
|
||||
* @param mixed $obj
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function refreshObject($obj): string;
|
||||
}
|
||||
203
app/Http/Controllers/DAV/DAVACL/PrincipalBackend.php
Normal file
203
app/Http/Controllers/DAV/DAVACL/PrincipalBackend.php
Normal file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV\DAVACL;
|
||||
|
||||
use Sabre\DAV;
|
||||
use App\Traits\WithUser;
|
||||
use Illuminate\Support\Str;
|
||||
use Sabre\DAV\Server as SabreServer;
|
||||
use Sabre\DAVACL\PrincipalBackend\AbstractBackend;
|
||||
|
||||
class PrincipalBackend extends AbstractBackend
|
||||
{
|
||||
use WithUser;
|
||||
|
||||
/**
|
||||
* This is the prefix that will be used to generate principal urls.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const PRINCIPAL_PREFIX = 'principals/';
|
||||
|
||||
/**
|
||||
* Get the principal for user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getPrincipalUser($user): string
|
||||
{
|
||||
return static::PRINCIPAL_PREFIX.$user->email;
|
||||
}
|
||||
|
||||
protected function getPrincipals()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'uri' => static::getPrincipalUser($this->user),
|
||||
'{DAV:}displayname' => $this->user->name,
|
||||
'{'.SabreServer::NS_SABREDAV.'}email-address' => $this->user->email,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of principals based on a prefix.
|
||||
*
|
||||
* This prefix will often contain something like 'principals'. You are only
|
||||
* expected to return principals that are in this base path.
|
||||
*
|
||||
* You are expected to return at least a 'uri' for every user, you can
|
||||
* return any additional properties if you wish so. Common properties are:
|
||||
* {DAV:}displayname
|
||||
* {http://sabredav.org/ns}email-address - This is a custom SabreDAV
|
||||
* field that's actually injected in a number of other properties. If
|
||||
* you have an email address, use this property.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @return array
|
||||
*/
|
||||
public function getPrincipalsByPrefix($prefixPath)
|
||||
{
|
||||
$prefixPath = Str::finish($prefixPath, '/');
|
||||
|
||||
return array_filter($this->getPrincipals(), function ($principal) use ($prefixPath) {
|
||||
return ! $prefixPath || strpos($principal['uri'], $prefixPath) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific principal, specified by its path.
|
||||
* The returned structure should be the exact same as from
|
||||
* getPrincipalsByPrefix.
|
||||
*
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
public function getPrincipalByPath($path)
|
||||
{
|
||||
foreach ($this->getPrincipalsByPrefix(static::PRINCIPAL_PREFIX) as $principal) {
|
||||
if ($principal['uri'] === $path) {
|
||||
return $principal;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates one ore more webdav properties on a principal.
|
||||
*
|
||||
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||
* To do the actual updates, you must tell this object which properties
|
||||
* you're going to process with the handle() method.
|
||||
*
|
||||
* Calling the handle method is like telling the PropPatch object "I
|
||||
* promise I can handle updating this property".
|
||||
*
|
||||
* Read the PropPatch documentation for more info and examples.
|
||||
*
|
||||
* @param string $path
|
||||
* @param \Sabre\DAV\PropPatch $propPatch
|
||||
* @return void
|
||||
*/
|
||||
public function updatePrincipal($path, DAV\PropPatch $propPatch)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to search for principals matching a set of
|
||||
* properties.
|
||||
*
|
||||
* This search is specifically used by RFC3744's principal-property-search
|
||||
* REPORT.
|
||||
*
|
||||
* The actual search should be a unicode-non-case-sensitive search. The
|
||||
* keys in searchProperties are the WebDAV property names, while the values
|
||||
* are the property values to search on.
|
||||
*
|
||||
* By default, if multiple properties are submitted to this method, the
|
||||
* various properties should be combined with 'AND'. If $test is set to
|
||||
* 'anyof', it should be combined using 'OR'.
|
||||
*
|
||||
* This method should simply return an array with full principal uri's.
|
||||
*
|
||||
* If somebody attempted to search on a property the backend does not
|
||||
* support, you should simply return 0 results.
|
||||
*
|
||||
* You can also just return 0 results if you choose to not support
|
||||
* searching at all, but keep in mind that this may stop certain features
|
||||
* from working.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @param array $searchProperties
|
||||
* @param string $test
|
||||
* @return array
|
||||
*/
|
||||
public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof')
|
||||
{
|
||||
$result = [];
|
||||
$principals = $this->getPrincipalsByPrefix($prefixPath);
|
||||
if (! $principals) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($principals as $principal) {
|
||||
$ok = false;
|
||||
foreach ($searchProperties as $key => $value) {
|
||||
if ($principal[$key] == $value) {
|
||||
$ok = true;
|
||||
} elseif ($test == 'allof') {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($ok) {
|
||||
$result[] = $principal['uri'];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of members for a group-principal.
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupMemberSet($principal)
|
||||
{
|
||||
$principal = $this->getPrincipalByPath($principal);
|
||||
if (! $principal) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
$principal['uri'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of groups a principal is a member of.
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupMembership($principal)
|
||||
{
|
||||
return $this->getGroupMemberSet($principal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of group members for a group principal.
|
||||
*
|
||||
* The principals should be passed as a list of uri's.
|
||||
*
|
||||
* @param string $principal
|
||||
* @param array $members
|
||||
* @return void
|
||||
*/
|
||||
public function setGroupMemberSet($principal, array $members)
|
||||
{
|
||||
}
|
||||
}
|
||||
34
app/Http/Controllers/DAV/DAVRedirect.php
Normal file
34
app/Http/Controllers/DAV/DAVRedirect.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\DAV;
|
||||
|
||||
use Sabre\DAV\Server;
|
||||
use Sabre\DAV\ServerPlugin;
|
||||
use Sabre\HTTP\RequestInterface;
|
||||
use Sabre\HTTP\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Redirect all GET methods to settings page.
|
||||
*/
|
||||
class DAVRedirect extends ServerPlugin
|
||||
{
|
||||
public function initialize(Server $server)
|
||||
{
|
||||
$server->on('method:GET', [$this, 'httpGet'], 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method intercepts GET requests to collections and returns the html.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return bool
|
||||
*/
|
||||
public function httpGet(RequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
$response->setStatus(302);
|
||||
$response->setHeader('Location', route('settings.dav'));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
184
app/Http/Controllers/DashboardController.php
Normal file
184
app/Http/Controllers/DashboardController.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use App\Models\Contact\Debt;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\AccountHelper;
|
||||
use function Safe\json_encode;
|
||||
use App\Helpers\InstanceHelper;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Http\Resources\Debt\Debt as DebtResource;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$account = auth()->user()->account()
|
||||
->withCount(
|
||||
'contacts', 'reminders', 'notes', 'activities', 'gifts', 'tasks'
|
||||
)->with('debts.contact')
|
||||
->first();
|
||||
|
||||
$numberOfContacts = $account->contacts()
|
||||
->real()
|
||||
->active()
|
||||
->count();
|
||||
|
||||
if ($numberOfContacts === 0) {
|
||||
return view('dashboard.blank');
|
||||
}
|
||||
|
||||
// Fetch last updated contacts
|
||||
$lastUpdatedContactsCollection = collect([]);
|
||||
$lastUpdatedContacts = $account->contacts()
|
||||
->real()
|
||||
->active()
|
||||
->alive()
|
||||
->latest('last_consulted_at')
|
||||
->limit(10)
|
||||
->get();
|
||||
foreach ($lastUpdatedContacts as $contact) {
|
||||
$data = [
|
||||
'id' => $contact->hashID(),
|
||||
'has_avatar' => $contact->has_avatar,
|
||||
'avatar_url' => $contact->getAvatarURL(),
|
||||
'initials' => $contact->getInitials(),
|
||||
'default_avatar_color' => $contact->default_avatar_color,
|
||||
'complete_name' => $contact->name,
|
||||
];
|
||||
$lastUpdatedContactsCollection->push(json_encode($data));
|
||||
}
|
||||
|
||||
$debts = $account->debts()->inProgress();
|
||||
|
||||
$debt_due = $debts->due()->get()
|
||||
->reduce(function ($totalDueDebt, Debt $debt) {
|
||||
return $totalDueDebt + $debt->amount;
|
||||
}, 0);
|
||||
|
||||
$debt_owed = $debts->owed()->get()
|
||||
->reduce(function ($totalOwedDebt, Debt $debt) {
|
||||
return $totalOwedDebt + $debt->amount;
|
||||
}, 0);
|
||||
|
||||
// get last 3 changelog entries
|
||||
$changelogs = InstanceHelper::getChangelogEntries(3);
|
||||
|
||||
// Load the reminderOutboxes for the upcoming three months
|
||||
$reminderOutboxes = [
|
||||
0 => AccountHelper::getUpcomingRemindersForMonth(auth()->user()->account, 0),
|
||||
1 => AccountHelper::getUpcomingRemindersForMonth(auth()->user()->account, 1),
|
||||
2 => AccountHelper::getUpcomingRemindersForMonth(auth()->user()->account, 2),
|
||||
];
|
||||
|
||||
$data = [
|
||||
'lastUpdatedContacts' => $lastUpdatedContactsCollection,
|
||||
'number_of_contacts' => $numberOfContacts,
|
||||
'number_of_reminders' => $account->reminders_count,
|
||||
'number_of_notes' => $account->notes_count,
|
||||
'number_of_activities' => $account->activities_count,
|
||||
'number_of_gifts' => $account->gifts_count,
|
||||
'number_of_tasks' => $account->tasks_count,
|
||||
'debt_due' => $debt_due,
|
||||
'debt_owed' => $debt_owed,
|
||||
'debts' => $debts,
|
||||
'user' => auth()->user(),
|
||||
'changelogs' => $changelogs,
|
||||
'reminderOutboxes' => $reminderOutboxes,
|
||||
];
|
||||
|
||||
return view('dashboard.index', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get calls for the dashboard.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function calls()
|
||||
{
|
||||
$callsCollection = collect([]);
|
||||
$calls = auth()->user()->account->calls()
|
||||
->get()
|
||||
->reject(function ($call) {
|
||||
return $call->contact === null;
|
||||
})
|
||||
->take(15);
|
||||
|
||||
foreach ($calls as $call) {
|
||||
$data = [
|
||||
'id' => $call->id,
|
||||
'called_at' => DateHelper::getShortDate($call->called_at),
|
||||
'name' => $call->contact->getIncompleteName(),
|
||||
'contact_id' => $call->contact->hashID(),
|
||||
];
|
||||
$callsCollection->push($data);
|
||||
}
|
||||
|
||||
return $callsCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notes for the dashboard.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function notes()
|
||||
{
|
||||
$notesCollection = collect([]);
|
||||
$notes = auth()->user()->account->notes()->favorited()->get();
|
||||
|
||||
foreach ($notes as $note) {
|
||||
$data = [
|
||||
'id' => $note->id,
|
||||
'body' => $note->body,
|
||||
'created_at' => DateHelper::getShortDate($note->created_at),
|
||||
'name' => $note->contact->getIncompleteName(),
|
||||
'contact' => [
|
||||
'id' => $note->contact->hashID(),
|
||||
'has_avatar' => $note->contact->has_avatar,
|
||||
'avatar_url' => $note->contact->getAvatarURL(),
|
||||
'initials' => $note->contact->getInitials(),
|
||||
'default_avatar_color' => $note->contact->default_avatar_color,
|
||||
'complete_name' => $note->contact->name,
|
||||
],
|
||||
];
|
||||
$notesCollection->push($data);
|
||||
}
|
||||
|
||||
return $notesCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get debts for the dashboard.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function debts()
|
||||
{
|
||||
$debtsCollection = collect([]);
|
||||
$debts = auth()->user()->account->debts()->get();
|
||||
|
||||
foreach ($debts as $debt) {
|
||||
$debtsCollection->push(new DebtResource($debt));
|
||||
}
|
||||
|
||||
return $debtsCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current active tab to the User table.
|
||||
*/
|
||||
public function setTab(Request $request)
|
||||
{
|
||||
auth()->user()->dashboard_active_tab = $request->input('tab');
|
||||
auth()->user()->save();
|
||||
}
|
||||
}
|
||||
48
app/Http/Controllers/EmotionController.php
Normal file
48
app/Http/Controllers/EmotionController.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Instance\Emotion\Emotion;
|
||||
use App\Models\Instance\Emotion\PrimaryEmotion;
|
||||
use App\Models\Instance\Emotion\SecondaryEmotion;
|
||||
use App\Http\Resources\Emotion\Emotion as EmotionResource;
|
||||
|
||||
class EmotionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get the list of primary emotions.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function primaries()
|
||||
{
|
||||
return EmotionResource::collection(PrimaryEmotion::get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of secondary emotions.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function secondaries(Request $request, $primaryEmotionId)
|
||||
{
|
||||
$secondaries = SecondaryEmotion::where('emotion_primary_id', $primaryEmotionId)
|
||||
->get();
|
||||
|
||||
return EmotionResource::collection($secondaries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of emotions.
|
||||
*
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function emotions(Request $request, $primaryEmotionId, $secondaryEmotionId)
|
||||
{
|
||||
$emotions = Emotion::where('emotion_secondary_id', $secondaryEmotionId)
|
||||
->get();
|
||||
|
||||
return EmotionResource::collection($emotions);
|
||||
}
|
||||
}
|
||||
273
app/Http/Controllers/JournalController.php
Normal file
273
app/Http/Controllers/JournalController.php
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\DateHelper;
|
||||
use App\Models\Journal\Day;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Journal\Entry;
|
||||
use App\Helpers\JournalHelper;
|
||||
use App\Models\Journal\JournalEntry;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Requests\Journal\DaysRequest;
|
||||
|
||||
class JournalController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('journal.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the journal entries.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
|
||||
$startDate = $request->input('start_date');
|
||||
$endDate = $request->input('end_date');
|
||||
$sortBy = $request->input('sort_by', 'created_at');
|
||||
$sortOrder = $request->input('sort_order', 'desc');
|
||||
$perPage = $request->input('per_page', 30);
|
||||
|
||||
$entries = collect([]);
|
||||
|
||||
$journalEntriesQuery = auth()->user()->account->journalEntries();
|
||||
|
||||
if ($startDate && $endDate) {
|
||||
$journalEntriesQuery->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
}
|
||||
$journalEntries = $journalEntriesQuery->orderBy($sortBy, $sortOrder)
|
||||
->paginate($perPage);
|
||||
|
||||
|
||||
// this is needed to determine if we need to display the calendar
|
||||
// (month + year) next to the journal entry
|
||||
$previousEntryMonth = 0;
|
||||
$previousEntryYear = 0;
|
||||
$showCalendar = true;
|
||||
|
||||
foreach ($journalEntries->items() as $journalEntry) {
|
||||
if ($previousEntryMonth == $journalEntry->date->month && $previousEntryYear == $journalEntry->date->year) {
|
||||
$showCalendar = false;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $journalEntry->id,
|
||||
'date' => $journalEntry->date,
|
||||
'journalable_id' => $journalEntry->journalable_id,
|
||||
'journalable_type' => $journalEntry->journalable_type,
|
||||
'object' => $journalEntry->getObjectData(),
|
||||
'show_calendar' => $showCalendar,
|
||||
];
|
||||
$entries->push($data);
|
||||
|
||||
$previousEntryMonth = $journalEntry->date->month;
|
||||
$previousEntryYear = $journalEntry->date->year;
|
||||
$showCalendar = true;
|
||||
}
|
||||
|
||||
// I need the pagination items when I send back the array.
|
||||
// There is probably a simpler way to achieve this.
|
||||
return [
|
||||
'total' => $journalEntries->total(),
|
||||
'per_page' => $journalEntries->perPage(),
|
||||
'current_page' => $journalEntries->currentPage(),
|
||||
'next_page_url' => $journalEntries->nextPageUrl(),
|
||||
'prev_page_url' => $journalEntries->previousPageUrl(),
|
||||
'data' => $entries,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the details of a single Journal Entry.
|
||||
*
|
||||
* @param JournalEntry $journalEntry
|
||||
* @return array
|
||||
*/
|
||||
public function get(JournalEntry $journalEntry)
|
||||
{
|
||||
return $journalEntry->getObjectData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the day entry.
|
||||
*/
|
||||
public function storeDay(DaysRequest $request)
|
||||
{
|
||||
$day = auth()->user()->account->days()->create([
|
||||
'date' => now(DateHelper::getTimezone()),
|
||||
'rate' => $request->input('rate'),
|
||||
'comment' => $request->input('comment'),
|
||||
]);
|
||||
|
||||
// Log a journal entry
|
||||
$journalEntry = JournalEntry::add($day);
|
||||
|
||||
return [
|
||||
'id' => $journalEntry->id,
|
||||
'date' => $journalEntry->date,
|
||||
'journalable_id' => $journalEntry->journalable_id,
|
||||
'journalable_type' => $journalEntry->journalable_type,
|
||||
'object' => $journalEntry->getObjectData(),
|
||||
'show_calendar' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the Day entry.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function trashDay(Day $day): void
|
||||
{
|
||||
$day->deleteJournalEntry();
|
||||
$day->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the user has already rated the current day.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function hasRated()
|
||||
{
|
||||
if (JournalHelper::hasAlreadyRatedToday(auth()->user())) {
|
||||
return 'true';
|
||||
}
|
||||
|
||||
return 'notYet';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the Create journal entry screen.
|
||||
*
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('journal.add');
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the journal entry.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'entry' => 'required|string',
|
||||
'date' => 'required|date',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($validator);
|
||||
}
|
||||
|
||||
$entry = new Entry;
|
||||
$entry->account_id = $request->user()->account_id;
|
||||
$entry->post = $request->input('entry');
|
||||
|
||||
if ($request->input('title') != '') {
|
||||
$entry->title = $request->input('title');
|
||||
}
|
||||
|
||||
$entry->save();
|
||||
|
||||
$entry->date = $request->input('date');
|
||||
// Log a journal entry
|
||||
JournalEntry::add($entry);
|
||||
|
||||
return redirect()->route('journal.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the Edit journal entry screen.
|
||||
*
|
||||
* @param Entry $entry
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Entry $entry)
|
||||
{
|
||||
return view('journal.edit')
|
||||
->withEntry($entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method updateDay
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Day $day
|
||||
*
|
||||
*/
|
||||
public function updateDay(Request $request, Day $day)
|
||||
{
|
||||
$validatedData = $request->validate([
|
||||
'comment' => 'required|string',
|
||||
]);
|
||||
|
||||
$day->update($validatedData);
|
||||
|
||||
return response()->json(['message' => 'Day updated successfully']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a journal entry.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Request $request, Entry $entry)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'entry' => 'required|string',
|
||||
'date' => 'required|date',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return back()
|
||||
->withInput()
|
||||
->withErrors($validator);
|
||||
}
|
||||
|
||||
$entry->post = $request->input('entry');
|
||||
|
||||
if ($request->input('title') != '') {
|
||||
$entry->title = $request->input('title');
|
||||
}
|
||||
|
||||
$entry->save();
|
||||
|
||||
// Update journal entry
|
||||
$journalEntry = $entry->journalEntry;
|
||||
if ($journalEntry) {
|
||||
$entry->date = $request->input('date');
|
||||
$journalEntry->edit($entry);
|
||||
}
|
||||
|
||||
return redirect()->route('journal.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the reminder.
|
||||
*/
|
||||
public function deleteEntry(Request $request, Entry $entry)
|
||||
{
|
||||
$entry->deleteJournalEntry();
|
||||
$entry->delete();
|
||||
|
||||
return ['true'];
|
||||
}
|
||||
}
|
||||
51
app/Http/Controllers/MeController.php
Normal file
51
app/Http/Controllers/MeController.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Contact\Contact;
|
||||
use App\Traits\JsonRespondController;
|
||||
use App\Services\Contact\Contact\SetMeContact;
|
||||
use App\Services\Contact\Contact\DeleteMeContact;
|
||||
|
||||
class MeController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Set a contact as 'me'.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'contact_id' => 'required|integer|exists:contacts,id',
|
||||
]);
|
||||
|
||||
app(SetMeContact::class)->execute([
|
||||
'contact_id' => $request->input('contact_id'),
|
||||
'account_id' => $request->user()->account_id,
|
||||
'user_id' => $request->user()->id,
|
||||
]);
|
||||
|
||||
return $this->respond(['true']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes contact as 'me' association.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
app(DeleteMeContact::class)->execute([
|
||||
'account_id' => $request->user()->account_id,
|
||||
'user_id' => $request->user()->id,
|
||||
]);
|
||||
|
||||
return $this->respond(['true']);
|
||||
}
|
||||
}
|
||||
28
app/Http/Controllers/Settings/AuditLogController.php
Normal file
28
app/Http/Controllers/Settings/AuditLogController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Helpers\AuditLogHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AuditLogController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the page listing all the audit logs.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$logs = auth()->user()->account->auditLogs()
|
||||
->with('author')
|
||||
->orderBy('created_at', 'desc')
|
||||
->paginate(15);
|
||||
|
||||
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
|
||||
|
||||
return view('settings.auditlog.index')
|
||||
->withLogsCollection(AuditLogHelper::getCollectionOfAudits($logs))
|
||||
->withAccountHasLimitations($accountHasLimitations)
|
||||
->withLogsPagination($logs);
|
||||
}
|
||||
}
|
||||
124
app/Http/Controllers/Settings/ExportController.php
Normal file
124
app/Http/Controllers/Settings/ExportController.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Jobs\ExportAccount;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\AccountHelper;
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Models\Account\ExportJob;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ExportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the export view.
|
||||
*
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$exports = ExportJob::where([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
])
|
||||
->orderByDesc('created_at')
|
||||
->get();
|
||||
|
||||
return view('settings.export')
|
||||
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account))
|
||||
->withExports($exports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the data of the account in SQL format.
|
||||
*
|
||||
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response|null
|
||||
*/
|
||||
public function storeSql()
|
||||
{
|
||||
$job = $this->newExport(ExportJob::SQL);
|
||||
ExportAccount::dispatch($job);
|
||||
|
||||
return redirect()->route('settings.export.index')
|
||||
->withStatus(trans('settings.export_submitted'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the data of the account in SQL format.
|
||||
*
|
||||
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response|null
|
||||
*/
|
||||
public function storeJson()
|
||||
{
|
||||
$job = $this->newExport(ExportJob::JSON);
|
||||
ExportAccount::dispatch($job);
|
||||
|
||||
return redirect()->route('settings.export.index')
|
||||
->withStatus(trans('settings.export_submitted'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ExportJob.
|
||||
*
|
||||
* @param string $type
|
||||
* @return ExportJob
|
||||
*/
|
||||
private function newExport(string $type): ExportJob
|
||||
{
|
||||
$exports = ExportJob::where([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
])
|
||||
->orderBy('created_at')
|
||||
->get();
|
||||
|
||||
if ($exports->count() >= config('monica.export_size')) {
|
||||
$job = $exports->first();
|
||||
try {
|
||||
if ($job->filename !== null) {
|
||||
StorageHelper::disk($job->location)
|
||||
->delete($job->filename);
|
||||
}
|
||||
} finally {
|
||||
$job->delete();
|
||||
}
|
||||
}
|
||||
|
||||
return ExportJob::create([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
'type' => $type,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the generated file.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $uuid
|
||||
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response|null
|
||||
*/
|
||||
public function download(Request $request, string $uuid)
|
||||
{
|
||||
$job = ExportJob::where([
|
||||
'account_id' => auth()->user()->account_id,
|
||||
'user_id' => auth()->user()->id,
|
||||
'uuid' => $uuid,
|
||||
])->firstOrFail();
|
||||
|
||||
if ($job->status !== ExportJob::EXPORT_DONE) {
|
||||
return redirect()->route('settings.export.index')
|
||||
->withErrors(trans('settings.export_not_done'));
|
||||
}
|
||||
$disk = StorageHelper::disk($job->location);
|
||||
|
||||
return $disk->response($job->filename,
|
||||
"monica.{$job->type}",
|
||||
[
|
||||
'Content-Type' => "application/{$job->type}; charset=utf-8",
|
||||
'Content-Disposition' => "attachment; filename=monica.{$job->type}",
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
178
app/Http/Controllers/Settings/GendersController.php
Normal file
178
app/Http/Controllers/Settings/GendersController.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\GenderHelper;
|
||||
use App\Models\Contact\Gender;
|
||||
use Illuminate\Validation\Rule;
|
||||
use App\Helpers\CollectionHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Requests\Settings\GendersRequest;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class GendersController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get all the gender types.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$gendersData = collect([]);
|
||||
$genders = auth()->user()->account->genders;
|
||||
|
||||
foreach ($genders as $gender) {
|
||||
$gendersData->push($this->formatData($gender));
|
||||
}
|
||||
|
||||
return CollectionHelper::sortByCollator($gendersData, 'name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the gender sex types.
|
||||
*/
|
||||
public function types()
|
||||
{
|
||||
$gendersData = collect([]);
|
||||
|
||||
$types = [
|
||||
Gender::MALE,
|
||||
Gender::FEMALE,
|
||||
Gender::OTHER,
|
||||
Gender::UNKNOWN,
|
||||
Gender::NONE,
|
||||
];
|
||||
|
||||
foreach ($types as $type) {
|
||||
$gendersData->push([
|
||||
'id' => $type,
|
||||
'name' => trans('settings.personalization_genders_'.strtolower($type)),
|
||||
]);
|
||||
}
|
||||
|
||||
return CollectionHelper::sortByCollator($gendersData, 'name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the gender.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
Validator::make($request->all(), [
|
||||
'name' => 'required|max:255',
|
||||
'type' => ['required', Rule::in(Gender::LIST)],
|
||||
])->validate();
|
||||
|
||||
$gender = auth()->user()->account->genders()->create(
|
||||
$request->only([
|
||||
'name',
|
||||
'type',
|
||||
])
|
||||
+ [
|
||||
'account_id' => auth()->user()->account_id,
|
||||
]
|
||||
);
|
||||
|
||||
if ($request->input('isDefault')) {
|
||||
$this->updateDefault($gender);
|
||||
}
|
||||
|
||||
return $this->formatData($gender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given gender.
|
||||
*/
|
||||
public function update(GendersRequest $request, Gender $gender)
|
||||
{
|
||||
$gender->update(
|
||||
$request->only([
|
||||
'name',
|
||||
'type',
|
||||
])
|
||||
);
|
||||
if ($request->input('isDefault')) {
|
||||
$this->updateDefault($gender);
|
||||
$gender->refresh();
|
||||
} elseif ($gender->isDefault()) {
|
||||
// Case of this gender was the default one previously
|
||||
$account = auth()->user()->account;
|
||||
$account->default_gender_id = null;
|
||||
$account->save();
|
||||
$gender->refresh();
|
||||
}
|
||||
|
||||
return $this->formatData($gender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a gender type.
|
||||
*/
|
||||
public function destroyAndReplaceGender(Gender $gender, $genderId)
|
||||
{
|
||||
$account = auth()->user()->account;
|
||||
try {
|
||||
$genderToReplaceWith = Gender::where('account_id', $account->id)
|
||||
->findOrFail($genderId);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return response()->json([
|
||||
'message' => trans('settings.personalization_genders_modal_error'),
|
||||
], 403);
|
||||
}
|
||||
|
||||
// We get the new gender to associate the contacts with.
|
||||
GenderHelper::replace($account, $gender, $genderToReplaceWith);
|
||||
|
||||
if ($gender->isDefault()) {
|
||||
$account->default_gender_id = $genderToReplaceWith->id;
|
||||
$account->save();
|
||||
}
|
||||
|
||||
$gender->delete();
|
||||
|
||||
return $this->respondObjectDeleted($gender->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a gender type.
|
||||
*/
|
||||
public function destroy(Gender $gender)
|
||||
{
|
||||
$gender->delete();
|
||||
|
||||
return $this->respondObjectDeleted($gender->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given gender to the default gender.
|
||||
*/
|
||||
public function updateDefault(Gender $gender)
|
||||
{
|
||||
$account = auth()->user()->account;
|
||||
$account->default_gender_id = $gender->id;
|
||||
$account->save();
|
||||
|
||||
return $this->formatData($gender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format data for output.
|
||||
*
|
||||
* @param Gender $gender
|
||||
* @return array
|
||||
*/
|
||||
private function formatData($gender)
|
||||
{
|
||||
return [
|
||||
'id' => $gender->id,
|
||||
'name' => $gender->name,
|
||||
'type' => $gender->type,
|
||||
'isDefault' => $gender->isDefault(),
|
||||
'numberOfContacts' => $gender->contacts->count(),
|
||||
];
|
||||
}
|
||||
}
|
||||
45
app/Http/Controllers/Settings/ModulesController.php
Normal file
45
app/Http/Controllers/Settings/ModulesController.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Models\User\Module;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
|
||||
class ModulesController extends Controller
|
||||
{
|
||||
use JsonRespondController;
|
||||
|
||||
/**
|
||||
* Get all the reminder rules.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$modules = auth()->user()->account->modules;
|
||||
|
||||
return $modules->map(function ($module) {
|
||||
return $this->format($module);
|
||||
});
|
||||
}
|
||||
|
||||
public function toggle(Request $request, Module $module)
|
||||
{
|
||||
$module->active = ! $module->active;
|
||||
$module->save();
|
||||
|
||||
return $this->respond([
|
||||
'data' => $this->format($module),
|
||||
]);
|
||||
}
|
||||
|
||||
private function format(Module $module)
|
||||
{
|
||||
return [
|
||||
'id' => $module->id,
|
||||
'key' => $module->key,
|
||||
'name' => trans($module->translation_key),
|
||||
'active' => $module->active,
|
||||
];
|
||||
}
|
||||
}
|
||||
157
app/Http/Controllers/Settings/MultiFAController.php
Normal file
157
app/Http/Controllers/Settings/MultiFAController.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Models\User\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\JsonRespondController;
|
||||
use Illuminate\Foundation\Auth\RedirectsUsers;
|
||||
use PragmaRX\Google2FALaravel\Facade as Google2FA;
|
||||
use PragmaRX\Google2FALaravel\Support\Authenticator;
|
||||
|
||||
class MultiFAController extends Controller
|
||||
{
|
||||
use RedirectsUsers, JsonRespondController;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/settings/security';
|
||||
|
||||
/**
|
||||
* Session var name to store secret code.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $SESSION_TFA_SECRET = '2FA_secret';
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function enableTwoFactor(Request $request)
|
||||
{
|
||||
//generate new secret
|
||||
$secret = $this->generateSecret();
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
//generate image for QR barcode
|
||||
$imageDataUri = Google2FA::getQRCodeInline(
|
||||
$request->getHttpHost(),
|
||||
$user->email,
|
||||
$secret,
|
||||
200
|
||||
);
|
||||
|
||||
$request->session()->put($this->SESSION_TFA_SECRET, $secret);
|
||||
|
||||
return response()->json(['image' => $imageDataUri, 'secret' => $secret]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function validateTwoFactor(Request $request)
|
||||
{
|
||||
//get user
|
||||
$user = $request->user();
|
||||
|
||||
if (! is_null($user->google2fa_secret)) {
|
||||
return response()->json(['error' => trans('settings.2fa_enable_error_already_set')]);
|
||||
}
|
||||
|
||||
$this->validate($request, [
|
||||
'one_time_password' => 'required',
|
||||
]);
|
||||
|
||||
//retrieve secret
|
||||
$secret = $request->session()->pull($this->SESSION_TFA_SECRET);
|
||||
|
||||
$authenticator = app(Authenticator::class)->boot($request);
|
||||
|
||||
if ($authenticator->verifyGoogle2FA($secret, $request['one_time_password'])) {
|
||||
//encrypt and then save secret
|
||||
$user->google2fa_secret = $secret;
|
||||
$user->save();
|
||||
|
||||
$authenticator->login();
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
$authenticator->logout();
|
||||
|
||||
return response()->json(['success' => false]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
|
||||
*/
|
||||
public function disableTwoFactor(Request $request)
|
||||
{
|
||||
return view('settings.security.2fa-disable');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function deactivateTwoFactor(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'one_time_password' => 'required',
|
||||
]);
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
if ($this->validateTwoFactorLogin($request, $user, $request['one_time_password'])) {
|
||||
//make secret column blank
|
||||
$user->google2fa_secret = null;
|
||||
$user->save();
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
return response()->json(['success' => false]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate 2nd factor for user with 2FA code or recovery code.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param User $user
|
||||
* @param string $oneTimePassword
|
||||
* @return bool
|
||||
*/
|
||||
private function validateTwoFactorLogin(Request $request, User $user, string $oneTimePassword): bool
|
||||
{
|
||||
//retrieve secret
|
||||
$secret = $user->google2fa_secret;
|
||||
|
||||
$authenticator = app(Authenticator::class)->boot($request);
|
||||
|
||||
// try provided token as a 2FA code, or as a recovery code
|
||||
if ($authenticator->verifyGoogle2FA($secret, $oneTimePassword)
|
||||
|| $user->recoveryChallenge($oneTimePassword)) {
|
||||
$authenticator->logout();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secret key in Base32 format.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateSecret()
|
||||
{
|
||||
return Google2FA::generateSecretKey(32);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user