onConnection('provisioning'); $this->onQueue('provisioning'); } /** Auch was an handle() vorbeifliegt, muss am Sitz sichtbar werden. */ public function failed(?Throwable $e): void { Seat::query()->where('uuid', $this->seatUuid)->update([ 'nc_state' => Seat::STATE_FAILED, 'nc_error' => 'unexpected', ]); } public function handle(NextcloudUsers $users): void { $seat = Seat::query()->with('customer')->where('uuid', $this->seatUuid)->first(); if ($seat === null) { return; } // Erneut geprueft, nicht der Seite geglaubt: eine geschlossene Instanz // kann ihre VMID auf demselben Host weiterverliehen haben — dieselbe // Falle, die in IssueInstanceAdminAccess schon beschrieben steht. $instance = $seat->customer?->instances() ->whereIn('status', ['active', 'cancellation_scheduled']) ->latest('id')->first(); if ($instance === null || $instance->host === null || blank($instance->vmid)) { $this->record($seat, false, 'no_instance'); return; } $ok = match ($this->action) { 'invite' => $this->invite($users, $instance, $seat), 'role' => $users->applyRole($instance, $seat), 'disable' => $users->disable($instance, $seat), 'enable' => $users->enable($instance, $seat), default => false, }; $this->record($seat, $ok, $ok ? null : 'guest_failed'); } /** * Einladen setzt in einem Zug auch die Gruppe: ein Benutzer, der angelegt * ist und in keiner Rolle steckt, sieht in seiner neuen Cloud nichts und * meldet sich am ersten Tag beim Inhaber. * * Das Anlegen wird dabei SOFORT vermerkt, noch bevor die Gruppe gesetzt * wird. `nc_synced_at` beantwortet die Frage „gibt es dieses Konto dort * ueberhaupt?", und ab dem geglueckten `user:add` lautet die Antwort ja — * auch wenn der naechste Befehl scheitert. Die Seite entscheidet genau * daran, ob ein spaeteres Sperren etwas zu sperren haette; ohne diese Zeile * bliebe der gefaehrlichste Fall offen: Konto angelegt, Rolle gescheitert, * Zugang entzogen — und nie eine Sperre losgeschickt. * * `nc_state` bleibt davon unberuehrt: der Versuch ist erst gelungen, wenn * auch die Rolle sitzt. */ private function invite(NextcloudUsers $users, Instance $instance, Seat $seat): bool { if (! $users->invite($instance, $seat)) { return false; } $seat->forceFill(['nc_synced_at' => now()])->save(); return $users->applyRole($instance, $seat); } /** * `nc_synced_at` bleibt beim Fehlschlag stehen, statt geleert zu werden: * wann dieser Sitz zuletzt WIRKLICH stimmte, ist genau die Angabe, die * einen Fehlschlag einordnet — heute Morgen oder vor drei Wochen. */ private function record(Seat $seat, bool $ok, ?string $grund): void { $seat->forceFill([ 'nc_state' => $ok ? Seat::STATE_SYNCED : Seat::STATE_FAILED, 'nc_error' => $grund, 'nc_synced_at' => $ok ? now() : $seat->nc_synced_at, ])->save(); } }