Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/components/create-domains/SoaCreate.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script lang="ts">
import type {ApiRecordFormat, SoaValue} from "../../types/records";

export let editItem: ApiRecordFormat<SoaValue>;
export let editMode: boolean;
</script>

<div>Name</div>
<div class="code-font">{editItem.name}</div>

<!--
<div>Master Nameserver</div>
<div><input type="text" class="code-font" bind:value={editItem.value.target} size={Math.max(20, editItem.value.target.length + 2)} /></div>

<div>Admin Mailbox</div>
<div><input type="text" class="code-font" bind:value={editItem.value.target} size={Math.max(20, editItem.value.target.length + 2)} /></div>
-->

<div>Refresh</div>
<div><input type="number" class="code-font" bind:value={editItem.value.refresh} /></div>
<div>Retry</div>
<div><input type="number" class="code-font" bind:value={editItem.value.retry} /></div>
<div>Expire</div>
<div><input type="number" class="code-font" bind:value={editItem.value.expire} /></div>
<div>Default Time-to-Live</div>
<div><input type="number" class="code-font" bind:value={editItem.value.minttl} /></div>
115 changes: 115 additions & 0 deletions src/views/DomainsView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
type MxValue,
type NsValue,
type PtrValue,
type SoaValue,
type SrvValue,
type TxtValue,
} from "../types/records";
Expand Down Expand Up @@ -54,6 +55,7 @@
import PtrCreate from "../components/create-domains/PtrCreate.svelte";
import download from "downloadjs";
import {parseArpaToPrefix} from "../utils/arpa";
import SoaCreate from "../components/create-domains/SoaCreate.svelte";

const apiVerbena = import.meta.env.VITE_API_VERBENA;
const apiAllZones = apiVerbena + "/zones";
Expand All @@ -77,6 +79,20 @@
allZones = rows;
}

async function fetchSingleZone(id: number) {
let f = await LOGIN.clientRequest(apiAllZones + "/" + id, {method: "GET"});
if (f.status != 200) throw new Error("Unexpected status code: " + f.status);
let fJson = await f.json();
let row = fJson as Zone;
let newAllZones = allZones.map(x => {
if (x.id === row.id) {
return row;
}
return x;
});
allZones = newAllZones;
}

onMount(() => {
(async () => {
await fetchAllZones();
Expand Down Expand Up @@ -285,6 +301,46 @@
let blob = await f.blob();
download(blob, `${currentZone.name}.zone`);
}

let editSoaItem: ApiRecordFormat<SoaValue>;
let editSoaPopup: boolean = false;
let editSoaErrorMessage: string | null = null;

$: if (currentZone) {
editSoaItem = {
name: currentZone.name,
type: "SOA",
ttl: 0,
value: {
ns: currentZone.nameservers[0] ?? "",
mbox: currentZone.admin,
serial: currentZone.serial,
refresh: currentZone.refresh,
retry: currentZone.retry,
expire: currentZone.expire,
minttl: currentZone.ttl,
},
};
}

async function editSoaRecord() {
if (editSoaItem == null) return;
if (!currentZone) return;

let zone = currentZone;
let item = {
refresh: editSoaItem.value.refresh,
retry: editSoaItem.value.retry,
expire: editSoaItem.value.expire,
ttl: editSoaItem.value.minttl,
};

let f = await LOGIN.clientRequest(apiAllZones + "/" + zone.id, {method: "PUT", body: JSON.stringify(item)});
if (f.status !== 200 && f.status !== 201) throw new Error("Unexpected status code: " + f.status);
await f.json();

await fetchSingleZone(zone.id);
}
</script>

{#if domainTitle}
Expand All @@ -310,6 +366,54 @@
{/if}

{#if currentZone}
<div class="row">
<h2>SOA Record</h2>

<button class="edit-soa-button" on:click={() => (editSoaPopup = true)}>Edit SOA Record</button>

<ActionPopup name="Edit SOA Record" bind:show={editSoaPopup} on:save={editSoaRecord}>
<SoaCreate editItem={editSoaItem} editMode={true} />

{#if editSoaErrorMessage}
<div>{editSoaErrorMessage}</div>
{/if}
</ActionPopup>
</div>
<table>
<tbody>
<tr>
<th>Zone</th>
<td>{currentZone.name}</td>
</tr>
<tr>
<th>Admin</th>
<td>{currentZone.admin}</td>
</tr>
{#if currentZone.nameservers?.length > 0}
<tr>
<th>Nameservers</th>
<td>{(currentZone.nameservers || []).join(", ")}</td>
</tr>
{/if}
<tr>
<th>Refresh</th>
<td>{currentZone.refresh}</td>
</tr>
<tr>
<th>Retry</th>
<td>{currentZone.retry}</td>
</tr>
<tr>
<th>Expire</th>
<td>{currentZone.expire}</td>
</tr>
<tr>
<th>Default Time-to-Live</th>
<td>{currentZone.ttl}</td>
</tr>
</tbody>
</table>

{#each recordTypes as recordType}
<DomainTableView recordName={recordType.name} table={$table} emptyRecord={recordType.empty} {rowOrdering} isTRecord={recordType.filter}>
<tr slot="headers">
Expand Down Expand Up @@ -349,6 +453,17 @@
}
}

.row {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}

.edit-soa-button {
@include button-green-box;
}

.bot-token-selection {
-webkit-touch-callout: all; /* iOS Safari */
-webkit-user-select: all; /* Safari */
Expand Down
17 changes: 13 additions & 4 deletions test-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,21 @@ func apiServer(verify *mjwt.KeyStore) {
}))
r.Handle("/v1/verbena/zones", hasPerm(verify, "verbena:domains", func(rw http.ResponseWriter, req *http.Request, b mjwt.BaseTypeClaims[auth.AccessTokenClaims]) {
type Zone struct {
ID int64 `json:"id"`
Name string `json:"name"`
ID int64 `json:"id"`
Name string `json:"name"`
Serial int64 `json:"serial"`
Admin string `json:"admin"`
Refresh int64 `json:"refresh"`
Retry int64 `json:"retry"`
Expire int64 `json:"expire"`
Ttl int64 `json:"ttl"`
Active bool `json:"active"`
Nameservers []string `json:"nameservers"`
}

json.NewEncoder(rw).Encode([]Zone{
{ID: 1, Name: "example.com"},
{ID: 2, Name: "example.org"},
{ID: 1, Name: "example.com", Serial: 20260101, Admin: "hostmaster.example.com", Refresh: 7200, Retry: 1800, Expire: 86400, Ttl: 600, Active: true, Nameservers: []string{"ns1.example.com", "ns2.example.com"}},
{ID: 2, Name: "example.org", Serial: 20260101, Admin: "hostmaster.example.org", Refresh: 7200, Retry: 1800, Expire: 86400, Ttl: 600, Active: true, Nameservers: []string{"ns1.example.org", "ns2.example.org"}},
})
}))
r.Handle("/v1/verbena/zones/0/records", hasPerm(verify, "verbena:domains", func(rw http.ResponseWriter, req *http.Request, b mjwt.BaseTypeClaims[auth.AccessTokenClaims]) {
Expand Down