reCoreD-UI/web/src/stores/records.ts
Sense T 021ec9c8f6 Squashed commit of the following:
commit a394259f0a515c4ee68377e73546de9b0e69beea
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 15:10:08 2024 +0800

    done

commit af9d9663760af0d1984dec085230e434f79e84cb
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 13:52:33 2024 +0800

    debug done.

commit 47335ca5e9447b2de08a4a83e55541918914835e
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 12:47:00 2024 +0800

    swagger done

commit 34fb2a478b90760c1efd4401a59a29bb236a8653
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 10:05:19 2024 +0800

    stage 2, not completed

commit 88b2255f8bf72840b7f050692fccc34cef1a0c14
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 19 09:44:37 2024 +0800

    test stage 1

commit b5837202235c0a96140b4629b85ef27800125fe8
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 15 21:53:09 2024 +0800

    Squashed commit of the following:

    commit 1e92328a0fc570fe9419ad5dbaaef77f7dc9ad2e
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 21:52:44 2024 +0800

        yes, react it!

    commit 09fffff6139b4cecb81cb1444139f225e95e8917
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 17:33:26 2024 +0800

        actions to be done

    commit 1611b0b338cfd965d15f43fb10308bc56015895f
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 15:22:08 2024 +0800

        modal needed.

    commit 88453e7382618fb6774ff1cc4c0f7045d4dfcf46
    Author: Sense T <me@sense-t.eu.org>
    Date:   Mon Apr 15 10:52:13 2024 +0800

        Domain View done

    commit 8cedca27c79ca2ba69c8777dfcb6019799875e31
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sun Apr 14 21:24:14 2024 +0800

        domain delete modal done

    commit 60cd00c0cad0774bae5b57bcfc4723a29d28d221
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sun Apr 14 07:55:11 2024 +0800

        1

    commit 285853e988db6e6a6371135869da0129fd73afd7
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 17:29:43 2024 +0800

        eslint

    commit 8f0ffbf744fd85a612daacd7bd6cbc45d58907d3
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 17:20:50 2024 +0800

        f

    commit 9762b632225f185d83388e58d93ed49f62fe6b3f
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 17:08:37 2024 +0800

        views, components to be done

    commit 321e5255f2b1e705844179dd910d5f5a1ae58298
    Author: Sense T <me@sense-t.eu.org>
    Date:   Sat Apr 13 14:29:04 2024 +0800

        prepare for react

commit 3305d8d618d6d4f8332e8cd5cffe25e3a526808c
Author: Sense T <me@sense-t.eu.org>
Date:   Sat Apr 13 10:30:02 2024 +0800

    swagger to be done

commit 2c754e7eec2bbfba8fcb8eaa3d9d0c90c8141216
Author: Sense T <me@sense-t.eu.org>
Date:   Sat Apr 13 10:14:45 2024 +0800

    validate 'em !

commit 7b529ad8f61d8c2dda66064a44011976d91f0665
Author: Sense T <me@sense-t.eu.org>
Date:   Sat Apr 13 09:22:27 2024 +0800

    try to avoid nil point panic

commit 0012a697cbf2712228a0c78670180c317f0132cf
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 12 22:26:35 2024 +0800

    fix some bug

commit a098d3056ce0694587394177e3b06b6ce6f59fe3
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 12 20:03:34 2024 +0800

    web debug done

commit 01765c4e7f8f1345980bee1c849985408c6195e5
Author: Sense T <me@sense-t.eu.org>
Date:   Fri Apr 12 15:16:52 2024 +0800

    all tsx used, no vue SFC

commit 731504ae8283d7a47d1915c9d115df6f80e65245
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 22:05:58 2024 +0800

    tsx used - stage 2

commit b669a3e68e66b18dcb6d49b8113a3244c2715d4f
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 16:18:11 2024 +0800

    use tsx for compoents stage 1

commit 2ab1b0bf1ba52622af3500b7488a2209adfedddb
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 12:10:57 2024 +0800

    rr validation

commit 58c66fc3a8bbb9b2635e7af16974bc7d0878b26d
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 11:41:33 2024 +0800

    stage 1

commit 7a5fcf19725af32af31ac7aec4d715501a0665f8
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 10:51:50 2024 +0800

    long options supported

commit c3b80093d20ea4a284d3df38b6955f6ac3cdab3b
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 10:51:33 2024 +0800

    for develop use

commit 7f527073236238f768f7233a5b6c9893973eccf8
Author: Sense T <me@sense-t.eu.org>
Date:   Thu Apr 11 10:51:24 2024 +0800

    fix typo

