update client and todo
This commit is contained in:
+263
-263
@@ -11,7 +11,6 @@
|
|||||||
.config label { color: #888; }
|
.config label { color: #888; }
|
||||||
.config input { background: #2a2a2a; color: #e0e0e0; border: 1px solid #444; padding: 4px 8px; width: 300px; }
|
.config input { background: #2a2a2a; color: #e0e0e0; border: 1px solid #444; padding: 4px 8px; width: 300px; }
|
||||||
|
|
||||||
/* LOG */
|
|
||||||
#log-header { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
|
#log-header { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
|
||||||
#log-header span { color: #888; font-size: 1em; }
|
#log-header span { color: #888; font-size: 1em; }
|
||||||
#clear-log { background: #2a2a2a; color: #888; border: 1px solid #444; padding: 3px 10px; cursor: pointer; font-size: 0.85em; font-family: monospace; }
|
#clear-log { background: #2a2a2a; color: #888; border: 1px solid #444; padding: 3px 10px; cursor: pointer; font-size: 0.85em; font-family: monospace; }
|
||||||
@@ -21,7 +20,6 @@
|
|||||||
.log-err { color: #f88; }
|
.log-err { color: #f88; }
|
||||||
.log-info { color: #666; }
|
.log-info { color: #666; }
|
||||||
|
|
||||||
/* BUTTON ROW */
|
|
||||||
#btn-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
|
#btn-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
|
||||||
#btn-row button {
|
#btn-row button {
|
||||||
background: #2a2a2a; color: #ccc; border: 1px solid #444;
|
background: #2a2a2a; color: #ccc; border: 1px solid #444;
|
||||||
@@ -32,10 +30,11 @@
|
|||||||
#btn-row button.active.ws { background: #2a2a3a; border-color: #44a; color: #88f; }
|
#btn-row button.active.ws { background: #2a2a3a; border-color: #44a; color: #88f; }
|
||||||
#btn-row button.warn { color: #f88; }
|
#btn-row button.warn { color: #f88; }
|
||||||
|
|
||||||
/* FORM PANEL */
|
|
||||||
#form-panel { display: none; background: #1e1e1e; border: 1px solid #333; padding: 12px; margin-bottom: 6px; }
|
#form-panel { display: none; background: #1e1e1e; border: 1px solid #333; padding: 12px; margin-bottom: 6px; }
|
||||||
#form-panel.open { display: block; }
|
#form-panel.open { display: block; }
|
||||||
#form-title { color: #888; font-size: 0.85em; margin-bottom: 10px; }
|
#form-title { color: #888; font-size: 0.85em; margin-bottom: 10px; }
|
||||||
|
.form-content { display: none; }
|
||||||
|
.form-content.active { display: block; }
|
||||||
.field { margin-bottom: 7px; }
|
.field { margin-bottom: 7px; }
|
||||||
.field label { display: inline-block; width: 160px; color: #777; font-size: 0.88em; }
|
.field label { display: inline-block; width: 160px; color: #777; font-size: 0.88em; }
|
||||||
.field input { background: #2a2a2a; color: #e0e0e0; border: 1px solid #444; padding: 4px 8px; width: 260px; font-family: monospace; font-size: 0.88em; }
|
.field input { background: #2a2a2a; color: #e0e0e0; border: 1px solid #444; padding: 4px 8px; width: 260px; font-family: monospace; font-size: 0.88em; }
|
||||||
@@ -66,215 +65,170 @@
|
|||||||
<div id="log"></div>
|
<div id="log"></div>
|
||||||
|
|
||||||
<div id="btn-row">
|
<div id="btn-row">
|
||||||
<button data-form="new-user" onclick="showForm('new-user')">POST /new/user</button>
|
<button data-form="new-user" onclick="showForm('new-user')">POST /user</button>
|
||||||
<button data-form="new-token" onclick="showForm('new-token')">POST /new/token</button>
|
<button data-form="new-token" onclick="showForm('new-token')">POST /token</button>
|
||||||
<button data-form="new-connection" onclick="showForm('new-connection')">POST /new/connection</button>
|
<button data-form="new-connection" onclick="showForm('new-connection')">POST /connection</button>
|
||||||
<button data-form="file-upload" onclick="showForm('file-upload')">POST /new/file</button>
|
<button data-form="file-upload" onclick="showForm('file-upload')">POST /file</button>
|
||||||
<button data-form="mod-user-profile" onclick="showForm('mod-user-profile')">POST /mod/user/profile</button>
|
<button data-form="mod-user-profile" onclick="showForm('mod-user-profile')">PATCH /user/profile</button>
|
||||||
<button data-form="mod-user-avatar" onclick="showForm('mod-user-avatar')">POST /mod/user/avatar</button>
|
<button data-form="mod-user-avatar" onclick="showForm('mod-user-avatar')">PATCH /user/avatar</button>
|
||||||
<button data-form="mod-user-profilebg" onclick="showForm('mod-user-profilebg')">POST /mod/user/profilebg</button>
|
<button data-form="mod-user-profilebg" onclick="showForm('mod-user-profilebg')">PATCH /user/profilebg</button>
|
||||||
<button data-form="mod-connection-elevate" onclick="showForm('mod-connection-elevate')">POST /mod/connection/elevate</button>
|
<button data-form="mod-connection-elevate" onclick="showForm('mod-connection-elevate')">POST /connection/elevate</button>
|
||||||
<button data-form="mod-connection-deelevate" onclick="showForm('mod-connection-deelevate')">POST /mod/connection/deelevate</button>
|
<button data-form="mod-connection-deelevate" onclick="showForm('mod-connection-deelevate')">POST /connection/deelevate</button>
|
||||||
<button data-form="get-user" onclick="showForm('get-user')">POST /get/user</button>
|
<button data-form="get-user" onclick="showForm('get-user')">GET /user</button>
|
||||||
<button data-form="get-connections" onclick="showForm('get-connections')">POST /get/connections</button>
|
<button data-form="get-connections" onclick="showForm('get-connections')">GET /connections</button>
|
||||||
<button data-form="get-connection-messages" onclick="showForm('get-connection-messages')">POST /get/connection/messages</button>
|
<button data-form="get-connection-messages" onclick="showForm('get-connection-messages')">GET /connection/messages</button>
|
||||||
<button data-form="file-download" onclick="showForm('file-download')">POST /get/file</button>
|
<button data-form="file-download" onclick="showForm('file-download')">GET /file</button>
|
||||||
<button data-form="get-user-avatar" onclick="showForm('get-user-avatar')">POST /get/user/avatar</button>
|
<button data-form="get-user-avatar" onclick="showForm('get-user-avatar')">GET /user/avatar</button>
|
||||||
<button data-form="get-user-profilebg" onclick="showForm('get-user-profilebg')">POST /get/user/profilebg</button>
|
<button data-form="get-user-profilebg" onclick="showForm('get-user-profilebg')">GET /user/profilebg</button>
|
||||||
<button data-form="del-user" class="warn" onclick="showForm('del-user')">POST /del/user</button>
|
<button data-form="del-user" class="warn" onclick="showForm('del-user')">DELETE /user</button>
|
||||||
<button data-form="del-connection" class="warn" onclick="showForm('del-connection')">POST /del/connection</button>
|
<button data-form="del-connection" class="warn" onclick="showForm('del-connection')">DELETE /connection</button>
|
||||||
<button data-form="msg-user" onclick="showForm('msg-user')">POST /msg/user</button>
|
<button data-form="msg-user" onclick="showForm('msg-user')">POST /message</button>
|
||||||
<button data-form="websocket" onclick="showForm('websocket')">WS /ws</button>
|
<button data-form="websocket" onclick="showForm('websocket')">WS /ws</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="form-panel">
|
<div id="form-panel">
|
||||||
<div id="form-title"></div>
|
<div id="form-title"></div>
|
||||||
<div id="form-fields"></div>
|
|
||||||
|
<!-- POST /user -->
|
||||||
|
<div class="form-content" id="fc-new-user">
|
||||||
|
<div class="field"><label>username</label><input id="nu-username" placeholder="min 4 chars"></div>
|
||||||
|
<div class="field"><label>password</label><input id="nu-password" placeholder="min 8 chars"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('new-user')">Send</button></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<!-- POST /token -->
|
||||||
let ws = null;
|
<div class="form-content" id="fc-new-token">
|
||||||
let activeForm = null;
|
<div class="field"><label>username</label><input id="nt-username" placeholder="min 4 chars"></div>
|
||||||
let currentToken = '';
|
<div class="field"><label>password</label><input id="nt-password" placeholder="min 8 chars"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('new-token')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
function autofillTokens() {
|
<!-- POST /connection -->
|
||||||
if (!currentToken) return;
|
<div class="form-content" id="fc-new-connection">
|
||||||
document.querySelectorAll('input[id$="-token"]').forEach(el => { el.value = currentToken; });
|
<div class="field"><label>token</label><input id="nconn-token" placeholder=""></div>
|
||||||
}
|
<div class="field"><label>recipient</label><input id="nconn-recipient" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('new-connection')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
var formDefs = {
|
<!-- POST /file -->
|
||||||
'new-user': {
|
<div class="form-content" id="fc-file-upload">
|
||||||
title: 'POST /new/user — register new user',
|
|
||||||
fields: [
|
|
||||||
{ id: 'nu-username', label: 'username', ph: 'min 4 chars' },
|
|
||||||
{ id: 'nu-password', label: 'password', ph: 'min 8 chars' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/new/user', { username:'nu-username', password:'nu-password' })
|
|
||||||
},
|
|
||||||
'new-token': {
|
|
||||||
title: 'POST /new/token — login / get token',
|
|
||||||
fields: [
|
|
||||||
{ id: 'nt-username', label: 'username', ph: 'min 4 chars' },
|
|
||||||
{ id: 'nt-password', label: 'password', ph: 'min 8 chars' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/new/token', { username:'nt-username', password:'nt-password' })
|
|
||||||
},
|
|
||||||
'new-connection': {
|
|
||||||
title: 'POST /new/connection — send connection request',
|
|
||||||
fields: [
|
|
||||||
{ id: 'nconn-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'nconn-recipient', label: 'recipient', ph: 'uint32' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/new/connection', { token:'nconn-token', recipient:'nconn-recipient' })
|
|
||||||
},
|
|
||||||
'mod-user-profile': {
|
|
||||||
title: 'POST /mod/user/profile — update profile',
|
|
||||||
fields: [
|
|
||||||
{ id: 'mup-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'mup-pronouns', label: 'pronouns', ph: 'optional' },
|
|
||||||
{ id: 'mup-description', label: 'description', ph: 'optional' },
|
|
||||||
{ id: 'mup-color', label: 'color', ph: '255,100,50 optional', hint: 'R,G,B' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/mod/user/profile', { token:'mup-token', pronouns:'mup-pronouns', description:'mup-description', color:'mup-color' })
|
|
||||||
},
|
|
||||||
'mod-user-avatar': {
|
|
||||||
title: 'POST /mod/user/avatar — set avatar image (token in header)',
|
|
||||||
renderCustom: () => `
|
|
||||||
<div class="field"><label>token</label><input id="mua-token" placeholder=""></div>
|
|
||||||
<div class="field"><label>file</label><input id="mua-file" type="file"></div>
|
|
||||||
<div class="form-actions">
|
|
||||||
<button class="send" onclick="submitAvatarUpload()">Send</button>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
'mod-user-profilebg': {
|
|
||||||
title: 'POST /mod/user/profilebg — set profile background (token in header)',
|
|
||||||
renderCustom: () => `
|
|
||||||
<div class="field"><label>token</label><input id="mpb-token" placeholder=""></div>
|
|
||||||
<div class="field"><label>file</label><input id="mpb-file" type="file"></div>
|
|
||||||
<div class="form-actions">
|
|
||||||
<button class="send" onclick="submitProfileBgUpload()">Send</button>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
'mod-connection-elevate': {
|
|
||||||
title: 'POST /mod/connection/elevate — elevate connection',
|
|
||||||
fields: [
|
|
||||||
{ id: 'mce-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'mce-connectionid', label: 'connectionid', ph: 'UUID' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/mod/connection/elevate', { token:'mce-token', connectionid:'mce-connectionid' })
|
|
||||||
},
|
|
||||||
'mod-connection-deelevate': {
|
|
||||||
title: 'POST /mod/connection/deelevate — de-elevate connection',
|
|
||||||
fields: [
|
|
||||||
{ id: 'mcde-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'mcde-connectionid', label: 'connectionid', ph: 'UUID' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/mod/connection/deelevate', { token:'mcde-token', connectionid:'mcde-connectionid' })
|
|
||||||
},
|
|
||||||
'get-user': {
|
|
||||||
title: 'POST /get/user — get user info',
|
|
||||||
fields: [
|
|
||||||
{ id: 'gu-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'gu-targetid', label: 'targetid', ph: 'uint32' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/get/user', { token:'gu-token', targetid:'gu-targetid' })
|
|
||||||
},
|
|
||||||
'get-connections': {
|
|
||||||
title: "POST /get/connections — get user's connections",
|
|
||||||
fields: [
|
|
||||||
{ id: 'gconn-token', label: 'token', ph: '' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/get/connections', { token:'gconn-token' })
|
|
||||||
},
|
|
||||||
'get-connection-messages': {
|
|
||||||
title: 'POST /get/connection/messages — fetch message history',
|
|
||||||
fields: [
|
|
||||||
{ id: 'gcm-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'gcm-connectionid', label: 'connectionid', ph: 'UUID' },
|
|
||||||
{ id: 'gcm-messages', label: 'messages', ph: 'count (optional)' },
|
|
||||||
{ id: 'gcm-before', label: 'before', ph: 'RFC3339 (optional)', hint: 'e.g. 2025-01-01T00:00:00Z' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/get/connection/messages', { token:'gcm-token', connectionid:'gcm-connectionid', messages:'gcm-messages', before:'gcm-before' })
|
|
||||||
},
|
|
||||||
'get-user-avatar': {
|
|
||||||
title: 'POST /get/user/avatar — get avatar URL (token in header)',
|
|
||||||
renderCustom: () => `
|
|
||||||
<div class="field"><label>token</label><input id="gua-token" placeholder=""></div>
|
|
||||||
<div class="field"><label>userid</label><input id="gua-userid" placeholder="uint32"></div>
|
|
||||||
<div class="form-actions">
|
|
||||||
<button class="send" onclick="submitGetUserAvatar()">Send</button>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
'get-user-profilebg': {
|
|
||||||
title: 'POST /get/user/profilebg — get profile background URL (token in header)',
|
|
||||||
renderCustom: () => `
|
|
||||||
<div class="field"><label>token</label><input id="gpb-token" placeholder=""></div>
|
|
||||||
<div class="field"><label>userid</label><input id="gpb-userid" placeholder="uint32"></div>
|
|
||||||
<div class="form-actions">
|
|
||||||
<button class="send" onclick="submitGetUserProfileBg()">Send</button>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
'del-user': {
|
|
||||||
title: 'POST /del/user — delete own account',
|
|
||||||
fields: [
|
|
||||||
{ id: 'du-token', label: 'token', ph: '' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/del/user', { token:'du-token' })
|
|
||||||
},
|
|
||||||
'del-connection': {
|
|
||||||
title: 'POST /del/connection — delete a connection',
|
|
||||||
fields: [
|
|
||||||
{ id: 'dc-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'dc-connectionid', label: 'connectionid', ph: 'UUID' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/del/connection', { token:'dc-token', connectionid:'dc-connectionid' })
|
|
||||||
},
|
|
||||||
'msg-user': {
|
|
||||||
title: 'POST /msg/user — send direct message to user',
|
|
||||||
fields: [
|
|
||||||
{ id: 'mu-token', label: 'token', ph: '' },
|
|
||||||
{ id: 'mu-connectionid', label: 'connectionid', ph: 'UUID' },
|
|
||||||
{ id: 'mu-msgContent', label: 'msgContent', ph: 'message text (optional if mediaKey set)' },
|
|
||||||
{ id: 'mu-attachedFile', label: 'attachedFile', ph: 'key returned by /new/file (optional)' },
|
|
||||||
],
|
|
||||||
submit: () => httpPost('/msg/user', { token:'mu-token', connectionid:'mu-connectionid', msgContent:'mu-msgContent', attachedFile:'mu-attachedFile' })
|
|
||||||
},
|
|
||||||
'file-upload': {
|
|
||||||
title: 'POST /new/file — upload file (multipart, token in header)',
|
|
||||||
renderCustom: () => `
|
|
||||||
<div class="field"><label>token</label><input id="fu-token" placeholder=""></div>
|
<div class="field"><label>token</label><input id="fu-token" placeholder=""></div>
|
||||||
<div class="field"><label>connectionid</label><input id="fu-connectionid" placeholder="UUID"></div>
|
<div class="field"><label>connectionid</label><input id="fu-connectionid" placeholder="UUID"></div>
|
||||||
<div class="field"><label>file</label><input id="fu-file" type="file"></div>
|
<div class="field"><label>file</label><input id="fu-file" type="file"></div>
|
||||||
<div class="form-actions">
|
<div class="form-actions"><button class="send" onclick="submitFileUpload()">Send</button></div>
|
||||||
<button class="send" onclick="submitFileUpload()">Send</button>
|
|
||||||
</div>
|
</div>
|
||||||
`
|
|
||||||
},
|
<!-- PATCH /user/profile -->
|
||||||
'file-download': {
|
<div class="form-content" id="fc-mod-user-profile">
|
||||||
title: 'POST /get/file — get presigned download URL (token in header)',
|
<div class="field"><label>token</label><input id="mup-token" placeholder=""></div>
|
||||||
renderCustom: () => `
|
<div class="field"><label>pronouns</label><input id="mup-pronouns" placeholder="optional"></div>
|
||||||
|
<div class="field"><label>description</label><input id="mup-description" placeholder="optional"></div>
|
||||||
|
<div class="field"><label>color</label><input id="mup-color" placeholder="255,100,50 optional"><span class="hint">R,G,B</span></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('mod-user-profile')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /user/avatar -->
|
||||||
|
<div class="form-content" id="fc-mod-user-avatar">
|
||||||
|
<div class="field"><label>token</label><input id="mua-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>file</label><input id="mua-file" type="file"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submitAvatarUpload()">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /user/profilebg -->
|
||||||
|
<div class="form-content" id="fc-mod-user-profilebg">
|
||||||
|
<div class="field"><label>token</label><input id="mpb-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>file</label><input id="mpb-file" type="file"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submitProfileBgUpload()">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- POST /connection/elevate -->
|
||||||
|
<div class="form-content" id="fc-mod-connection-elevate">
|
||||||
|
<div class="field"><label>token</label><input id="mce-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>connectionid</label><input id="mce-connectionid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('mod-connection-elevate')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- POST /connection/deelevate -->
|
||||||
|
<div class="form-content" id="fc-mod-connection-deelevate">
|
||||||
|
<div class="field"><label>token</label><input id="mcde-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>connectionid</label><input id="mcde-connectionid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('mod-connection-deelevate')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /user -->
|
||||||
|
<div class="form-content" id="fc-get-user">
|
||||||
|
<div class="field"><label>token</label><input id="gu-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>targetid</label><input id="gu-targetid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-user')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /connections -->
|
||||||
|
<div class="form-content" id="fc-get-connections">
|
||||||
|
<div class="field"><label>token</label><input id="gconn-token" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-connections')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /connection/messages -->
|
||||||
|
<div class="form-content" id="fc-get-connection-messages">
|
||||||
|
<div class="field"><label>token</label><input id="gcm-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>connectionid</label><input id="gcm-connectionid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>messages</label><input id="gcm-messages" placeholder="count (optional)"></div>
|
||||||
|
<div class="field"><label>before</label><input id="gcm-before" placeholder="RFC3339 (optional)"><span class="hint">e.g. 2025-01-01T00:00:00Z</span></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-connection-messages')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /file -->
|
||||||
|
<div class="form-content" id="fc-file-download">
|
||||||
<div class="field"><label>token</label><input id="fd-token" placeholder=""></div>
|
<div class="field"><label>token</label><input id="fd-token" placeholder=""></div>
|
||||||
<div class="field"><label>connectionid</label><input id="fd-connectionid" placeholder="UUID"></div>
|
<div class="field"><label>connectionid</label><input id="fd-connectionid" placeholder="UUID"></div>
|
||||||
<div class="field"><label>key</label><input id="fd-key" placeholder="returned by upload"></div>
|
<div class="field"><label>key</label><input id="fd-key" placeholder="returned by upload"></div>
|
||||||
<div class="form-actions">
|
<div class="form-actions"><button class="send" onclick="submitFileDownload()">Send</button></div>
|
||||||
<button class="send" onclick="submitFileDownload()">Send</button>
|
|
||||||
</div>
|
</div>
|
||||||
`
|
|
||||||
},
|
<!-- GET /user/avatar -->
|
||||||
'websocket': {
|
<div class="form-content" id="fc-get-user-avatar">
|
||||||
title: 'WS /ws — WebSocket connection',
|
<div class="field"><label>token</label><input id="gua-token" placeholder=""></div>
|
||||||
renderCustom: () => {
|
<div class="field"><label>userid</label><input id="gua-userid" placeholder="UUID"></div>
|
||||||
return `
|
<div class="form-actions"><button class="send" onclick="submitGetUserAvatar()">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /user/profilebg -->
|
||||||
|
<div class="form-content" id="fc-get-user-profilebg">
|
||||||
|
<div class="field"><label>token</label><input id="gpb-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>userid</label><input id="gpb-userid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submitGetUserProfileBg()">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /user -->
|
||||||
|
<div class="form-content" id="fc-del-user">
|
||||||
|
<div class="field"><label>token</label><input id="du-token" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('del-user')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /connection -->
|
||||||
|
<div class="form-content" id="fc-del-connection">
|
||||||
|
<div class="field"><label>token</label><input id="dc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>connectionid</label><input id="dc-connectionid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('del-connection')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- POST /message -->
|
||||||
|
<div class="form-content" id="fc-msg-user">
|
||||||
|
<div class="field"><label>token</label><input id="mu-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>connectionid</label><input id="mu-connectionid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>msgContent</label><input id="mu-msgContent" placeholder="message text (optional if file set)"></div>
|
||||||
|
<div class="field"><label>attachedFile</label><input id="mu-attachedFile" placeholder="key from POST /file (optional)"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('msg-user')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- WS /ws -->
|
||||||
|
<div class="form-content" id="fc-websocket">
|
||||||
<div class="form-actions" style="margin-bottom:10px">
|
<div class="form-actions" style="margin-bottom:10px">
|
||||||
<button class="ws-action" onclick="wsConnect()">Connect</button>
|
<button class="ws-action" onclick="wsConnect()">Connect</button>
|
||||||
<button class="ws-danger" onclick="wsDisconnect()">Disconnect</button>
|
<button class="ws-danger" onclick="wsDisconnect()">Disconnect</button>
|
||||||
<span id="ws-status" class="ws-status disconnected">disconnected</span>
|
<span id="ws-status" class="ws-status disconnected">disconnected</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field"><label>token (auth)</label><input id="ws-token" placeholder="send as first message to authenticate"></div>
|
<div class="field"><label>token (auth)</label><input id="ws-token" placeholder="sent as first message"></div>
|
||||||
<div class="form-actions" style="margin-bottom:10px">
|
<div class="form-actions" style="margin-bottom:10px">
|
||||||
<button class="ws-action" onclick="wsAuth()">Send Auth Token</button>
|
<button class="ws-action" onclick="wsAuth()">Send Auth Token</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -282,31 +236,66 @@
|
|||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button class="ws-action" onclick="wsSend()">Send Raw</button>
|
<button class="ws-action" onclick="wsSend()">Send Raw</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
</div>
|
||||||
}
|
</div>
|
||||||
},
|
|
||||||
|
<script>
|
||||||
|
let ws = null;
|
||||||
|
let activeForm = null;
|
||||||
|
let currentToken = '';
|
||||||
|
|
||||||
|
// method, path, which field ids go where
|
||||||
|
// dest: 'header' | 'body' | 'query'
|
||||||
|
const formDefs = {
|
||||||
|
'new-user': { method:'POST', path:'/user', title:'POST /user — register new user', fields:[{id:'nu-username',dest:'body',name:'username'},{id:'nu-password',dest:'body',name:'password'}] },
|
||||||
|
'new-token': { method:'POST', path:'/token', title:'POST /token — login / get token', fields:[{id:'nt-username',dest:'body',name:'username'},{id:'nt-password',dest:'body',name:'password'}] },
|
||||||
|
'new-connection': { method:'POST', path:'/connection', title:'POST /connection — send connection request', fields:[{id:'nconn-token',dest:'header',name:'token'},{id:'nconn-recipient',dest:'body',name:'recipient'}] },
|
||||||
|
'mod-user-profile': { method:'PATCH', path:'/user/profile', title:'PATCH /user/profile — update profile', fields:[{id:'mup-token',dest:'header',name:'token'},{id:'mup-pronouns',dest:'body',name:'pronouns'},{id:'mup-description',dest:'body',name:'description'},{id:'mup-color',dest:'body',name:'color'}] },
|
||||||
|
'mod-connection-elevate': { method:'POST', path:'/connection/elevate', title:'POST /connection/elevate — elevate', fields:[{id:'mce-token',dest:'header',name:'token'},{id:'mce-connectionid',dest:'body',name:'connectionid'}] },
|
||||||
|
'mod-connection-deelevate':{ method:'POST', path:'/connection/deelevate', title:'POST /connection/deelevate — de-elevate', fields:[{id:'mcde-token',dest:'header',name:'token'},{id:'mcde-connectionid',dest:'body',name:'connectionid'}] },
|
||||||
|
'get-user': { method:'GET', path:'/user', title:'GET /user — get user info', fields:[{id:'gu-token',dest:'header',name:'token'},{id:'gu-targetid',dest:'query',name:'targetid'}] },
|
||||||
|
'get-connections': { method:'GET', path:'/connections', title:'GET /connections — get connections', fields:[{id:'gconn-token',dest:'header',name:'token'}] },
|
||||||
|
'get-connection-messages': { method:'GET', path:'/connection/messages', title:'GET /connection/messages — message history', fields:[{id:'gcm-token',dest:'header',name:'token'},{id:'gcm-connectionid',dest:'query',name:'connectionid'},{id:'gcm-messages',dest:'query',name:'messages'},{id:'gcm-before',dest:'query',name:'before'}] },
|
||||||
|
'del-user': { method:'DELETE', path:'/user', title:'DELETE /user — delete own account', fields:[{id:'du-token',dest:'header',name:'token'}] },
|
||||||
|
'del-connection': { method:'DELETE', path:'/connection', title:'DELETE /connection — delete a connection', fields:[{id:'dc-token',dest:'header',name:'token'},{id:'dc-connectionid',dest:'query',name:'connectionid'}] },
|
||||||
|
'msg-user': { method:'POST', path:'/message', title:'POST /message — send direct message', fields:[{id:'mu-token',dest:'header',name:'token'},{id:'mu-connectionid',dest:'body',name:'connectionid'},{id:'mu-msgContent',dest:'body',name:'msgContent'},{id:'mu-attachedFile',dest:'body',name:'attachedFile'}] },
|
||||||
|
'mod-user-avatar': { title:'PATCH /user/avatar — set avatar image' },
|
||||||
|
'mod-user-profilebg': { title:'PATCH /user/profilebg — set profile background' },
|
||||||
|
'file-upload': { title:'POST /file — upload file (multipart)' },
|
||||||
|
'file-download': { title:'GET /file — get presigned download URL' },
|
||||||
|
'get-user-avatar': { title:'GET /user/avatar — get avatar URL' },
|
||||||
|
'get-user-profilebg': { title:'GET /user/profilebg — get profile background URL' },
|
||||||
|
'websocket': { title:'WS /ws — WebSocket connection' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function autofillTokens() {
|
||||||
|
if (!currentToken) return;
|
||||||
|
document.querySelectorAll('input[id$="-token"]').forEach(el => { el.value = currentToken; });
|
||||||
|
}
|
||||||
|
|
||||||
function showForm(name) {
|
function showForm(name) {
|
||||||
const panel = document.getElementById('form-panel');
|
const panel = document.getElementById('form-panel');
|
||||||
const titleEl = document.getElementById('form-title');
|
const titleEl = document.getElementById('form-title');
|
||||||
const fieldsEl = document.getElementById('form-fields');
|
|
||||||
const buttons = document.querySelectorAll('#btn-row button');
|
const buttons = document.querySelectorAll('#btn-row button');
|
||||||
|
|
||||||
// deactivate all buttons
|
|
||||||
buttons.forEach(b => b.classList.remove('active'));
|
buttons.forEach(b => b.classList.remove('active'));
|
||||||
|
|
||||||
if (activeForm === name) {
|
if (activeForm === name) {
|
||||||
panel.classList.remove('open');
|
panel.classList.remove('open');
|
||||||
|
document.querySelectorAll('.form-content').forEach(el => el.classList.remove('active'));
|
||||||
activeForm = null;
|
activeForm = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (activeForm) {
|
||||||
|
const prev = document.getElementById('fc-' + activeForm);
|
||||||
|
if (prev) prev.classList.remove('active');
|
||||||
|
}
|
||||||
|
|
||||||
activeForm = name;
|
activeForm = name;
|
||||||
const def = formDefs[name];
|
const def = formDefs[name];
|
||||||
|
|
||||||
// activate clicked button
|
const btn = document.querySelector('#btn-row button[data-form="' + name + '"]');
|
||||||
const btn = document.querySelector(`#btn-row button[data-form="${name}"]`);
|
|
||||||
if (btn) {
|
if (btn) {
|
||||||
btn.classList.add('active');
|
btn.classList.add('active');
|
||||||
if (name === 'websocket') btn.classList.add('ws');
|
if (name === 'websocket') btn.classList.add('ws');
|
||||||
@@ -314,24 +303,33 @@
|
|||||||
|
|
||||||
titleEl.textContent = def.title;
|
titleEl.textContent = def.title;
|
||||||
|
|
||||||
if (def.renderCustom) {
|
const fc = document.getElementById('fc-' + name);
|
||||||
fieldsEl.innerHTML = def.renderCustom();
|
if (fc) fc.classList.add('active');
|
||||||
autofillTokens();
|
|
||||||
} else {
|
panel.classList.add('open');
|
||||||
let html = '';
|
|
||||||
for (const f of def.fields) {
|
|
||||||
html += `<div class="field">
|
|
||||||
<label>${f.label}</label>
|
|
||||||
<input id="${f.id}" placeholder="${f.ph || ''}">
|
|
||||||
${f.hint ? `<span class="hint">${f.hint}</span>` : ''}
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
html += `<div class="form-actions"><button class="send" onclick="formDefs['${name}'].submit()">Send</button></div>`;
|
|
||||||
fieldsEl.innerHTML = html;
|
|
||||||
autofillTokens();
|
autofillTokens();
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.classList.add('open');
|
function submit(name) {
|
||||||
|
const def = formDefs[name];
|
||||||
|
if (!def || !def.fields) return;
|
||||||
|
|
||||||
|
const headers = {};
|
||||||
|
const bodyFields = {};
|
||||||
|
const queryFields = {};
|
||||||
|
|
||||||
|
for (const f of def.fields) {
|
||||||
|
const el = document.getElementById(f.id);
|
||||||
|
const v = el ? el.value : '';
|
||||||
|
if (!v) continue;
|
||||||
|
if (f.dest === 'header') headers[f.name] = v;
|
||||||
|
else if (f.dest === 'query') queryFields[f.name] = v;
|
||||||
|
else bodyFields[f.name] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = Object.keys(bodyFields).length ? new URLSearchParams(bodyFields) : null;
|
||||||
|
const query = Object.keys(queryFields).length ? queryFields : null;
|
||||||
|
apiCall(def.method, def.path, { headers, body, query });
|
||||||
}
|
}
|
||||||
|
|
||||||
function log(prefix, text, cls) {
|
function log(prefix, text, cls) {
|
||||||
@@ -341,44 +339,50 @@
|
|||||||
line.className = cls;
|
line.className = cls;
|
||||||
let formatted = text;
|
let formatted = text;
|
||||||
try { formatted = JSON.stringify(JSON.parse(text), null, 2); } catch(e) {}
|
try { formatted = JSON.stringify(JSON.parse(text), null, 2); } catch(e) {}
|
||||||
line.textContent = `[${ts}] ${prefix}: ${formatted}`;
|
line.textContent = '[' + ts + '] ' + prefix + ': ' + formatted;
|
||||||
div.appendChild(line);
|
div.appendChild(line);
|
||||||
div.scrollTop = div.scrollHeight;
|
div.scrollTop = div.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearLog() { document.getElementById('log').innerHTML = ''; }
|
function clearLog() { document.getElementById('log').textContent = ''; }
|
||||||
|
|
||||||
function baseUrl() { return document.getElementById('baseUrl').value.replace(/\/$/, ''); }
|
function baseUrl() { return document.getElementById('baseUrl').value.replace(/\/$/, ''); }
|
||||||
|
|
||||||
async function httpPost(path, fieldMap) {
|
async function apiCall(method, path, { headers = {}, body = null, query = null } = {}) {
|
||||||
const params = new URLSearchParams();
|
let url = baseUrl() + path;
|
||||||
for (const [key, id] of Object.entries(fieldMap)) {
|
if (query) url += '?' + new URLSearchParams(query).toString();
|
||||||
const el = document.getElementById(id);
|
|
||||||
if (el && el.value !== '') params.append(key, el.value);
|
const opts = { method, headers };
|
||||||
}
|
if (body) opts.body = body;
|
||||||
const url = baseUrl() + path;
|
|
||||||
log(`HTTP ${path}`, `→ ${params.toString()}`, 'log-info');
|
const detail = body ? body.toString() : (query ? new URLSearchParams(query).toString() : '');
|
||||||
|
log(method + ' ' + path, detail || '(no params)', 'log-info');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(url, { method: 'POST', body: params });
|
const resp = await fetch(url, opts);
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
log(`HTTP ${resp.status}`, text, resp.ok ? 'log-http' : 'log-err');
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
|
||||||
if (path === '/new/token' && resp.ok) {
|
|
||||||
|
if (method === 'POST' && path === '/token' && resp.ok) {
|
||||||
try { currentToken = JSON.parse(text).token; } catch(e) {}
|
try { currentToken = JSON.parse(text).token; } catch(e) {}
|
||||||
autofillTokens();
|
autofillTokens();
|
||||||
wsConnectAndAuth();
|
wsConnectAndAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { ok: resp.ok, text, status: resp.status };
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
log('HTTP ERR', e.message, 'log-err');
|
log('HTTP ERR', e.message, 'log-err');
|
||||||
|
return { ok: false };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function wsConnectAndAuth() {
|
function wsConnectAndAuth() {
|
||||||
if (ws) { wsAuth(); return; }
|
if (ws) { wsAuth(); return; }
|
||||||
const url = baseUrl().replace(/^http/, 'ws') + '/ws';
|
const url = baseUrl().replace(/^http/, 'ws') + '/ws';
|
||||||
log('WS', `auto-connecting to ${url}`, 'log-info');
|
log('WS', 'auto-connecting to ' + url, 'log-info');
|
||||||
ws = new WebSocket(url);
|
ws = new WebSocket(url);
|
||||||
ws.onopen = () => { setWsStatus(true); log('WS', 'connected', 'log-ws'); wsAuth(); };
|
ws.onopen = () => { setWsStatus(true); log('WS', 'connected', 'log-ws'); wsAuth(); };
|
||||||
ws.onmessage = (e) => { log('WS', e.data, 'log-ws'); };
|
ws.onmessage = (e) => { log('WS ←', e.data, 'log-ws'); };
|
||||||
ws.onerror = () => { log('WS ERR', 'error', 'log-err'); };
|
ws.onerror = () => { log('WS ERR', 'error', 'log-err'); };
|
||||||
ws.onclose = () => { setWsStatus(false); log('WS', 'disconnected', 'log-info'); ws = null; };
|
ws.onclose = () => { setWsStatus(false); log('WS', 'disconnected', 'log-info'); ws = null; };
|
||||||
}
|
}
|
||||||
@@ -386,10 +390,10 @@
|
|||||||
function wsConnect() {
|
function wsConnect() {
|
||||||
if (ws) { log('WS', 'already connected', 'log-info'); return; }
|
if (ws) { log('WS', 'already connected', 'log-info'); return; }
|
||||||
const url = baseUrl().replace(/^http/, 'ws') + '/ws';
|
const url = baseUrl().replace(/^http/, 'ws') + '/ws';
|
||||||
log('WS', `connecting to ${url}`, 'log-info');
|
log('WS', 'connecting to ' + url, 'log-info');
|
||||||
ws = new WebSocket(url);
|
ws = new WebSocket(url);
|
||||||
ws.onopen = () => { setWsStatus(true); log('WS', 'connected', 'log-ws'); };
|
ws.onopen = () => { setWsStatus(true); log('WS', 'connected', 'log-ws'); };
|
||||||
ws.onmessage = (e) => { log('WS', e.data, 'log-ws'); };
|
ws.onmessage = (e) => { log('WS ←', e.data, 'log-ws'); };
|
||||||
ws.onerror = () => { log('WS ERR', 'error', 'log-err'); };
|
ws.onerror = () => { log('WS ERR', 'error', 'log-err'); };
|
||||||
ws.onclose = () => { setWsStatus(false); log('WS', 'disconnected', 'log-info'); ws = null; };
|
ws.onclose = () => { setWsStatus(false); log('WS', 'disconnected', 'log-info'); ws = null; };
|
||||||
}
|
}
|
||||||
@@ -413,6 +417,13 @@
|
|||||||
log('WS →', msg, 'log-info');
|
log('WS →', msg, 'log-info');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWsStatus(connected) {
|
||||||
|
const el = document.getElementById('ws-status');
|
||||||
|
if (!el) return;
|
||||||
|
el.textContent = connected ? 'connected' : 'disconnected';
|
||||||
|
el.className = 'ws-status ' + (connected ? 'connected' : 'disconnected');
|
||||||
|
}
|
||||||
|
|
||||||
async function submitFileUpload() {
|
async function submitFileUpload() {
|
||||||
const token = document.getElementById('fu-token').value;
|
const token = document.getElementById('fu-token').value;
|
||||||
const connectionid = document.getElementById('fu-connectionid').value;
|
const connectionid = document.getElementById('fu-connectionid').value;
|
||||||
@@ -421,35 +432,31 @@
|
|||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('connectionid', connectionid);
|
form.append('connectionid', connectionid);
|
||||||
form.append('file', fileInput.files[0]);
|
form.append('file', fileInput.files[0]);
|
||||||
log('HTTP /new/file', `→ connectionid=${connectionid} file=${fileInput.files[0].name}`, 'log-info');
|
log('POST /file', 'connectionid=' + connectionid + ' file=' + fileInput.files[0].name, 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/new/file', { method: 'POST', headers: { token }, body: form });
|
const resp = await fetch(baseUrl() + '/file', { method: 'POST', headers: { token }, body: form });
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
log(`HTTP ${resp.status}`, text, resp.ok ? 'log-http' : 'log-err');
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
const keyEl = document.getElementById('fd-key');
|
const keyEl = document.getElementById('fd-key');
|
||||||
if (keyEl) keyEl.value = text;
|
if (keyEl) keyEl.value = text;
|
||||||
const dmKeyEl = document.getElementById('mu-attachedFile');
|
const dmKeyEl = document.getElementById('mu-attachedFile');
|
||||||
if (dmKeyEl) dmKeyEl.value = text;
|
if (dmKeyEl) dmKeyEl.value = text;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
||||||
log('HTTP ERR', e.message, 'log-err');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitFileDownload() {
|
async function submitFileDownload() {
|
||||||
const token = document.getElementById('fd-token').value;
|
const token = document.getElementById('fd-token').value;
|
||||||
const connectionid = document.getElementById('fd-connectionid').value;
|
const connectionid = document.getElementById('fd-connectionid').value;
|
||||||
const key = document.getElementById('fd-key').value;
|
const key = document.getElementById('fd-key').value;
|
||||||
const params = new URLSearchParams({ connectionid, key });
|
const query = new URLSearchParams({ connectionid, key });
|
||||||
log('HTTP /get/file', `→ ${params.toString()}`, 'log-info');
|
log('GET /file', query.toString(), 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/get/file', { method: 'POST', headers: { token }, body: params });
|
const resp = await fetch(baseUrl() + '/file?' + query.toString(), { method: 'GET', headers: { token } });
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
log(`HTTP ${resp.status}`, text, resp.ok ? 'log-http' : 'log-err');
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
|
||||||
} catch(e) {
|
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
||||||
log('HTTP ERR', e.message, 'log-err');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitAvatarUpload() {
|
async function submitAvatarUpload() {
|
||||||
@@ -458,11 +465,11 @@
|
|||||||
if (!fileInput.files.length) { log('HTTP ERR', 'no file selected', 'log-err'); return; }
|
if (!fileInput.files.length) { log('HTTP ERR', 'no file selected', 'log-err'); return; }
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('file', fileInput.files[0]);
|
form.append('file', fileInput.files[0]);
|
||||||
log('HTTP /mod/user/avatar', `→ file=${fileInput.files[0].name}`, 'log-info');
|
log('PATCH /user/avatar', 'file=' + fileInput.files[0].name, 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/mod/user/avatar', { method: 'POST', headers: { token }, body: form });
|
const resp = await fetch(baseUrl() + '/user/avatar', { method: 'PATCH', headers: { token }, body: form });
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
log(`HTTP ${resp.status}`, text, resp.ok ? 'log-http' : 'log-err');
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
|
||||||
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,44 +479,37 @@
|
|||||||
if (!fileInput.files.length) { log('HTTP ERR', 'no file selected', 'log-err'); return; }
|
if (!fileInput.files.length) { log('HTTP ERR', 'no file selected', 'log-err'); return; }
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('file', fileInput.files[0]);
|
form.append('file', fileInput.files[0]);
|
||||||
log('HTTP /mod/user/profilebg', `→ file=${fileInput.files[0].name}`, 'log-info');
|
log('PATCH /user/profilebg', 'file=' + fileInput.files[0].name, 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/mod/user/profilebg', { method: 'POST', headers: { token }, body: form });
|
const resp = await fetch(baseUrl() + '/user/profilebg', { method: 'PATCH', headers: { token }, body: form });
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
log(`HTTP ${resp.status}`, text, resp.ok ? 'log-http' : 'log-err');
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
|
||||||
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitGetUserAvatar() {
|
async function submitGetUserAvatar() {
|
||||||
const token = document.getElementById('gua-token').value;
|
const token = document.getElementById('gua-token').value;
|
||||||
const userid = document.getElementById('gua-userid').value;
|
const userid = document.getElementById('gua-userid').value;
|
||||||
const params = new URLSearchParams({ userid });
|
const query = new URLSearchParams({ userid });
|
||||||
log('HTTP /get/user/avatar', `→ ${params.toString()}`, 'log-info');
|
log('GET /user/avatar', query.toString(), 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/get/user/avatar', { method: 'POST', headers: { token }, body: params });
|
const resp = await fetch(baseUrl() + '/user/avatar?' + query.toString(), { method: 'GET', headers: { token } });
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
log(`HTTP ${resp.status}`, text, resp.ok ? 'log-http' : 'log-err');
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
|
||||||
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitGetUserProfileBg() {
|
async function submitGetUserProfileBg() {
|
||||||
const token = document.getElementById('gpb-token').value;
|
const token = document.getElementById('gpb-token').value;
|
||||||
const userid = document.getElementById('gpb-userid').value;
|
const userid = document.getElementById('gpb-userid').value;
|
||||||
const params = new URLSearchParams({ userid });
|
const query = new URLSearchParams({ userid });
|
||||||
log('HTTP /get/user/profilebg', `→ ${params.toString()}`, 'log-info');
|
log('GET /user/profilebg', query.toString(), 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/get/user/profilebg', { method: 'POST', headers: { token }, body: params });
|
const resp = await fetch(baseUrl() + '/user/profilebg?' + query.toString(), { method: 'GET', headers: { token } });
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
log(`HTTP ${resp.status}`, text, resp.ok ? 'log-http' : 'log-err');
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
|
||||||
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWsStatus(connected) {
|
|
||||||
const el = document.getElementById('ws-status');
|
|
||||||
if (!el) return;
|
|
||||||
el.textContent = connected ? 'connected' : 'disconnected';
|
|
||||||
el.className = 'ws-status ' + (connected ? 'connected' : 'disconnected');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user