Merge branch '25-add-ssl-for-alias-domains-automatically' into develop

# Conflicts:
#	public/js/app.js
This commit is contained in:
Dennis Smink
2022-07-20 08:06:48 +02:00
38 changed files with 27713 additions and 181 deletions

View File

@@ -6,7 +6,6 @@ use App\Http\Requests\SiteAliasRequest;
use App\Http\Resources\SiteAliasResource;
use App\Jobs\Aliases\CreateAlias;
use App\Jobs\Aliases\DeleteAlias;
use Illuminate\Http\Request;
class SiteAliasController extends Controller
{
@@ -26,7 +25,7 @@ class SiteAliasController extends Controller
$site->addAlias($request->input('domain'));
dispatch(new CreateAlias($site, $request->input('domain')));
dispatch(new CreateAlias($site, $request->input('domain'), $request->boolean('request_new_certificate')));
return redirect()->route('sites.aliases.index', $id)->with('success', __('Alias has been created'));
}

View File

@@ -19,6 +19,9 @@ class SiteAliasRequest extends FormRequest
'required',
'string',
new Hostname,
],
'request_new_certificate' => [
'required',
]
];
}

View File

@@ -2,10 +2,12 @@
namespace App\Jobs\Aliases;
use App\Jobs\Certificates\CreateCertificate;
use App\Jobs\Certificates\DeleteCertificate;
use App\Models\Certificate;
use App\Models\Site;
use App\Traits\HasPloi;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
@@ -15,14 +17,11 @@ class CreateAlias implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, HasPloi;
public Site $site;
public string $alias;
public function __construct(Site $site, $alias)
{
$this->site = $site;
$this->alias = $alias;
}
public function __construct(
public Site $site,
public string $alias,
public bool $requestNewCertificate = false,
) {}
public function handle()
{
@@ -31,6 +30,35 @@ class CreateAlias implements ShouldQueue
->sites($this->site->ploi_id)
->aliases()
->create([$this->alias]);
if ($this->requestNewCertificate) {
$currentCertificate = $this
->site
->certificates()
->whereIn('status', [Certificate::STATUS_ACTIVE, Certificate::STATUS_BUSY])
->latest()
->first();
if (! $currentCertificate) {
return;
}
dispatch(new DeleteCertificate($this->site->server->ploi_id, $this->site->ploi_id, $currentCertificate->ploi_id));
$newCertificate = $this->site->certificates()->create([
'domain' => $currentCertificate->domain . ',' . $this->alias,
'type' => $currentCertificate->type,
'certificate' => $currentCertificate->certificate,
'private' => $currentCertificate->private
]);
$currentCertificate->delete();
$newCertificate->server_id = $this->site->server_id;
$newCertificate->save();
dispatch(new CreateCertificate($newCertificate))->delay(now()->addSeconds(5));
}
}
public function failed()

27379
public/js/app.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -35,7 +35,7 @@
<option value="danger">{{ __('Danger') }}</option>
</FormSelect>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -30,7 +30,7 @@
<option value="danger">{{ __('Danger') }}</option>
</FormSelect>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
<Button variant="danger" type="button" @click="confirmDelete">
{{ __('Delete') }}
</Button>

View File

@@ -29,7 +29,7 @@
:errors="$page.props.errors.content" v-model="form.content"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -29,7 +29,7 @@
v-model="form.content"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -25,7 +25,7 @@
<FormTextarea :label="__('Description')" :helper-text="__('You may use markdown in this field for markup')" :errors="$page.props.errors.description" v-model="form.description" />
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -25,7 +25,7 @@
<FormTextarea :label="__('Description')" helper-text="You may use markdown in this field for markup" :errors="$page.props.errors.description" v-model="form.description" />
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -143,7 +143,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -133,7 +133,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
<Button variant="danger" type="button" @click="confirmDelete">
{{ __('Delete') }}
</Button>

View File

@@ -59,7 +59,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
<Button variant="danger" type="button" @click="confirmDelete">{{ __('Delete') }}</Button>
</FormActions>
</form>

View File

@@ -28,7 +28,7 @@
:errors="$page.props.errors.maximum_sites"
v-model="form.maximum_sites"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
<Button variant="danger" type="button" @click="confirmDelete">
{{ __('Delete') }}
</Button>
@@ -44,7 +44,7 @@
<FormInput :label="__('Email')" :errors="$page.props.errors.email"
v-model="formAttach.email"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -22,7 +22,7 @@
<form class="space-y-4" @submit.prevent="submit">
<FormInput :label="__('Domain')" :errors="$page.props.errors.domain" v-model="form.domain" />
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
<Button variant="danger" type="button" @click="confirmDelete">{{ __('Delete') }}</Button>
</FormActions>
</form>
@@ -35,7 +35,7 @@
<form class="space-y-4" @submit.prevent="attach">
<FormInput :label="__('Email')" :errors="$page.props.errors.email" v-model="formAttach.email"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -191,7 +191,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -48,7 +48,7 @@
<vue-simplemde v-model="form.privacy"/>
</FormCustom>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -47,7 +47,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -55,7 +55,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
<Button variant="danger" type="button" @click="confirmDelete">
{{ __('Delete') }}
</Button>