commit 9cc2696bbea57907ee4aeb2fdf8dbaae79b4a804
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 16:53:03 2024 +0800

    record data validate done

commit 5e2ae637a0fa75393a34cc982f761fc8d2d5a0eb
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 14:56:15 2024 +0800

    end with dot.

commit ed4fee935daf4af4928d4c6c60d4a52fed31613d
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 13:41:32 2024 +0800

    content safety

commit 29f75938bb4bd28943fc921d24ed71b321cc302c
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 13:24:01 2024 +0800

    cmd is ok

commit 9465bb885d2f7eac7f7a74b789ba4426ba710792
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 11:00:47 2024 +0800

    web done

commit 65bf461d448127b52dde0dfe735baddc303353a0
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 10 11:00:38 2024 +0800

    use tokei for stat

commit 61395ab61b4177a4f023941fbcb86233bd889922
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 21:53:12 2024 +0800

    errors handler

commit 9752e7d9ae547b8cfbf489cdcf65e4c283df62e3
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 21:16:19 2024 +0800

    model with generics done

commit 7dd3af37079e0abfd69ed35a64706dfb1f6a2a29
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 16:28:18 2024 +0800

    use DAO

commit 236973423082b6d6e61d4d92067135f4bc247223
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 13:06:31 2024 +0800

    dao for future

commit e18781ba259b79c9bc5bf464b5b7204e33607e40
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 11:36:34 2024 +0800

    DotEnd

commit 613ef7fdd9325a3495dbfd84805c953f170d9851
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 10:16:06 2024 +0800

    record should endwith .

commit c93e8107dc43605e4d5197aad6c03dbdec7fc9c9
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 10:06:47 2024 +0800

    update regexp

commit 84e9961f4befbf99fc88de31119f69fc5ba26c35
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 08:30:32 2024 +0800

    error log

commit db77b0fdb215ad767d3466e654774da78ac7b587
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 08:25:25 2024 +0800

    no console log

commit 0c197820a09b8ffdc3b3152160e4b4314dfe0fbe
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 08:25:01 2024 +0800

    use flags for validate

commit 33c90506539a6d5e0c0003d5e7832f9293deeed3
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 07:58:27 2024 +0800

    SOA Email Format

commit fb9c78efed5c4078d666149d0b04f11838e4904a
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 00:19:03 2024 +0800

    no debug

commit 1a7bf83cb9c5f693ab191f1160e4e235450f4988
Author: Sense T <me@sense-t.eu.org>
Date:   Tue Apr 9 00:18:18 2024 +0800

    1

commit e72de1479771954aa9d4be0e79a9909cf0ccb8af
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 17:30:25 2024 +0800

    last modal

commit e884840b7dabc2c3aedd1cff8072cf4f30d1fb12
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 15:56:03 2024 +0800

    add

commit 36b03843191004fc29b8e7276b9bd8e7ca478d09
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 15:02:55 2024 +0800

    delete domain modal done

commit 753e950faeee8dda8c1c6dbd7da5d1fd8f297ff5
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 13:49:11 2024 +0800

    add domainRemovemodal

commit 69613f9b6eee1e8b5dd132ca38d1019da5f304c0
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 13:32:01 2024 +0800

    modal needed for edit

commit 8c0b79066f8886674d33baeafef29dd504506c8c
Author: Sense T <me@sense-t.eu.org>
Date:   Mon Apr 8 09:37:32 2024 +0800

    base UI

commit a67b2d7724123f2fdcfe911f3150804f27ffe03f
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 21:07:20 2024 +0800

    route update

commit 5a266e9e6c942def49931bd70ff88c7e3c2622a3
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 14:36:55 2024 +0800

    ui base data struct

commit 3449df913c553614a4b5c4e2c31e5fbb1cfde509
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 13:08:45 2024 +0800

    web store for dev

commit 156bf651dd8b770a277eaa7087a2364467931001
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 13:08:30 2024 +0800

    store friendly

commit d90e9494722fc11017889fadb24298421793eb10
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 10:08:02 2024 +0800

    base code update

commit 0a20b5a67048ac5ee48edac049969591d81f0586
Author: Sense T <me@sense-t.eu.org>
Date:   Sun Apr 7 10:07:26 2024 +0800

    metrics

commit bdd4866c10b07ea918608e8b653760a246a60dad
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 3 22:37:15 2024 +0800

    all api done

commit 8a8ea59b71c1842ab1f40e76333ffb2134018faf
Author: Sense T <me@sense-t.eu.org>
Date:   Wed Apr 3 17:05:12 2024 +0800

    1
2024-04-19 15:16:24 +08:00

358 lines
11 KiB
TypeScript

