This commit is contained in:
Andras Bacsai
2023-06-09 15:55:21 +02:00
parent 127d42d873
commit b097842d01
45 changed files with 322 additions and 158 deletions

View File

@@ -43,34 +43,21 @@ class CreateNewUser implements CreatesNewUsers
if (User::count() == 0) {
// If this is the first user, make them the root user
// Team is already created in the database/seeders/ProductionSeeder.php
$team = Team::find(0);
$user = User::create([
'id' => 0,
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
'is_root_user' => true,
]);
$team = $user->teams()->first();
} else {
$team = Team::create([
'name' => explode(' ', $input['name'], 2)[0] . "'s Team",
'personal_team' => true,
]);
$user = User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
'is_root_user' => false,
]);
$team = $user->teams()->first();
}
// Add user to team
DB::table('team_user')->insert([
'user_id' => $user->id,
'team_id' => $team->id,
'role' => 'admin',
]);
// Set session variable
session(['currentTeam' => $user->currentTeam = $team]);
return $user;

View File

@@ -51,4 +51,16 @@ class Controller extends BaseController
return redirect()->route('dashboard');
}
}
public function team()
{
ray(auth()->user()->isAdmin());
$invitations = [];
if (auth()->user()->isAdmin()) {
$invitations = auth()->user()->currentTeam()->invitations;
}
return view('team.show', [
'transactional_emails_active' => data_get(InstanceSettings::get(), 'extra_attributes.smtp_host') ? true : false,
'invitations' => $invitations,
]);
}
}

View File

@@ -31,7 +31,7 @@ class Form extends Component
$this->destination->delete();
return redirect()->route('dashboard');
} catch (\Exception $e) {
return general_error_handler($e);
return general_error_handler(err: $e);
}
}
}

View File

@@ -14,7 +14,7 @@ class ForceUpgrade extends Component
$this->visible = true;
dispatch(new InstanceAutoUpdateJob(force: true));
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -26,15 +26,15 @@ class EmailSettings extends Component
'model.extra_attributes.smtp_test_recipients' => 'nullable',
];
protected $validationAttributes = [
'model.extra_attributes.smtp_from_address' => '',
'model.extra_attributes.smtp_from_name' => '',
'model.extra_attributes.smtp_recipients' => '',
'model.extra_attributes.smtp_host' => '',
'model.extra_attributes.smtp_port' => '',
'model.extra_attributes.smtp_encryption' => '',
'model.extra_attributes.smtp_username' => '',
'model.extra_attributes.smtp_password' => '',
'model.extra_attributes.smtp_test_recipients' => '',
'model.extra_attributes.smtp_from_address' => 'From Address',
'model.extra_attributes.smtp_from_name' => 'From Name',
'model.extra_attributes.smtp_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_test_recipients' => 'Test Recipients',
];
public function copySMTP()
{

View File

@@ -35,7 +35,7 @@ class Change extends Component
$this->private_key->save();
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -38,7 +38,7 @@ class Create extends Component
}
return redirect()->route('private-key.show', ['private_key_uuid' => $private_key->uuid]);
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -28,8 +28,8 @@ class Form extends Component
User::where('id', $this->userId)->update([
'name' => $this->name,
]);
} catch (\Throwable $error) {
return general_error_handler($error, $this);
} catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -37,8 +37,8 @@ class DeploymentNavbar extends Component
// Remove builder container
instant_remote_process(["docker rm -f {$this->deployment_uuid}"], $this->application->destination->server, throwError: false, repeat: 25);
queue_next_deployment($this->application);
} catch (\Throwable $th) {
return general_error_handler($th, $this);
} catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -27,7 +27,7 @@ class All extends Component
$this->application->refresh();
$this->emit('clearAddEnv');
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -112,7 +112,7 @@ class General extends Component
$this->application->fqdn = $domains->implode(',');
$this->application->save();
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -41,9 +41,9 @@ class Previews extends Component
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = get_from_git_api($this->application->source, "/repos/{$this->application->git_repository}/pulls");
$this->rate_limit_remaining = $rate_limit_remaining;
$this->pull_requests = $data->sortBy('number')->values();
} catch (\Throwable $th) {
} catch (\Throwable $e) {
$this->rate_limit_remaining = 0;
return general_error_handler($th, $this);
return general_error_handler(err: $e, that: $this);
}
}
public function deploy(int $pull_request_id, string|null $pull_request_html_url = null)
@@ -70,8 +70,8 @@ class Previews extends Component
'deployment_uuid' => $this->deployment_uuid,
'environment_name' => $this->parameters['environment_name'],
]);
} catch (\Throwable $th) {
return general_error_handler($th, $this);
} catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this);
}
}
public function stop(int $pull_request_id)
@@ -83,8 +83,8 @@ class Previews extends Component
instant_remote_process(["docker rm -f $container_name"], $this->application->destination->server, throwError: false);
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
$this->application->refresh();
} catch (\Throwable $th) {
return general_error_handler($th, $this);
} catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -44,7 +44,7 @@ class ResourceLimits extends Component
$this->validate();
$this->application->save();
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -63,7 +63,7 @@ class Rollback extends Component
];
})->toArray();
} catch (\Throwable $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -27,7 +27,7 @@ class All extends Component
$this->application->refresh();
$this->emit('clearAddStorage');
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -138,7 +138,7 @@ class GithubPrivateRepository extends Component
'project_uuid' => $project->uuid,
]);
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
public function instantSave()

