diff --git a/public/scripts/records.js b/public/scripts/records.js index aab7604..d427d6c 100644 --- a/public/scripts/records.js +++ b/public/scripts/records.js @@ -13,6 +13,12 @@ const rdataInputProperties = { MasterServerName: {label: 'Serveur primaire', type: 'text'}, Expire: {label: 'Expiration', type: 'number'}, Target: {label: 'Cible', type: 'text'}, + Service: {label: 'Service', type: 'text'}, + Protocol: {label: 'Protocole', type: 'text'}, + Priority: {label: 'Priorité', type: 'number'}, + Weight: {label: 'Poids', type: 'number'}, + Port: {label: 'Port', type: 'number'}, + Server: {label: 'Serveur', type: 'text'}, }; const realRecordDataConfig = { @@ -30,7 +36,7 @@ const realRecordDataConfig = { }, 'SRV': { friendlyType: 'service', - fields: [ /* TODO */ ], + fields: [ 'Priority', 'Weight', 'Port', 'Server' ], }, 'NS': { friendlyType: 'name_server', @@ -43,38 +49,84 @@ const realRecordDataConfig = { }; function defaultBuildData(realRecordType) { - const defaultFields = realRecordDataConfig[realRecordType].fields.map(field => [field, null]); + const defaultFields = Object.fromEntries(realRecordDataConfig[realRecordType].fields.map(field => [field, null])); return (fields) => { return {...defaultFields, ...fields, Type: realRecordType}; } } -function defaultRecordToField(realRecord) { +function defaultRecordToFields(realRecord) { const type = realRecord.Type; return realRecordDataConfig[type].fields.map(field => [field, realRecord[field]]); } +function defaultGetName(name) { + return name; +} + +function srvRecordToFields({ Name, Type, Class, ...fields }) { + const [ serviceName, protocol] = Name.split('.'); + return { + Service: serviceName.replace(/^_/, ''), + Protocol: protocol.replace(/^_/, ''), + ...fields + } +} + +function srvGetName(originalName) { + const [_serviceName, _protocol, ...name] = originalName.split('.'); + return name.join('.'); +} + +function buildAddressRecord(fields) { + const address = fields.Address || ''; + if (address.indexOf('.') >= 0) { + fields.Type = 'A'; + } else if (address.indexOf(':') >= 0) { + fields.Type = 'AAAA'; + } else { + fields.Type = ''; + } + return fields; +} + +function buildServiceRecord({ Name, Service, Protocol, ...fields}) { + fields.Name = `_${Service}._${Protocol}.${Name}`; + fields.Type = 'SRV'; + return fields; +} + const friendlyRecordDataConfig = { 'address': { - realRecordToFields: defaultRecordToField, + realRecordToFields: defaultRecordToFields, fields: realRecordDataConfig['AAAA'].fields, buildData: buildAddressRecord, + getName: defaultGetName, }, 'alias': { - realRecordToFields: defaultRecordToField, + realRecordToFields: defaultRecordToFields, fields: realRecordDataConfig['CNAME'].fields, buildData: defaultBuildData('CNAME'), + getName: defaultGetName, }, 'name_server': { - realRecordToFields: defaultRecordToField, + realRecordToFields: defaultRecordToFields, fields: realRecordDataConfig['CNAME'].fields, buildData: defaultBuildData('NS'), + getName: defaultGetName, }, 'soa': { - realRecordToFields: defaultRecordToField, + realRecordToFields: defaultRecordToFields, fields: realRecordDataConfig['SOA'].fields, buildData: defaultBuildData('SOA'), + getName: defaultGetName, + }, + 'service': { + realRecordToFields: srvRecordToFields, + fields: ['Service', 'Protocol', 'Priority', 'Weight', 'Port', 'Server'], + buildData: buildServiceRecord, + getName: srvGetName, }, }; @@ -87,11 +139,6 @@ const recordTypeNames = { 'soa': 'SOA', } -/* Type to use for SRV to derive name without port / service */ -function getNameForRecord(name, type) { - return name; -} - /* Name to use with _spf for example */ function getFriendlyTypeForRecord(name, type) { return realRecordDataConfig[type].friendlyType; @@ -99,8 +146,8 @@ function getFriendlyTypeForRecord(name, type) { function processRecords(records) { return records.reduce((acc, record) => { - let name = getNameForRecord(record.Name, record.Type); let type = getFriendlyTypeForRecord(record.Name, record.Type); + let name = friendlyRecordDataConfig[type].getName(record.Name); if (!(name in acc)) { acc[name] = {}; } @@ -112,13 +159,6 @@ function processRecords(records) { }, {}); } -function buildAddressRecord({ Address = ''}) { - return { - Type: Address.indexOf(':') > -1 ? 'AAAA' : 'A', - Address - } -} - function FriendlyRecord({type, record}) { let keys = friendlyRecordDataConfig[type].realRecordToFields(record); if (keys.length == 1) { @@ -154,8 +194,6 @@ function RecordsByName({ name, recordSets }) { `; } - - function RecordListFriendly({ zone }) { const [records, setRecords] = useState({}); const [editable, setEditable] = useState(false); @@ -176,19 +214,21 @@ function RecordListFriendly({ zone }) { `; } -function NewRecordFormFriendly({ zone, enabled, id, onCancel }) { +function NewRecordFormFriendly({ zone }) { + const defaultVaules = {Name: '', TTL: 3600, Class: 'IN'}; const [recordType, setRecordType] = useState(Object.keys(recordTypeNames)[0]); - const [recordData, setRecordData] = useState({}); + const [recordData, setRecordData] = useState(defaultVaules); const [realRecordData, setRealRecordData] = useState({}); const [realType, setRealType] = useState(''); - const [domain, setDomain] = useState(''); - const [ttl, setTTL] = useState(3600); + + const absoluteName = (name) => name ? `${name}.${zone}` : zone; const setRecordDataFactory = (field) => { return (e) => { const newData = {...recordData}; - newData[field] = e.target.value; - const newRealRecordData = friendlyRecordDataConfig[recordType].buildData(newData) + newData[field] = e.target.type == 'number' ? Number(e.target.value) : e.target.value; + const newRealRecordData = friendlyRecordDataConfig[recordType].buildData({...newData, Class: 'IN', Name: absoluteName(newData.Name)}) + setRecordData(newData); setRealRecordData(newRealRecordData); setRealType(newRealRecordData.Type); @@ -197,75 +237,90 @@ function NewRecordFormFriendly({ zone, enabled, id, onCancel }) { const createNewRecord = (e) => { e.preventDefault(); - const newRecords = [{...realRecordData, Class: 'IN', TTL: ttl, Name: `${domain}.${zone}`}]; + const newRecords = [realRecordData]; console.log(newRecords) createRecords(zone, newRecords); } - // TODO: Reset valeurs champs quand changement de type => bound la valeur de l'input au state + const resetData = (resetName = false) => { + setRealType(''); + const newName = resetName ? defaultVaules.Name : recordData.Name; + setRecordData({ Name: newName, TTL: defaultVaules.TTL }); + setRealRecordData({...defaultVaules, Name: absoluteName(newName)}); + } + + useEffect(() => resetData(true), []); + + // TODO: Reset valeurs champs quand changement de type + "annuler" => bound la valeur de l'input au state // TODO: Dans le cas où un domain est dans le RDATA mettre le domaine absolue dans la preview // TODO: Déplacer preview dans son component, faire une vue en "diff" et l'appeler "prévisualisation des changements" // TODO: Validation des données client et serveur return html` -