Skip to content

Commit 9f49eeb

Browse files
committed
Merge branch '2025-05-09-remove-duplicate-vault-reminders' of github.com:cmpickle/monica into 2025-05-09-remove-duplicate-vault-reminders
2 parents 787e649 + 0ff1a4a commit 9f49eeb

File tree

311 files changed

+16481
-4065
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

311 files changed

+16481
-4065
lines changed

.devcontainer/devcontainer.json

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,40 @@
11
{
22
"name": "PHP & SQLite",
3-
"image": "ghcr.io/asbiin/devcontainers/php:8.3",
3+
"image": "ghcr.io/asbiin/devcontainers/php:8.4",
4+
5+
"customizations": {
6+
"vscode": {
7+
"extensions": [
8+
"dbaeumer.vscode-eslint",
9+
"xdebug.php-debug",
10+
"bmewburn.vscode-intelephense-client",
11+
"xdebug.php-pack",
12+
"devsense.phptools-vscode",
13+
"mikestead.dotenv",
14+
"editorconfig.editorconfig",
15+
"esbenp.prettier-vscode",
16+
"bradlc.vscode-tailwindcss",
17+
"vue.volar",
18+
"qwtel.sqlite-viewer"
19+
]
20+
}
21+
},
422

523
// For use with PHP or Apache (e.g.php -S localhost:8080 or apache2ctl start)
624
"forwardPorts": [8080],
725
"features": {
26+
"ghcr.io/devcontainers/features/common-utils:2": {},
827
"ghcr.io/devcontainers/features/github-cli:1": {}
928
},
1029

1130
// Use 'postCreateCommand' to run commands after the container is created.
1231
"postCreateCommand": ".devcontainer/postCreate.sh",
13-
"postStartCommand": ".devcontainer/postStart.sh"
32+
"postStartCommand": ".devcontainer/postStart.sh",
33+
34+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
35+
// "remoteUser": "root",
36+
37+
"mounts": [
38+
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
39+
]
1440
}

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ APP_DEBUG=true
2626
# The URL of your application.
2727
APP_URL=http://localhost:8000
2828

29+
# Ability to disable signups on your instance.
30+
# Can be true or false. Default to false.
31+
APP_DISABLE_SIGNUP=false
32+
2933
# Database to store information
3034
# The documentation is here: https://laravel.com/docs/10.x/database
3135
# You can also see the different values you can use in config/database.php

.sonarlint/connectedMode.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"sonarCloudOrganization": "monicahq",
3-
"projectKey": "monica"
3+
"projectKey": "monica",
4+
"region": "EU"
45
}

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"sonarlint.connectedMode.project": {
3+
"connectionId": "monicahq",
4+
"projectKey": "monica"
5+
}
6+
}

app/Actions/Jetstream/UserProfile.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
namespace App\Actions\Jetstream;
44

55
use App\Domains\Vault\ManageVault\Web\ViewHelpers\VaultIndexViewHelper;
6+
use App\Models\WebauthnKey;
67
use Illuminate\Http\Request;
7-
use LaravelWebauthn\Models\WebauthnKey;
88

99
class UserProfile
1010
{
@@ -27,7 +27,7 @@ public function __invoke(Request $request, array $data): array
2727
'id' => $key->id,
2828
'name' => $key->name,
2929
'type' => $key->type,
30-
'last_active' => $key->updated_at->diffForHumans(),
30+
'last_used' => optional($key->used_at)->diffForHumans(),
3131
])
3232
->toArray();
3333

app/Console/Commands/SetupApplication.php

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ class SetupApplication extends Command
2424
protected $signature = 'monica:setup
2525
{--force : Force the operation to run when in production.}
2626
{--skip-storage-link : Skip storage link create.}
27-
{--skip-docs : Skip api docs generation.}';
27+
{--skip-docs : Skip api docs generation.}
28+
{--build : Run only build commands.}
29+
{--deploy : Run only deploy commands.}';
2830