View File

@@ -96,7 +96,7 @@ class GithubPrivateRepositoryDeployKey extends Component
'application_uuid' => $application->uuid,
]);
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -68,8 +68,8 @@ class PublicGitRepository extends Component
try {
['data' => $data] = get_from_git_api($this->git_source, "/repos/{$this->git_repository}/branches");
$this->branches = collect($data)->pluck('name')->toArray();
} catch (\Throwable $th) {
return general_error_handler($th, $this);
} catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this);
}
}
private function get_git_source()
@@ -135,7 +135,7 @@ class PublicGitRepository extends Component
'application_uuid' => $application->uuid,
]);
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -29,7 +29,7 @@ class RunCommand extends Component
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true);
$this->emit('newMonitorActivity', $activity->id);
} catch (\Exception $e) {
return general_error_handler($e);
return general_error_handler(err: $e);
}
}
}

View File

@@ -55,7 +55,7 @@ class Form extends Component
$this->dockerComposeVersion = 'Not installed.';
}
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
public function delete()

View File

@@ -61,7 +61,7 @@ class ByIp extends Component
$server->settings->save();
return redirect()->route('server.show', $server->uuid);
} catch (\Exception $e) {
return general_error_handler($e);
return general_error_handler(err: $e);
}
}
}

View File

@@ -64,7 +64,7 @@ class Proxy extends Component
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
], $server);
} catch (\Exception $e) {
return general_error_handler($e);
return general_error_handler(err: $e);
}
}
public function resetProxy()
@@ -72,7 +72,7 @@ class Proxy extends Component
try {
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server, true);
} catch (\Exception $e) {
return general_error_handler($e);
return general_error_handler(err: $e);
}
}
public function checkProxySettingsInSync()
@@ -80,7 +80,7 @@ class Proxy extends Component
try {
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server);
} catch (\Exception $e) {
return general_error_handler($e);
return general_error_handler(err: $e);
}
}
}

View File

@@ -35,7 +35,7 @@ class Change extends Component
$this->validate();
$this->github_app->save();
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
public function instantSave()
@@ -45,7 +45,7 @@ class Change extends Component
$this->github_app->save();
$this->emit('saved', 'GitHub settings updated!');
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
public function mount()
@@ -63,7 +63,7 @@ class Change extends Component
$this->github_app->delete();
redirect()->route('dashboard');
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -43,7 +43,7 @@ class Create extends Component
]);
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
} catch (\Exception $e) {
return general_error_handler($e, $this);
return general_error_handler(err: $e, that: $this);
}
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Http\Livewire\Team;
use App\Models\TeamInvitation;
use App\Models\User;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class InviteLink extends Component
{
public string $email;
public function mount()
{
$this->email = config('app.env') === 'local' ? 'test@example.com' : '';
}
public function inviteByLink()
{
$uuid = new Cuid2(32);
$link = url('/') . '/api/invitation/' . $uuid;
try {
$user_exists = User::whereEmail($this->email)->exists();
if (!$user_exists) {
return general_error_handler(that: $this, customErrorMessage: "$this->email must be registered first (or activate transactional emails to invite via email).");
}
$invitation = TeamInvitation::where('email', $this->email);
if ($invitation->exists()) {
$created_at = $invitation->first()->created_at;
$diff = $created_at->diffInMinutes(now());
if ($diff < 11) {
return general_error_handler(that: $this, customErrorMessage: "Invitation already sent and active for $this->email.");
} else {
$invitation->delete();
}
}
$invitation = TeamInvitation::firstOrCreate([
'team_id' => session('currentTeam')->id,
'email' => $this->email,
'role' => 'readonly',
'link' => $link,
]);
$this->emit('reloadWindow');
} catch (\Throwable $e) {
$error_message = $e->getMessage();
if ($e->getCode() === '23505') {
$error_message = 'Invitation already sent.';
}
return general_error_handler(err: $e, that: $this, customErrorMessage: $error_message);
}
}
}

