user domains API, .value on input, fix flex sizing

This commit is contained in:
Face
2025-08-19 18:27:25 +03:00
parent dacda095d5
commit 99f17dc42c
18 changed files with 705 additions and 356 deletions

View File

@@ -26,15 +26,15 @@
}
.primary-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#dc2626] text-white
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#dc2626] text-white w-32 h-12
}
.success-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#ef4444] text-white
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#ef4444] text-white w-32 h-12
}
.danger-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#b91c1c] text-white
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#b91c1c] text-white w-32 h-12
}
.secondary-btn {
@@ -42,7 +42,7 @@
}
.warning-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#dc2626] text-white
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#dc2626] text-white w-32 h-12
}
.form-group {
@@ -58,7 +58,7 @@
}
.stats-card {
bg-[#1f1f1f] p-4 rounded-lg border border-[#dc2626]
p-4 rounded-lg border border-[#dc2626]
}
.domain-item {
@@ -98,48 +98,10 @@
<div style="stats-card mb-6">
<div style="flex justify-between items-center w-full">
<p id="user-info" style="text-white text-lg font-semibold">Loading...</p>
<button id="logout-btn" style="secondary-btn">Logout</button>
</div>
</div>
<div style="card mb-6">
<h2 style="mb-4">Register New Domain</h2>
<div style="form-group">
<p>Domain Name:</p>
<input id="domain-name" type="text" style="form-input" placeholder="myawesome" />
</div>
<div style="form-group">
<p>Select TLD:</p>
<div id="tld-selector" style="tld-selector">
<p id="tld-loading">Loading TLDs...</p>
</div>
</div>
<div style="form-group">
<p>IP Address:</p>
<input id="domain-ip" type="text" style="form-input" placeholder="192.168.1.100" />
</div>
<div id="domain-error" style="error-text hidden mb-2"></div>
<button id="submit-domain-btn" style="success-btn">Submit for Approval</button>
</div>
<div style="card mb-6">
<h2>Invite System</h2>
<p style="text-[#6b7280] mb-4">Create invite codes to share with friends, or redeem codes to get more domain
registrations.</p>
<p id="invite-code-display" style="invite-code-display mt-2">Placeholder</p>
<div style="flex flex-col gap-4 items-center justify-center mx-auto">
<h3>Create Invite</h3>
<button id="create-invite-btn" style="warning-btn">Generate Invite Code</button>
</div>
<div style="flex flex-col gap-4 mx-auto">
<h3>Redeem Invite</h3>
<div style="flex gap-2">
<input id="invite-code-input" type="text" style="form-input" placeholder="Enter invite code" />
<button id="redeem-invite-btn" style="primary-btn">Redeem</button>
<button id="new-btn" style="success-btn">New</button>
<button id="logout-btn" style="secondary-btn">Logout</button>
</div>
<div id="redeem-error" style="error-text hidden mt-2"></div>
</div>
</div>

View File

@@ -1,16 +1,12 @@
local user = nil
local domains = {}
local tlds = {}
local authToken = nil
local userInfo = gurt.select('#user-info')
local domainsList = gurt.select('#domains-list')
local tldSelector = gurt.select('#tld-selector')
local loadingElement = gurt.select('#tld-loading')
local displayElement = gurt.select('#invite-code-display')
local options
displayElement:hide()
local options
local function showError(elementId, message)
local element = gurt.select('#' .. elementId)
@@ -29,57 +25,17 @@ local function updateUserInfo()
userInfo.text = 'Welcome, ' .. user.username .. '!'
end
local function renderTLDSelector()
loadingElement:remove()
tldSelector.text = ''
local i = 1
local total = #tlds
local intervalId
intervalId = gurt.setInterval(function()
if i > total then
gurt.clearInterval(intervalId)
return
end
local tld = tlds[i]
local option = gurt.create('button', {
text = '.' .. tld,
style = 'tld-option',
['data-tld'] = tld
})
tldSelector:append(option)
option:on('click', function()
-- Clear previous selection
if not options then
options = gurt.selectAll('.tld-option')
end
for j = 1, #options do
if options[j].classList:contains('tld-selected') then
options[j].classList:remove('tld-selected')
end
end
-- Select this option
option.classList:add('tld-selected')
end)
i = i + 1
end, 16)
end
local function renderDomains()
local loadingElement = gurt.select('#domains-loading')
loadingElement:remove()
if loadingElement then
loadingElement:remove()
end
domainsList.text = ''
if #domains == 0 then
local emptyMessage = gurt.create('div', {
text = 'No domains registered yet. Submit your first domain below!',
text = 'No domains registered yet. Click "New" to register your first domain!',
style = 'text-center text-[#6b7280] py-8'
})
domainsList:append(emptyMessage)
@@ -91,7 +47,7 @@ local function renderDomains()
style = 'domain-item'
})
local domainInfo = gurt.create('div', {})
local domainInfo = gurt.create('div', { style = 'w-full' })
local domainName = gurt.create('div', {
text = domain.name .. '.' .. domain.tld,
@@ -103,8 +59,14 @@ local function renderDomains()
style = 'text-[#6b7280]'
})
local domainStatus = gurt.create('div', {
text = 'Status: ' .. (domain.status or 'Unknown'),
style = 'text-[#6b7280]'
})
domainInfo:append(domainName)
domainInfo:append(domainIP)
domainInfo:append(domainStatus)
local actions = gurt.create('div', {
style = 'flex gap-2'
@@ -143,7 +105,7 @@ end
local function loadDomains()
print('Loading domains...')
local response = fetch('gurt://localhost:8877/domains?page=1&size=100', {
local response = fetch('gurt://localhost:8877/auth/domains?page=1&size=100', {
headers = {
Authorization = 'Bearer ' .. authToken
}
@@ -159,19 +121,6 @@ local function loadDomains()
end
end
local function loadTLDs()
print('Loading available TLDs...')
local response = fetch('gurt://localhost:8877/tlds')
if response:ok() then
tlds = response:json()
print('Loaded ' .. #tlds .. ' TLDs')
renderTLDSelector()
else
print('Failed to load TLDs: ' .. response:text())
end
end
local function checkAuth()
authToken = gurt.crumbs.get("auth_token")
@@ -188,7 +137,6 @@ local function checkAuth()
print('Authentication successful for user: ' .. user.username)
updateUserInfo()
loadDomains()
loadTLDs()
else
print('Token invalid, redirecting to login...')
gurt.crumbs.delete('auth_token')
@@ -206,126 +154,13 @@ local function logout()
gurt.location.goto("../")
end
local function submitDomain(name, tld, ip)
hideError('domain-error')
print('Submitting domain: ' .. name .. '.' .. tld)
local response = fetch('gurt://localhost:8877/domain', {
method = 'POST',
headers = {
['Content-Type'] = 'application/json',
Authorization = 'Bearer ' .. authToken
},
body = JSON.stringify({ name = name, tld = tld, ip = ip })
})
if response:ok() then
local data = response:json()
print('Domain submitted successfully: ' .. data.domain)
-- Update user registrations remaining
user.registrations_remaining = user.registrations_remaining - 1
updateUserInfo()
-- Clear form
gurt.select('#domain-name').text = ''
gurt.select('#domain-ip').text = ''
-- Refresh domains list
loadDomains()
else
local error = response:text()
showError('domain-error', 'Domain submission failed: ' .. error)
print('Domain submission failed: ' .. error)
end
end
local function createInvite()
print('Creating invite code...')
local response = fetch('gurt://localhost:8877/auth/invite', {
method = 'POST',
headers = {
Authorization = 'Bearer ' .. authToken
}
})
if response:ok() then
local data = response:json()
local inviteCode = data.invite_code
displayElement.text = 'Invite code: ' .. inviteCode .. ' (copied to clipboard)'
displayElement:show()
Clipboard.write(inviteCode)
print('Invite code created and copied to clipboard: ' .. inviteCode)
else
print('Failed to create invite: ' .. response:text())
end
end
local function redeemInvite(code)
hideError('redeem-error')
print('Redeeming invite code: ' .. code)
local response = fetch('gurt://localhost:8877/auth/redeem-invite', {
method = 'POST',
headers = {
['Content-Type'] = 'application/json',
Authorization = 'Bearer ' .. authToken
},
body = JSON.stringify({ invite_code = code })
})
if response:ok() then
local data = response:json()
print('Invite redeemed: +' .. data.registrations_added .. ' registrations')
-- Update user info
user.registrations_remaining = user.registrations_remaining + data.registrations_added
updateUserInfo()
-- Clear form
gurt.select('#invite-code-input').text = ''
else
local error = response:text()
showError('redeem-error', 'Failed to redeem invite: ' .. error)
print('Failed to redeem invite: ' .. error)
end
local function goToRegister()
gurt.location.goto("/register.html")
end
-- Event handlers
gurt.select('#logout-btn'):on('click', logout)
gurt.select('#submit-domain-btn'):on('click', function()
local name = gurt.select('#domain-name').text
local ip = gurt.select('#domain-ip').text
local selectedTLD = gurt.select('.tld-selected')
if not name or name == '' then
showError('domain-error', 'Domain name is required')
return
end
if not ip or ip == '' then
showError('domain-error', 'IP address is required')
return
end
if not selectedTLD then
showError('domain-error', 'Please select a TLD')
return
end
local tld = selectedTLD:getAttribute('data-tld')
submitDomain(name, tld, ip)
end)
gurt.select('#create-invite-btn'):on('click', createInvite)
gurt.select('#redeem-invite-btn'):on('click', function()
local code = gurt.select('#invite-code-input').text
if code and code ~= '' then
redeemInvite(code)
end
end)
gurt.select('#new-btn'):on('click', goToRegister)
-- Initialize
print('Dashboard initialized')

View File

@@ -38,6 +38,7 @@
#log-output { text-white p-4 rounded-md mt-4 font-mono max-h-40 }
</style>
<script src="script.lua" />
</head>
<body>

136
dns/frontend/register.html Normal file
View File

@@ -0,0 +1,136 @@
<head>
<title>Register Domain</title>
<icon src="https://cdn-icons-png.flaticon.com/512/295/295128.png">
<meta name="theme-color" content="#0891b2">
<meta name="description" content="Register a new domain">
<style>
body {
bg-[#171616] font-sans text-white
}
h1 {
text-[#ef4444] text-3xl font-bold text-center
}
h2 {
text-[#dc2626] text-xl font-semibold
}
h3 {
text-[#fca5a5] text-lg font-medium
}
.container {
bg-[#262626] p-6 rounded-lg shadow-lg max-w-6xl
}
.primary-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#dc2626] text-white
}
.success-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#ef4444] text-white
}
.secondary-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#525252] text-white w-32 h-12
}
.warning-btn {
p-3 rounded-lg font-medium cursor-pointer transition-colors bg-[#dc2626] text-white
}
.form-group {
flex flex-col gap-2 mb-4 w-full
}
.form-input {
w-full p-3 border border-gray-600 rounded-md bg-[#374151] text-white active:border-red-500
}
.card {
bg-[#262626] p-6 rounded-lg shadow border border-gray-700
}
.stats-card {
bg-[#1f1f1f] p-4 rounded-lg border border-[#dc2626]
}
.error-text {
text-[#fca5a5] text-sm
}
.tld-selector {
flex flex-wrap gap-2
}
.tld-option {
px-3 py-1 rounded border border-gray-600 cursor-pointer bg-[#374151] text-white w-12 h-12
}
.tld-selected {
bg-[#dc2626] text-white
}
.invite-code-display {
bg-[#374151] p-3 rounded font-mono text-center mb-2 text-white
}
</style>
<script src="register.lua" />
</head>
<body>
<div style="container mt-6">
<div style="stats-card mb-6">
<div style="flex justify-between items-center w-full">
<p id="user-info" style="text-white text-lg font-semibold">Loading...</p>
<div style="flex gap-2">
<button id="dashboard-btn" style="secondary-btn">Dashboard</button>
<button id="logout-btn" style="secondary-btn">Logout</button>
</div>
</div>
</div>
<div style="card mb-6">
<h2 id="remaining" style="mb-4">Register New Domain</h2>
<div style="form-group">
<p>Domain Name:</p>
<input id="domain-name" type="text" style="form-input" placeholder="myawesome" />
</div>
<div style="form-group">
<p>Select TLD:</p>
<div id="tld-selector" style="tld-selector">
<p id="tld-loading">Loading TLDs...</p>
</div>
</div>
<div style="form-group">
<p>IP Address:</p>
<input id="domain-ip" type="text" style="form-input" placeholder="192.168.1.100" />
</div>
<div id="domain-error" style="error-text hidden mb-2"></div>
<button id="submit-domain-btn" style="success-btn">Submit for Approval</button>
</div>
<div style="card mb-6">
<h2>Invite System</h2>
<p style="text-[#6b7280] mb-4">Create invite codes to share with friends, or redeem codes to get more domain registrations.</p>
<p id="invite-code-display" style="invite-code-display mt-2">Placeholder</p>
<div style="flex flex-col gap-4 items-center justify-center mx-auto">
<h3>Create Invite</h3>
<button id="create-invite-btn" style="warning-btn">Generate Invite Code</button>
</div>
<div style="flex flex-col gap-4 mx-auto">
<h3>Redeem Invite</h3>
<div style="flex gap-2">
<input id="invite-code-input" type="text" style="form-input" placeholder="Enter invite code" />
<button id="redeem-invite-btn" style="primary-btn">Redeem</button>
</div>
<div id="redeem-error" style="error-text hidden mt-2"></div>
</div>
</div>
</div>
</body>

257
dns/frontend/register.lua Normal file
View File

@@ -0,0 +1,257 @@
local user = nil
local tlds = {}
local authToken = nil
local userInfo = gurt.select('#user-info')
local tldSelector = gurt.select('#tld-selector')
local loadingElement = gurt.select('#tld-loading')
local displayElement = gurt.select('#invite-code-display')
local remainingElement = gurt.select('#remaining')
local options
displayElement:hide()
local function showError(elementId, message)
local element = gurt.select('#' .. elementId)
element.text = message
element.classList:remove('hidden')
end
local function hideError(elementId)
local element = gurt.select('#' .. elementId)
element.classList:add('hidden')
end
local function updateUserInfo()
userInfo.text = 'Welcome, ' .. user.username .. '!'
remainingElement.text = 'Register New Domain (' .. user.registrations_remaining .. ' remaining)'
end
local function renderTLDSelector()
loadingElement:remove()
tldSelector.text = ''
local i = 1
local total = #tlds
local intervalId
intervalId = gurt.setInterval(function()
if i > total then
gurt.clearInterval(intervalId)
return
end
local tld = tlds[i]
local option = gurt.create('button', {
text = '.' .. tld,
style = 'tld-option',
['data-tld'] = tld
})
tldSelector:append(option)
option:on('click', function()
-- Clear previous selection
if not options then
options = gurt.selectAll('.tld-option')
end
for j = 1, #options do
if options[j].classList:contains('tld-selected') then
options[j].classList:remove('tld-selected')
end
end
-- Select this option
option.classList:add('tld-selected')
end)
i = i + 1
end, 16)
end
local function loadTLDs()
print('Loading available TLDs...')
local response = fetch('gurt://localhost:8877/tlds')
if response:ok() then
tlds = response:json()
print('Loaded ' .. #tlds .. ' TLDs')
renderTLDSelector()
else
print('Failed to load TLDs: ' .. response:text())
end
end
local function checkAuth()
authToken = gurt.crumbs.get("auth_token")
if authToken then
print('Found auth token, checking validity...')
local response = fetch('gurt://localhost:8877/auth/me', {
headers = {
Authorization = 'Bearer ' .. authToken
}
})
if response:ok() then
user = response:json()
print('Authentication successful for user: ' .. user.username)
updateUserInfo()
loadTLDs()
else
print('Token invalid, redirecting to login...')
gurt.crumbs.delete('auth_token')
gurt.location.goto('../')
end
else
print('No auth token found, redirecting to login...')
gurt.location.goto('../')
end
end
local function logout()
gurt.crumbs.delete('auth_token')
print('Logged out successfully')
gurt.location.goto("../")
end
local function goToDashboard()
gurt.location.goto("/dashboard.html")
end
local function submitDomain(name, tld, ip)
hideError('domain-error')
print('Submitting domain: ' .. name .. '.' .. tld)
local response = fetch('gurt://localhost:8877/domain', {
method = 'POST',
headers = {
['Content-Type'] = 'application/json',
Authorization = 'Bearer ' .. authToken
},
body = JSON.stringify({ name = name, tld = tld, ip = ip })
})
if response:ok() then
print('Domain submitted successfully.')
-- Update user registrations remaining
user.registrations_remaining = user.registrations_remaining - 1
updateUserInfo()
-- Clear form
gurt.select('#domain-name').text = ''
gurt.select('#domain-ip').text = ''
-- Redirect to dashboard
gurt.location.goto('/dashboard.html')
else
local error = response:text()
showError('domain-error', 'Domain submission failed: ' .. error)
print('Domain submission failed: ' .. error)
end
end
local function createInvite()
print('Creating invite code...')
local response = fetch('gurt://localhost:8877/auth/invite', {
method = 'POST',
headers = {
Authorization = 'Bearer ' .. authToken
}
})
if response:ok() then
local data = response:json()
local inviteCode = data.invite_code
displayElement.text = 'Invite code: ' .. inviteCode .. ' (copied to clipboard)'
displayElement:show()
Clipboard.write(inviteCode)
print('Invite code created and copied to clipboard: ' .. inviteCode)
else
print('Failed to create invite: ' .. response:text())
end
end
local function redeemInvite(code)
hideError('redeem-error')
print('Redeeming invite code: ' .. code)
local response = fetch('gurt://localhost:8877/auth/redeem-invite', {
method = 'POST',
headers = {
['Content-Type'] = 'application/json',
Authorization = 'Bearer ' .. authToken
},
body = JSON.stringify({ invite_code = code })
})
if response:ok() then
local data = response:json()
print('Invite redeemed: +' .. data.registrations_added .. ' registrations')
-- Update user info
user.registrations_remaining = user.registrations_remaining + data.registrations_added
updateUserInfo()
-- Clear form
gurt.select('#invite-code-input').text = ''
else
local error = response:text()
showError('redeem-error', 'Failed to redeem invite: ' .. error)
print('Failed to redeem invite: ' .. error)
end
end
-- Event handlers
gurt.select('#logout-btn'):on('click', logout)
gurt.select('#dashboard-btn'):on('click', goToDashboard)
gurt.select('#submit-domain-btn'):on('click', function()
local name = gurt.select('#domain-name').value
local ip = gurt.select('#domain-ip').value
local selectedTLD = gurt.select('.tld-selected')
print('Submit domain button clicked')
print('Input name:', name)
print('Input IP:', ip)
print('Selected TLD element:', selectedTLD)
if not name or name == '' then
print('Validation failed: Domain name is required')
showError('domain-error', 'Domain name is required')
return
end
if not ip or ip == '' then
print('Validation failed: IP address is required')
showError('domain-error', 'IP address is required')
return
end
if not selectedTLD then
print('Validation failed: No TLD selected')
showError('domain-error', 'Please select a TLD')
return
end
local tld = selectedTLD:getAttribute('data-tld')
print('Submitting domain with name:', name, 'tld:', tld, 'ip:', ip)
submitDomain(name, tld, ip)
end)
gurt.select('#create-invite-btn'):on('click', createInvite)
gurt.select('#redeem-invite-btn'):on('click', function()
local code = gurt.select('#invite-code-input').text
if code and code ~= '' then
redeemInvite(code)
end
end)
-- Initialize
print('Register page initialized')
checkAuth()