fix hub bugs, add channel role permission endpoints
Covers: snake_case param renames, mutex RLock/Unlock mismatches, user.Hubs keyed by hub.Id, hub color using new_name, DELETE params sent as query, delete(target.Hubs, hub.Id), root/member role Id swap, and the three new PATCH /hub/channel/roles/* handlers.
This commit is contained in:
+352
-16
@@ -12,6 +12,7 @@
|
|||||||
<label>Base URL: </label>
|
<label>Base URL: </label>
|
||||||
<input id="baseUrl" value="http://localhost:8080">
|
<input id="baseUrl" value="http://localhost:8080">
|
||||||
<span id="current-user" style="margin-left:14px;color:#666;font-size:0.85em"></span>
|
<span id="current-user" style="margin-left:14px;color:#666;font-size:0.85em"></span>
|
||||||
|
<span id="current-hub" style="margin-left:14px;color:#666;font-size:0.85em"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="log-header">
|
<div id="log-header">
|
||||||
@@ -41,9 +42,38 @@
|
|||||||
<button data-form="del-connection" class="warn" onclick="showForm('del-connection')">DELETE /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 /connection/message</button>
|
<button data-form="msg-user" onclick="showForm('msg-user')">POST /connection/message</button>
|
||||||
<button data-form="hub-create" onclick="showForm('hub-create')">POST /hub</button>
|
<button data-form="hub-create" onclick="showForm('hub-create')">POST /hub</button>
|
||||||
<button data-form="hub-message" onclick="showForm('hub-message')">POST /hub/message</button>
|
<button data-form="hub-message" onclick="showForm('hub-message')">POST /hub/channel/message</button>
|
||||||
<button data-form="hub-join" onclick="showForm('hub-join')">PUT /hub/join</button>
|
<button data-form="hub-join" onclick="showForm('hub-join')">PUT /hub/join</button>
|
||||||
<button data-form="get-hubs" onclick="showForm('get-hubs')">GET /hubs</button>
|
<button data-form="get-hubs" onclick="showForm('get-hubs')">GET /hubs</button>
|
||||||
|
<button data-form="get-hub-data" onclick="showForm('get-hub-data')">GET /hub</button>
|
||||||
|
<button data-form="get-hub-channel-data" onclick="showForm('get-hub-channel-data')">GET /hub/channel</button>
|
||||||
|
<button data-form="get-hub-channels" onclick="showForm('get-hub-channels')">GET /hubs/channels</button>
|
||||||
|
<button data-form="get-hub-users" onclick="showForm('get-hub-users')">GET /hubs/users</button>
|
||||||
|
<button data-form="get-hub-roles" onclick="showForm('get-hub-roles')">GET /hubs/roles</button>
|
||||||
|
<button data-form="get-users" onclick="showForm('get-users')">GET /users</button>
|
||||||
|
<button data-form="hub-set-name" onclick="showForm('hub-set-name')">PATCH /hub/name</button>
|
||||||
|
<button data-form="hub-set-color" onclick="showForm('hub-set-color')">PATCH /hub/color</button>
|
||||||
|
<button data-form="hub-toggle-color" onclick="showForm('hub-toggle-color')">PATCH /hub/usercolorallowed</button>
|
||||||
|
<button data-form="hub-user-rename" onclick="showForm('hub-user-rename')">PATCH /hub/user/name</button>
|
||||||
|
<button data-form="hub-self-rename" onclick="showForm('hub-self-rename')">PATCH /hub/self/name</button>
|
||||||
|
<button data-form="hub-user-mute" onclick="showForm('hub-user-mute')">PATCH /hub/user/mute</button>
|
||||||
|
<button data-form="hub-role-set-name" onclick="showForm('hub-role-set-name')">PATCH /hub/role/name</button>
|
||||||
|
<button data-form="hub-role-set-color" onclick="showForm('hub-role-set-color')">PATCH /hub/role/color</button>
|
||||||
|
<button data-form="hub-role-set-perms" onclick="showForm('hub-role-set-perms')">PATCH /hub/role/permissions</button>
|
||||||
|
<button data-form="hub-channel-set-name" onclick="showForm('hub-channel-set-name')">PATCH /hub/channel/name</button>
|
||||||
|
<button data-form="hub-channel-set-desc" onclick="showForm('hub-channel-set-desc')">PATCH /hub/channel/description</button>
|
||||||
|
<button data-form="hub-channel-role-view" onclick="showForm('hub-channel-role-view')">PATCH /hub/channel/roles/view</button>
|
||||||
|
<button data-form="hub-channel-role-send" onclick="showForm('hub-channel-role-send')">PATCH /hub/channel/roles/send</button>
|
||||||
|
<button data-form="hub-channel-role-history" onclick="showForm('hub-channel-role-history')">PATCH /hub/channel/roles/history</button>
|
||||||
|
<button data-form="hub-user-add-role" onclick="showForm('hub-user-add-role')">PUT /hub/user/role</button>
|
||||||
|
<button data-form="hub-role-create" onclick="showForm('hub-role-create')">PUT /hub/role</button>
|
||||||
|
<button data-form="hub-channel-create" onclick="showForm('hub-channel-create')">PUT /hub/channel</button>
|
||||||
|
<button data-form="hub-remove" class="warn" onclick="showForm('hub-remove')">DELETE /hub</button>
|
||||||
|
<button data-form="hub-user-remove" class="warn" onclick="showForm('hub-user-remove')">DELETE /hub/user</button>
|
||||||
|
<button data-form="hub-user-remove-role" class="warn" onclick="showForm('hub-user-remove-role')">DELETE /hub/user/role</button>
|
||||||
|
<button data-form="hub-role-remove" class="warn" onclick="showForm('hub-role-remove')">DELETE /hub/role</button>
|
||||||
|
<button data-form="hub-self-remove-role" class="warn" onclick="showForm('hub-self-remove-role')">DELETE /hub/self/role</button>
|
||||||
|
<button data-form="hub-channel-remove" class="warn" onclick="showForm('hub-channel-remove')">DELETE /hub/channel</button>
|
||||||
<button data-form="websocket" onclick="showForm('websocket')">WS /ws</button>
|
<button data-form="websocket" onclick="showForm('websocket')">WS /ws</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -199,7 +229,7 @@
|
|||||||
<!-- POST /hub/message -->
|
<!-- POST /hub/message -->
|
||||||
<div class="form-content" id="fc-hub-message">
|
<div class="form-content" id="fc-hub-message">
|
||||||
<div class="field"><label>token</label><input id="hm-token" placeholder=""></div>
|
<div class="field"><label>token</label><input id="hm-token" placeholder=""></div>
|
||||||
<div class="field"><label>hubid</label><input id="hm-hubid" placeholder="UUID"></div>
|
<div class="field"><label>hubid</label><input id="hm-hubid" placeholder="UUID"><span class="hint">sent as header</span></div>
|
||||||
<div class="field"><label>channelid</label><input id="hm-channelid" placeholder="UUID"><span class="hint">sent as header</span></div>
|
<div class="field"><label>channelid</label><input id="hm-channelid" placeholder="UUID"><span class="hint">sent as header</span></div>
|
||||||
<div class="field"><label>msgContent</label><input id="hm-msgContent" placeholder="message text (optional if file set)"></div>
|
<div class="field"><label>msgContent</label><input id="hm-msgContent" placeholder="message text (optional if file set)"></div>
|
||||||
<div class="field"><label>attachedFile</label><input id="hm-attachedFile" placeholder="key from POST /file (optional)"></div>
|
<div class="field"><label>attachedFile</label><input id="hm-attachedFile" placeholder="key from POST /file (optional)"></div>
|
||||||
@@ -219,6 +249,245 @@
|
|||||||
<div class="form-actions"><button class="send" onclick="submit('get-hubs')">Send</button></div>
|
<div class="form-actions"><button class="send" onclick="submit('get-hubs')">Send</button></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /users -->
|
||||||
|
<div class="form-content" id="fc-get-users">
|
||||||
|
<div class="field"><label>token</label><input id="gus-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>targetids</label><input id="gus-targetids" placeholder="UUID,UUID,..."></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-users')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /hubs/channels -->
|
||||||
|
<div class="form-content" id="fc-get-hub-channels">
|
||||||
|
<div class="field"><label>token</label><input id="ghc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="ghc-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-hub-channels')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /hubs/users -->
|
||||||
|
<div class="form-content" id="fc-get-hub-users">
|
||||||
|
<div class="field"><label>token</label><input id="ghu-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="ghu-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-hub-users')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/name -->
|
||||||
|
<div class="form-content" id="fc-hub-set-name">
|
||||||
|
<div class="field"><label>token</label><input id="hsn-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hsn-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>newname</label><input id="hsn-newname" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-set-name')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/color -->
|
||||||
|
<div class="form-content" id="fc-hub-set-color">
|
||||||
|
<div class="field"><label>token</label><input id="hsc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hsc-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>new_color (R,G,B,A)</label><input id="hsc-newcolor" placeholder="255,100,50,255"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-set-color')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /hub -->
|
||||||
|
<div class="form-content" id="fc-hub-remove">
|
||||||
|
<div class="field"><label>token</label><input id="hr-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hr-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-remove')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/usercolorallowed -->
|
||||||
|
<div class="form-content" id="fc-hub-toggle-color">
|
||||||
|
<div class="field"><label>token</label><input id="htc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="htc-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-toggle-color')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /hub/user -->
|
||||||
|
<div class="form-content" id="fc-hub-user-remove">
|
||||||
|
<div class="field"><label>token</label><input id="hur-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hur-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>targetid</label><input id="hur-targetid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-user-remove')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/user/name -->
|
||||||
|
<div class="form-content" id="fc-hub-user-rename">
|
||||||
|
<div class="field"><label>token</label><input id="hun-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hun-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>targetid</label><input id="hun-targetid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>newname</label><input id="hun-newname" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-user-rename')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/self/name -->
|
||||||
|
<div class="form-content" id="fc-hub-self-rename">
|
||||||
|
<div class="field"><label>token</label><input id="hsr-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hsr-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>newname</label><input id="hsr-newname" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-self-rename')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/user/mute -->
|
||||||
|
<div class="form-content" id="fc-hub-user-mute">
|
||||||
|
<div class="field"><label>token</label><input id="hum-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hum-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>targetid</label><input id="hum-targetid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-user-mute')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PUT /hub/user/role -->
|
||||||
|
<div class="form-content" id="fc-hub-user-add-role">
|
||||||
|
<div class="field"><label>token</label><input id="huar-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="huar-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>targetid</label><input id="huar-targetid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>roleid</label><input id="huar-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-user-add-role')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /hub/user/role -->
|
||||||
|
<div class="form-content" id="fc-hub-user-remove-role">
|
||||||
|
<div class="field"><label>token</label><input id="hurr-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hurr-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>targetid</label><input id="hurr-targetid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>roleid</label><input id="hurr-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-user-remove-role')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PUT /hub/role -->
|
||||||
|
<div class="form-content" id="fc-hub-role-create">
|
||||||
|
<div class="field"><label>token</label><input id="hrc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hrc-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>name</label><input id="hrc-name" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-role-create')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /hub/role -->
|
||||||
|
<div class="form-content" id="fc-hub-role-remove">
|
||||||
|
<div class="field"><label>token</label><input id="hrr-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hrr-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>roleid</label><input id="hrr-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-role-remove')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/role/name -->
|
||||||
|
<div class="form-content" id="fc-hub-role-set-name">
|
||||||
|
<div class="field"><label>token</label><input id="hrsn-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hrsn-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>roleid</label><input id="hrsn-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="field"><label>newname</label><input id="hrsn-newname" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-role-set-name')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/role/color -->
|
||||||
|
<div class="form-content" id="fc-hub-role-set-color">
|
||||||
|
<div class="field"><label>token</label><input id="hrsc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hrsc-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>roleid</label><input id="hrsc-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="field"><label>newcolor (R,G,B,A)</label><input id="hrsc-newcolor" placeholder="255,100,50,255"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-role-set-color')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/role/permissions -->
|
||||||
|
<div class="form-content" id="fc-hub-role-set-perms">
|
||||||
|
<div class="field"><label>token</label><input id="hrsp-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hrsp-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>roleid</label><input id="hrsp-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="field"><label>permissions</label><input id="hrsp-permissions" placeholder="set_hub_name=true&remove_hub=false"><span class="hint">key=bool pairs</span></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submitHubRoleSetPerms()">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /hub/self/role -->
|
||||||
|
<div class="form-content" id="fc-hub-self-remove-role">
|
||||||
|
<div class="field"><label>token</label><input id="hsrr-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hsrr-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>roleid</label><input id="hsrr-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-self-remove-role')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PUT /hub/channel -->
|
||||||
|
<div class="form-content" id="fc-hub-channel-create">
|
||||||
|
<div class="field"><label>token</label><input id="hcc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hcc-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>name</label><input id="hcc-name" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-channel-create')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DELETE /hub/channel -->
|
||||||
|
<div class="form-content" id="fc-hub-channel-remove">
|
||||||
|
<div class="field"><label>token</label><input id="hcr-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hcr-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channel_id</label><input id="hcr-channel-id" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-channel-remove')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/channel/name -->
|
||||||
|
<div class="form-content" id="fc-hub-channel-set-name">
|
||||||
|
<div class="field"><label>token</label><input id="hcsn-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hcsn-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channel_id</label><input id="hcsn-channel-id" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>new_name</label><input id="hcsn-newname" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-channel-set-name')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/channel/description -->
|
||||||
|
<div class="form-content" id="fc-hub-channel-set-desc">
|
||||||
|
<div class="field"><label>token</label><input id="hcsd-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hcsd-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channel_id</label><input id="hcsd-channel-id" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>description</label><input id="hcsd-description" placeholder=""></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-channel-set-desc')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/channel/roles/view -->
|
||||||
|
<div class="form-content" id="fc-hub-channel-role-view">
|
||||||
|
<div class="field"><label>token</label><input id="hcrv-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hcrv-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channel_id</label><input id="hcrv-channelid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>role_id</label><input id="hcrv-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="field"><label>allow</label><input id="hcrv-allow" placeholder="true / false"><span class="hint">sent as query</span></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-channel-role-view')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/channel/roles/send -->
|
||||||
|
<div class="form-content" id="fc-hub-channel-role-send">
|
||||||
|
<div class="field"><label>token</label><input id="hcrs-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hcrs-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channel_id</label><input id="hcrs-channelid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>role_id</label><input id="hcrs-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="field"><label>allow</label><input id="hcrs-allow" placeholder="true / false"><span class="hint">sent as query</span></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-channel-role-send')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PATCH /hub/channel/roles/history -->
|
||||||
|
<div class="form-content" id="fc-hub-channel-role-history">
|
||||||
|
<div class="field"><label>token</label><input id="hcrh-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hcrh-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channel_id</label><input id="hcrh-channelid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>role_id</label><input id="hcrh-roleid" placeholder="uint8"></div>
|
||||||
|
<div class="field"><label>allow</label><input id="hcrh-allow" placeholder="true / false"><span class="hint">sent as query</span></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-channel-role-history')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /hub -->
|
||||||
|
<div class="form-content" id="fc-get-hub-data">
|
||||||
|
<div class="field"><label>token</label><input id="ghd-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="ghd-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-hub-data')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /hub/channel -->
|
||||||
|
<div class="form-content" id="fc-get-hub-channel-data">
|
||||||
|
<div class="field"><label>token</label><input id="ghcd-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="ghcd-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channel_id</label><input id="ghcd-channelid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-hub-channel-data')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GET /hubs/roles -->
|
||||||
|
<div class="form-content" id="fc-get-hub-roles">
|
||||||
|
<div class="field"><label>token</label><input id="ghr-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="ghr-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('get-hub-roles')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- WS /ws -->
|
<!-- WS /ws -->
|
||||||
<div class="form-content" id="fc-websocket">
|
<div class="form-content" id="fc-websocket">
|
||||||
<div class="form-actions" style="margin-bottom:10px">
|
<div class="form-actions" style="margin-bottom:10px">
|
||||||
@@ -242,6 +511,7 @@
|
|||||||
let activeForm = null;
|
let activeForm = null;
|
||||||
let currentToken = '';
|
let currentToken = '';
|
||||||
let currentUserId = '';
|
let currentUserId = '';
|
||||||
|
let currentHubId = '';
|
||||||
|
|
||||||
// method, path, which field ids go where
|
// method, path, which field ids go where
|
||||||
// dest: 'header' | 'body' | 'query'
|
// dest: 'header' | 'body' | 'query'
|
||||||
@@ -250,19 +520,48 @@
|
|||||||
'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-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'}] },
|
'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-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-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:'connection_id'}] },
|
||||||
'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'}] },
|
'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:'connection_id'}] },
|
||||||
'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-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:'target_id'}] },
|
||||||
'get-connections': { method:'GET', path:'/connections', title:'GET /connections — get connections', fields:[{id:'gconn-token',dest:'header',name:'token'}] },
|
'get-connections': { method:'GET', path:'/connections', title:'GET /connections — get connections', fields:[{id:'gconn-token',dest:'header',name:'token'}] },
|
||||||
'get-connections-unread': { method:'GET', path:'/connections/unreadmessages', title:'GET /connections/unreadmessages — unread counts for given connections (returns []uint32 in same order)', fields:[{id:'gcur-token',dest:'header',name:'token'},{id:'gcur-connections',dest:'query',name:'connections'}] },
|
'get-connections-unread': { method:'GET', path:'/connections/unreadmessages', title:'GET /connections/unreadmessages — unread counts for given connections (returns []uint32 in same order)', fields:[{id:'gcur-token',dest:'header',name:'token'},{id:'gcur-connections',dest:'query',name:'connections'}] },
|
||||||
'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'}] },
|
'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:'connection_id'},{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-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'}] },
|
'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:'connection_id'}] },
|
||||||
'msg-user': { method:'POST', path:'/connection/message', title:'POST /connection/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'}] },
|
'msg-user': { method:'POST', path:'/connection/message', title:'POST /connection/message — send direct message', fields:[{id:'mu-token',dest:'header',name:'token'},{id:'mu-connectionid',dest:'body',name:'connection_id'},{id:'mu-msgContent',dest:'body',name:'msg_content'},{id:'mu-attachedFile',dest:'body',name:'attached_file'}] },
|
||||||
'hub-create': { method:'POST', path:'/hub', title:'POST /hub — create a new hub', fields:[{id:'hc-token',dest:'header',name:'token'},{id:'hc-hubname',dest:'body',name:'hubname'}] },
|
'hub-create': { method:'POST', path:'/hub', title:'POST /hub — create a new hub', fields:[{id:'hc-token',dest:'header',name:'token'},{id:'hc-hubname',dest:'body',name:'hub_name'}] },
|
||||||
'hub-message': { method:'POST', path:'/hub/message', title:'POST /hub/message — send hub channel message', fields:[{id:'hm-token',dest:'header',name:'token'},{id:'hm-hubid',dest:'body',name:'hubid'},{id:'hm-channelid',dest:'header',name:'channelid'},{id:'hm-msgContent',dest:'body',name:'msgContent'},{id:'hm-attachedFile',dest:'body',name:'attachedFile'}] },
|
'hub-message': { method:'POST', path:'/hub/channel/message', title:'POST /hub/channel/message — send hub channel message', fields:[{id:'hm-token',dest:'header',name:'token'},{id:'hm-hubid',dest:'header',name:'hub_id'},{id:'hm-channelid',dest:'header',name:'channel_id'},{id:'hm-msgContent',dest:'body',name:'msg_content'},{id:'hm-attachedFile',dest:'body',name:'attached_file'}] },
|
||||||
'hub-join': { method:'PUT', path:'/hub/join', title:'PUT /hub/join — join hub (hubid as header)', fields:[{id:'hj-token',dest:'header',name:'token'},{id:'hj-hubid',dest:'header',name:'hubid'}] },
|
'hub-join': { method:'PUT', path:'/hub/join', title:'PUT /hub/join — join hub (hubid as header)', fields:[{id:'hj-token',dest:'header',name:'token'},{id:'hj-hubid',dest:'header',name:'hub_id'}] },
|
||||||
'get-hubs': { method:'GET', path:'/hubs', title:'GET /hubs — get own hubs', fields:[{id:'gh-token',dest:'header',name:'token'}] },
|
'get-hubs': { method:'GET', path:'/hubs', title:'GET /hubs — get own hubs', fields:[{id:'gh-token',dest:'header',name:'token'}] },
|
||||||
|
'get-hub-data': { method:'GET', path:'/hub', title:'GET /hub — get hub data', fields:[{id:'ghd-token',dest:'header',name:'token'},{id:'ghd-hubid',dest:'header',name:'hub_id'}] },
|
||||||
|
'get-hub-channel-data': { method:'GET', path:'/hub/channel', title:'GET /hub/channel — get channel data', fields:[{id:'ghcd-token',dest:'header',name:'token'},{id:'ghcd-hubid',dest:'header',name:'hub_id'},{id:'ghcd-channelid',dest:'query',name:'channel_id'}] },
|
||||||
|
'get-hub-channels': { method:'GET', path:'/hubs/channels', title:'GET /hubs/channels — get hub channels', fields:[{id:'ghc-token',dest:'header',name:'token'},{id:'ghc-hubid',dest:'header',name:'hub_id'}] },
|
||||||
|
'get-hub-users': { method:'GET', path:'/hubs/users', title:'GET /hubs/users — get hub users (excludes self)', fields:[{id:'ghu-token',dest:'header',name:'token'},{id:'ghu-hubid',dest:'header',name:'hub_id'}] },
|
||||||
|
'get-hub-roles': { method:'GET', path:'/hubs/roles', title:'GET /hubs/roles — get hub roles', fields:[{id:'ghr-token',dest:'header',name:'token'},{id:'ghr-hubid',dest:'header',name:'hub_id'}] },
|
||||||
|
'get-users': { method:'GET', path:'/users', title:'GET /users — get multiple users by IDs', fields:[{id:'gus-token',dest:'header',name:'token'},{id:'gus-targetids',dest:'query',name:'target_ids'}] },
|
||||||
|
'hub-set-name': { method:'PATCH', path:'/hub/name', title:'PATCH /hub/name — set hub name', fields:[{id:'hsn-token',dest:'header',name:'token'},{id:'hsn-hubid',dest:'header',name:'hub_id'},{id:'hsn-newname',dest:'body',name:'new_name'}] },
|
||||||
|
'hub-set-color': { method:'PATCH', path:'/hub/color', title:'PATCH /hub/color — set hub color (R,G,B,A)', fields:[{id:'hsc-token',dest:'header',name:'token'},{id:'hsc-hubid',dest:'header',name:'hub_id'},{id:'hsc-newcolor',dest:'body',name:'new_color'}] },
|
||||||
|
'hub-remove': { method:'DELETE', path:'/hub', title:'DELETE /hub — remove hub', fields:[{id:'hr-token',dest:'header',name:'token'},{id:'hr-hubid',dest:'header',name:'hub_id'}] },
|
||||||
|
'hub-toggle-color': { method:'PATCH', path:'/hub/usercolorallowed', title:'PATCH /hub/usercolorallowed — toggle user color allowed', fields:[{id:'htc-token',dest:'header',name:'token'},{id:'htc-hubid',dest:'header',name:'hub_id'}] },
|
||||||
|
'hub-user-remove': { method:'DELETE', path:'/hub/user', title:'DELETE /hub/user — remove user from hub', fields:[{id:'hur-token',dest:'header',name:'token'},{id:'hur-hubid',dest:'header',name:'hub_id'},{id:'hur-targetid',dest:'query',name:'target_id'}] },
|
||||||
|
'hub-user-rename': { method:'PATCH', path:'/hub/user/name', title:'PATCH /hub/user/name — rename hub user', fields:[{id:'hun-token',dest:'header',name:'token'},{id:'hun-hubid',dest:'header',name:'hub_id'},{id:'hun-targetid',dest:'body',name:'target_id'},{id:'hun-newname',dest:'body',name:'new_name'}] },
|
||||||
|
'hub-self-rename': { method:'PATCH', path:'/hub/self/name', title:'PATCH /hub/self/name — rename self in hub', fields:[{id:'hsr-token',dest:'header',name:'token'},{id:'hsr-hubid',dest:'header',name:'hub_id'},{id:'hsr-newname',dest:'body',name:'new_name'}] },
|
||||||
|
'hub-user-mute': { method:'PATCH', path:'/hub/user/mute', title:'PATCH /hub/user/mute — toggle mute user', fields:[{id:'hum-token',dest:'header',name:'token'},{id:'hum-hubid',dest:'header',name:'hub_id'},{id:'hum-targetid',dest:'body',name:'target_id'}] },
|
||||||
|
'hub-user-add-role': { method:'PUT', path:'/hub/user/role', title:'PUT /hub/user/role — add role to user', fields:[{id:'huar-token',dest:'header',name:'token'},{id:'huar-hubid',dest:'header',name:'hub_id'},{id:'huar-targetid',dest:'body',name:'target_id'},{id:'huar-roleid',dest:'body',name:'role_id'}] },
|
||||||
|
'hub-user-remove-role': { method:'DELETE', path:'/hub/user/role', title:'DELETE /hub/user/role — remove role from user', fields:[{id:'hurr-token',dest:'header',name:'token'},{id:'hurr-hubid',dest:'header',name:'hub_id'},{id:'hurr-targetid',dest:'query',name:'target_id'},{id:'hurr-roleid',dest:'query',name:'role_id'}] },
|
||||||
|
'hub-role-create': { method:'PUT', path:'/hub/role', title:'PUT /hub/role — create role', fields:[{id:'hrc-token',dest:'header',name:'token'},{id:'hrc-hubid',dest:'header',name:'hub_id'},{id:'hrc-name',dest:'body',name:'name'}] },
|
||||||
|
'hub-role-remove': { method:'DELETE', path:'/hub/role', title:'DELETE /hub/role — remove role', fields:[{id:'hrr-token',dest:'header',name:'token'},{id:'hrr-hubid',dest:'header',name:'hub_id'},{id:'hrr-roleid',dest:'query',name:'role_id'}] },
|
||||||
|
'hub-role-set-name': { method:'PATCH', path:'/hub/role/name', title:'PATCH /hub/role/name — set role name', fields:[{id:'hrsn-token',dest:'header',name:'token'},{id:'hrsn-hubid',dest:'header',name:'hub_id'},{id:'hrsn-roleid',dest:'body',name:'role_id'},{id:'hrsn-newname',dest:'body',name:'new_name'}] },
|
||||||
|
'hub-role-set-color': { method:'PATCH', path:'/hub/role/color', title:'PATCH /hub/role/color — set role color (R,G,B,A)', fields:[{id:'hrsc-token',dest:'header',name:'token'},{id:'hrsc-hubid',dest:'header',name:'hub_id'},{id:'hrsc-roleid',dest:'body',name:'role_id'},{id:'hrsc-newcolor',dest:'body',name:'new_color'}] },
|
||||||
|
'hub-role-set-perms': { title:'PATCH /hub/role/permissions — set role permissions (roleid in body, perm=bool in query)' },
|
||||||
|
'hub-self-remove-role': { method:'DELETE', path:'/hub/self/role', title:'DELETE /hub/self/role — remove own role', fields:[{id:'hsrr-token',dest:'header',name:'token'},{id:'hsrr-hubid',dest:'header',name:'hub_id'},{id:'hsrr-roleid',dest:'body',name:'role_id'}] },
|
||||||
|
'hub-channel-create': { method:'PUT', path:'/hub/channel', title:'PUT /hub/channel — create channel', fields:[{id:'hcc-token',dest:'header',name:'token'},{id:'hcc-hubid',dest:'header',name:'hub_id'},{id:'hcc-name',dest:'body',name:'name'}] },
|
||||||
|
'hub-channel-remove': { method:'DELETE', path:'/hub/channel', title:'DELETE /hub/channel — remove channel', fields:[{id:'hcr-token',dest:'header',name:'token'},{id:'hcr-hubid',dest:'header',name:'hub_id'},{id:'hcr-channel-id',dest:'query',name:'channel_id'}] },
|
||||||
|
'hub-channel-set-name': { method:'PATCH', path:'/hub/channel/name', title:'PATCH /hub/channel/name — set channel name', fields:[{id:'hcsn-token',dest:'header',name:'token'},{id:'hcsn-hubid',dest:'header',name:'hub_id'},{id:'hcsn-channel-id',dest:'body',name:'channel_id'},{id:'hcsn-newname',dest:'body',name:'new_name'}] },
|
||||||
|
'hub-channel-role-view': { method:'PATCH', path:'/hub/channel/roles/view', title:'PATCH /hub/channel/roles/view — set role can view channel', fields:[{id:'hcrv-token',dest:'header',name:'token'},{id:'hcrv-hubid',dest:'header',name:'hub_id'},{id:'hcrv-channelid',dest:'body',name:'channel_id'},{id:'hcrv-roleid',dest:'body',name:'role_id'},{id:'hcrv-allow',dest:'query',name:'allow'}] },
|
||||||
|
'hub-channel-role-send': { method:'PATCH', path:'/hub/channel/roles/send', title:'PATCH /hub/channel/roles/send — set role can send in channel', fields:[{id:'hcrs-token',dest:'header',name:'token'},{id:'hcrs-hubid',dest:'header',name:'hub_id'},{id:'hcrs-channelid',dest:'body',name:'channel_id'},{id:'hcrs-roleid',dest:'body',name:'role_id'},{id:'hcrs-allow',dest:'query',name:'allow'}] },
|
||||||
|
'hub-channel-role-history':{ method:'PATCH', path:'/hub/channel/roles/history', title:'PATCH /hub/channel/roles/history — set role can read history', fields:[{id:'hcrh-token',dest:'header',name:'token'},{id:'hcrh-hubid',dest:'header',name:'hub_id'},{id:'hcrh-channelid',dest:'body',name:'channel_id'},{id:'hcrh-roleid',dest:'body',name:'role_id'},{id:'hcrh-allow',dest:'query',name:'allow'}] },
|
||||||
|
'hub-channel-set-desc': { method:'PATCH', path:'/hub/channel/description',title:'PATCH /hub/channel/description — set channel description', fields:[{id:'hcsd-token',dest:'header',name:'token'},{id:'hcsd-hubid',dest:'header',name:'hub_id'},{id:'hcsd-channel-id',dest:'body',name:'channel_id'},{id:'hcsd-description',dest:'body',name:'description'}] },
|
||||||
'mod-user-avatar': { title:'PATCH /user/avatar — set avatar image' },
|
'mod-user-avatar': { title:'PATCH /user/avatar — set avatar image' },
|
||||||
'mod-user-profilebg': { title:'PATCH /user/profilebg — set profile background' },
|
'mod-user-profilebg': { title:'PATCH /user/profilebg — set profile background' },
|
||||||
'file-upload': { title:'POST /file — upload file (multipart)' },
|
'file-upload': { title:'POST /file — upload file (multipart)' },
|
||||||
@@ -277,6 +576,13 @@
|
|||||||
document.querySelectorAll('input[id$="-token"]').forEach(el => { el.value = currentToken; });
|
document.querySelectorAll('input[id$="-token"]').forEach(el => { el.value = currentToken; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function autofillHubIds() {
|
||||||
|
if (!currentHubId) return;
|
||||||
|
document.querySelectorAll('input[id$="-hubid"]').forEach(el => { el.value = currentHubId; });
|
||||||
|
const hubEl = document.getElementById('current-hub');
|
||||||
|
if (hubEl) hubEl.textContent = 'hubId: ' + currentHubId;
|
||||||
|
}
|
||||||
|
|
||||||
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');
|
||||||
@@ -312,6 +618,7 @@
|
|||||||
|
|
||||||
panel.classList.add('open');
|
panel.classList.add('open');
|
||||||
autofillTokens();
|
autofillTokens();
|
||||||
|
autofillHubIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
function submit(name) {
|
function submit(name) {
|
||||||
@@ -379,6 +686,19 @@
|
|||||||
wsConnectAndAuth();
|
wsConnectAndAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (method === 'POST' && path === '/hub' && resp.ok) {
|
||||||
|
currentHubId = text.trim();
|
||||||
|
autofillHubIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method === 'PUT' && path === '/hub/join' && resp.ok) {
|
||||||
|
const el = document.getElementById('hj-hubid');
|
||||||
|
if (el && el.value) {
|
||||||
|
currentHubId = el.value;
|
||||||
|
autofillHubIds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { ok: resp.ok, text, status: resp.status };
|
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');
|
||||||
@@ -440,9 +760,9 @@
|
|||||||
const fileInput = document.getElementById('fu-file');
|
const fileInput = document.getElementById('fu-file');
|
||||||
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('connectionid', connectionid);
|
form.append('connection_id', connectionid);
|
||||||
form.append('file', fileInput.files[0]);
|
form.append('file', fileInput.files[0]);
|
||||||
log('POST /file', 'connectionid=' + connectionid + ' file=' + fileInput.files[0].name, 'log-info');
|
log('POST /file', 'connection_id=' + connectionid + ' file=' + fileInput.files[0].name, 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/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();
|
||||||
@@ -460,7 +780,7 @@
|
|||||||
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 query = new URLSearchParams({ connectionid, key });
|
const query = new URLSearchParams({ connection_id: connectionid, key });
|
||||||
log('GET /file', query.toString(), 'log-info');
|
log('GET /file', query.toString(), 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/file?' + query.toString(), { method: 'GET', headers: { token } });
|
const resp = await fetch(baseUrl() + '/file?' + query.toString(), { method: 'GET', headers: { token } });
|
||||||
@@ -500,7 +820,7 @@
|
|||||||
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 query = new URLSearchParams({ userid });
|
const query = new URLSearchParams({ user_id: userid });
|
||||||
log('GET /user/avatar', query.toString(), 'log-info');
|
log('GET /user/avatar', query.toString(), 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/user/avatar?' + query.toString(), { method: 'GET', headers: { token } });
|
const resp = await fetch(baseUrl() + '/user/avatar?' + query.toString(), { method: 'GET', headers: { token } });
|
||||||
@@ -509,10 +829,26 @@
|
|||||||
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function submitHubRoleSetPerms() {
|
||||||
|
const token = document.getElementById('hrsp-token').value;
|
||||||
|
const hubid = document.getElementById('hrsp-hubid').value;
|
||||||
|
const roleid = document.getElementById('hrsp-roleid').value;
|
||||||
|
const permsRaw = document.getElementById('hrsp-permissions').value;
|
||||||
|
const body = new URLSearchParams({ role_id: roleid });
|
||||||
|
let queryStr = permsRaw;
|
||||||
|
log('PATCH /hub/role/permissions', 'role_id=' + roleid + ' ' + permsRaw, 'log-info');
|
||||||
|
try {
|
||||||
|
const url = baseUrl() + '/hub/role/permissions' + (queryStr ? '?' + queryStr : '');
|
||||||
|
const resp = await fetch(url, { method: 'PATCH', headers: { token, hub_id: hubid }, body });
|
||||||
|
const text = await resp.text();
|
||||||
|
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : '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 query = new URLSearchParams({ userid });
|
const query = new URLSearchParams({ user_id: userid });
|
||||||
log('GET /user/profilebg', query.toString(), 'log-info');
|
log('GET /user/profilebg', query.toString(), 'log-info');
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(baseUrl() + '/user/profilebg?' + query.toString(), { method: 'GET', headers: { token } });
|
const resp = await fetch(baseUrl() + '/user/profilebg?' + query.toString(), { method: 'GET', headers: { token } });
|
||||||
|
|||||||
@@ -59,10 +59,13 @@ func main() {
|
|||||||
http.HandleFunc("GET /file", withCORS(httpRequest.HandleAttachmentFileDownload))
|
http.HandleFunc("GET /file", withCORS(httpRequest.HandleAttachmentFileDownload))
|
||||||
|
|
||||||
http.HandleFunc("POST /hub", withCORS(httpRequest.HandleHubCreate))
|
http.HandleFunc("POST /hub", withCORS(httpRequest.HandleHubCreate))
|
||||||
http.HandleFunc("POST /hub/message", withCORS(httpRequest.HandleHubMessage))
|
http.HandleFunc("GET /hub", withCORS(httpRequest.GetHubData))
|
||||||
|
http.HandleFunc("POST /hub/channel/message", withCORS(httpRequest.HandleHubMessage))
|
||||||
|
http.HandleFunc("GET /hub/channel", withCORS(httpRequest.GetChannelData))
|
||||||
http.HandleFunc("GET /hubs", withCORS(httpRequest.HandleGetHubs))
|
http.HandleFunc("GET /hubs", withCORS(httpRequest.HandleGetHubs))
|
||||||
http.HandleFunc("GET /hubs/channels", withCORS(httpRequest.HandleGetChannels))
|
http.HandleFunc("GET /hubs/channels", withCORS(httpRequest.HandleGetChannels))
|
||||||
http.HandleFunc("GET /hubs/users", withCORS(httpRequest.HandleGetHubUsers))
|
http.HandleFunc("GET /hubs/users", withCORS(httpRequest.HandleGetHubUsers))
|
||||||
|
http.HandleFunc("GET /hubs/roles", withCORS(httpRequest.GetRoles))
|
||||||
http.HandleFunc("PUT /hub/join", withCORS(httpRequest.HandleHubJoin))
|
http.HandleFunc("PUT /hub/join", withCORS(httpRequest.HandleHubJoin))
|
||||||
http.HandleFunc("PATCH /hub/name", withCORS(httpRequest.HandleHubSetName))
|
http.HandleFunc("PATCH /hub/name", withCORS(httpRequest.HandleHubSetName))
|
||||||
http.HandleFunc("PATCH /hub/color", withCORS(httpRequest.HandleHubSetColor))
|
http.HandleFunc("PATCH /hub/color", withCORS(httpRequest.HandleHubSetColor))
|
||||||
@@ -82,8 +85,11 @@ func main() {
|
|||||||
http.HandleFunc("DELETE /hub/self/role", withCORS(httpRequest.HandleRoleSelfRemove))
|
http.HandleFunc("DELETE /hub/self/role", withCORS(httpRequest.HandleRoleSelfRemove))
|
||||||
http.HandleFunc("PUT /hub/channel", withCORS(httpRequest.HandleChannelCreate))
|
http.HandleFunc("PUT /hub/channel", withCORS(httpRequest.HandleChannelCreate))
|
||||||
http.HandleFunc("DELETE /hub/channel", withCORS(httpRequest.HandleChannelRemove))
|
http.HandleFunc("DELETE /hub/channel", withCORS(httpRequest.HandleChannelRemove))
|
||||||
http.HandleFunc("PATCH /hub/name", withCORS(httpRequest.HandleChannelSetName))
|
http.HandleFunc("PATCH /hub/channel/name", withCORS(httpRequest.HandleChannelSetName))
|
||||||
http.HandleFunc("PATCH /hub/description", withCORS(httpRequest.HandleChannelSetDescription))
|
http.HandleFunc("PATCH /hub/channel/description", withCORS(httpRequest.HandleChannelSetDescription))
|
||||||
|
http.HandleFunc("PATCH /hub/channel/roles/view", withCORS(httpRequest.HandleChannelSetPermittedVisibleRole))
|
||||||
|
http.HandleFunc("PATCH /hub/channel/roles/send", withCORS(httpRequest.HandleChannelSetPermittedSendRole))
|
||||||
|
http.HandleFunc("PATCH /hub/channel/roles/history", withCORS(httpRequest.HandleChannelSetPermittedHistoryRole))
|
||||||
|
|
||||||
http.HandleFunc("POST /connection/message", withCORS(httpRequest.HandleDm))
|
http.HandleFunc("POST /connection/message", withCORS(httpRequest.HandleDm))
|
||||||
http.HandleFunc("GET /ws", wsServer.ServeWsConnection)
|
http.HandleFunc("GET /ws", wsServer.ServeWsConnection)
|
||||||
|
|||||||
@@ -33,21 +33,21 @@ func HandleDm(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user)
|
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connection_id"), user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
msgContent := request.FormValue("msgContent")
|
msgContent := request.FormValue("msg_content")
|
||||||
attachedFile := request.FormValue("attachedFile")
|
attachedFile := request.FormValue("attached_file")
|
||||||
|
|
||||||
if msgContent == "" && attachedFile == "" {
|
if msgContent == "" && attachedFile == "" {
|
||||||
http.Error(response, "empty msgContent", http.StatusBadRequest)
|
http.Error(response, "empty msg_content", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if attachedFile != "" && !strings.HasPrefix(attachedFile, string(minio.ConnectionFilePrefix)+conn.Id.String()+"/") {
|
if attachedFile != "" && !strings.HasPrefix(attachedFile, string(minio.ConnectionFilePrefix)+conn.Id.String()+"/") {
|
||||||
http.Error(response, "invalid attachedFile", http.StatusBadRequest)
|
http.Error(response, "invalid attached_file", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ func HandleUserGetConnectionMessages(response http.ResponseWriter, request *http
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user)
|
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connection_id"), user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,7 @@ func HandleUserDeleteConnection(response http.ResponseWriter, request *http.Requ
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user)
|
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connection_id"), user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -305,7 +305,7 @@ func HandleUserElevateConnection(response http.ResponseWriter, request *http.Req
|
|||||||
http.Error(response, "invalid token", http.StatusUnauthorized)
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user)
|
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connection_id"), user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -374,7 +374,7 @@ func HandleUserDeElevateConnection(response http.ResponseWriter, request *http.R
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user)
|
conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connection_id"), user)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,9 +153,9 @@ func HandleGetUserAvatar(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
targetId, err := convertions.StringToUuid(request.URL.Query().Get("userid"))
|
targetId, err := convertions.StringToUuid(request.URL.Query().Get("user_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid userid", http.StatusBadRequest)
|
http.Error(response, "invalid user_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,9 +274,9 @@ func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
targetId, err := convertions.StringToUuid(request.URL.Query().Get("userid"))
|
targetId, err := convertions.StringToUuid(request.URL.Query().Get("user_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid userid", http.StatusBadRequest)
|
http.Error(response, "invalid user_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ func getHubUserIfValidWithResponseOnFail(ctx context.Context, response http.Resp
|
|||||||
return nil, nil, nil, errors.New("invalid token")
|
return nil, nil, nil, errors.New("invalid token")
|
||||||
}
|
}
|
||||||
|
|
||||||
hub, err := getHubByIdStr(ctx, request.Header.Get("hubid"))
|
hub, err := getHubByIdStr(ctx, request.Header.Get("hub_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid hubid", http.StatusBadRequest)
|
http.Error(response, "invalid hub_id", http.StatusBadRequest)
|
||||||
return nil, nil, nil, errors.New("no such hub")
|
return nil, nil, nil, errors.New("no such hub")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@ func getHubUserIfValidWithResponseOnFail(ctx context.Context, response http.Resp
|
|||||||
hubUser, ok := hub.Users[user.Id]
|
hubUser, ok := hub.Users[user.Id]
|
||||||
hub.Mu.RUnlock()
|
hub.Mu.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
http.Error(response, "invalid hubid", http.StatusUnauthorized)
|
http.Error(response, "invalid hub_id", http.StatusUnauthorized)
|
||||||
return nil, nil, nil, errors.New("invalid hubid")
|
return nil, nil, nil, errors.New("invalid hub_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, hubUser, hub, nil
|
return user, hubUser, hub, nil
|
||||||
@@ -94,13 +94,16 @@ func getHubChannelIfValidWithResponseOnFail(ctx context.Context, response http.R
|
|||||||
*types.HubChannel, error) {
|
*types.HubChannel, error) {
|
||||||
channelUuid, err := convertions.StringToUuid(channelId)
|
channelUuid, err := convertions.StringToUuid(channelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid channelid", http.StatusBadRequest)
|
http.Error(response, "invalid channel_id", http.StatusBadRequest)
|
||||||
return nil, errors.New("invalid channelid")
|
return nil, errors.New("invalid channel_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hub.Mu.RLock()
|
||||||
channel, ok := hub.Channels[channelUuid]
|
channel, ok := hub.Channels[channelUuid]
|
||||||
|
hub.Mu.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
http.Error(response, "invalid channelid", http.StatusBadRequest)
|
http.Error(response, "channel not found", http.StatusNotFound)
|
||||||
return nil, errors.New("invalid channelid")
|
return nil, errors.New("channel not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !haveHubUserCachedPermissions(types.CachedUserCanView, hubUser, channel) {
|
if !haveHubUserCachedPermissions(types.CachedUserCanView, hubUser, channel) {
|
||||||
|
|||||||
+284
-145
@@ -3,9 +3,7 @@ package httpRequest
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"maps"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -57,10 +55,10 @@ func hubUserHighestRoleId(u *types.HubUser, h *types.Hub) (id uint8) {
|
|||||||
func updateChannelCacheForSpecUserAndChannel(u *types.HubUser, c *types.HubChannel) {
|
func updateChannelCacheForSpecUserAndChannel(u *types.HubUser, c *types.HubChannel) {
|
||||||
c.Mu.Lock()
|
c.Mu.Lock()
|
||||||
defer c.Mu.Unlock()
|
defer c.Mu.Unlock()
|
||||||
|
|
||||||
if u == nil {
|
if u == nil {
|
||||||
delete(c.UsersCachedPermissions, c.Id)
|
delete(c.UsersCachedPermissions, c.Id)
|
||||||
} else {
|
return
|
||||||
|
}
|
||||||
if u.Roles.DoesIntersect(c.RolesCanView) {
|
if u.Roles.DoesIntersect(c.RolesCanView) {
|
||||||
c.UsersCachedPermissions[u.OriginalId] |= types.CachedUserCanView
|
c.UsersCachedPermissions[u.OriginalId] |= types.CachedUserCanView
|
||||||
} else {
|
} else {
|
||||||
@@ -77,7 +75,6 @@ func updateChannelCacheForSpecUserAndChannel(u *types.HubUser, c *types.HubChann
|
|||||||
c.UsersCachedPermissions[u.OriginalId] &^= types.CachedUserCanMessage
|
c.UsersCachedPermissions[u.OriginalId] &^= types.CachedUserCanMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func updateChannelCacheForSpecChannel(c *types.HubChannel, h *types.Hub) {
|
func updateChannelCacheForSpecChannel(c *types.HubChannel, h *types.Hub) {
|
||||||
h.Mu.RLock()
|
h.Mu.RLock()
|
||||||
@@ -91,17 +88,23 @@ func updateChannelCacheForSpecUser(u *types.HubUser, h *types.Hub) {
|
|||||||
h.Mu.RLock()
|
h.Mu.RLock()
|
||||||
defer h.Mu.RUnlock()
|
defer h.Mu.RUnlock()
|
||||||
for _, c := range h.Channels {
|
for _, c := range h.Channels {
|
||||||
|
if c == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
updateChannelCacheForSpecUserAndChannel(u, c)
|
updateChannelCacheForSpecUserAndChannel(u, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateChannelCacheForSpecRole(r *types.HubRole, h *types.Hub) {
|
func updateChannelCacheForSpecRole(r *types.HubRole, h *types.Hub) {
|
||||||
h.Mu.Lock()
|
h.Mu.RLock()
|
||||||
defer h.Mu.Unlock()
|
var users []*types.HubUser
|
||||||
for _, u := range h.Users {
|
for _, u := range h.Users {
|
||||||
if !u.Roles.ContainsRoleId(r.Id) {
|
if u.Roles.ContainsRoleId(r.Id) {
|
||||||
continue
|
users = append(users, u)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
h.Mu.RUnlock()
|
||||||
|
for _, u := range users {
|
||||||
updateChannelCacheForSpecUser(u, h)
|
updateChannelCacheForSpecUser(u, h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,7 +131,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hubName := request.FormValue("hubname")
|
hubName := request.FormValue("hub_name")
|
||||||
if hubName == "" {
|
if hubName == "" {
|
||||||
http.Error(response, "hub name is required", http.StatusBadRequest)
|
http.Error(response, "hub name is required", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -140,7 +143,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
hub.Id = uuid.New()
|
hub.Id = uuid.New()
|
||||||
hub.Creator = user.Id
|
hub.Creator = user.Id
|
||||||
hub.CreatedAt = time.Now()
|
hub.CreatedAt = time.Now()
|
||||||
user.Hubs[user.Id] = hub
|
user.Hubs[hub.Id] = hub
|
||||||
|
|
||||||
creator := types.NewHubUser()
|
creator := types.NewHubUser()
|
||||||
creator.OriginalId = user.Id
|
creator.OriginalId = user.Id
|
||||||
@@ -148,7 +151,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
hub.Users[creator.OriginalId] = creator
|
hub.Users[creator.OriginalId] = creator
|
||||||
|
|
||||||
rootRole := &types.HubRole{
|
rootRole := &types.HubRole{
|
||||||
Id: uint8(0),
|
Id: types.HubBoundRolesMax,
|
||||||
Permissions: types.PermissionAll(),
|
Permissions: types.PermissionAll(),
|
||||||
Name: "root",
|
Name: "root",
|
||||||
Color: types.RandomRgba(),
|
Color: types.RandomRgba(),
|
||||||
@@ -158,7 +161,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
creator.Roles.Add(rootRole.Id)
|
creator.Roles.Add(rootRole.Id)
|
||||||
|
|
||||||
memberRole := &types.HubRole{
|
memberRole := &types.HubRole{
|
||||||
Id: types.HubBoundRolesMax,
|
Id: uint8(0),
|
||||||
Name: "member",
|
Name: "member",
|
||||||
Color: types.RandomRgba(),
|
Color: types.RandomRgba(),
|
||||||
CreatedAt: hub.CreatedAt,
|
CreatedAt: hub.CreatedAt,
|
||||||
@@ -179,9 +182,13 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
channel.RolesCanReadHistory.Add(rootRole.Id)
|
channel.RolesCanReadHistory.Add(rootRole.Id)
|
||||||
channel.RolesCanReadHistory.Add(memberRole.Id)
|
channel.RolesCanReadHistory.Add(memberRole.Id)
|
||||||
channel.UsersCachedPermissions[creator.OriginalId] = types.CachedUserPermissionsAll
|
channel.UsersCachedPermissions[creator.OriginalId] = types.CachedUserPermissionsAll
|
||||||
hub.Channels[0] = channel
|
channel.Position = 0
|
||||||
|
hub.Channels[channel.Id] = channel
|
||||||
|
|
||||||
cache.SaveHub(hub)
|
cache.SaveHub(hub)
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
response.Write([]byte(hub.Id.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
|
func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
|
||||||
@@ -194,12 +201,19 @@ func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
|
|||||||
http.Error(response, "invalid token", http.StatusUnauthorized)
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub, err := getHubByIdStr(ctx, request.Header.Get("hubid"))
|
hub, err := getHubByIdStr(ctx, request.Header.Get("hub_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid hubid", http.StatusBadRequest)
|
http.Error(response, "invalid hub_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, ok := hub.Users[user.Id]
|
||||||
|
if ok {
|
||||||
|
http.Error(response, "hub already joined", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Hubs[hub.Id] = hub
|
||||||
hubUser := types.NewHubUser()
|
hubUser := types.NewHubUser()
|
||||||
hubUser.OriginalId = user.Id
|
hubUser.OriginalId = user.Id
|
||||||
if hub.JoinRole != nil {
|
if hub.JoinRole != nil {
|
||||||
@@ -208,6 +222,8 @@ func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
|
|||||||
hubUser.CreatedAt = time.Now()
|
hubUser.CreatedAt = time.Now()
|
||||||
hub.Users[hubUser.OriginalId] = hubUser
|
hub.Users[hubUser.OriginalId] = hubUser
|
||||||
updateChannelCacheForSpecUser(hubUser, hub)
|
updateChannelCacheForSpecUser(hubUser, hub)
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
||||||
@@ -219,7 +235,7 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channel, err := getHubChannelIfValidWithResponseOnFail(ctx, response, hub, hubUser, request.Header.Get("channelid"))
|
channel, err := getHubChannelIfValidWithResponseOnFail(ctx, response, hub, hubUser, request.Header.Get("channel_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -229,8 +245,8 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
msgContent := request.FormValue("msgContent")
|
msgContent := request.FormValue("msg_content")
|
||||||
attachedFile := request.FormValue("attachedFile")
|
attachedFile := request.FormValue("attached_file")
|
||||||
|
|
||||||
if msgContent == "" && attachedFile == "" {
|
if msgContent == "" && attachedFile == "" {
|
||||||
http.Error(response, "empty msgContent", http.StatusBadRequest)
|
http.Error(response, "empty msgContent", http.StatusBadRequest)
|
||||||
@@ -266,69 +282,10 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
wsServer.WsSendMessageCloseIfTimeout(target, msg)
|
wsServer.WsSendMessageCloseIfTimeout(target, msg)
|
||||||
}
|
}
|
||||||
}
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
|
||||||
func HandleGetHubs(response http.ResponseWriter, request *http.Request) {
|
|
||||||
if !validCheckWithResponseOnFail(response, request, normal) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx := request.Context()
|
|
||||||
user, err := getUserByToken(ctx, request.Header.Get("token"))
|
|
||||||
if err != nil {
|
|
||||||
http.Error(response, "invalid token", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
user.Mu.RLock()
|
|
||||||
hubs := slices.Collect(maps.Values(user.Hubs))
|
|
||||||
user.Mu.RUnlock()
|
|
||||||
if len(hubs) == 0 {
|
|
||||||
response.WriteHeader(http.StatusNoContent)
|
|
||||||
response.Write([]byte("no hubs found"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
converted, err := json.Marshal(hubs)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(response, "json error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
response.WriteHeader(http.StatusOK)
|
|
||||||
response.Write(converted)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleGetChannels(response http.ResponseWriter, request *http.Request) {
|
func HandleGetChannels(response http.ResponseWriter, request *http.Request) {
|
||||||
if !validCheckWithResponseOnFail(response, request, normal) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx := request.Context()
|
|
||||||
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
channelMap := make(map[uint8]*types.HubChannel)
|
|
||||||
hub.Mu.RLock()
|
|
||||||
for i, channel := range hub.Channels {
|
|
||||||
if channel == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
channelMap[uint8(i)] = channel
|
|
||||||
}
|
|
||||||
hub.Mu.Unlock()
|
|
||||||
if len(channelMap) == 0 {
|
|
||||||
response.WriteHeader(http.StatusNoContent)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
channels, err := json.Marshal(channelMap)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(response, "json error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
response.WriteHeader(http.StatusOK)
|
|
||||||
response.Write(channels)
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleGetHubUsers(response http.ResponseWriter, request *http.Request) {
|
|
||||||
if !validCheckWithResponseOnFail(response, request, normal) {
|
if !validCheckWithResponseOnFail(response, request, normal) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -337,27 +294,129 @@ func HandleGetHubUsers(response http.ResponseWriter, request *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
users := make([]*types.HubUser, 0)
|
channels := make([]uuid.UUID, 0)
|
||||||
hub.Mu.RLock()
|
hub.Mu.RLock()
|
||||||
for userId, user := range hub.Users {
|
for _, channel := range hub.Channels {
|
||||||
if userId == requestor.OriginalId {
|
if channel == nil || !haveHubUserCachedPermissions(types.CachedUserCanView, requestor, channel) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
users = append(users, user)
|
channels = append(channels, channel.Id)
|
||||||
}
|
}
|
||||||
hub.Mu.Unlock()
|
hub.Mu.RUnlock()
|
||||||
if len(users) == 0 {
|
if len(channels) == 0 {
|
||||||
response.WriteHeader(http.StatusNoContent)
|
response.WriteHeader(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channels, err := json.Marshal(users)
|
marshal, err := json.Marshal(channels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "json error", http.StatusInternalServerError)
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.WriteHeader(http.StatusOK)
|
response.WriteHeader(http.StatusOK)
|
||||||
response.Write(channels)
|
response.Write(marshal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleGetHubUsers(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !validCheckWithResponseOnFail(response, request, normal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
users := make([]*types.HubUser, 0)
|
||||||
|
hub.Mu.RLock()
|
||||||
|
for _, user := range hub.Users {
|
||||||
|
users = append(users, user)
|
||||||
|
}
|
||||||
|
hub.Mu.RUnlock()
|
||||||
|
if len(users) == 0 {
|
||||||
|
response.WriteHeader(http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
marshal, err := json.Marshal(users)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
response.Write(marshal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRoles(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !validCheckWithResponseOnFail(response, request, normal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hub.Mu.RLock()
|
||||||
|
roles := make([]*types.HubRole, 0)
|
||||||
|
for _, role := range hub.Roles {
|
||||||
|
if role == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
roles = append(roles, role)
|
||||||
|
}
|
||||||
|
hub.Mu.RUnlock()
|
||||||
|
marshal, err := json.Marshal(roles)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
response.Write(marshal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetHubData(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !validCheckWithResponseOnFail(response, request, normal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
marshal, err := json.Marshal(hub)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
response.Write(marshal)
|
||||||
|
}
|
||||||
|
func GetChannelData(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !validCheckWithResponseOnFail(response, request, normal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
channelId, err := convertions.StringToUuid(request.FormValue("channel_id"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid channel_id", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hub.Mu.RLock()
|
||||||
|
channel, ok := hub.Channels[channelId]
|
||||||
|
hub.Mu.RUnlock()
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "no such channel", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
marshal, err := json.Marshal(channel)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
response.Write(marshal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hubPermissionContext(response http.ResponseWriter, request *http.Request, rt bodyLimit, needed types.Permissions) (*types.HubUser, *types.Hub, context.Context, uint8, bool) {
|
func hubPermissionContext(response http.ResponseWriter, request *http.Request, rt bodyLimit, needed types.Permissions) (*types.HubUser, *types.Hub, context.Context, uint8, bool) {
|
||||||
@@ -384,7 +443,7 @@ func HandleHubSetName(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newName := request.FormValue("newname")
|
newName := request.FormValue("new_name")
|
||||||
if newName == "" {
|
if newName == "" {
|
||||||
http.Error(response, "empty name", http.StatusBadRequest)
|
http.Error(response, "empty name", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -398,7 +457,7 @@ func HandleHubSetColor(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
color, err := convertions.StringToRgba(request.FormValue("newname"))
|
color, err := convertions.StringToRgba(request.FormValue("new_color"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad color", http.StatusBadRequest)
|
http.Error(response, "bad color", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -430,28 +489,37 @@ func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetId, err := convertions.StringToUuid(request.FormValue("targetid"))
|
targetId, err := convertions.StringToUuid(request.FormValue("target_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad targetid", http.StatusBadRequest)
|
http.Error(response, "bad target_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.Mu.RLock()
|
hub.Mu.RLock()
|
||||||
target, exists := hub.Users[targetId]
|
hubTarget, exists := hub.Users[targetId]
|
||||||
|
hub.Mu.RUnlock()
|
||||||
if !exists {
|
if !exists {
|
||||||
hub.Mu.Unlock()
|
|
||||||
http.Error(response, "user not found", http.StatusNotFound)
|
http.Error(response, "user not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.Mu.RUnlock()
|
|
||||||
|
|
||||||
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
if usedRoleId <= hubUserHighestRoleId(hubTarget, hub) {
|
||||||
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target, err := cache.GetUserById(targetId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "target not found", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
target.Mu.Lock()
|
||||||
|
delete(target.Hubs, hub.Id)
|
||||||
|
target.Mu.Unlock()
|
||||||
|
|
||||||
hub.Mu.Lock()
|
hub.Mu.Lock()
|
||||||
delete(hub.Users, targetId)
|
delete(hub.Users, targetId)
|
||||||
updateChannelCacheForSpecUser(target, hub)
|
|
||||||
hub.Mu.Unlock()
|
hub.Mu.Unlock()
|
||||||
|
updateChannelCacheForSpecUser(hubTarget, hub)
|
||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,27 +528,25 @@ func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newName := request.FormValue("newname")
|
newName := request.FormValue("new_name")
|
||||||
targetId, err := convertions.StringToUuid(request.FormValue("targetid"))
|
targetId, err := convertions.StringToUuid(request.FormValue("target_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad targetid", http.StatusBadRequest)
|
http.Error(response, "bad target_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.Mu.RLock()
|
hub.Mu.RLock()
|
||||||
target, exists := hub.Users[targetId]
|
target, exists := hub.Users[targetId]
|
||||||
|
hub.Mu.RUnlock()
|
||||||
if !exists {
|
if !exists {
|
||||||
hub.Mu.Unlock()
|
|
||||||
http.Error(response, "user not found", http.StatusNotFound)
|
http.Error(response, "user not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.Mu.RUnlock()
|
|
||||||
|
|
||||||
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
||||||
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target.Name = newName
|
target.Name = newName
|
||||||
|
|
||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +555,7 @@ func HandleHubRenameSelf(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
requestor.Name = request.FormValue("newname")
|
requestor.Name = request.FormValue("new_name")
|
||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,25 +564,23 @@ func HandleHubToggleMuteUser(response http.ResponseWriter, request *http.Request
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetId, err := convertions.StringToUuid(request.FormValue("targetid"))
|
targetId, err := convertions.StringToUuid(request.FormValue("target_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad targetid", http.StatusBadRequest)
|
http.Error(response, "bad target_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.Mu.RLock()
|
hub.Mu.RLock()
|
||||||
target, exists := hub.Users[targetId]
|
target, exists := hub.Users[targetId]
|
||||||
|
hub.Mu.RUnlock()
|
||||||
if !exists {
|
if !exists {
|
||||||
hub.Mu.Unlock()
|
|
||||||
http.Error(response, "user not found", http.StatusNotFound)
|
http.Error(response, "user not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.Mu.RUnlock()
|
|
||||||
|
|
||||||
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
if usedRoleId <= hubUserHighestRoleId(target, hub) {
|
||||||
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
http.Error(response, "target higher in hierarchy", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hub.Mu.RLock()
|
|
||||||
target.IsMuted = !target.IsMuted
|
target.IsMuted = !target.IsMuted
|
||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
@@ -526,14 +590,14 @@ func HandleHubUserAddRole(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetId, err := convertions.StringToUuid(request.FormValue("targetid"))
|
targetId, err := convertions.StringToUuid(request.FormValue("target_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad targetid", http.StatusBadRequest)
|
http.Error(response, "bad target_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
roleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
roleId, err := convertions.StringToUint8(request.FormValue("role_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
http.Error(response, "bad role_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if roleId > usedRoleId {
|
if roleId > usedRoleId {
|
||||||
@@ -563,14 +627,14 @@ func HandleHubUserRemoveRole(response http.ResponseWriter, request *http.Request
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetId, err := convertions.StringToUuid(request.FormValue("targetid"))
|
targetId, err := convertions.StringToUuid(request.FormValue("target_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad targetid", http.StatusBadRequest)
|
http.Error(response, "bad target_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
roleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
roleId, err := convertions.StringToUint8(request.FormValue("role_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
http.Error(response, "bad role_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if roleId > usedRoleId {
|
if roleId > usedRoleId {
|
||||||
@@ -630,9 +694,9 @@ func HandleHubRemoveRole(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetRoleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
targetRoleId, err := convertions.StringToUint8(request.FormValue("role_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
http.Error(response, "bad role_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if targetRoleId == 0 {
|
if targetRoleId == 0 {
|
||||||
@@ -660,16 +724,16 @@ func HandleRoleSetName(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
roleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
roleId, err := convertions.StringToUint8(request.FormValue("role_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
http.Error(response, "bad role_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if roleId > usedRoleId {
|
if roleId > usedRoleId {
|
||||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newName := request.FormValue("newname")
|
newName := request.FormValue("new_name")
|
||||||
if newName == "" {
|
if newName == "" {
|
||||||
http.Error(response, "name empty", http.StatusBadRequest)
|
http.Error(response, "name empty", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -678,6 +742,7 @@ func HandleRoleSetName(response http.ResponseWriter, request *http.Request) {
|
|||||||
hub.Mu.Lock()
|
hub.Mu.Lock()
|
||||||
role := hub.Roles[roleId]
|
role := hub.Roles[roleId]
|
||||||
if role == nil {
|
if role == nil {
|
||||||
|
hub.Mu.Unlock()
|
||||||
http.Error(response, "no such role", http.StatusNotFound)
|
http.Error(response, "no such role", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -691,16 +756,16 @@ func HandleRoleSetColor(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
roleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
roleId, err := convertions.StringToUint8(request.FormValue("role_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
http.Error(response, "bad role_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if roleId > usedRoleId {
|
if roleId > usedRoleId {
|
||||||
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
color, err := convertions.StringToRgba(request.FormValue("newcolor"))
|
color, err := convertions.StringToRgba(request.FormValue("new_color"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid newcolor", http.StatusBadRequest)
|
http.Error(response, "invalid newcolor", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -709,6 +774,7 @@ func HandleRoleSetColor(response http.ResponseWriter, request *http.Request) {
|
|||||||
hub.Mu.Lock()
|
hub.Mu.Lock()
|
||||||
role := hub.Roles[roleId]
|
role := hub.Roles[roleId]
|
||||||
if role == nil {
|
if role == nil {
|
||||||
|
hub.Mu.Unlock()
|
||||||
http.Error(response, "no such role", http.StatusNotFound)
|
http.Error(response, "no such role", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -722,9 +788,9 @@ func HandleRoleSetPermissions(response http.ResponseWriter, request *http.Reques
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetRoleId, err := convertions.StringToUint8(request.FormValue("roleid"))
|
targetRoleId, err := convertions.StringToUint8(request.FormValue("role_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "bad roleid", http.StatusBadRequest)
|
http.Error(response, "bad role_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if targetRoleId > usedRoleId {
|
if targetRoleId > usedRoleId {
|
||||||
@@ -814,13 +880,16 @@ func HandleChannelCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
newHubChannel.RolesCanReadHistory.Add(types.HubBoundRolesMax)
|
newHubChannel.RolesCanReadHistory.Add(types.HubBoundRolesMax)
|
||||||
}
|
}
|
||||||
hub.Mu.Lock()
|
hub.Mu.Lock()
|
||||||
for i, channel := range hub.Channels {
|
usedPositions := make(map[uint8]bool, len(hub.Channels))
|
||||||
if channel != nil {
|
for _, ch := range hub.Channels {
|
||||||
continue
|
usedPositions[ch.Position] = true
|
||||||
}
|
}
|
||||||
hub.Channels[i] = newHubChannel
|
var position uint8
|
||||||
break
|
for usedPositions[position] {
|
||||||
|
position++
|
||||||
}
|
}
|
||||||
|
newHubChannel.Position = position
|
||||||
|
hub.Channels[newHubChannel.Id] = newHubChannel
|
||||||
hub.Mu.Unlock()
|
hub.Mu.Unlock()
|
||||||
|
|
||||||
updateChannelCacheForSpecChannel(newHubChannel, hub)
|
updateChannelCacheForSpecChannel(newHubChannel, hub)
|
||||||
@@ -832,14 +901,19 @@ func HandleChannelRemove(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channelId, err := convertions.StringToUint8(request.FormValue("id"))
|
channelId, err := convertions.StringToUuid(request.FormValue("channel_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid channel id", http.StatusBadRequest)
|
http.Error(response, "invalid channel_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hub.Mu.Lock()
|
hub.Mu.Lock()
|
||||||
hub.Channels[channelId] = nil
|
if _, ok := hub.Channels[channelId]; !ok {
|
||||||
|
hub.Mu.Unlock()
|
||||||
|
http.Error(response, "no such channel", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(hub.Channels, channelId)
|
||||||
hub.Mu.Unlock()
|
hub.Mu.Unlock()
|
||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
@@ -848,26 +922,26 @@ func HandleChannelSetName(response http.ResponseWriter, request *http.Request) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newName := request.FormValue("newname")
|
newName := request.FormValue("new_name")
|
||||||
if newName == "" {
|
if newName == "" {
|
||||||
http.Error(response, "newname empty", http.StatusBadRequest)
|
http.Error(response, "newname empty", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channelId, err := convertions.StringToUint8(request.FormValue("id"))
|
channelId, err := convertions.StringToUuid(request.FormValue("channel_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid channel id", http.StatusBadRequest)
|
http.Error(response, "invalid channel_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hub.Mu.Lock()
|
hub.Mu.Lock()
|
||||||
channel := hub.Channels[channelId]
|
channel, ok := hub.Channels[channelId]
|
||||||
if channel == nil {
|
if !ok {
|
||||||
|
hub.Mu.Unlock()
|
||||||
http.Error(response, "no such channel", http.StatusNotFound)
|
http.Error(response, "no such channel", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channel.Name = newName
|
channel.Name = newName
|
||||||
hub.Mu.Unlock()
|
hub.Mu.Unlock()
|
||||||
|
|
||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,20 +951,85 @@ func HandleChannelSetDescription(response http.ResponseWriter, request *http.Req
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
newDescription := request.FormValue("description")
|
newDescription := request.FormValue("description")
|
||||||
channelId, err := convertions.StringToUint8(request.FormValue("id"))
|
channelId, err := convertions.StringToUuid(request.FormValue("channel_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid channel id", http.StatusBadRequest)
|
http.Error(response, "invalid channel_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hub.Mu.Lock()
|
hub.Mu.Lock()
|
||||||
channel := hub.Channels[channelId]
|
channel, ok := hub.Channels[channelId]
|
||||||
if channel == nil {
|
if !ok {
|
||||||
|
hub.Mu.Unlock()
|
||||||
http.Error(response, "no such channel", http.StatusNotFound)
|
http.Error(response, "no such channel", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channel.Description = newDescription
|
channel.Description = newDescription
|
||||||
hub.Mu.Unlock()
|
hub.Mu.Unlock()
|
||||||
|
|
||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleChannelRolePermission(response http.ResponseWriter, request *http.Request, perm types.Permissions, modify func(*types.HubChannel, uint8, bool)) {
|
||||||
|
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, perm)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
channelId, err := convertions.StringToUuid(request.FormValue("channel_id"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid channel_id", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
roleId, err := convertions.StringToUint8(request.FormValue("role_id"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid role_id", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if roleId > usedRoleId {
|
||||||
|
http.Error(response, "target role higher in hierarchy", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
allow := convertions.StringToBool(request.URL.Query().Get("allow"))
|
||||||
|
|
||||||
|
hub.Mu.Lock()
|
||||||
|
channel, ok := hub.Channels[channelId]
|
||||||
|
if !ok {
|
||||||
|
hub.Mu.Unlock()
|
||||||
|
http.Error(response, "channel not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
modify(channel, roleId, allow)
|
||||||
|
hub.Mu.Unlock()
|
||||||
|
|
||||||
|
updateChannelCacheForSpecChannel(channel, hub)
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleChannelSetPermittedVisibleRole(response http.ResponseWriter, request *http.Request) {
|
||||||
|
handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedVisibleRoles, func(c *types.HubChannel, roleId uint8, allow bool) {
|
||||||
|
if allow {
|
||||||
|
c.RolesCanView.Add(roleId)
|
||||||
|
} else {
|
||||||
|
c.RolesCanView.Remove(roleId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleChannelSetPermittedSendRole(response http.ResponseWriter, request *http.Request) {
|
||||||
|
handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedSendMessageRoles, func(c *types.HubChannel, roleId uint8, allow bool) {
|
||||||
|
if allow {
|
||||||
|
c.RolesCanMessage.Add(roleId)
|
||||||
|
} else {
|
||||||
|
c.RolesCanMessage.Remove(roleId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleChannelSetPermittedHistoryRole(response http.ResponseWriter, request *http.Request) {
|
||||||
|
handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedReadHistoryRoles, func(c *types.HubChannel, roleId uint8, allow bool) {
|
||||||
|
if allow {
|
||||||
|
c.RolesCanReadHistory.Add(roleId)
|
||||||
|
} else {
|
||||||
|
c.RolesCanReadHistory.Remove(roleId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -232,9 +232,9 @@ func HandleUserGetUser(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
targetId, err := convertions.StringToUuid(request.URL.Query().Get("targetid"))
|
targetId, err := convertions.StringToUuid(request.URL.Query().Get("target_id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid userid", http.StatusBadRequest)
|
http.Error(response, "invalid target_id", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target, err := getUserById(ctx, targetId)
|
target, err := getUserById(ctx, targetId)
|
||||||
@@ -265,7 +265,7 @@ func HandleUserGetUsers(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
targetIds, err := convertions.StringToUuids(request.URL.Query().Get("targetids"))
|
targetIds, err := convertions.StringToUuids(request.URL.Query().Get("target_ids"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "invalid targetids", http.StatusBadRequest)
|
http.Error(response, "invalid targetids", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -286,3 +286,31 @@ func HandleUserGetUsers(response http.ResponseWriter, request *http.Request) {
|
|||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
response.Write(userData)
|
response.Write(userData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleGetHubs(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !validCheckWithResponseOnFail(response, request, normal) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := getUserByToken(ctx, request.Header.Get("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Mu.RLock()
|
||||||
|
hubs := slices.Collect(maps.Keys(user.Hubs))
|
||||||
|
user.Mu.RUnlock()
|
||||||
|
if len(hubs) == 0 {
|
||||||
|
response.WriteHeader(http.StatusNoContent)
|
||||||
|
response.Write([]byte("no hubs found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
converted, err := json.Marshal(hubs)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
response.Write(converted)
|
||||||
|
}
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ type Hub struct {
|
|||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
Roles [256]*HubRole `json:"-"`
|
Roles [256]*HubRole `json:"-"`
|
||||||
Users map[uuid.UUID]*HubUser `json:"-"`
|
Users map[uuid.UUID]*HubUser `json:"-"`
|
||||||
Channels [256]*HubChannel `json:"-"`
|
Channels map[uuid.UUID]*HubChannel `json:"-"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
IconUrl string `json:"iconUrl"`
|
IconUrl string `json:"iconUrl"`
|
||||||
BgUrl string `json:"backgroundUrl"`
|
BgUrl string `json:"backgroundUrl"`
|
||||||
@@ -282,6 +282,7 @@ type Hub struct {
|
|||||||
func NewHub() *Hub {
|
func NewHub() *Hub {
|
||||||
return &Hub{
|
return &Hub{
|
||||||
Users: make(map[uuid.UUID]*HubUser),
|
Users: make(map[uuid.UUID]*HubUser),
|
||||||
|
Channels: map[uuid.UUID]*HubChannel{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,9 +306,9 @@ func (h *HubRole) HasPermission(r Permissions) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HubUser struct {
|
type HubUser struct {
|
||||||
Mu sync.RWMutex `json:"mu"`
|
Mu sync.RWMutex `json:"-"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
Roles HubBoundRoles `json:"-"`
|
Roles HubBoundRoles `json:"roles"`
|
||||||
Name string `json:"name"` // Name empty = original name
|
Name string `json:"name"` // Name empty = original name
|
||||||
OriginalId uuid.UUID `json:"originalId"`
|
OriginalId uuid.UUID `json:"originalId"`
|
||||||
IsMuted bool `json:"isMuted"`
|
IsMuted bool `json:"isMuted"`
|
||||||
@@ -330,6 +331,7 @@ type HubChannel struct {
|
|||||||
UsersCachedPermissions map[uuid.UUID]CachedUserPermissions `json:"-"`
|
UsersCachedPermissions map[uuid.UUID]CachedUserPermissions `json:"-"`
|
||||||
NextBuffIdx uint32 `json:"-"`
|
NextBuffIdx uint32 `json:"-"`
|
||||||
Id uuid.UUID `json:"id"`
|
Id uuid.UUID `json:"id"`
|
||||||
|
Position uint8 `json:"position"`
|
||||||
HaveOverflowed bool `json:"-"`
|
HaveOverflowed bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user