2931
/**
3032
* The console command description.
@@ -39,15 +41,17 @@ class SetupApplication extends Command
3941
public function handle(): void
4042
{
4143
if ($this->confirmToProceed()) {
42-
$this->resetCache();
43-
$this->clearConfig();
44-
$this->symlink();
45-
$this->migrate();
46-
if ($this->option('skip-docs') !== true) {
44+
if ($this->option('build') === true || ($this->option('build') === false && $this->option('deploy') === false)) {
45+
$this->symlink();
46+
$this->resetCache();
47+
$this->clearConfig();
4748
$this->documentation();
49+
$this->cacheConfig();
50+
}
51+
if ($this->option('deploy') === true || ($this->option('build') === false && $this->option('deploy') === false)) {
52+
$this->migrate();
53+
$this->scout();
4854
}
49-
$this->cacheConfig();
50-
$this->scout();
5155
}
5256
}
5357

@@ -69,7 +73,7 @@ protected function clearConfig(): void
6973
if ($this->getLaravel()->environment() == 'production') {
7074
$this->artisan('✓ Clear config cache', 'config:clear');
7175
$this->artisan('✓ Resetting route cache', 'route:cache');
72-
$this->artisan('✓ Resetting view cache', 'view:clear');
76+
$this->artisan('✓ Resetting view cache', 'view:cache');
7377
$this->artisan('✓ Resetting event cache', 'event:cache');
7478
} else {
7579
$this->artisan('✓ Clear config cache', 'config:clear');
@@ -124,7 +128,9 @@ protected function scout(): void
124128
*/
125129
protected function documentation(): void
126130
{
127-
$this->artisan('✓ Generate api documentation', 'scribe:setup', ['--clean' => true, '--force' => true]);
131+
if ($this->option('skip-docs') !== true) {
132+
$this->artisan('✓ Generate api documentation', 'scribe:setup', ['--clean' => true, '--force' => true]);
133+
}
128134
}
129135

130136
private function artisan(string $message, string $command, array $options = [])