import { useState } from 'react'
import i18n from '../locale'
import api from '../api';
const { t } = i18n
export class ARecord {
ip?: string
static validate(v: ARecord): true | Error {
if (!v.ip || v.ip === '') return new Error(t('common.mandatory'))
if (!/^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])$/.test(v.ip)) return new Error(t('records.errors.badIPv4'))
return true
}
toString(): string | undefined {
return this.ip
}
}
export class AAAARecord {
ip?: string
static validate(v: AAAARecord): true | Error {
if (!v.ip || v.ip === '') return new Error(t('common.mandatory'))
if (!/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(v.ip)) return new Error(t('records.errors.badIPv4'))
return true
}
toString(): string | undefined {
return this.ip
}
}
export class TXTRecord {
text?: string
static validate(v: TXTRecord): true | Error {
if (!v.text || v.text === '') return new Error(t('common.mandatory'))
if (v.text.length > 512) return new Error('records.errors.tooLong')
return true
}
toString(): string | undefined {
return this.text
}
}
export class CNAMERecord {
host?: string
static validate(v: CNAMERecord): true | Error {
if (!v.host || v.host === '') return new Error(t('common.mandatory'))
if (v.host.includes(' ')) return new Error(t('records.errors.hasSpace'))
if (!v.host.endsWith('.')) return new Error(t('records.errors.endWithDot'))
return true
}
toString(): string | undefined {
return this.host
}
}
export class NSRecord {
host?: string
static validate(v: NSRecord): true | Error {
if (!v.host || v.host === '') return new Error(t('common.mandatory'))
if (v.host.includes(' ')) return new Error(t('records.errors.hasSpace'))
if (!v.host.endsWith('.')) return new Error(t('records.errors.endWithDot'))
return true
}
toString(): string | undefined {
return this.host
}
}
export class MXRecord {
host?: string
preference?: number
static validate(v: MXRecord): true | Error {
if (!v.host || v.host === '' || !v.preference) return new Error(t('common.mandatory'))
if (v.host.includes(' ')) return new Error(t('records.errors.hasSpace'))
if (!v.host.endsWith('.')) return new Error(t('records.errors.endWithDot'))
return true
}
toString(): string | undefined {
return Object.entries(this).map(i => i[1]).join(" ")
}
}
export class SRVRecord {
priority?: number;
weight?: number;
port?: number;
target?: string;
static validate(v: SRVRecord): true | Error {
if (!v.port || !v.priority || !v.weight || !v.target || v.target === '') return new Error(t('common.mandatory'))
if (v.target?.includes(' ')) return new Error(t('records.errors.hasSpace'))
if (!v.target?.endsWith('.')) return new Error(t('records.errors.endWithDot'))
return true
}
toString(): string | undefined {
return Object.entries(this).map(i => i[1]).join(" ")
}
}
export class SOARecord {
ns?: string;
MBox?: string;
refresh?: number;
retry?: number;
expire?: number;
minttl?: number;
static validate(v: SOARecord): true | Error {
if (!v.refresh || !v.retry || !v.expire! || !v.minttl || !v.MBox || v.MBox === '' || !v.ns || v.ns === '') return new Error(t('common.mandatory'))
if (v.ns?.includes(' ') || v.MBox?.includes(' ')) return new Error(t('records.errors.hasSpace'))
if (!v.ns?.endsWith('.') || !v.MBox?.endsWith('.')) return new Error(t('records.errors.endWithDot'))
if (v.MBox?.includes('@')) return new Error(t('records.errors.badEmail'))
return true
}
toString(): string | undefined {
return Object.entries(this).map(i => i[1]).join(" ")
}
}
export class CAARecord {
flag?: number
tag?: string
value?: string
static validate(v: CAARecord): true | Error {
if (!v.flag || !v.tag || v.tag === '' || !v.value || v.value === '') return new Error(t('common.mandatory'))
if (v.tag?.includes(' ')) return new Error(t('records.errors.hasSpace'))
return true
}
toString(): string | undefined {
return Object.entries(this).map(i => i[1]).join(" ")
}
}
export enum RecordTypes {
RecordTypeA = "A",
RecordTypeAAAA = "AAAA",
RecordTypeCNAME = "CNAME",
RecordTypeSOA = "SOA",
RecordTypeTXT = "TXT",
RecordTypeNS = "NS",
RecordTypeMX = "MX",
RecordTypeCAA = "CAA",
RecordTypeSRV = "SRV"
}
export type RecordT = ARecord | AAAARecord | TXTRecord | CNAMERecord | NSRecord | MXRecord | SRVRecord | SOARecord | CAARecord
export class Record<T = RecordT> {
id?: number
zone?: string
name?: string
ttl?: number
content?: T
record_type?: RecordTypes
validate(): true | Error {
const zone = Record.validateZone(this.zone!)
if (zone !== true) return zone
const name = Record.validateName(this.name!)
if (name !== true) return name
return true
}
static validateZone(zone: string): true | Error {
if (zone === '') return new Error(t('common.mandatory'))
if (zone.includes(' ')) new Error(t('records.errors.hasSpace'))
if (zone.endsWith('.')) return new Error(t('records.errors.endWithDot'))
return true
}
static validateName(name: string): true | Error {
if (name === '') return new Error(t('common.mandatory'))
// RR should not contain space, and should not start or end with '-' or '.'
if (name.includes(' ')) return new Error(t('records.errors.hasSpace'))
if (name.startsWith('.') || name.endsWith('.')) return new Error(t('records.errors.badName.dotAndMinus'))
if (name.startsWith('-') || name.endsWith('.')) return new Error(t('records.errors.badName.dotAndMinus'))
// RR should not have continuous dots
if (name.includes('..')) new Error(t('records.errors.badName.doubleDots'))
// RR should not longer than 63 characters for every section seprated by '.'
if (name.split('.').filter(e => e.length > 63).length > 0) return new Error(t('records.errors.badName.longerThan63'))
return true
}
}
// example data for development
const recordDevData = new Map<string, Record[]>([
['example.com', [
{
id: 1,
zone: "example.com",
name: "@",
ttl: 3600,
record_type: RecordTypes.RecordTypeSOA,
content: {
ns: "ns1.example.com.",
MBox: "admin@example.com.",
refresh: 86400,
retry: 7200,
expire: 3600000,
minttl: 86400,
}
},
{
id: 2,
zone: "example.com",
name: "@",
ttl: 3600,
record_type: RecordTypes.RecordTypeNS,
content: {
host: "ns1.example.com."
}
},
{
id: 3,
zone: "example.com",
name: "@",
ttl: 3600,
record_type: RecordTypes.RecordTypeNS,
content: {
host: "ns2.example.com."
}
},
{
id: 4,
zone: "example.com",
name: "www",
ttl: 3600,
record_type: RecordTypes.RecordTypeA,
content: {
ip: "233.233.233.233"
}
},
{
id: 5,
zone: "example.com",
name: "cname",
ttl: 3600,
record_type: RecordTypes.RecordTypeCNAME,
content: {
host: "www.example.com."
}
}
] as Record[]],
['example.org', [
{
id: 1,
zone: "example.org",
name: "@",
ttl: 3600,
record_type: RecordTypes.RecordTypeSOA,
content: {
ns: "ns1.example.org.",
MBox: "admin@example.org.",
refresh: 86400,
retry: 7200,
expire: 3600000,
minttl: 86400,
}
},
{
id: 2,
zone: "example.org",
name: "@",
ttl: 3600,
record_type: RecordTypes.RecordTypeNS,
content: {
host: "ns1.example.org."
}
},
{
id: 3,
zone: "example.org",
name: "@",
ttl: 3600,
record_type: RecordTypes.RecordTypeNS,
content: {
host: "ns2.example.org."
}
},
{
id: 4,
zone: "example.org",
name: "www",
ttl: 3600,
record_type: RecordTypes.RecordTypeA,
content: {
ip: "233.233.233.233"
}
},
{
id: 5,
zone: "example.org",
name: "cname",
ttl: 3600,
record_type: RecordTypes.RecordTypeCNAME,
content: {
host: "www.example.org."
}
}
] as Record[]]
])
export const useRecordStore = () => {
const [records, setRecords] = useState<Record[]>([])
async function loadRecords(domain: string) {
// TODO: load from api
setRecords(import.meta.env.DEV ?
recordDevData.get(domain)! :
(await api.get<Record[]>(`/records/${domain}`)).data.data)
}
async function addRecord(domain: string, record: Record) {
// TODO: load from api
if (!import.meta.env.DEV) {
record = (await api.post(`/records/${domain}`, record)).data.data
}
setRecords(records.concat(record))
}
async function updateRecord(domain: string, record: Record) {
// TODO: load from api
if (!import.meta.env.DEV) {
await api.put(`/records/${domain}`, record)
}
setRecords(records.map(e => e.id === record.id ? record : e))
}
async function removeRecord(domain: string, record: Record) {
// TODO: load from api
if (!import.meta.env.DEV) {
await api.delete(`/records/${domain}/${record.id}`)
}
setRecords(records.filter(e => e.id !== record.id))
}
return { records, loadRecords, addRecord, updateRecord, removeRecord }
}