View File

@@ -8,10 +8,19 @@ use Livewire\Component;
class Member extends Component
{
public User $member;
public function makeAdmin()
{
$this->member->teams()->updateExistingPivot(session('currentTeam')->id, ['role' => 'admin']);
$this->emit('reloadWindow');
}
public function makeReadonly()
{
$this->member->teams()->updateExistingPivot(session('currentTeam')->id, ['role' => 'readonly']);
$this->emit('reloadWindow');
}
public function remove()
{
$this->member->teams()->detach(session('currentTeam'));
session(['currentTeam' => session('currentTeam')->fresh()]);
$this->emit('reloadWindow');
}
}

View File

@@ -62,6 +62,10 @@ class Team extends BaseModel implements SendsDiscord, SendsEmail
}
public function members()
{
return $this->belongsToMany(User::class, 'team_user', 'team_id', 'user_id');
return $this->belongsToMany(User::class, 'team_user', 'team_id', 'user_id')->withPivot('role');
}
public function invitations()
{
return $this->hasMany(TeamInvitation::class);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class TeamInvitation extends Model
{
protected $fillable = [
'team_id',
'email',
'role',
'link',
];
public function team()
{
return $this->belongsTo(Team::class);
}
}

View File

@@ -33,11 +33,37 @@ class User extends Authenticatable
static::creating(function (Model $model) {
$model->uuid = (string) new Cuid2(7);
});
static::created(function (User $user) {
$team = [
'name' => $user->name . "'s Team",
'personal_team' => true,
];
if ($user->id === 0) {
$team['id'] = 0;
$team['name'] = 'Root Team';
}
$new_team = Team::create($team);
$user->teams()->attach($new_team, ['role' => 'owner']);
});
}
public function isAdmin()
{
ray(session('currentTeam'));
return session('currentTeam');
if (auth()->user()->id === 0) {
ray('is root user');
return true;
}
$teams = $this->teams()->get();
$is_part_of_root_team = $teams->where('id', 0)->first();
$is_admin_of_root_team = $is_part_of_root_team &&
($is_part_of_root_team->pivot->role === 'admin' || $is_part_of_root_team->pivot->role === 'owner');
if ($is_part_of_root_team && $is_admin_of_root_team) {
ray('is admin of root team');
return true;
}
$role = $teams->where('id', session('currentTeam')->id)->first()->pivot->role;
return $role === 'admin' || $role === 'owner';
}
public function isInstanceAdmin()
{
@@ -51,14 +77,12 @@ class User extends Authenticatable
}
public function teams()
{
return $this->belongsToMany(Team::class);
return $this->belongsToMany(Team::class)->withPivot('role');
}
public function currentTeam()
{
return $this->teams()->where('team_id', session('currentTeam')->id)->first();
}
// public function currentTeam()
// {
// return $this->belongsTo(Team::class);
// }
public function otherTeams()
{
$team_id = session('currentTeam')->id;
@@ -66,6 +90,13 @@ class User extends Authenticatable
return $team->id != $team_id;
});
}
public function role()
{
if ($this->teams()->where('team_id', 0)->first()) {
return 'admin';
}
return $this->teams()->where('team_id', session('currentTeam')->id)->first()->pivot->role;
}
public function resources()
{
$team_id = session('currentTeam')->id;