working resman version
This commit is contained in:
+264
-334
@@ -1,379 +1,272 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<title>ResMan</title>
|
||||
|
||||
<style>
|
||||
|
||||
body{
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
background:#0f172a;
|
||||
color:#e5e7eb;
|
||||
margin:0;
|
||||
padding:20px;
|
||||
}
|
||||
|
||||
h1{
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
button{
|
||||
background:#3b82f6;
|
||||
border:none;
|
||||
padding:8px 14px;
|
||||
color:white;
|
||||
border-radius:6px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
button:hover{
|
||||
background:#2563eb;
|
||||
}
|
||||
|
||||
button.delete{
|
||||
background:#ef4444;
|
||||
}
|
||||
|
||||
button.delete:hover{
|
||||
background:#dc2626;
|
||||
}
|
||||
|
||||
.card{
|
||||
background:#1e293b;
|
||||
padding:15px;
|
||||
border-radius:10px;
|
||||
margin-bottom:15px;
|
||||
border:1px solid #334155;
|
||||
}
|
||||
body{font-family:Arial;margin:40px;background:#f2f2f2}
|
||||
h1,h2{margin-top:30px}
|
||||
|
||||
table{
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
margin-top:10px;
|
||||
border-collapse:collapse;
|
||||
width:100%;
|
||||
background:white;
|
||||
margin-bottom:20px
|
||||
}
|
||||
|
||||
th,td{
|
||||
padding:10px;
|
||||
border-bottom:1px solid #334155;
|
||||
border:1px solid #ddd;
|
||||
padding:8px
|
||||
}
|
||||
|
||||
th{
|
||||
text-align:left;
|
||||
background:#333;
|
||||
color:white
|
||||
}
|
||||
|
||||
tr:hover{
|
||||
background:#273449;
|
||||
button{
|
||||
padding:5px 10px;
|
||||
margin-right:4px;
|
||||
cursor:pointer
|
||||
}
|
||||
|
||||
.modal{
|
||||
position:fixed;
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
background:rgba(0,0,0,0.6);
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
input{
|
||||
padding:4px
|
||||
}
|
||||
|
||||
.modal-content{
|
||||
background:#1e293b;
|
||||
padding:25px;
|
||||
border-radius:10px;
|
||||
max-height:90vh;
|
||||
overflow:auto;
|
||||
width:700px;
|
||||
border:1px solid #334155;
|
||||
.form{
|
||||
background:white;
|
||||
padding:10px;
|
||||
margin-bottom:20px
|
||||
}
|
||||
|
||||
input,select,textarea{
|
||||
width:100%;
|
||||
padding:8px;
|
||||
margin-bottom:10px;
|
||||
border-radius:6px;
|
||||
border:1px solid #334155;
|
||||
background:#0f172a;
|
||||
color:#e5e7eb;
|
||||
}
|
||||
|
||||
label{
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.form-grid{
|
||||
display:grid;
|
||||
grid-template-columns:1fr 1fr;
|
||||
gap:10px;
|
||||
}
|
||||
|
||||
.ip-list{
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.ip-item{
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
padding:6px;
|
||||
border-bottom:1px solid #334155;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Resource Manager</h1>
|
||||
<h1>ResMan</h1>
|
||||
|
||||
<button onclick="openCreate()">➕ New Resource</button>
|
||||
<h2>Create Resource</h2>
|
||||
|
||||
<div class="form">
|
||||
|
||||
<input id="r_name" placeholder="Name">
|
||||
<input id="r_provider" placeholder="Provider">
|
||||
<input id="r_cpu" placeholder="CPU">
|
||||
<input id="r_ram" placeholder="RAM">
|
||||
<input id="r_disk" placeholder="Disk">
|
||||
|
||||
<button onclick="createResource()">Create</button>
|
||||
|
||||
</div>
|
||||
|
||||
<h2>Active Resources</h2>
|
||||
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Provider</th>
|
||||
<th>Produkt</th>
|
||||
<th>CPU</th>
|
||||
<th>RAM</th>
|
||||
<th>Disk</th>
|
||||
<th>IPs</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
<tbody id="activeResources"></tbody>
|
||||
<tbody id="resources"></tbody>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<h2>Cancelled Resources</h2>
|
||||
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Provider</th>
|
||||
<th>Produkt</th>
|
||||
<th>CPU</th>
|
||||
<th>RAM</th>
|
||||
<th>Disk</th>
|
||||
<th>IPs</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
<tbody id="cancelledResources"></tbody>
|
||||
<tbody id="cancelled"></tbody>
|
||||
|
||||
</table>
|
||||
|
||||
<h2>Domains</h2>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="form">
|
||||
|
||||
<div class="modal" id="resourceModal">
|
||||
<input id="d_name" placeholder="Domain">
|
||||
<input id="d_provider" placeholder="Provider">
|
||||
<input id="d_ip" placeholder="IP">
|
||||
<input id="d_cost" placeholder="Yearly €">
|
||||
|
||||
<div class="modal-content">
|
||||
|
||||
<h2 id="modalTitle"></h2>
|
||||
|
||||
<input id="name" placeholder="Name">
|
||||
<input id="produkt" placeholder="Produkt">
|
||||
<input id="provider" placeholder="Provider">
|
||||
<input id="art" placeholder="Art">
|
||||
|
||||
<input id="cpu" placeholder="CPU">
|
||||
<input id="ram" placeholder="RAM">
|
||||
<input id="disk" placeholder="Disk">
|
||||
|
||||
<input id="os" placeholder="OS">
|
||||
|
||||
<input id="ipv6_net" placeholder="IPv6 Netz">
|
||||
|
||||
<input id="providername" placeholder="Provider Name">
|
||||
|
||||
<input id="kosten_monat" placeholder="Kosten Monat">
|
||||
<input id="kosten_jahr" placeholder="Kosten Jahr">
|
||||
|
||||
<input id="laufzeit_monate" placeholder="Laufzeit Monate">
|
||||
|
||||
<input id="bestelldatum" type="date">
|
||||
<input id="kuendbar_ab" type="date">
|
||||
|
||||
<select id="status">
|
||||
<option value="aktiv">aktiv</option>
|
||||
<option value="gekündigt">gekündigt</option>
|
||||
</select>
|
||||
|
||||
<input id="kuendigungsdatum" type="date">
|
||||
|
||||
<textarea id="bemerkung" placeholder="Bemerkung"></textarea>
|
||||
|
||||
<button onclick="saveResource()">Save</button>
|
||||
<button onclick="closeModal()">Cancel</button>
|
||||
<button onclick="createDomain()">Create</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Domain</th>
|
||||
<th>Provider</th>
|
||||
<th>IP</th>
|
||||
<th>Server</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="domains"></tbody>
|
||||
|
||||
</table>
|
||||
|
||||
<h2>Domain → Server Mapping</h2>
|
||||
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>IP</th>
|
||||
<th>Server</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="mapping"></tbody>
|
||||
|
||||
</table>
|
||||
|
||||
<script>
|
||||
|
||||
const API="/resman/api/resources"
|
||||
|
||||
let editId=null
|
||||
const API="/resman/api"
|
||||
|
||||
|
||||
|
||||
function val(v){
|
||||
/* LOAD RESOURCES */
|
||||
|
||||
if(v==="" || v===undefined) return null
|
||||
async function loadResources(){
|
||||
|
||||
return v
|
||||
const res=await fetch(API+"/resources/active")
|
||||
const data=await res.json()
|
||||
|
||||
}
|
||||
const table=document.getElementById("resources")
|
||||
table.innerHTML=""
|
||||
|
||||
data.forEach(r=>{
|
||||
|
||||
const ips=r.ips.map(ip=>ip.ip).join("<br>")
|
||||
|
||||
function getForm(){
|
||||
const tr=document.createElement("tr")
|
||||
|
||||
return{
|
||||
tr.innerHTML=`
|
||||
|
||||
name:document.getElementById("name").value,
|
||||
<td>${r.id}</td>
|
||||
<td>${r.name}</td>
|
||||
<td>${r.provider||""}</td>
|
||||
<td>${r.cpu||""}</td>
|
||||
<td>${r.ram||""}</td>
|
||||
<td>${r.disk||""}</td>
|
||||
|
||||
produkt:val(document.getElementById("produkt").value),
|
||||
<td>
|
||||
|
||||
provider:val(document.getElementById("provider").value),
|
||||
${ips}
|
||||
|
||||
art:val(document.getElementById("art").value),
|
||||
<br>
|
||||
|
||||
cpu:val(document.getElementById("cpu").value),
|
||||
<input id="ip_${r.id}" placeholder="new ip">
|
||||
<button onclick="addIP(${r.id})">Add</button>
|
||||
|
||||
ram:val(document.getElementById("ram").value),
|
||||
</td>
|
||||
|
||||
disk:val(document.getElementById("disk").value),
|
||||
<td>
|
||||
|
||||
os:val(document.getElementById("os").value),
|
||||
<button onclick="editResource(${r.id})">Edit</button>
|
||||
|
||||
ipv6_net:val(document.getElementById("ipv6_net").value),
|
||||
<button onclick="deleteResource(${r.id})">Delete</button>
|
||||
|
||||
providername:val(document.getElementById("providername").value),
|
||||
</td>
|
||||
|
||||
kosten_monat:val(document.getElementById("kosten_monat").value),
|
||||
`
|
||||
|
||||
kosten_jahr:val(document.getElementById("kosten_jahr").value),
|
||||
|
||||
laufzeit_monate:val(document.getElementById("laufzeit_monate").value),
|
||||
|
||||
bestelldatum:val(document.getElementById("bestelldatum").value),
|
||||
|
||||
kuendbar_ab:val(document.getElementById("kuendbar_ab").value),
|
||||
|
||||
status:document.getElementById("status").value,
|
||||
|
||||
kuendigungsdatum:val(document.getElementById("kuendigungsdatum").value),
|
||||
|
||||
bemerkung:val(document.getElementById("bemerkung").value)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function openCreate(){
|
||||
|
||||
editId=null
|
||||
|
||||
document.getElementById("modalTitle").innerText="New Resource"
|
||||
|
||||
document.getElementById("resourceModal").style.display="flex"
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function editResource(r){
|
||||
|
||||
editId=r.id
|
||||
|
||||
document.getElementById("modalTitle").innerText="Edit Resource"
|
||||
|
||||
Object.keys(r).forEach(k=>{
|
||||
|
||||
const el=document.getElementById(k)
|
||||
|
||||
if(el) el.value=r[k] || ""
|
||||
table.appendChild(tr)
|
||||
|
||||
})
|
||||
|
||||
document.getElementById("resourceModal").style.display="flex"
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function closeModal(){
|
||||
/* CANCELLED */
|
||||
|
||||
document.getElementById("resourceModal").style.display="none"
|
||||
async function loadCancelled(){
|
||||
|
||||
}
|
||||
const res=await fetch(API+"/resources/cancelled")
|
||||
const data=await res.json()
|
||||
|
||||
const table=document.getElementById("cancelled")
|
||||
table.innerHTML=""
|
||||
|
||||
data.forEach(r=>{
|
||||
|
||||
async function saveResource(){
|
||||
const tr=document.createElement("tr")
|
||||
|
||||
const data=getForm()
|
||||
tr.innerHTML=`
|
||||
<td>${r.id}</td>
|
||||
<td>${r.name}</td>
|
||||
<td>${r.provider||""}</td>
|
||||
`
|
||||
|
||||
if(editId){
|
||||
|
||||
await fetch(API+"/"+editId,{
|
||||
|
||||
method:"PUT",
|
||||
|
||||
headers:{"Content-Type":"application/json"},
|
||||
|
||||
body:JSON.stringify(data)
|
||||
table.appendChild(tr)
|
||||
|
||||
})
|
||||
|
||||
}else{
|
||||
}
|
||||
|
||||
await fetch(API,{
|
||||
|
||||
|
||||
/* CREATE RESOURCE */
|
||||
|
||||
async function createResource(){
|
||||
|
||||
const body={
|
||||
name:document.getElementById("r_name").value,
|
||||
provider:document.getElementById("r_provider").value,
|
||||
cpu:document.getElementById("r_cpu").value,
|
||||
ram:document.getElementById("r_ram").value,
|
||||
disk:document.getElementById("r_disk").value
|
||||
}
|
||||
|
||||
await fetch(API+"/resources",{
|
||||
|
||||
method:"POST",
|
||||
|
||||
headers:{"Content-Type":"application/json"},
|
||||
headers:{'Content-Type':'application/json'},
|
||||
|
||||
body:JSON.stringify(data)
|
||||
body:JSON.stringify(body)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
closeModal()
|
||||
|
||||
loadResources()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DELETE RESOURCE */
|
||||
|
||||
async function deleteResource(id){
|
||||
|
||||
if(!confirm("Delete resource?")) return
|
||||
if(!confirm("delete resource?")) return
|
||||
|
||||
await fetch(API+"/"+id,{method:"DELETE"})
|
||||
await fetch(API+"/resources/"+id,{method:"DELETE"})
|
||||
|
||||
loadResources()
|
||||
|
||||
@@ -381,21 +274,20 @@ loadResources()
|
||||
|
||||
|
||||
|
||||
async function addIP(resourceId){
|
||||
/* EDIT RESOURCE */
|
||||
|
||||
const ip=prompt("IP")
|
||||
async function editResource(id){
|
||||
|
||||
if(!ip) return
|
||||
const name=prompt("Name")
|
||||
if(!name) return
|
||||
|
||||
const type=prompt("Type (public/vlan/ipv6)")
|
||||
await fetch(API+"/resources/"+id,{
|
||||
|
||||
await fetch(API+"/"+resourceId+"/ips",{
|
||||
method:"PUT",
|
||||
|
||||
method:"POST",
|
||||
headers:{'Content-Type':'application/json'},
|
||||
|
||||
headers:{"Content-Type":"application/json"},
|
||||
|
||||
body:JSON.stringify({ip,type})
|
||||
body:JSON.stringify({name})
|
||||
|
||||
})
|
||||
|
||||
@@ -405,15 +297,17 @@ loadResources()
|
||||
|
||||
|
||||
|
||||
async function editIP(ipId){
|
||||
/* IP MANAGER */
|
||||
|
||||
const ip=prompt("New IP")
|
||||
async function addIP(resource_id){
|
||||
|
||||
await fetch("/resman/api/ips/"+ipId,{
|
||||
const ip=document.getElementById("ip_"+resource_id).value
|
||||
|
||||
method:"PUT",
|
||||
await fetch(API+"/resources/"+resource_id+"/ips",{
|
||||
|
||||
headers:{"Content-Type":"application/json"},
|
||||
method:"POST",
|
||||
|
||||
headers:{'Content-Type':'application/json'},
|
||||
|
||||
body:JSON.stringify({ip})
|
||||
|
||||
@@ -425,108 +319,144 @@ loadResources()
|
||||
|
||||
|
||||
|
||||
async function deleteIP(ipId){
|
||||
/* DOMAINS */
|
||||
|
||||
await fetch("/resman/api/ips/"+ipId,{method:"DELETE"})
|
||||
async function loadDomains(){
|
||||
|
||||
loadResources()
|
||||
const res=await fetch(API+"/domains")
|
||||
|
||||
}
|
||||
const data=await res.json()
|
||||
|
||||
const table=document.getElementById("domains")
|
||||
|
||||
table.innerHTML=""
|
||||
|
||||
function renderIPs(r){
|
||||
data.forEach(d=>{
|
||||
|
||||
let html=""
|
||||
const tr=document.createElement("tr")
|
||||
|
||||
if(Array.isArray(r.ips)){
|
||||
tr.innerHTML=`
|
||||
|
||||
r.ips.forEach(ip=>{
|
||||
<td>${d.id}</td>
|
||||
|
||||
html+=`
|
||||
<td>${d.domain_name}</td>
|
||||
|
||||
<div class="ip">
|
||||
<td>${d.provider||""}</td>
|
||||
|
||||
${ip.ip} (${ip.type})
|
||||
<td>${d.ip_address||""}</td>
|
||||
|
||||
<button onclick="editIP(${ip.id})">Edit</button>
|
||||
|
||||
<button onclick="deleteIP(${ip.id})">Delete</button>
|
||||
|
||||
</div>
|
||||
|
||||
`
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
html+=`<button onclick="addIP(${r.id})">Add IP</button>`
|
||||
|
||||
return html
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function renderRow(r){
|
||||
|
||||
return `
|
||||
|
||||
<tr>
|
||||
|
||||
<td>${r.name}</td>
|
||||
<td>${r.provider||""}</td>
|
||||
<td>${r.produkt||""}</td>
|
||||
<td>${r.cpu||""}</td>
|
||||
<td>${r.ram||""}</td>
|
||||
<td>${r.disk||""}</td>
|
||||
|
||||
<td>${renderIPs(r)}</td>
|
||||
<td>${d.resource_name||""}</td>
|
||||
|
||||
<td>
|
||||
|
||||
<button onclick='editResource(${JSON.stringify(r)})'>Edit</button>
|
||||
|
||||
<button onclick="deleteResource(${r.id})">Delete</button>
|
||||
<button onclick="deleteDomain(${d.id})">Delete</button>
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
`
|
||||
|
||||
table.appendChild(tr)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* CREATE DOMAIN */
|
||||
|
||||
async function createDomain(){
|
||||
|
||||
const body={
|
||||
|
||||
domain_name:document.getElementById("d_name").value,
|
||||
|
||||
provider:document.getElementById("d_provider").value,
|
||||
|
||||
ip_address:document.getElementById("d_ip").value,
|
||||
|
||||
yearly_cost:document.getElementById("d_cost").value
|
||||
|
||||
}
|
||||
|
||||
await fetch(API+"/domains",{
|
||||
|
||||
method:"POST",
|
||||
|
||||
headers:{'Content-Type':'application/json'},
|
||||
|
||||
body:JSON.stringify(body)
|
||||
|
||||
})
|
||||
|
||||
loadDomains()
|
||||
|
||||
loadMapping()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DELETE DOMAIN */
|
||||
|
||||
async function deleteDomain(id){
|
||||
|
||||
if(!confirm("delete domain?")) return
|
||||
|
||||
await fetch(API+"/domains/"+id,{method:"DELETE"})
|
||||
|
||||
loadDomains()
|
||||
|
||||
loadMapping()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DOMAIN MAPPING */
|
||||
|
||||
async function loadMapping(){
|
||||
|
||||
const res=await fetch(API+"/domainmap")
|
||||
|
||||
const data=await res.json()
|
||||
|
||||
const table=document.getElementById("mapping")
|
||||
|
||||
table.innerHTML=""
|
||||
|
||||
data.forEach(m=>{
|
||||
|
||||
const tr=document.createElement("tr")
|
||||
|
||||
tr.innerHTML=`
|
||||
|
||||
<td>${m.domain_name}</td>
|
||||
|
||||
<td>${m.ip_address}</td>
|
||||
|
||||
<td>${m.server_name||""}</td>
|
||||
|
||||
`
|
||||
|
||||
}
|
||||
table.appendChild(tr)
|
||||
|
||||
|
||||
|
||||
async function loadResources(){
|
||||
|
||||
const active=await fetch(API+"/active").then(r=>r.json())
|
||||
|
||||
const cancelled=await fetch(API+"/cancelled").then(r=>r.json())
|
||||
|
||||
const activeTable=document.getElementById("activeResources")
|
||||
|
||||
const cancelledTable=document.getElementById("cancelledResources")
|
||||
|
||||
activeTable.innerHTML=""
|
||||
cancelledTable.innerHTML=""
|
||||
|
||||
active.forEach(r=>{
|
||||
activeTable.innerHTML+=renderRow(r)
|
||||
})
|
||||
|
||||
cancelled.forEach(r=>{
|
||||
cancelledTable.innerHTML+=renderRow(r)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* INIT */
|
||||
|
||||
loadResources()
|
||||
|
||||
loadCancelled()
|
||||
|
||||
loadDomains()
|
||||
|
||||
loadMapping()
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
const express = require('express')
|
||||
const router = express.Router()
|
||||
const db = require('../db')
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
|
||||
try {
|
||||
|
||||
const [rows] = await db.query(`
|
||||
SELECT
|
||||
d.id AS domain_id,
|
||||
d.domain_name,
|
||||
d.ip_address,
|
||||
r.id AS resource_id,
|
||||
r.name AS server_name
|
||||
FROM domains d
|
||||
LEFT JOIN resource_ips ip ON d.ip_address = ip.ip
|
||||
LEFT JOIN resources r ON ip.resource_id = r.id
|
||||
ORDER BY d.domain_name
|
||||
`)
|
||||
|
||||
res.json(rows)
|
||||
|
||||
} catch(err){
|
||||
|
||||
console.error(err)
|
||||
res.status(500).json({error:"DB error"})
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
@@ -0,0 +1,120 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const pool = require('../db');
|
||||
|
||||
|
||||
// GET ALL DOMAINS
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query(`
|
||||
SELECT
|
||||
d.id,
|
||||
d.domain_name,
|
||||
d.provider,
|
||||
d.ip_address,
|
||||
d.yearly_cost,
|
||||
d.notes,
|
||||
r.name AS resource_name
|
||||
FROM domains d
|
||||
LEFT JOIN resource_ips ip ON d.ip_address = ip.ip
|
||||
LEFT JOIN resources r ON ip.resource_id = r.id
|
||||
ORDER BY d.domain_name
|
||||
`);
|
||||
|
||||
res.json(rows);
|
||||
|
||||
} catch (err) {
|
||||
console.error("GET domains error:", err);
|
||||
res.status(500).json({ error: "DB error" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// GET SINGLE DOMAIN
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT * FROM domains WHERE id = ?`,
|
||||
[req.params.id]
|
||||
);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return res.status(404).json({ error: "Domain not found" });
|
||||
}
|
||||
|
||||
res.json(rows[0]);
|
||||
|
||||
} catch (err) {
|
||||
console.error("GET domain error:", err);
|
||||
res.status(500).json({ error: "DB error" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// CREATE DOMAIN
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
const { domain_name, provider, ip_address, yearly_cost, notes } = req.body;
|
||||
|
||||
const [result] = await pool.query(
|
||||
`INSERT INTO domains
|
||||
(domain_name, provider, ip_address, yearly_cost, notes)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
[domain_name, provider, ip_address, yearly_cost, notes]
|
||||
);
|
||||
|
||||
res.json({
|
||||
message: "Domain created",
|
||||
id: result.insertId
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error("CREATE domain error:", err);
|
||||
res.status(500).json({ error: "DB error" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// UPDATE DOMAIN
|
||||
router.put('/:id', async (req, res) => {
|
||||
try {
|
||||
const { domain_name, provider, ip_address, yearly_cost, notes } = req.body;
|
||||
|
||||
await pool.query(
|
||||
`UPDATE domains SET
|
||||
domain_name = ?,
|
||||
provider = ?,
|
||||
ip_address = ?,
|
||||
yearly_cost = ?,
|
||||
notes = ?
|
||||
WHERE id = ?`,
|
||||
[domain_name, provider, ip_address, yearly_cost, notes, req.params.id]
|
||||
);
|
||||
|
||||
res.json({ message: "Domain updated" });
|
||||
|
||||
} catch (err) {
|
||||
console.error("UPDATE domain error:", err);
|
||||
res.status(500).json({ error: "DB error" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// DELETE DOMAIN
|
||||
router.delete('/:id', async (req, res) => {
|
||||
try {
|
||||
await pool.query(
|
||||
`DELETE FROM domains WHERE id = ?`,
|
||||
[req.params.id]
|
||||
);
|
||||
|
||||
res.json({ message: "Domain deleted" });
|
||||
|
||||
} catch (err) {
|
||||
console.error("DELETE domain error:", err);
|
||||
res.status(500).json({ error: "DB error" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
@@ -4,6 +4,8 @@ const path = require("path");
|
||||
|
||||
const resourceRoutes = require("./routes/resources");
|
||||
const ipRoutes = require("./routes/ips");
|
||||
const domainsRoutes = require('./routes/domains');
|
||||
const domainMapping = require('./routes/domainMapping')
|
||||
|
||||
const app = express();
|
||||
|
||||
@@ -29,6 +31,11 @@ app.use("/resman/api/resources", resourceRoutes);
|
||||
|
||||
app.use("/resman/api", ipRoutes);
|
||||
|
||||
app.use('/resman/api/domains', domainsRoutes);
|
||||
|
||||
app.use('/resman/api/domainmap', domainMapping)
|
||||
|
||||
|
||||
app.use((err, req, res, next) => {
|
||||
|
||||
console.error("EXPRESS ERROR:");
|
||||
|
||||
Reference in New Issue
Block a user