app/Domains/Contact/ManageContactAddresses/Web/Controllers/ContactModuleAddressController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function update(Request $request, string $vaultId, string $contactId, int
7777
$contact = Contact::find($contactId);
7878

7979
// update pivot table
80-
$contact->addresses()->where('address_id', $addressId)->update([
80+
$contact->addresses()->updateExistingPivot($addressId, [
8181
'is_past_address' => $request->input('is_past_address'),
8282
]);
8383

app/Domains/Contact/ManageContactFeed/Web/ViewHelpers/Actions/ActionFeedAddress.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions;
44

55
use App\Helpers\MapHelper;
6+
use App\Models\Address;
67
use App\Models\ContactFeedItem;
78
use App\Models\User;
89

@@ -15,7 +16,7 @@ public static function data(ContactFeedItem $item, User $user): array
1516

1617
return [
1718
'address' => [
18-
'object' => $address ? [
19+
'object' => $address instanceof Address ? [
1920
'id' => $address->id,
2021
'line_1' => $address->line_1,
2122
'line_2' => $address->line_2,

app/Domains/Contact/ManageDocuments/Listeners/DeleteFileInStorage.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ class DeleteFileInStorage
2828
*/
2929
public Api $api;
3030

31-
/**
32-
* Create the event listener.
33-
*/
34-
public function __construct() {}
35-
3631
/**
3732
* Handle the event.
3833
*/

app/Domains/Contact/ManageLoans/Web/ViewHelpers/ModuleLoanViewHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static function data(Contact $contact, User $user): array
2121
->concat($loansAsLoanee)
2222
->sortBy('loaned_at')
2323
->unique('id')
24-
->map(fn (Loan $loan): array => self::dtoLoan($loan, $contact, $user)); // @phpstan-ignore-line
24+
->map(fn (Loan $loan): array => self::dtoLoan($loan, $contact, $user));
2525

2626
return [
2727
'loans' => $loansAssociatedWithContactCollection,

app/Domains/Vault/ManageVaultSettings/Web/ViewHelpers/VaultSettingsIndexViewHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static function data(Vault $vault): array
3131
$usersInAccount = $vault->account->users()->whereNotNull('email_verified_at')->get();
3232
$usersInVault = $vault->users()->get();
3333
$usersInAccount = $usersInAccount->diff($usersInVault);
34-
$usersInAccountCollection = $usersInAccount->map(fn (User $user): array => self::dtoUser($user, $vault)); // @phpstan-ignore-line
34+
$usersInAccountCollection = $usersInAccount->map(fn (User $user): array => self::dtoUser($user, $vault));
3535
$usersInVaultCollection = $usersInVault->map(fn (User $user): array => self::dtoUser($user, $vault));
3636

3737
// labels

app/Helpers/SignupHelper.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Helpers;
4+
5+
use App\Models\Account;
6+
use Illuminate\Config\Repository as Config;
7+
8+
class SignupHelper
9+
{
10+
/**
11+
* Create a new instance.
12+
*
13+
* @return void
14+
*/
15+
public function __construct(
16+
private Config $config
17+
) {}
18+
19+
/**
20+
* Check if signup is enabled.
21+
*/
22+
public function isEnabled(): bool
23+
{
24+
return ! ($this->isDisabledByConfig() && $this->hasAtLeastOneAccount());
25+
}
26+
27+
private function isDisabledByConfig(): bool
28+
{
29+
return $this->config->get('monica.disable_signup', false);
30+
}
31+
32+
private function hasAtLeastOneAccount(): bool
33+
{
34+
return ! empty(Account::first());
35+
}
36+
}

app/Http/Controllers/Auth/LoginController.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
namespace App\Http\Controllers\Auth;
44

5+
use App\Helpers\SignupHelper;
56
use App\Helpers\WallpaperHelper;
67
use App\Http\Controllers\Controller;
7-
use App\Models\User;
88
use Illuminate\Http\Request;
9-
use Illuminate\Support\Facades\Cookie;
9+
use Illuminate\Http\Response as HttpResponse;
1010
use Illuminate\Support\Facades\Route;
1111
use Inertia\Inertia;
1212
use Inertia\Response;
@@ -30,20 +30,27 @@ public function __invoke(Request $request): Response
3030

3131
$data = [];
3232

33-
if ($webauthnRemember = $request->cookie('webauthn_remember')) {
34-
if (($user = User::find($webauthnRemember)) && $user->webauthnKeys()->count() > 0) {
35-
$data['publicKey'] = Webauthn::prepareAssertion($user);
36-
$data['userName'] = $user->name;
37-
} else {
38-
Cookie::expire('webauthn_remember');
39-
}
33+
if (Webauthn::userless()) {
34+
$data['publicKey'] = Webauthn::prepareAssertion(null);
35+
$data['userless'] = true;
36+
$data['autologin'] = $request->cookie('return') === 'true';
4037
}
4138

4239
return Inertia::render('Auth/Login', $data + [
40+
'isSignupEnabled' => app(SignupHelper::class)->isEnabled(),
4341
'canResetPassword' => Route::has('password.request'),
4442
'status' => session('status'),
4543
'wallpaperUrl' => WallpaperHelper::getRandomWallpaper(),
4644
'providers' => $providers,
45+
'beta' => $request->cookie('beta') !== 'false',
4746
]);
4847
}
48+
49+
/**
50+
* Remove beta text box.
51+
*/
52+
public function closeBeta(Request $request): HttpResponse
53+
{
54+
return response([])->cookie('beta', 'false', 60 * 24 * 365);
55+
}
4956
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Auth;
4+
5+
use App\Http\Controllers\Controller;
6+
use Illuminate\Http\Request;
7+
use Inertia\Inertia;
8+
use Inertia\Response;
9+
10+
class RegisterController extends Controller
11+
{
12+
/**
13+
* Display the register view.
14+
*/
15+
public function __invoke(Request $request): Response
16+
{
17+
$providers = collect(config('auth.login_providers'))
18+
->filter(fn ($provider) => ! empty($provider))
19+
->mapWithKeys(fn ($provider) => [
20+
$provider => [
21+
'name' => config("services.$provider.name") ?? trans_ignore("auth.login_provider_{$provider}"),
22+
'logo' => config("services.$provider.logo") ?? "/img/auth/$provider.svg",
23+
],
24+
]);
25+
26+
return Inertia::render('Auth/Register', [
27+
'providers' => $providers,
28+
'beta' => $request->cookie('beta') !== 'false',
29+
]);
30+
}
31+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use App\Helpers\SignupHelper;
6+
use Closure;
7+
use Illuminate\Contracts\Foundation\Application;
8+
use Illuminate\Http\Request;
9+
use Symfony\Component\HttpFoundation\Response;
10+
11+
class EnsureSignupIsEnabled
12+
{
13+
/**
14+
* Create a new middleware instance.
15+
*
16+
* @return void
17+
*/
18+
public function __construct(
19+
private Application $app,
20+
) {}
21+
22+
public function handle(Request $request, Closure $next): Response
23+
{
24+
abort_if(! $this->app[SignupHelper::class]->isEnabled(), 403, trans('Registration is currently disabled'));
25+
26+
return $next($request);
27+
}
28+
}

0 commit comments

Comments
 (0)