Skip to content

Commit

Permalink
feat: force password reset + waitlist
Browse files Browse the repository at this point in the history
  • Loading branch information
andrasbacsai committed Aug 15, 2023
1 parent 952d335 commit 88b3005
Show file tree
Hide file tree
Showing 35 changed files with 482 additions and 44 deletions.
3 changes: 3 additions & 0 deletions app/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Jobs\CheckResaleLicenseJob;
use App\Jobs\CheckResaleLicenseKeys;
use App\Jobs\CleanupInstanceStuffsJob;
use App\Jobs\DatabaseBackupJob;
use App\Jobs\DockerCleanupJob;
use App\Jobs\InstanceApplicationsStatusJob;
Expand All @@ -22,12 +23,14 @@ protected function schedule(Schedule $schedule): void
$schedule->command('horizon:snapshot')->everyMinute();
$schedule->job(new InstanceApplicationsStatusJob)->everyMinute();
$schedule->job(new ProxyCheckJob)->everyFiveMinutes();
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute();

// $schedule->job(new CheckResaleLicenseJob)->hourly();
// $schedule->job(new DockerCleanupJob)->everyOddHour();
// $schedule->job(new InstanceAutoUpdateJob(true))->everyMinute();
} else {
$schedule->command('horizon:snapshot')->everyFiveMinutes();
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute();
$schedule->job(new InstanceApplicationsStatusJob)->everyMinute();
$schedule->job(new CheckResaleLicenseJob)->hourly();
$schedule->job(new ProxyCheckJob)->everyFiveMinutes();
Expand Down
10 changes: 10 additions & 0 deletions app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use App\Models\StandalonePostgresql;
use App\Models\TeamInvitation;
use App\Models\User;
use App\Models\Waitlist;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
Expand All @@ -18,6 +19,12 @@ class Controller extends BaseController
{
use AuthorizesRequests, ValidatesRequests;

public function waitlist() {
$waiting_in_line = Waitlist::whereVerified(true)->count();
return view('auth.waitlist', [
'waiting_in_line' => $waiting_in_line,
]);
}
public function subscription()
{
if (!is_cloud()) {
Expand All @@ -38,6 +45,9 @@ public function license()
]);
}

public function force_passoword_reset() {
return view('auth.force-password-reset');
}
public function dashboard()
{
$projects = Project::ownedByCurrentTeam()->get();
Expand Down
1 change: 1 addition & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\CheckForcePasswordReset::class,
\App\Http\Middleware\SubscriptionValid::class,

],
Expand Down
36 changes: 36 additions & 0 deletions app/Http/Livewire/ForcePasswordReset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Http\Livewire;

use Illuminate\Support\Facades\Hash;
use Livewire\Component;

class ForcePasswordReset extends Component
{
public string $email;
public string $password;
public string $password_confirmation;

protected $rules = [
'email' => 'required|email',
'password' => 'required|min:8',
'password_confirmation' => 'required|same:password',
];
public function mount() {
$this->email = auth()->user()->email;
}
public function submit() {
try {
$this->validate();
auth()->user()->forceFill([
'password' => Hash::make($this->password),
'force_password_reset' => false,
])->save();
auth()->logout();
return redirect()->route('login')->with('status', 'Your initial password has been set.');
} catch(\Exception $e) {
return general_error_handler(err:$e, that:$this);
}
}

}
49 changes: 49 additions & 0 deletions app/Http/Livewire/Waitlist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace App\Http\Livewire;

use App\Jobs\SendConfirmationForWaitlistJob;
use App\Models\Waitlist as ModelsWaitlist;
use Livewire\Component;

class Waitlist extends Component
{
public string $email;
public int $waiting_in_line = 0;

protected $rules = [
'email' => 'required|email',
];
public function mount()
{
if (is_dev()) {
$this->email = '[email protected]';
}
}
public function submit()
{
$this->validate();
try {
$found = ModelsWaitlist::where('email', $this->email)->first();
ray($found);
if ($found) {
if (!$found->verified) {
$this->emit('error', 'You are already on the waitlist. <br>Please check your email to verify your email address.');
return;
}
$this->emit('error', 'You are already on the waitlist.');
return;
}
$waitlist = ModelsWaitlist::create([
'email' => $this->email,
'type' => 'registration',
]);

$this->emit('success', 'You have been added to the waitlist.');
dispatch(new SendConfirmationForWaitlistJob($this->email, $waitlist->uuid));
} catch (\Exception $e) {
return general_error_handler(err: $e, that: $this);
}

}
}
29 changes: 29 additions & 0 deletions app/Http/Middleware/CheckForcePasswordReset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CheckForcePasswordReset
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (auth()->user()) {
$force_password_reset = auth()->user()->force_password_reset;
if ($force_password_reset) {
if ($request->routeIs('auth.force-password-reset') || $request->path() === 'livewire/message/force-password-reset') {
return $next($request);
}
return redirect()->route('auth.force-password-reset');
}
}
return $next($request);
}
}
1 change: 0 additions & 1 deletion app/Http/Middleware/RedirectIfAuthenticated.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public function handle(Request $request, Closure $next, string ...$guards): Resp
return redirect(RouteServiceProvider::HOME);
}
}

