a lot hehe
This commit is contained in:
parent
c8f70a4e3b
commit
0aa816b4f2
@ -8,7 +8,9 @@ GROUPID=
|
||||
PROJECT_PATH_ON_HOST=/Users/your-username-here/code/coollabsio/coolify
|
||||
SERVEO_URL=<for receiving webhooks locally https://serveo.net/>
|
||||
MUX_ENABLED=false
|
||||
# If you are using the included Buggregator
|
||||
RAY_HOST=ray@host.docker.internal
|
||||
RAY_PORT=8001
|
||||
############################################################################################################
|
||||
|
||||
APP_NAME=Coolify
|
||||
@ -19,6 +21,10 @@ APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
APP_PORT=8000
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=coolify-mail
|
||||
MAIL_PORT=1025
|
||||
|
||||
SESSION_DRIVER=database
|
||||
DUSK_DRIVER_URL=http://selenium:4444
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Secrets related to pushing to GH, Sync files to BunnyCDN etc.
|
||||
# Secrets related to pushing to GH, Sync files to BunnyCDN etc. Only for maintainers.
|
||||
# Not related to Coolify, but to how we publish new versions.
|
||||
|
||||
GITHUB_TOKEN=
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\DemoNotification;
|
||||
use App\Notifications\TestNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Livewire\Component;
|
||||
|
||||
@ -13,31 +13,40 @@ class DiscordSettings extends Component
|
||||
public Team|Server $model;
|
||||
|
||||
protected $rules = [
|
||||
'model.extra_attributes.discord_webhook' => 'nullable|url',
|
||||
'model.extra_attributes.discord_active' => 'nullable|boolean',
|
||||
'model.smtp_attributes.discord_active' => 'nullable|boolean',
|
||||
'model.smtp_attributes.discord_webhook' => 'required|url',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'model.extra_attributes.discord_webhook' => 'Discord Webhook',
|
||||
'model.smtp_attributes.discord_webhook' => 'Discord Webhook',
|
||||
];
|
||||
public function mount($model)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function instantSave()
|
||||
{
|
||||
try {
|
||||
$this->submit();
|
||||
} catch (\Exception $e) {
|
||||
$this->model->smtp_attributes->discord_active = false;
|
||||
$this->addError('model.smtp_attributes.discord_webhook', $e->getMessage());
|
||||
}
|
||||
}
|
||||
private function saveModel()
|
||||
{
|
||||
$this->model->save();
|
||||
if (is_a($this->model, Team::class)) {
|
||||
session(['currentTeam' => $this->model]);
|
||||
}
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
$this->resetErrorBag();
|
||||
$this->validate();
|
||||
$this->model->save();
|
||||
if ( is_a($this->model, Team::class)) {
|
||||
session(['currentTeam' => $this->model]);
|
||||
}
|
||||
$this->saveModel();
|
||||
}
|
||||
public function sendTestNotification()
|
||||
{
|
||||
Notification::send($this->model, new DemoNotification);
|
||||
}
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.notifications.discord-settings');
|
||||
Notification::send($this->model, new TestNotification);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\DemoNotification;
|
||||
use App\Notifications\TestNotification;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Livewire\Component;
|
||||
|
||||
@ -13,27 +13,27 @@ class EmailSettings extends Component
|
||||
public Team|Server $model;
|
||||
|
||||
protected $rules = [
|
||||
'model.extra_attributes.smtp_active' => 'nullable|boolean',
|
||||
'model.extra_attributes.from_address' => 'nullable',
|
||||
'model.extra_attributes.from_name' => 'nullable',
|
||||
'model.extra_attributes.recipients' => 'nullable',
|
||||
'model.extra_attributes.smtp_host' => 'nullable',
|
||||
'model.extra_attributes.smtp_port' => 'nullable',
|
||||
'model.extra_attributes.smtp_encryption' => 'nullable',
|
||||
'model.extra_attributes.smtp_username' => 'nullable',
|
||||
'model.extra_attributes.smtp_password' => 'nullable',
|
||||
'model.extra_attributes.smtp_timeout' => 'nullable',
|
||||
'model.smtp_attributes.smtp_active' => 'nullable|boolean',
|
||||
'model.smtp_attributes.from_address' => 'required',
|
||||
'model.smtp_attributes.from_name' => 'required',
|
||||
'model.smtp_attributes.recipients' => 'required',
|
||||
'model.smtp_attributes.smtp_host' => 'required',
|
||||
'model.smtp_attributes.smtp_port' => 'required',
|
||||
'model.smtp_attributes.smtp_encryption' => 'nullable',
|
||||
'model.smtp_attributes.smtp_username' => 'nullable',
|
||||
'model.smtp_attributes.smtp_password' => 'nullable',
|
||||
'model.smtp_attributes.smtp_timeout' => 'nullable',
|
||||
'model.smtp_attributes.test_address' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'model.extra_attributes.from_address' => 'From Address',
|
||||
'model.extra_attributes.from_name' => 'From Name',
|
||||
'model.extra_attributes.recipients' => 'Recipients',
|
||||
'model.extra_attributes.smtp_host' => 'Host',
|
||||
'model.extra_attributes.smtp_port' => 'Port',
|
||||
'model.extra_attributes.smtp_encryption' => 'Encryption',
|
||||
'model.extra_attributes.smtp_username' => 'Username',
|
||||
'model.extra_attributes.smtp_password' => 'Password',
|
||||
'model.extra_attributes.smtp_timeout' => 'Timeout',
|
||||
'model.smtp_attributes.from_address' => 'From Address',
|
||||
'model.smtp_attributes.from_name' => 'From Name',
|
||||
'model.smtp_attributes.recipients' => 'Recipients',
|
||||
'model.smtp_attributes.smtp_host' => 'Host',
|
||||
'model.smtp_attributes.smtp_port' => 'Port',
|
||||
'model.smtp_attributes.smtp_encryption' => 'Encryption',
|
||||
'model.smtp_attributes.smtp_username' => 'Username',
|
||||
'model.smtp_attributes.smtp_password' => 'Password',
|
||||
];
|
||||
public function mount($model)
|
||||
{
|
||||
@ -43,17 +43,17 @@ public function submit()
|
||||
{
|
||||
$this->resetErrorBag();
|
||||
$this->validate();
|
||||
$this->saveModel();
|
||||
}
|
||||
private function saveModel()
|
||||
{
|
||||
$this->model->save();
|
||||
if ( is_a($this->model, Team::class)) {
|
||||
if (is_a($this->model, Team::class)) {
|
||||
session(['currentTeam' => $this->model]);
|
||||
}
|
||||
}
|
||||
public function sendTestNotification()
|
||||
public function instantSave()
|
||||
{
|
||||
Notification::send($this->model, new DemoNotification);
|
||||
}
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.notifications.email-settings');
|
||||
$this->saveModel();
|
||||
}
|
||||
}
|
||||
|
19
app/Http/Livewire/Notifications/Test.php
Normal file
19
app/Http/Livewire/Notifications/Test.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Notifications;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\TestNotification;
|
||||
use Livewire\Component;
|
||||
use Notification;
|
||||
|
||||
class Test extends Component
|
||||
{
|
||||
public Team|Server $model;
|
||||
public function sendTestNotification()
|
||||
{
|
||||
Notification::send($this->model, new TestNotification);
|
||||
$this->emit('saved', 'Test notification sent.');
|
||||
}
|
||||
}
|
41
app/Http/Livewire/Settings/Email.php
Normal file
41
app/Http/Livewire/Settings/Email.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Settings;
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use Livewire\Component;
|
||||
|
||||
class Email extends Component
|
||||
{
|
||||
public InstanceSettings $model;
|
||||
|
||||
protected $rules = [
|
||||
'model.extra_attributes.from_address' => 'nullable',
|
||||
'model.extra_attributes.from_name' => 'nullable',
|
||||
'model.extra_attributes.recipients' => 'nullable',
|
||||
'model.extra_attributes.smtp_host' => 'nullable',
|
||||
'model.extra_attributes.smtp_port' => 'nullable',
|
||||
'model.extra_attributes.smtp_encryption' => 'nullable',
|
||||
'model.extra_attributes.smtp_username' => 'nullable',
|
||||
'model.extra_attributes.smtp_password' => 'nullable',
|
||||
'model.extra_attributes.smtp_timeout' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'model.extra_attributes.from_address' => 'From Address',
|
||||
'model.extra_attributes.from_name' => 'From Name',
|
||||
'model.extra_attributes.recipients' => 'Recipients',
|
||||
'model.extra_attributes.smtp_host' => 'Host',
|
||||
'model.extra_attributes.smtp_port' => 'Port',
|
||||
'model.extra_attributes.smtp_encryption' => 'Encryption',
|
||||
'model.extra_attributes.smtp_username' => 'Username',
|
||||
'model.extra_attributes.smtp_password' => 'Password',
|
||||
];
|
||||
public function mount($model)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.settings.email');
|
||||
}
|
||||
}
|
@ -22,16 +22,23 @@ protected static function booted()
|
||||
'port',
|
||||
'team_id',
|
||||
'private_key_id',
|
||||
'extra_attributes',
|
||||
'smtp_attributes',
|
||||
];
|
||||
|
||||
public $casts = [
|
||||
'extra_attributes' => SchemalessAttributes::class,
|
||||
'smtp_attributes' => SchemalessAttributes::class,
|
||||
];
|
||||
|
||||
public function scopeWithExtraAttributes(): Builder
|
||||
{
|
||||
return $this->extra_attributes->modelScope();
|
||||
}
|
||||
public function scopeWithSmtpAttributes(): Builder
|
||||
{
|
||||
return $this->smtp_attributes->modelScope();
|
||||
}
|
||||
|
||||
public function standaloneDockers()
|
||||
{
|
||||
@ -43,8 +50,6 @@ public function swarmDockers()
|
||||
return $this->hasMany(SwarmDocker::class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function privateKey()
|
||||
{
|
||||
return $this->belongsTo(PrivateKey::class);
|
||||
|
@ -2,42 +2,41 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Notifications\Channels\SendsCoolifyEmail;
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use App\Notifications\Channels\SendsDiscord;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
||||
|
||||
class Team extends BaseModel implements SendsDiscord, SendsCoolifyEmail
|
||||
class Team extends BaseModel implements SendsDiscord, SendsEmail
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
protected $casts = [
|
||||
'extra_attributes' => SchemalessAttributes::class,
|
||||
'smtp_attributes' => SchemalessAttributes::class,
|
||||
'personal_team' => 'boolean',
|
||||
];
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'name',
|
||||
'personal_team',
|
||||
'extra_attributes',
|
||||
'smtp_attributes',
|
||||
];
|
||||
|
||||
public function routeNotificationForDiscord()
|
||||
{
|
||||
return $this->extra_attributes->get('discord_webhook');
|
||||
return $this->smtp_attributes->get('discord_webhook');
|
||||
}
|
||||
|
||||
public function routeNotificationForCoolifyEmail()
|
||||
public function routeNotificationForEmail(string $attribute = 'recipients')
|
||||
{
|
||||
$recipients = $this->extra_attributes->get('recipients', '');
|
||||
|
||||
$recipients = $this->smtp_attributes->get($attribute, '');
|
||||
return explode(PHP_EOL, $recipients);
|
||||
}
|
||||
|
||||
public function scopeWithExtraAttributes(): Builder
|
||||
{
|
||||
return $this->extra_attributes->modelScope();
|
||||
return $this->smtp_attributes->modelScope();
|
||||
}
|
||||
|
||||
public function projects()
|
||||
|
@ -8,10 +8,11 @@
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
use Laravel\Fortify\TwoFactorAuthenticatable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, HasFactory, Notifiable;
|
||||
use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable;
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'name',
|
||||
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Channels;
|
||||
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class CoolifyEmailChannel
|
||||
{
|
||||
/**
|
||||
* Send the given notification.
|
||||
*/
|
||||
public function send(SendsCoolifyEmail $notifiable, Notification $notification): void
|
||||
{
|
||||
$this->bootConfigs($notifiable);
|
||||
$bcc = $notifiable->routeNotificationForCoolifyEmail();
|
||||
$mailMessage = $notification->toMail($notifiable);
|
||||
|
||||
Mail::send([], [], fn(Message $message) => $message
|
||||
->from(
|
||||
$notifiable->extra_attributes?->get('from_address'),
|
||||
$notifiable->extra_attributes?->get('from_name')
|
||||
)
|
||||
->bcc($bcc)
|
||||
->subject($mailMessage->subject)
|
||||
->html((string)$mailMessage->render())
|
||||
);
|
||||
}
|
||||
|
||||
private function bootConfigs($notifiable): void
|
||||
{
|
||||
config()->set('mail.mailers.smtp', [
|
||||
"transport" => "smtp",
|
||||
"host" => $notifiable->extra_attributes?->get('smtp_host'),
|
||||
"port" => $notifiable->extra_attributes?->get('smtp_port'),
|
||||
"encryption" => $notifiable->extra_attributes?->get('smtp_encryption'),
|
||||
"username" => $notifiable->extra_attributes?->get('smtp_username'),
|
||||
"password" => $notifiable->extra_attributes?->get('smtp_password'),
|
||||
"timeout" => $notifiable->extra_attributes?->get('smtp_timeout'),
|
||||
"local_domain" => null,
|
||||
]);
|
||||
}
|
||||
}
|
@ -13,9 +13,7 @@ class DiscordChannel
|
||||
public function send(SendsDiscord $notifiable, Notification $notification): void
|
||||
{
|
||||
$message = $notification->toDiscord($notifiable);
|
||||
|
||||
$webhookUrl = $notifiable->routeNotificationForDiscord();
|
||||
|
||||
dispatch(new SendMessageToDiscordJob($message, $webhookUrl));
|
||||
}
|
||||
}
|
||||
|
56
app/Notifications/Channels/EmailChannel.php
Normal file
56
app/Notifications/Channels/EmailChannel.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Channels;
|
||||
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class EmailChannel
|
||||
{
|
||||
/**
|
||||
* Send the given notification.
|
||||
*/
|
||||
public function send(SendsEmail $notifiable, Notification $notification): void
|
||||
{
|
||||
$this->bootConfigs($notifiable);
|
||||
if ($notification instanceof \App\Notifications\TestNotification) {
|
||||
$bcc = $notifiable->routeNotificationForEmail('test_address');
|
||||
if (count($bcc) === 1) {
|
||||
$bcc = $notifiable->routeNotificationForEmail();
|
||||
}
|
||||
} else {
|
||||
$bcc = $notifiable->routeNotificationForEmail();
|
||||
}
|
||||
$mailMessage = $notification->toMail($notifiable);
|
||||
|
||||
Mail::send(
|
||||
[],
|
||||
[],
|
||||
fn (Message $message) => $message
|
||||
->from(
|
||||
$notifiable->smtp_attributes?->get('from_address'),
|
||||
$notifiable->smtp_attributes?->get('from_name')
|
||||
)
|
||||
->cc($bcc)
|
||||
->bcc($bcc)
|
||||
->subject($mailMessage->subject)
|
||||
->html((string)$mailMessage->render())
|
||||
);
|
||||
}
|
||||
|
||||
private function bootConfigs($notifiable): void
|
||||
{
|
||||
config()->set('mail.default', 'smtp');
|
||||
config()->set('mail.mailers.smtp', [
|
||||
"transport" => "smtp",
|
||||
"host" => $notifiable->smtp_attributes?->get('smtp_host'),
|
||||
"port" => $notifiable->smtp_attributes?->get('smtp_port'),
|
||||
"encryption" => $notifiable->smtp_attributes?->get('smtp_encryption'),
|
||||
"username" => $notifiable->smtp_attributes?->get('smtp_username'),
|
||||
"password" => $notifiable->smtp_attributes?->get('smtp_password'),
|
||||
"timeout" => $notifiable->smtp_attributes?->get('smtp_timeout'),
|
||||
"local_domain" => null,
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Channels;
|
||||
|
||||
interface SendsCoolifyEmail
|
||||
{
|
||||
public function routeNotificationForCoolifyEmail();
|
||||
}
|
8
app/Notifications/Channels/SendsEmail.php
Normal file
8
app/Notifications/Channels/SendsEmail.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Channels;
|
||||
|
||||
interface SendsEmail
|
||||
{
|
||||
public function routeNotificationForEmail();
|
||||
}
|
@ -2,14 +2,14 @@
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Notifications\Channels\CoolifyEmailChannel;
|
||||
use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\DiscordChannel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class DemoNotification extends Notification implements ShouldQueue
|
||||
class TestNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
@ -29,8 +29,8 @@ public function __construct()
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
$channels = [];
|
||||
$notifiable->extra_attributes?->get('smtp_active') && $channels[] = CoolifyEmailChannel::class;
|
||||
$notifiable->extra_attributes?->get('discord_active') && $channels[] = DiscordChannel::class;
|
||||
$notifiable->smtp_attributes?->get('smtp_active') && $channels[] = EmailChannel::class;
|
||||
$notifiable->smtp_attributes?->get('discord_active') && $channels[] = DiscordChannel::class;
|
||||
return $channels;
|
||||
}
|
||||
|
||||
@ -40,15 +40,14 @@ public function via(object $notifiable): array
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('Coolify demo notification')
|
||||
->line('Welcome to Coolify!')
|
||||
->action('Go to dashboard', url('/'))
|
||||
->line('We need your attention for disk usage.');
|
||||
->subject('Coolify Test Notification')
|
||||
->line('Congratulations!')
|
||||
->line('You have successfully received a test Email notification from Coolify. 🥳');
|
||||
}
|
||||
|
||||
public function toDiscord(object $notifiable): string
|
||||
{
|
||||
return 'Welcome to Coolify! We need your attention for disk usage. [Go to dashboard]('.url('/').')';
|
||||
return 'You have successfully received a test Discord notification from Coolify. 🥳 [Go to your dashboard](' . url('/') . ')';
|
||||
}
|
||||
|
||||
/**
|
@ -13,6 +13,7 @@
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Fortify\Contracts\RegisterResponse;
|
||||
use Laravel\Fortify\Fortify;
|
||||
|
||||
class FortifyServiceProvider extends ServiceProvider
|
||||
@ -22,7 +23,17 @@ class FortifyServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
$this->app->instance(RegisterResponse::class, new class implements RegisterResponse
|
||||
{
|
||||
public function toResponse($request)
|
||||
{
|
||||
// First user (root) will be redirected to /settings instead of / on registration.
|
||||
if ($request->user()->currentTeam->id === 0) {
|
||||
return redirect('/settings');
|
||||
}
|
||||
return redirect('/');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,6 +41,7 @@ public function register(): void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Fortify::createUsersUsing(CreateNewUser::class);
|
||||
Fortify::registerView(function () {
|
||||
$settings = InstanceSettings::get();
|
||||
if (!$settings->is_registration_enabled) {
|
||||
@ -58,10 +70,21 @@ public function boot(): void
|
||||
Fortify::requestPasswordResetLinkView(function () {
|
||||
return view('auth.forgot-password');
|
||||
});
|
||||
Fortify::createUsersUsing(CreateNewUser::class);
|
||||
Fortify::resetPasswordView(function ($request) {
|
||||
return view('auth.reset-password', ['request' => $request]);
|
||||
});
|
||||
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
|
||||
|
||||
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
|
||||
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
|
||||
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
|
||||
|
||||
Fortify::confirmPasswordView(function () {
|
||||
return view('auth.confirm-password');
|
||||
});
|
||||
|
||||
Fortify::twoFactorChallengeView(function () {
|
||||
return view('auth.two-factor-challenge');
|
||||
});
|
||||
|
||||
RateLimiter::for('login', function (Request $request) {
|
||||
$email = (string) $request->email;
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('MAIL_MAILER', 'smtp'),
|
||||
'default' => env('MAIL_MAILER', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -16,7 +16,7 @@ public function up(): void
|
||||
$table->string('uuid')->unique();
|
||||
$table->string('name');
|
||||
$table->boolean('personal_team')->default(false);
|
||||
$table->schemalessAttributes('extra_attributes');
|
||||
$table->schemalessAttributes('smtp_attributes');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ public function up(): void
|
||||
$table->foreignId('team_id');
|
||||
$table->foreignId('private_key_id');
|
||||
$table->schemalessAttributes('extra_attributes');
|
||||
$table->schemalessAttributes('smtp_attributes');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
@ -64,13 +64,17 @@ services:
|
||||
- "./_data/coolify/proxy/testing-host-2:/data/coolify/proxy"
|
||||
mailpit:
|
||||
image: 'axllent/mailpit:latest'
|
||||
container_name: coolify-mail
|
||||
ports:
|
||||
- '${FORWARD_MAILPIT_PORT:-1025}:1025'
|
||||
- '${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025'
|
||||
networks:
|
||||
- coolify
|
||||
|
||||
buggregator:
|
||||
image: ghcr.io/buggregator/server:latest
|
||||
container_name: coolify-debug
|
||||
ports:
|
||||
- 23517:8000
|
||||
- 8001:8000
|
||||
networks:
|
||||
- coolify
|
||||
|
13
lang/en.json
13
lang/en.json
@ -1,11 +1,14 @@
|
||||
{
|
||||
"auth.login": "Login",
|
||||
"auth.already-registered": "Already registered?",
|
||||
"auth.register-now": "Register now!",
|
||||
"auth.already_registered": "Already registered?",
|
||||
"auth.confirm_password": "Confirm password",
|
||||
"auth.forgot_password": "Forgot password",
|
||||
"auth.forgot_password_send_email": "Send password reset link via email",
|
||||
"auth.register_now": "Register now!",
|
||||
"auth.logout": "Logout",
|
||||
"auth.register": "Register",
|
||||
"auth.registration_disabled": "Registration is disabled. Please contact the administrator.",
|
||||
"auth.reset_password": "Reset Password",
|
||||
"auth.reset_password": "Reset password",
|
||||
"auth.failed": "These credentials do not match our records.",
|
||||
"auth.failed.password": "The provided password is incorrect.",
|
||||
"auth.failed.email": "We can't find a user with that e-mail address.",
|
||||
@ -13,6 +16,8 @@
|
||||
"input.name": "Name",
|
||||
"input.email": "Email",
|
||||
"input.password": "Password",
|
||||
"input.password.again": "Password Again",
|
||||
"input.password.again": "Password again",
|
||||
"input.code": "One-time code",
|
||||
"input.recovery_code": "Recovery code",
|
||||
"button.save": "Save"
|
||||
}
|
@ -55,11 +55,14 @@ h1 {
|
||||
@apply text-3xl font-bold pb-4 text-white;
|
||||
}
|
||||
h2 {
|
||||
@apply text-2xl font-bold pb-4 text-white;
|
||||
@apply text-2xl font-bold py-4 text-white;
|
||||
}
|
||||
h3 {
|
||||
@apply text-xl font-bold py-4 text-white;
|
||||
}
|
||||
h4 {
|
||||
@apply text-base font-bold pb-4 text-white;
|
||||
}
|
||||
a {
|
||||
@apply text-neutral-400 hover:text-white text-sm link link-hover hover:bg-transparent;
|
||||
}
|
||||
|
28
resources/views/auth/confirm-password.blade.php
Normal file
28
resources/views/auth/confirm-password.blade.php
Normal file
@ -0,0 +1,28 @@
|
||||
<x-layout-simple>
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
<div>
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<div class="text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<x-version />
|
||||
</div>
|
||||
<div class="w-96">
|
||||
<form action="/user/confirm-password" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
<x-forms.input required type="password" name="password " label="{{ __('input.password') }}"
|
||||
autofocus />
|
||||
<x-forms.button type="submit">{{ __('auth.confirm_password') }}</x-forms.button>
|
||||
</form>
|
||||
@if ($errors->any())
|
||||
<div class="text-center text-error">
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if (session('status'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout-simple>
|
@ -1,50 +1,32 @@
|
||||
<x-layout-simple>
|
||||
Forgot Password
|
||||
<form>
|
||||
@csrf
|
||||
<x-forms.input required value="test@example.com" type="email" name="email" label="{{ __('input.email') }}"
|
||||
autofocus />
|
||||
</form>
|
||||
@if (session('status'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
{{-- <div class="flex items-center justify-center h-screen">
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
<div>
|
||||
<div class="pb-8 text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<div class="text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<x-version />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">{{ __('auth.login') }}</h1>
|
||||
@if ($is_registration_enabled)
|
||||
<a href="/register" class="flex justify-center pt-2 hover:no-underline">
|
||||
<button
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.register-now') }}</button>
|
||||
</a>
|
||||
@endif
|
||||
<h1 class="pb-0">{{ __('auth.forgot_password') }}</h1>
|
||||
</div>
|
||||
<div class="w-96">
|
||||
<form action="/login" method="POST" class="flex flex-col gap-2">
|
||||
<form action="/forgot-password" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
@env('local')
|
||||
<x-forms.input required value="test@example.com" type="email" name="email"
|
||||
label="{{ __('input.email') }}" autofocus />
|
||||
<x-forms.input required value="password" type="password" name="password"
|
||||
label="{{ __('input.password') }}" />
|
||||
@else
|
||||
<x-forms.input required type="email" name="email" label="{{ __('input.email') }}" autofocus />
|
||||
<x-forms.input required type="password" name="password" label="{{ __('input.password') }}" />
|
||||
@endenv
|
||||
@if ($errors->any())
|
||||
<div class="text-center text-error">
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
|
||||
@if (!$is_registration_enabled)
|
||||
<div class="text-sm text-center">{{ __('auth.registration_disabled') }}</div>
|
||||
@endif
|
||||
<x-forms.button type="submit">{{ __('auth.forgot_password_send_email') }}</x-forms.button>
|
||||
</form>
|
||||
@if ($errors->any())
|
||||
<div class="text-center text-error">
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if (session('status'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div> --}}
|
||||
</div>
|
||||
</x-layout-simple>
|
||||
|
@ -1,13 +1,16 @@
|
||||
<x-layout-simple>
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
<div>
|
||||
<div class="pb-8 text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<div class="text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<x-version />
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">{{ __('auth.login') }}</h1>
|
||||
@if ($is_registration_enabled)
|
||||
<a href="/register" class="flex justify-center pt-2 hover:no-underline">
|
||||
<button
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.register-now') }}</button>
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.register_now') }}</button>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
@ -17,6 +20,17 @@ class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{
|
||||
@env('local')
|
||||
<x-forms.input required value="test@example.com" type="email" name="email"
|
||||
label="{{ __('input.email') }}" autofocus />
|
||||
{{-- @if (config('mail.default'))
|
||||
{{ dd('mailer configured') }}
|
||||
@else
|
||||
{{ dd('mailer not configured') }}
|
||||
@endif --}}
|
||||
|
||||
@if (!config('mail.default'))
|
||||
<a href="/forgot-password" class="text-xs">
|
||||
{{ __('auth.forgot_password') }}?
|
||||
</a>
|
||||
@endif
|
||||
<x-forms.input required value="password" type="password" name="password"
|
||||
label="{{ __('input.password') }}" />
|
||||
@else
|
||||
@ -28,6 +42,11 @@ class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if (session('status'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
|
||||
@if (!$is_registration_enabled)
|
||||
<div class="text-sm text-center">{{ __('auth.registration_disabled') }}</div>
|
||||
|
@ -1,12 +1,15 @@
|
||||
<x-layout-simple>
|
||||
<div class="flex items-center justify-center min-h-screen">
|
||||
<div>
|
||||
<div class="pb-8 text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<div class="text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<x-version />
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">{{ __('auth.register') }}</h1>
|
||||
<a href="/login" class="flex justify-center pt-2 hover:no-underline">
|
||||
<button
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.already-registered') }}</button>
|
||||
class="normal-case rounded-none btn btn-sm btn-primary bg-coollabs-gradient">{{ __('auth.already_registered') }}</button>
|
||||
</a>
|
||||
</div>
|
||||
<form action="/register" method="POST" class="flex flex-col gap-2">
|
||||
|
38
resources/views/auth/reset-password.blade.php
Normal file
38
resources/views/auth/reset-password.blade.php
Normal file
@ -0,0 +1,38 @@
|
||||
<x-layout-simple>
|
||||
<div class="flex items-center justify-center h-screen mx-auto">
|
||||
<div>
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<div class="text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<x-version />
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<h1 class="pb-0">{{ __('auth.reset_password') }}</h1>
|
||||
</div>
|
||||
<div>
|
||||
<form action="/reset-password" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
<input hidden id="token" name="token" value="{{ request()->route('token') }}">
|
||||
<input hidden value="{{ request()->query('email') }}" type="email" name="email"
|
||||
label="{{ __('input.email') }}" />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required type="password" id="password" name="password"
|
||||
label="{{ __('input.password') }}" autofocus />
|
||||
<x-forms.input required type="password" id="password_confirmation" name="password_confirmation"
|
||||
label="{{ __('input.password.again') }}" />
|
||||
</div>
|
||||
<x-forms.button type="submit">{{ __('auth.reset_password') }}</x-forms.button>
|
||||
</form>
|
||||
@if ($errors->any())
|
||||
<div class="text-center text-error">
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if (session('status'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout-simple>
|
46
resources/views/auth/two-factor-challenge.blade.php
Normal file
46
resources/views/auth/two-factor-challenge.blade.php
Normal file
@ -0,0 +1,46 @@
|
||||
<x-layout-simple>
|
||||
<div class="flex items-center justify-center h-screen">
|
||||
<div>
|
||||
<div class="flex flex-col items-center pb-8">
|
||||
<div class="text-5xl font-bold tracking-tight text-center text-white">Coolify</div>
|
||||
<x-version />
|
||||
</div>
|
||||
<div class="w-96" x-data="{ showRecovery: false }">
|
||||
<form action="/two-factor-challenge" method="POST" class="flex flex-col gap-2">
|
||||
@csrf
|
||||
<template x-if="!showRecovery">
|
||||
<div>
|
||||
<x-forms.input required type="number" name="code" label="{{ __('input.code') }}"
|
||||
autofocus />
|
||||
<div class="pt-2 text-xs cursor-pointer hover:underline hover:text-white"
|
||||
x-on:click="showRecovery = !showRecovery">Use
|
||||
Recovery Code
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="showRecovery">
|
||||
<div>
|
||||
<x-forms.input required type="text" name="recovery_code "
|
||||
label="{{ __('input.recovery_code') }}" />
|
||||
<div class="pt-2 text-xs cursor-pointer hover:underline hover:text-white"
|
||||
x-on:click="showRecovery = !showRecovery">Use
|
||||
One-Time Code
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<x-forms.button type="submit">{{ __('auth.login') }}</x-forms.button>
|
||||
</form>
|
||||
@if ($errors->any())
|
||||
<div class="text-center text-error">
|
||||
<span>{{ __('auth.failed') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@if (session('status'))
|
||||
<div class="mb-4 text-sm font-medium text-green-600">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-layout-simple>
|
@ -25,8 +25,7 @@
|
||||
<main>
|
||||
{{ $slot }}
|
||||
</main>
|
||||
<a
|
||||
class="fixed text-xs cursor-pointer left-2 bottom-1 opacity-20 hover:opacity-100 hover:text-white">v{{ config('version') }}</a>
|
||||
<x-version class="fixed left-2 bottom-1" />
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -35,8 +35,7 @@
|
||||
<main>
|
||||
{{ $slot }}
|
||||
</main>
|
||||
<a
|
||||
class="fixed text-xs cursor-pointer right-2 bottom-1 opacity-60 hover:opacity-100 hover:text-white">v{{ config('version') }}</a>
|
||||
<x-version class="fixed left-2 bottom-1" />
|
||||
@auth
|
||||
<script>
|
||||
window.addEventListener("keydown", function(event) {
|
||||
|
2
resources/views/components/version.blade.php
Normal file
2
resources/views/components/version.blade.php
Normal file
@ -0,0 +1,2 @@
|
||||
<a
|
||||
{{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-20 hover:opacity-100 hover:text-white']) }}>v{{ config('version') }}</a>
|
@ -1,23 +1,19 @@
|
||||
<div class="">
|
||||
<div class="text-xl">Discord</div>
|
||||
<div class="mt-2"></div>
|
||||
<div>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div class="flex flex-col gap-2 xl:flex-row w-96">
|
||||
<x-inputs.input type="checkbox" id="model.extra_attributes.discord_active" label="Active?" />
|
||||
<div class="flex items-center gap-2">
|
||||
<h3>Discord</h3>
|
||||
<x-forms.button class="w-16 mt-4" type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row w-96">
|
||||
<x-inputs.input id="model.extra_attributes.discord_webhook" label="Discord Webhook" />
|
||||
<x-forms.checkbox instantSave id="model.smtp_attributes.discord_active" label="Notification Enabled" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row w-96">
|
||||
<x-forms.input required id="model.smtp_attributes.discord_webhook" label="Webhook" />
|
||||
</div>
|
||||
<div>
|
||||
<x-inputs.button class="w-16 mt-4" type="submit">
|
||||
Submit
|
||||
</x-inputs.button>
|
||||
<x-inputs.button
|
||||
class="mt-4 btn btn-xs no-animation normal-case text-white btn-primary"
|
||||
wire:click="sendTestNotification"
|
||||
>
|
||||
Send test message
|
||||
</x-inputs.button>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -1,45 +1,35 @@
|
||||
<div class="mt-10">
|
||||
<div class="text-xl">E-mail - SMTP</div>
|
||||
<div class="mt-2"></div>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col mt-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3>E-mail (SMTP)</h3>
|
||||
<x-forms.button class="w-16 mt-4" type="submit">
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.input type="checkbox" id="model.extra_attributes.smtp_active" label="Active?" />
|
||||
<x-forms.checkbox instantSave id="model.smtp_attributes.smtp_active" label="Notification Enabled" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.textarea
|
||||
id="model.extra_attributes.recipients"
|
||||
helper="E-mails, one per line"
|
||||
<x-forms.textarea required id="model.smtp_attributes.recipients" helper="E-mails, one per line"
|
||||
label="Recipients" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.input id="model.extra_attributes.smtp_host" label="Host" />
|
||||
<x-inputs.input id="model.extra_attributes.smtp_port" label="Port" />
|
||||
<x-inputs.input id="model.extra_attributes.smtp_encryption" label="Encryption" />
|
||||
<x-forms.input required id="model.smtp_attributes.smtp_host" label="Host" />
|
||||
<x-forms.input required id="model.smtp_attributes.smtp_port" label="Port" />
|
||||
<x-forms.input id="model.smtp_attributes.smtp_encryption" label="Encryption" />
|
||||
</div>
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.input id="model.extra_attributes.smtp_username" label="Username" />
|
||||
<x-inputs.input id="model.extra_attributes.smtp_password" label="Password" />
|
||||
<x-inputs.input id="model.extra_attributes.smtp_timeout" label="Timeout" />
|
||||
<x-forms.input id="model.smtp_attributes.smtp_username" label="Username" />
|
||||
<x-forms.input id="model.smtp_attributes.smtp_password" label="Password" />
|
||||
<x-forms.input id="model.smtp_attributes.smtp_timeout" label="Timeout" />
|
||||
</div>
|
||||
<div class="flex flex-col w-96">
|
||||
<x-inputs.input id="model.extra_attributes.from_address" label="From Address" />
|
||||
<x-inputs.input id="model.extra_attributes.from_name" label="From Name" />
|
||||
<x-inputs.input id="model.extra_attributes.test_address" label="Send test e-mails to" />
|
||||
<x-forms.input required id="model.smtp_attributes.from_address" label="From Address" />
|
||||
<x-forms.input required id="model.smtp_attributes.from_name" label="From Name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<x-inputs.button class="w-16 mt-4" type="submit">
|
||||
Submit
|
||||
</x-inputs.button>
|
||||
<x-inputs.button
|
||||
class="mt-4 btn btn-xs no-animation normal-case text-white btn-primary"
|
||||
wire:click="sendTestNotification"
|
||||
>
|
||||
Send test message
|
||||
</x-inputs.button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
4
resources/views/livewire/notifications/test.blade.php
Normal file
4
resources/views/livewire/notifications/test.blade.php
Normal file
@ -0,0 +1,4 @@
|
||||
<x-forms.button isHighlighted class="mt-4 text-white normal-case btn btn-xs no-animation btn-primary"
|
||||
wire:click="sendTestNotification">
|
||||
Send Test Notifications
|
||||
</x-forms.button>
|
@ -1,10 +1,12 @@
|
||||
<div>
|
||||
<form wire:submit.prevent='submit'>
|
||||
<form wire:submit.prevent='submit' class="flex flex-col">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3>Profile</h3>
|
||||
<h3>General</h3>
|
||||
<x-forms.button type="submit" label="Save">Save</x-forms.button>
|
||||
</div>
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="email" label="Email" readonly />
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
<x-forms.input id="email" label="Email" readonly />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
18
resources/views/livewire/settings/email.blade.php
Normal file
18
resources/views/livewire/settings/email.blade.php
Normal file
@ -0,0 +1,18 @@
|
||||
<form>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="model.extra_attributes.smtp_host" label="Host" />
|
||||
<x-forms.input id="model.extra_attributes.smtp_port" label="Port" />
|
||||
<x-forms.input id="model.extra_attributes.smtp_encryption" label="Encryption" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="model.extra_attributes.smtp_username" label="Username" />
|
||||
<x-forms.input id="model.extra_attributes.smtp_password" label="Password" />
|
||||
<x-forms.input id="model.extra_attributes.smtp_timeout" label="Timeout" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="model.extra_attributes.from_address" label="From Address" />
|
||||
<x-forms.input id="model.extra_attributes.from_name" label="From Name" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -6,8 +6,7 @@
|
||||
Save
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div class="pb-4 text-sm">Instance wide settings for Coolify.
|
||||
</div>
|
||||
<div class="pb-4 text-sm">Instance wide settings for Coolify.</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="settings.fqdn" label="Coolify's Domain" />
|
||||
@ -22,7 +21,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<h3>Advanced</h3>
|
||||
<div class="flex flex-col text-right w-52">
|
||||
<x-forms.checkbox instantSave id="is_auto_update_enabled" label="Auto Update Coolify" />
|
||||
@ -30,7 +28,5 @@
|
||||
{{-- <x-forms.checkbox instantSave id="is_https_forced" label="Force https?" /> --}}
|
||||
<x-forms.checkbox instantSave id="do_not_track" label="Do Not Track" />
|
||||
</div>
|
||||
@if (auth()->user()->isPartOfRootTeam())
|
||||
<livewire:force-upgrade />
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
@ -1,12 +1,9 @@
|
||||
<div class="pt-4">
|
||||
<h3>Switch Team</h3>
|
||||
@if (auth()->user()->otherTeams()->count() > 0)
|
||||
<div class="flex gap-2">
|
||||
@foreach (auth()->user()->otherTeams() as $team)
|
||||
<x-forms.button isHighlighted wire:key="{{ $team->id }}"
|
||||
wire:click="switch_to('{{ $team->id }}')">
|
||||
{{ $team->name }}</x-forms.button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex gap-2">
|
||||
@foreach (auth()->user()->otherTeams() as $team)
|
||||
<x-forms.button isHighlighted wire:key="{{ $team->id }}" wire:click="switch_to('{{ $team->id }}')">
|
||||
{{ $team->name }}</x-forms.button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,3 +1,73 @@
|
||||
<x-layout>
|
||||
<livewire:profile.form />
|
||||
<h1>Profile</h1>
|
||||
<livewire:profile.form :request="$request" />
|
||||
<h3>2FA</h3>
|
||||
@if (session('status') == 'two-factor-authentication-enabled')
|
||||
<div class="mb-4 text-sm font-medium">
|
||||
Please finish configuring two factor authentication below. Read the QR code or enter the secret key
|
||||
manually.
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<form action="/user/confirmed-two-factor-authentication" method="POST" class="flex items-end w-32 gap-2">
|
||||
@csrf
|
||||
<x-forms.input type="number" id="code" label="One-time code" required />
|
||||
<x-forms.button type="submit">Validate 2FA</x-forms.button>
|
||||
</form>
|
||||
<div>
|
||||
<div>{!! $request->user()->twoFactorQrCodeSvg() !!}</div>
|
||||
<div x-data="{ showCode: false }">
|
||||
<x-forms.button x-on:click="showCode = !showCode">Show secret key to manually enter</x-forms.button>
|
||||
<template x-if="showCode">
|
||||
<div class="text-sm">{!! decrypt($request->user()->two_factor_secret) !!}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@elseif(session('status') == 'two-factor-authentication-confirmed')
|
||||
<div class="mb-4 text-sm">
|
||||
Two factor authentication confirmed and enabled successfully.
|
||||
</div>
|
||||
<div>
|
||||
<div class="pb-6 text-sm">Here are the recovery codes for your account. Please store them in a secure
|
||||
location.</div>
|
||||
<div class="text-white">
|
||||
@foreach ($request->user()->recoveryCodes() as $code)
|
||||
<div>{{ $code }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@if ($request->user()->two_factor_confirmed_at)
|
||||
<div class="text-sm"> Two factor authentication is <span class="text-helper">enabled</span>.</div>
|
||||
<div class="flex gap-2">
|
||||
<form action="/user/two-factor-authentication" method="POST">
|
||||
@csrf
|
||||
@method ('DELETE')
|
||||
<x-forms.button type="submit">Disable</x-forms.button>
|
||||
</form>
|
||||
<form action="/user/two-factor-recovery-codes" method="POST">
|
||||
@csrf
|
||||
<x-forms.button type="submit">Regenerate Recovery Codes</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
@if (session('status') == 'recovery-codes-generated')
|
||||
<div>
|
||||
<div class="py-6 text-sm">Here are the recovery codes for your account. Please store them in a
|
||||
secure
|
||||
location.</div>
|
||||
<div class="text-white">
|
||||
@foreach ($request->user()->recoveryCodes() as $code)
|
||||
<div>{{ $code }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<div class="text-sm">Two factor authentication is <span class="text-helper">disabled</span>.</div>
|
||||
<form action="/user/two-factor-authentication" method="POST">
|
||||
@csrf
|
||||
<x-forms.button type="submit">Configure 2FA</x-forms.button>
|
||||
</form>
|
||||
@endif
|
||||
@endif
|
||||
</x-layout>
|
||||
|
@ -1,4 +1,10 @@
|
||||
<x-layout>
|
||||
<h1>Settings</h1>
|
||||
<livewire:settings.form :settings="$settings" />
|
||||
@if (auth()->user()->isPartOfRootTeam())
|
||||
<livewire:force-upgrade />
|
||||
@endif
|
||||
<h3 class="pb-0">Notification</h3>
|
||||
<div class="pb-4 text-sm">Notification (email, discord, etc) settings for Coolify.</div>
|
||||
<h4>Email</h4>
|
||||
<livewire:settings.email :model="$settings" />
|
||||
</x-layout>
|
||||
|
@ -1,13 +1,12 @@
|
||||
<x-layout>
|
||||
<div>
|
||||
<h3>Current Team</h3>
|
||||
<p>Name: {{ session('currentTeam.name') }}</p>
|
||||
<h1>Team</h1>
|
||||
<p>Current Team: {{ session('currentTeam.name') }}</p>
|
||||
@if (auth()->user()->otherTeams()->count() > 0)
|
||||
<livewire:switch-team />
|
||||
<div class="h-12"></div>
|
||||
<h3>Notifications</h3>
|
||||
<livewire:notifications.discord-settings :model="session('currentTeam')" />
|
||||
<livewire:notifications.email-settings :model="session('currentTeam')" />
|
||||
<div class="h-12"></div>
|
||||
</div>
|
||||
<livewire:switch-team>
|
||||
@endif
|
||||
<h2>Notifications</h2>
|
||||
<livewire:notifications.test :model="session('currentTeam')" />
|
||||
<livewire:notifications.email-settings :model="session('currentTeam')" />
|
||||
<livewire:notifications.discord-settings :model="session('currentTeam')" />
|
||||
<div class="h-12"></div>
|
||||
</x-layout>
|
||||
|
@ -125,8 +125,10 @@
|
||||
]);
|
||||
})->name('dashboard');
|
||||
|
||||
Route::get('/profile', function () {
|
||||
return view('profile');
|
||||
Route::get('/profile', function (Request $request) {
|
||||
return view('profile', [
|
||||
'request' => $request,
|
||||
]);
|
||||
})->name('profile');
|
||||
Route::get('/profile/team', function () {
|
||||
return view('team');
|
||||
|
Loading…
Reference in New Issue
Block a user