View File

@@ -25,7 +25,7 @@
<FormInput :label="__('City')" type="text" :errors="$page.props.errors.city" v-model="form.city" />
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</PageBody>

View File

@@ -18,7 +18,7 @@
v-model="form.meta.cloudflare_email"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</PageBody>

View File

@@ -20,7 +20,7 @@
<FormInput :label="__('Confirm new password')" type="password" :errors="$page.props.errors.password_confirmation" v-model="form.password_confirmation" class="w-1/2" />
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -26,7 +26,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</PageBody>

View File

@@ -24,7 +24,7 @@
v-model="form.name"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -20,15 +20,23 @@
<template #title>{{ __('Create') }}</template>
<template #form>
<form class="space-y-4" @submit.prevent="submit">
<FormInput :label="__('Domain')" :errors="$page.props.errors.domain" v-model="form.domain"/>
<FormInput :label="__('Domain')" :errors="$page.props.errors.domain"
v-model="form.domain"/>
<div>
<input id="request_new_certificate" class="form-checkbox" type="checkbox"
v-model="form.request_new_certificate">
<label for="request_new_certificate" class="ml-2 text-sm">
{{ __('Request new certificate') }}
</label>
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>
</SettingsSegment>
<EmptyImage v-if="!aliases.length" />
<EmptyImage v-if="!aliases.length"/>
<SettingsSegment v-if="aliases.length">
<template #title>{{ __('Aliases') }}</template>
@@ -44,7 +52,9 @@
</TableHead>
<TableBody>
<TableRow v-for="(alias, index) in aliases" :key="index">
<TableData><StatusBubble :variant="'success'"/></TableData>
<TableData>
<StatusBubble :variant="'success'"/>
</TableData>
<TableData>{{ alias }}</TableData>
<TableData>
<Button variant="danger" size="sm"
@@ -66,145 +76,145 @@
</template>
<script>
import TopBar from './components/TopBar'
import Container from '@/components/Container'
import Content from '@/components/Content'
import Page from '@/components/Page'
import PageHeader from '@/components/PageHeader'
import PageHeaderTitle from '@/components/PageHeaderTitle'
import PageBody from '@/components/PageBody'
import Button from '@/components/Button'
import List from '@/components/List'
import ListItem from '@/components/ListItem'
import StatusBubble from '@/components/StatusBubble'
import NotificationBadge from '@/components/NotificationBadge'
import MainLayout from '@/Layouts/MainLayout'
import SettingsLayout from '@/components/layouts/SettingsLayout'
import SettingsSegment from '@/components/SettingsSegment'
import FormInput from '@/components/forms/FormInput'
import FormSelect from '@/components/forms/FormSelect'
import FormTextarea from '@/components/forms/FormTextarea'
import Form from '@/components/Form'
import Pagination from '@/components/Pagination'
import EmptyImage from '@/components/EmptyImage'
import FormActions from '@/components/FormActions'
import {useConfirm} from '@/hooks/confirm'
import Tabs from './Tabs'
import Table from '@/components/Table'
import TableHead from '@/components/TableHead'
import TableHeader from '@/components/TableHeader'
import TableRow from '@/components/TableRow'
import TableBody from '@/components/TableBody'
import TableData from '@/components/TableData'
import TopBar from './components/TopBar'
import Container from '@/components/Container'
import Content from '@/components/Content'
import Page from '@/components/Page'
import PageHeader from '@/components/PageHeader'
import PageHeaderTitle from '@/components/PageHeaderTitle'
import PageBody from '@/components/PageBody'
import Button from '@/components/Button'
import List from '@/components/List'
import ListItem from '@/components/ListItem'
import StatusBubble from '@/components/StatusBubble'
import NotificationBadge from '@/components/NotificationBadge'
import MainLayout from '@/Layouts/MainLayout'
import SettingsLayout from '@/components/layouts/SettingsLayout'
import SettingsSegment from '@/components/SettingsSegment'
import FormInput from '@/components/forms/FormInput'
import FormSelect from '@/components/forms/FormSelect'
import FormTextarea from '@/components/forms/FormTextarea'
import Form from '@/components/Form'
import Pagination from '@/components/Pagination'
import EmptyImage from '@/components/EmptyImage'
import FormActions from '@/components/FormActions'
import {useConfirm} from '@/hooks/confirm'
import Tabs from './Tabs'
import Table from '@/components/Table'
import TableHead from '@/components/TableHead'
import TableHeader from '@/components/TableHeader'
import TableRow from '@/components/TableRow'
import TableBody from '@/components/TableBody'
import TableData from '@/components/TableData'
export default {
metaInfo() {
return {
title: `${this.__('Certificates')} - ${this.site.domain}`,
}
},
export default {
metaInfo() {
return {
title: `${this.__('Certificates')} - ${this.site.domain}`,
}
},
layout: MainLayout,
layout: MainLayout,
components: {
TopBar,
Container,
Content,
Page,
PageHeader,
PageHeaderTitle,
PageBody,
Button,
List,
ListItem,
StatusBubble,
NotificationBadge,
FormInput,
FormSelect,
FormTextarea,
SettingsLayout,
SettingsSegment,
Form,
FormActions,
Pagination,
Tabs,
Table,
TableHead,
TableHeader,
TableRow,
TableBody,
TableData,
EmptyImage,
},
components: {
TopBar,
Container,
Content,
Page,
PageHeader,
PageHeaderTitle,
PageBody,
Button,
List,
ListItem,
StatusBubble,
NotificationBadge,
FormInput,
FormSelect,
FormTextarea,
SettingsLayout,
SettingsSegment,
Form,
FormActions,
Pagination,
Tabs,
Table,
TableHead,
TableHeader,
TableRow,
TableBody,
TableData,
EmptyImage,
},
data() {
return {
sending: false,
data() {
return {
sending: false,
form: {
domain: null,
form: {
domain: null,
request_new_certificate: false,
},
breadcrumbs: [
{
title: this.$page.props.settings.name,
to: '/',
},
{
title: this.__('Sites'),
to: this.route('sites.index'),
},
{
title: this.site.domain,
to: this.route('sites.show', this.site.id),
},
{
title: this.__('Aliases'),
to: this.route('sites.aliases.index', this.site.id),
},
],
}
},
breadcrumbs: [
{
title: this.$page.props.settings.name,
to: '/',
},
{
title: this.__('Sites'),
to: this.route('sites.index'),
},
{
title: this.site.domain,
to: this.route('sites.show', this.site.id),
},
{
title: this.__('Aliases'),
to: this.route('sites.aliases.index', this.site.id),
},
],
}
mounted() {
},
watch: {},
computed: {},
props: {
site: Object,
aliases: [Object, Array],
},
methods: {
submit() {
this.sending = true
this.$inertia.post(this.route('sites.aliases.store', this.site.id), this.form, {
onFinish: () => {
this.sending = false
this.form.domain = null;
this.form.request_new_certicate = false;
}
});
},
mounted() {
confirmDelete(alias) {
useConfirm({
title: this.__('Are you sure?'),
message: this.__('Your alias will be deleted permanently, this action cannot be undone.'),
onConfirm: () => this.delete(alias),
})
},
watch: {
delete(alias) {
this.$inertia.delete(this.route('sites.aliases.delete', [this.site.id, alias]), {
preserveScroll: true
})
},
computed: {
},
props: {
site: Object,
aliases: [Object, Array],
},
methods: {
submit() {
this.sending = true
this.$inertia.post(this.route('sites.aliases.store', this.site.id), this.form, {
onFinish: () => {
this.sending = false
this.form.domain = null;
}
});
},
confirmDelete(alias) {
useConfirm({
title: this.__('Are you sure?'),
message: this.__('Your alias will be deleted permanently, this action cannot be undone.'),
onConfirm: () => this.delete(alias),
})
},
delete(alias) {
this.$inertia.delete(this.route('sites.aliases.delete', [this.site.id, alias]), {
preserveScroll: true
})
},
},
}
},
}
</script>

View File

@@ -37,7 +37,7 @@
<FormTextarea v-if="form.type === 'custom'" :label="__('Private key')" :errors="$page.props.errors.private" rows="2" v-model="form.private" />
<FormTextarea v-if="form.type === 'custom'" :label="__('Certificate')" :errors="$page.props.errors.certificate" rows="2" v-model="form.certificate" />
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -72,7 +72,7 @@
</div>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -31,7 +31,7 @@
v-model="form.password"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -27,7 +27,7 @@
<FormInput :disabled="sending" :label="__('IPv4 address')" :errors="$page.props.errors.address" v-model="form.address"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -30,7 +30,7 @@
<option value="permanent">{{ __('Permanent') }} (301)</option>
</FormSelect>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -24,7 +24,7 @@
v-model="form.domain"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>
@@ -73,7 +73,7 @@
v-model="form.dns_id"/>
<FormActions>
<Button>{{ __('Save changes') }}</Button>
<Button>{{ __('Save') }}</Button>
</FormActions>
</form>
</template>

View File

@@ -0,0 +1,115 @@
<template>
<FormGroup class="">
<div class="flex flex-row items-center">
<input :id="id"
:class="[
defaultClasses,
disabled || loading ? 'opacity-50' : '',
loading ? 'cursor-wait' : '',
]"
type="checkbox"
:required="required"
:value="value"
@input="updateValue($event.target.value)"
:disabled="loading || disabled"
:autofocus="autofocus"
:placeholder="placeholder" />
<ErrorText v-if="errors">{{ errors[0] }}</ErrorText>
<HelperText v-if="helperText && !errors">{{ helperText }}</HelperText>
<Label :errors="errors" :forId="id" class="ml-2">{{ label }}</Label>
</div>
</FormGroup>
</template>
<script>
import FormGroup from '@/components/FormGroup'
import Label from '@/components/Label'
import ErrorText from '@/components/ErrorText'
import HelperText from '@/components/HelperText'
import IconClipboard from '@/components/icons/IconClipboard'
import IconKey from '@/components/icons/IconKey'
const defaultClasses = ''
export default {
props: {
id: {
type: String,
required: false,
},
label: {
type: String,
required: true,
},
required: {
type: Boolean,
default: () => false,
},
errors: {
type: Array,
},
helperText: {
type: String
},
placeholder: {
type: String,
},
value: {
required: false,
default: '',
},
loading: {
type: Boolean,
required: false,
default: false,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
autofocus: {
type: Boolean,
required: false,
default: false,
}
},
components: {
FormGroup,
Label,
ErrorText,
HelperText,
IconClipboard,
IconKey,
},
data() {
return {
defaultClasses,
copied: false,
}
},
watch: {
copied() {
let vm = this;
if (this.copied) {
setTimeout(() => {
vm.copied = false;
}, 1250);
}
}
},
methods: {
updateValue(value) {
this.$emit('input', value);
},
},
computed: {},
}
</script>

View File

@@ -3,7 +3,7 @@
"Name": "Navn",
"Edit": "Rediger",
"Save": "Gem",
"Save changes": "Gem ændringer",
"Save": "Gem ændringer",
"Delete": "Slet",
"Create": "Opret",
"Cancel": "Annuller",

View File

@@ -3,7 +3,7 @@
"Name": "Nombre",
"Edit": "Editar",
"Save": "Guardar",
"Save changes": "Guardar Cambios",
"Save": "Guardar Cambios",
"Delete": "Borrar",
"Create": "Crear",
"Cancel": "Cancelar",

View File

@@ -3,7 +3,7 @@
"Name": "Nom",
"Edit": "Modifier",
"Save": "Sauvegarder",
"Save changes": "Sauvegarder",
"Save": "Sauvegarder",
"Delete": "Supprimer",
"Create": "Créer",
"Cancel": "Annuler",

View File

@@ -3,7 +3,7 @@
"Name": "Navn",
"Edit": "Rediger",
"Save": "Lagre",
"Save changes": "Lagre endringer",
"Save": "Lagre endringer",
"Delete": "Slett",
"Create": "Opprett",
"Cancel": "Avbryt",
@@ -209,4 +209,4 @@
"You can synchronize your servers here. It is safe to synchronize already existing servers. If you have installed a extra PHP version for example, you can synchronize to update the versions here.": "Du kan synkronisere serverne dine her. Det er trygt å synkronisere allerede eksisterende servere. Hvis du for eksempel har installert en ekstra PHP-versjon, kan du synkronisere for å oppdatere versjonene her.",
"Create a new package here to attach to your users. You can create as many packages as you want, the advantage is that you are able to provide custom packages for your users.": "Lag en ny pakke her for å knytte til brukerne dine. Du kan lage så mange pakker du vil, fordelen er at du er i stand til å tilby tilpassede pakker til brukerne dine.",
"System update has been dispatched, this could take around 2/3 minutes for it to complete": "Systemoppdateringen er sendt, dette kan ta rundt 2 til 3 minutter før den er fullført"
}
}

View File

@@ -3,7 +3,7 @@
"Name": "Naam",
"Edit": "Bewerk",
"Save": "Opslaan",
"Save changes": "Opslaan",
"Save": "Opslaan",
"Delete": "Verwijderen",
"Create": "Aanmaken",
"Cancel": "Annuleren",

View File

@@ -3,7 +3,7 @@
"Name": "Nome",
"Edit": "Editar",
"Save": "Salvar",
"Save changes": "Salvar alterações",
"Save": "Salvar alterações",
"Delete": "Remover",
"Create": "Criar",
"Cancel": "Cancelar",