app/Http/Controllers/SettingsController.php (289 lines of code) (raw):
<?php
namespace App\Http\Controllers;
use App\Models\User\User;
use App\Helpers\DateHelper;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Helpers\LocaleHelper;
use App\Helpers\AccountHelper;
use App\Helpers\TimezoneHelper;
use App\Models\Contact\Contact;
use App\Jobs\ExportAccountAsSQL;
use App\Jobs\AddContactFromVCard;
use App\Models\Account\ImportJob;
use App\Models\Account\Invitation;
use App\Services\User\EmailChange;
use App\Exceptions\StripeException;
use App\Http\Requests\ImportsRequest;
use App\Notifications\InvitationMail;
use App\Http\Requests\SettingsRequest;
use LaravelWebauthn\Models\WebauthnKey;
use App\Http\Requests\InvitationRequest;
use App\Services\Contact\Tag\DestroyTag;
use App\Services\Account\Settings\ResetAccount;
use App\Services\Account\Settings\DestroyAccount;
use PragmaRX\Google2FALaravel\Facade as Google2FA;
use App\Http\Resources\Contact\ContactShort as ContactResource;
use App\Http\Resources\Settings\WebauthnKey\WebauthnKey as WebauthnKeyResource;
class SettingsController
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\View\View
*/
public function index()
{
// names order
$namesOrder = [
'firstname_lastname',
'lastname_firstname',
'firstname_lastname_nickname',
'firstname_nickname_lastname',
'lastname_firstname_nickname',
'lastname_nickname_firstname',
'nickname_firstname_lastname',
'nickname_lastname_firstname',
'nickname',
];
$meContact = null;
$search = auth()->user()->first_name.' '.
auth()->user()->last_name.' '.
auth()->user()->email;
$existingContacts = Contact::search($search, auth()->user()->account_id, 'id')
->real()
->whereNotIn('id', [auth()->user()->me_contact_id])
->paginate(20);
if (auth()->user()->me_contact_id) {
$meContact = Contact::where('account_id', auth()->user()->account_id)
->find(auth()->user()->me_contact_id);
$existingContacts->prepend($meContact);
}
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
return view('settings.index')
->withAccountHasLimitations($accountHasLimitations)
->withMeContact($meContact ? new ContactResource($meContact) : null)
->withExistingContacts(ContactResource::collection($existingContacts))
->withNamesOrder($namesOrder)
->withLocales(LocaleHelper::getLocaleList()->sortByCollator('name-orig'))
->withHours(DateHelper::getListOfHours())
->withSelectedTimezone(TimezoneHelper::adjustEquivalentTimezone(DateHelper::getTimezone()))
->withTimezones(collect(TimezoneHelper::getListOfTimezones())->map(function ($timezone) {
return ['id' => $timezone['timezone'], 'name'=>$timezone['name']];
}));
}
/**
* Save user settings.
*
* @param SettingsRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function save(SettingsRequest $request)
{
$user = $request->user();
$user->update(
$request->only([
'first_name',
'last_name',
'timezone',
'locale',
'currency_id',
'name_order',
]) + [
'fluid_container' => $request->input('layout'),
'temperature_scale' => $request->input('temperature_scale'),
]
);
if ($user->email != $request->input('email')) {
app(EmailChange::class)->execute([
'account_id' => $user->account_id,
'email' => $request->input('email'),
'user_id' => $user->id,
]);
}
if (! AccountHelper::hasLimitations($user->account) && $request->input('me_contact_id')) {
$user->me_contact_id = $request->input('me_contact_id');
$user->save();
}
$user->account->default_time_reminder_is_sent = $request->input('reminder_time');
$user->account->save();
return redirect()->route('settings.index')
->with('status', trans('settings.settings_success', [], $request['locale']));
}
/**
* Delete user account.
*
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function delete(Request $request)
{
$account = auth()->user()->account;
try {
app(DestroyAccount::class)->execute([
'account_id' => $account->id,
]);
} catch (StripeException $e) {
return redirect()->route('settings.index')
->withErrors($e->getMessage());
}
auth('')->logout();
return redirect()->route('loginRedirect');
}
/**
* Reset user account.
*
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function reset(Request $request)
{
$user = $request->user();
$account = $user->account;
app(ResetAccount::class)->execute([
'account_id' => $account->id,
]);
return redirect()->route('settings.index')
->with('status', trans('settings.reset_success'));
}
/**
* Display the export view.
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
public function export()
{
return view('settings.export')
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account));
}
/**
* Exports the data of the account in SQL format.
*
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response|null
*/
public function exportToSql()
{
$path = dispatch_now(new ExportAccountAsSQL());
$adapter = disk_adapter(ExportAccountAsSQL::STORAGE);
return response()
->download($adapter->getPathPrefix().$path, 'monica.sql')
->deleteFileAfterSend(true);
}
/**
* Display the import view.
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
public function import()
{
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
if (auth()->user()->account->importjobs->count() == 0) {
return view('settings.imports.blank')
->withAccountHasLimitations($accountHasLimitations);
}
return view('settings.imports.index')
->withAccountHasLimitations($accountHasLimitations);
}
/**
* Display the Import people's view.
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse
*/
public function upload()
{
if (AccountHelper::hasLimitations(auth()->user()->account)) {
return redirect()->route('settings.subscriptions.index');
}
return view('settings.imports.upload');
}
public function storeImport(ImportsRequest $request)
{
$filename = $request->file('vcard')->store('imports', 'public');
$importJob = auth()->user()->account->importjobs()->create([
'user_id' => auth()->user()->id,
'type' => 'vcard',
'filename' => $filename,
]);
dispatch(new AddContactFromVCard($importJob, $request->input('behaviour')));
return redirect()->route('settings.import');
}
/**
* Display the import report view.
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
public function report($importJobId)
{
$importJob = ImportJob::where('account_id', auth()->user()->account_id)
->findOrFail($importJobId);
return view('settings.imports.report', compact('importJob'));
}
/**
* Display the users view.
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
public function users()
{
$users = auth()->user()->account->users;
$accountHasLimitations = AccountHelper::hasLimitations(auth()->user()->account);
if ($users->count() == 1 && auth()->user()->account->invitations()->count() == 0) {
return view('settings.users.blank')
->withAccountHasLimitations($accountHasLimitations);
}
return view('settings.users.index', compact('users'))
->withAccountHasLimitations($accountHasLimitations);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse
*/
public function addUser()
{
if (AccountHelper::hasLimitations(auth()->user()->account)) {
return redirect()->route('settings.subscriptions.index');
}
return view('settings.users.add');
}
/**
* Store a newly created resource in storage.
*
* @param InvitationRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function inviteUser(InvitationRequest $request)
{
// Make sure the confirmation to invite has not been bypassed
if (! $request->input('confirmation')) {
return redirect()->back()->withErrors(trans('settings.users_error_please_confirm'))->withInput();
}
// Is the email address already taken?
$users = User::where('email', $request->only(['email']))->count();
if ($users > 0) {
return redirect()->back()->withErrors(trans('settings.users_error_email_already_taken'))->withInput();
}
// Has this user already been invited?
$invitations = Invitation::where('email', $request->only(['email']))->count();
if ($invitations > 0) {
return redirect()->back()->withErrors(trans('settings.users_error_already_invited'))->withInput();
}
$invitation = auth()->user()->account->invitations()->create(
$request->only([
'email',
])
+ [
'invited_by_user_id' => auth()->user()->id,
'account_id' => auth()->user()->account_id,
'invitation_key' => Str::random(100),
]
);
$invitation->notify((new InvitationMail())->locale(auth()->user()->locale));
auth()->user()->account->update([
'number_of_invitations_sent' => auth()->user()->account->number_of_invitations_sent + 1,
]);
return redirect()->route('settings.users.index')
->with('status', trans('settings.settings_success'));
}
/**
* Remove the specified resource from storage.
*
* @param Invitation $invitation
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroyInvitation(Invitation $invitation)
{
$invitation->delete();
return redirect()->route('settings.users.index')
->with('success', trans('settings.users_invitation_deleted_confirmation_message'));
}
/**
* Delete additional user account.
*
* @param int $userID
*
* @return \Illuminate\Http\RedirectResponse
*/
public function deleteAdditionalUser($userID)
{
$user = User::where('account_id', auth()->user()->account_id)
->findOrFail($userID);
// make sure you don't delete yourself from this screen
if ($user->id == auth()->user()->id) {
return redirect()->route('loginRedirect');
}
$user->delete();
return redirect()->route('settings.users.index')
->with('success', trans('settings.users_list_delete_success'));
}
/**
* Display the list of tags for this account.
*/
public function tags()
{
return view('settings.tags')
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account));
}
/**
* Destroy the tag.
*
* @param int $tagId
*
* @return \Illuminate\Http\RedirectResponse
*/
public function deleteTag($tagId)
{
app(DestroyTag::class)->execute([
'tag_id' => $tagId,
'account_id' => auth()->user()->account_id,
]);
return redirect()->route('settings.tags.index')
->with('success', trans('settings.tags_list_delete_success'));
}
public function api()
{
return view('settings.api.index')
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account));
}
public function dav()
{
$davroute = route('sabre.dav');
$email = auth()->user()->email;
return view('settings.dav.index')
->withDavRoute($davroute)
->withCardDavRoute("{$davroute}/addressbooks/{$email}/contacts")
->withCalDavBirthdaysRoute("{$davroute}/calendars/{$email}/birthdays")
->withCalDavTasksRoute("{$davroute}/calendars/{$email}/tasks")
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account));
}
public function security()
{
$webauthnKeys = WebauthnKey::where('user_id', auth()->id())->get();
return view('settings.security.index')
->with('is2FAActivated', Google2FA::isActivated())
->withWebauthnKeys(WebauthnKeyResource::collection($webauthnKeys))
->withAccountHasLimitations(AccountHelper::hasLimitations(auth()->user()->account));
}
/**
* Update the default view when viewing a contact.
* The default view can be either the life events feed or the general data
* about the contact (notes, reminders, ...).
* Possible values: life-events | notes.
*
* @param Request $request
* @return string
*/
public function updateDefaultProfileView(Request $request)
{
$allowedValues = ['life-events', 'notes', 'photos'];
/** @var string */
$view = $request->input('name');
if (! in_array($view, $allowedValues)) {
return 'not allowed';
}
auth()->user()->profile_active_tab = $view;
if ($view == 'life-events') {
auth()->user()->profile_new_life_event_badge_seen = true;
}
auth()->user()->save();
return $view;
}
}