return $next($request);
}
}
4 changes: 3 additions & 1 deletion app/Http/Middleware/SubscriptionValid.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class SubscriptionValid
{
public function handle(Request $request, Closure $next): Response
{

if (!auth()->user() || !is_cloud()) {
if ($request->path() === 'subscription') {
return redirect('/');
Expand All @@ -36,7 +35,10 @@ public function handle(Request $request, Closure $next): Response
'subscription',
'login',
'register',
'waitlist',
'force-password-reset',
'logout',
'livewire/message/force-password-reset',
'livewire/message/check-license',
'livewire/message/switch-team',
];
Expand Down
43 changes: 43 additions & 0 deletions app/Jobs/CleanupInstanceStuffsJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace App\Jobs;

use App\Models\Waitlist;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public function __construct()
{

}

// public function uniqueId(): string
// {
// return $this->container_name;
// }

public function handle(): void
{
try {
$this->cleanup_waitlist();
} catch (\Exception $e) {
ray($e->getMessage());
}
}

private function cleanup_waitlist()
{
$waitlist = Waitlist::whereVerified(false)->where('created_at', '<', now()->subMinutes(config('constants.waitlist.confirmation_valid_for_minutes')))->get();
foreach ($waitlist as $item) {
$item->delete();
}
}
}
59 changes: 59 additions & 0 deletions app/Jobs/SendConfirmationForWaitlistJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace App\Jobs;

use App\Models\InstanceSettings;
use App\Models\Waitlist;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Mail\Message;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;

class SendConfirmationForWaitlistJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public function __construct(public string $email, public string $uuid)
{
}

public function handle()
{
try {
$settings = InstanceSettings::get();


set_transanctional_email_settings($settings);
$mail = new MailMessage();

$confirmation_url = base_url() . '/webhooks/waitlist/confirm?email=' . $this->email . '&confirmation_code=' . $this->uuid;
$cancel_url = base_url() . '/webhooks/waitlist/cancel?email=' . $this->email . '&confirmation_code=' . $this->uuid;

$mail->view('emails.waitlist-confirmation',
[
'confirmation_url' => $confirmation_url,
'cancel_url' => $cancel_url,
]);
$mail->subject('You are on the waitlist!');
Mail::send(
[],
[],
fn(Message $message) => $message
->from(
data_get($settings, 'smtp_from_address'),
data_get($settings, 'smtp_from_name')
)
->to($this->email)
->subject($mail->subject)
->html((string) $mail->render())
);
} catch (\Throwable $th) {
ray($th->getMessage());
throw $th;
}
}
}
11 changes: 4 additions & 7 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Models;

use App\Notifications\Channels\SendsEmail;
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
use App\Notifications\TrnsactionalEmails\ResetPassword;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
Expand All @@ -14,18 +15,14 @@ class User extends Authenticatable implements SendsEmail
{
use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable;

protected $fillable = [
'id',
'name',
'email',
'password',
];
protected $guarded = [];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'force_password_reset' => 'boolean',
];

protected static function boot()
Expand Down Expand Up @@ -57,7 +54,7 @@ public function getRecepients($notification)

public function sendPasswordResetNotification($token): void
{
$this->notify(new ResetPassword($token));
$this->notify(new TransactionalEmailsResetPassword($token));
}

public function isAdmin()
Expand Down
11 changes: 11 additions & 0 deletions app/Models/Waitlist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;

class Waitlist extends BaseModel
{
use HasFactory;
protected $guarded = [];
}
9 changes: 8 additions & 1 deletion app/Providers/FortifyServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Laravel\Fortify\Contracts\RegisterResponse;
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;

class FortifyServiceProvider extends ServiceProvider
Expand Down Expand Up @@ -41,13 +42,19 @@ public function toResponse($request)
*/
public function boot(): void
{

Fortify::createUsersUsing(CreateNewUser::class);
Fortify::registerView(function () {
ray('asd');
$settings = InstanceSettings::get();
if (!$settings->is_registration_enabled) {
return redirect()->route('login');
}
return view('auth.register');
if (config('coolify.waitlist')) {
return view('auth.waitlist');
} else {
return view('auth.register');
}
});

Fortify::loginView(function () {
Expand Down
Loading

0 comments on commit 88b3005

Please sign in to comment.