Update static/js/01-api.js

This commit is contained in:
admin 2026-10-08 00:38:44 +00:00
parent 0b45bd657c
commit d7fedb6295

View File

@ -1,8 +1,6 @@
// static/js/01-api.js // static/js/01-api.js
"use strict"; "use strict";
window.Glow = window.Glow || {}; window.Glow = window.Glow || {};
Glow.refreshCsrfToken = async () => { Glow.refreshCsrfToken = async () => {
const response = await fetch("/api/csrf", { const response = await fetch("/api/csrf", {
credentials: "same-origin", credentials: "same-origin",
@ -10,15 +8,12 @@ Glow.refreshCsrfToken = async () => {
Accept: "application/json" Accept: "application/json"
} }
}); });
if (!response.ok) { if (!response.ok) {
throw new Error("Could not refresh security token."); throw new Error("Could not refresh security token.");
} }
const data = await response.json(); const data = await response.json();
Glow.state.csrfToken = data.csrf_token || ""; Glow.state.csrfToken = data.csrf_token || "";
}; };
Glow.handleUnauthorized = () => { Glow.handleUnauthorized = () => {
Glow.state.currentUser = null; Glow.state.currentUser = null;
Glow.state.csrfToken = ""; Glow.state.csrfToken = "";
@ -55,11 +50,9 @@ Glow.handleUnauthorized = () => {
Glow.state.calls.signalLastSeenId = 0; Glow.state.calls.signalLastSeenId = 0;
Glow.state.calls.incomingCall = null; Glow.state.calls.incomingCall = null;
Glow.state.calls.pendingOffer = null; Glow.state.calls.pendingOffer = null;
clearTimeout(Glow.state.pollTimer); clearTimeout(Glow.state.pollTimer);
clearTimeout(Glow.state.typingTimer); clearTimeout(Glow.state.typingTimer);
clearTimeout(Glow.state.calls.pollTimer); clearTimeout(Glow.state.calls.pollTimer);
Glow.clearMessages?.(); Glow.clearMessages?.();
Glow.clearFeed?.(); Glow.clearFeed?.();
Glow.clearDms?.(); Glow.clearDms?.();
@ -67,53 +60,41 @@ Glow.handleUnauthorized = () => {
Glow.closeReactionPopup?.(); Glow.closeReactionPopup?.();
Glow.closeMediaModal?.(); Glow.closeMediaModal?.();
Glow.endLocalCallUi?.(); Glow.endLocalCallUi?.();
Glow.setSelectedAttachment?.([]); Glow.setSelectedAttachment?.([]);
Glow.setSelectedThreadAttachment?.([]); Glow.setSelectedThreadAttachment?.([]);
Glow.els.threadBox?.replaceChildren(); Glow.els.threadBox?.replaceChildren();
Glow.els.pagesBox?.replaceChildren(); Glow.els.pagesBox?.replaceChildren();
Glow.els.pageDetailBox?.replaceChildren(); Glow.els.pageDetailBox?.replaceChildren();
Glow.els.profileBox?.replaceChildren(); Glow.els.profileBox?.replaceChildren();
if (Glow.els.teamSelect) { if (Glow.els.teamSelect) {
Glow.els.teamSelect.replaceChildren(); Glow.els.teamSelect.replaceChildren();
Glow.els.teamSelect.disabled = true; Glow.els.teamSelect.disabled = true;
} }
if (Glow.els.roomSelect) { if (Glow.els.roomSelect) {
Glow.els.roomSelect.replaceChildren(); Glow.els.roomSelect.replaceChildren();
Glow.els.roomSelect.disabled = true; Glow.els.roomSelect.disabled = true;
} }
if (Glow.els.typingBar) { if (Glow.els.typingBar) {
Glow.els.typingBar.textContent = ""; Glow.els.typingBar.textContent = "";
Glow.els.typingBar.classList.add("hidden"); Glow.els.typingBar.classList.add("hidden");
} }
if (Glow.els.presenceLabel) { if (Glow.els.presenceLabel) {
Glow.els.presenceLabel.textContent = ""; Glow.els.presenceLabel.textContent = "";
Glow.els.presenceLabel.classList.add("hidden"); Glow.els.presenceLabel.classList.add("hidden");
} }
Glow.state.activeView = "feed"; Glow.state.activeView = "feed";
Glow.updateAuthUI?.(); Glow.updateAuthUI?.();
Glow.showAuthNotice?.("Your session has expired. Please sign in again."); Glow.showAuthNotice?.("Your session has expired. Please sign in again.");
Glow.els.authOverlay.classList.remove("hidden"); Glow.els.authOverlay.classList.remove("hidden");
}; };
Glow.apiRequest = async (url, options = {}, retryCsrf = true) => { Glow.apiRequest = async (url, options = {}, retryCsrf = true) => {
const method = (options.method || "GET").toUpperCase(); const method = (options.method || "GET").toUpperCase();
const headers = new Headers(options.headers || {}); const headers = new Headers(options.headers || {});
headers.set("Accept", "application/json"); headers.set("Accept", "application/json");
if (!["GET", "HEAD"].includes(method)) { if (!["GET", "HEAD"].includes(method)) {
headers.set("X-CSRF-Token", Glow.state.csrfToken || ""); headers.set("X-CSRF-Token", Glow.state.csrfToken || "");
} }
let response; let response;
try { try {
response = await fetch(url, { response = await fetch(url, {
credentials: "same-origin", credentials: "same-origin",
@ -126,29 +107,23 @@ Glow.apiRequest = async (url, options = {}, retryCsrf = true) => {
error.code = "network"; error.code = "network";
throw error; throw error;
} }
let data = {}; let data = {};
try { try {
data = await response.json(); data = await response.json();
} catch (_) { } catch (_) {
data = {}; data = {};
} }
if (response.status === 403 && data.code === "blacklisted") { if (response.status === 403 && data.code === "blacklisted") {
Glow.showBlocked(data.error); Glow.showBlocked(data.error);
throw new Error(data.error || "Access blocked."); throw new Error(data.error || "Access blocked.");
} }
if (response.status === 403 && data.code === "csrf" && retryCsrf) { if (response.status === 403 && data.code === "csrf" && retryCsrf) {
await Glow.refreshCsrfToken(); await Glow.refreshCsrfToken();
return Glow.apiRequest(url, options, false); return Glow.apiRequest(url, options, false);
} }
if (response.status === 401) { if (response.status === 401) {
Glow.handleUnauthorized(); Glow.handleUnauthorized();
} }
if (!response.ok) { if (!response.ok) {
const error = new Error(data.error || "Request failed."); const error = new Error(data.error || "Request failed.");
error.status = response.status; error.status = response.status;
@ -158,11 +133,9 @@ Glow.apiRequest = async (url, options = {}, retryCsrf = true) => {
error.data = data; error.data = data;
throw error; throw error;
} }
if (data.csrf_token) { if (data.csrf_token) {
Glow.state.csrfToken = data.csrf_token; Glow.state.csrfToken = data.csrf_token;
} }
return data; return data;
}; };
@ -174,10 +147,8 @@ Glow.apiUpdateMyProfile = payload =>
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiGetPublicProfile = username => Glow.apiGetPublicProfile = username =>
Glow.apiRequest(`/api/profiles/${encodeURIComponent(username)}`); Glow.apiRequest(`/api/profiles/${encodeURIComponent(username)}`);
Glow.apiGetMySettings = () => Glow.apiRequest("/api/settings"); Glow.apiGetMySettings = () => Glow.apiRequest("/api/settings");
Glow.apiUpdateMySettings = payload => Glow.apiUpdateMySettings = payload =>
Glow.apiRequest("/api/settings", { Glow.apiRequest("/api/settings", {
@ -186,6 +157,54 @@ Glow.apiUpdateMySettings = payload =>
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
/* pins / shares / bookmarks / schedule */
Glow.apiPinMessage = messageId =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/pin`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({})
});
Glow.apiUnpinMessage = messageId =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/pin`, {
method: "DELETE"
});
Glow.apiListPins = (scope, scopeId) =>
Glow.apiRequest(`/api/pins?scope=${encodeURIComponent(scope)}&scope_id=${encodeURIComponent(scopeId)}`);
Glow.apiCreateMessageShare = messageId =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/share`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({})
});
Glow.apiCreateAttachmentShare = attachmentId =>
Glow.apiRequest(`/api/attachments/${encodeURIComponent(attachmentId)}/share`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({})
});
Glow.apiBookmarkMessage = messageId =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/bookmark`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({})
});
Glow.apiUnbookmarkMessage = messageId =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/bookmark`, {
method: "DELETE"
});
Glow.apiListBookmarks = () => Glow.apiRequest("/api/bookmarks");
Glow.apiCreateScheduledMessage = payload =>
Glow.apiRequest("/api/scheduled-messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
Glow.apiListScheduledMessages = () => Glow.apiRequest("/api/scheduled-messages");
Glow.apiCancelScheduledMessage = id =>
Glow.apiRequest(`/api/scheduled-messages/${encodeURIComponent(id)}`, {
method: "DELETE"
});
/* teams/channels */ /* teams/channels */
Glow.apiCreateTeam = payload => Glow.apiCreateTeam = payload =>
Glow.apiRequest("/api/teams", { Glow.apiRequest("/api/teams", {
@ -193,21 +212,18 @@ Glow.apiCreateTeam = payload =>
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiUpdateTeam = (teamSlug, payload) => Glow.apiUpdateTeam = (teamSlug, payload) =>
Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}`, { Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}`, {
method: "PATCH", method: "PATCH",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiCreateChannel = (teamSlug, payload) => Glow.apiCreateChannel = (teamSlug, payload) =>
Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/channels`, { Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/channels`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiUpdateChannel = (teamSlug, channelSlug, payload) => Glow.apiUpdateChannel = (teamSlug, channelSlug, payload) =>
Glow.apiRequest( Glow.apiRequest(
`/api/teams/${encodeURIComponent(teamSlug)}/channels/${encodeURIComponent(channelSlug)}`, `/api/teams/${encodeURIComponent(teamSlug)}/channels/${encodeURIComponent(channelSlug)}`,
@ -217,23 +233,19 @@ Glow.apiUpdateChannel = (teamSlug, channelSlug, payload) =>
body: JSON.stringify(payload) body: JSON.stringify(payload)
} }
); );
Glow.apiDeleteChannel = (teamSlug, channelSlug) => Glow.apiDeleteChannel = (teamSlug, channelSlug) =>
Glow.apiRequest( Glow.apiRequest(
`/api/teams/${encodeURIComponent(teamSlug)}/channels/${encodeURIComponent(channelSlug)}`, `/api/teams/${encodeURIComponent(teamSlug)}/channels/${encodeURIComponent(channelSlug)}`,
{ method: "DELETE" } { method: "DELETE" }
); );
Glow.apiListTeamMembers = teamSlug => Glow.apiListTeamMembers = teamSlug =>
Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/members`); Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/members`);
Glow.apiAddTeamMember = (teamSlug, payload) => Glow.apiAddTeamMember = (teamSlug, payload) =>
Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/members`, { Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/members`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiUpdateTeamMember = (teamSlug, userId, payload) => Glow.apiUpdateTeamMember = (teamSlug, userId, payload) =>
Glow.apiRequest( Glow.apiRequest(
`/api/teams/${encodeURIComponent(teamSlug)}/members/${encodeURIComponent(userId)}`, `/api/teams/${encodeURIComponent(teamSlug)}/members/${encodeURIComponent(userId)}`,
@ -243,20 +255,17 @@ Glow.apiUpdateTeamMember = (teamSlug, userId, payload) =>
body: JSON.stringify(payload) body: JSON.stringify(payload)
} }
); );
Glow.apiRemoveTeamMember = (teamSlug, userId) => Glow.apiRemoveTeamMember = (teamSlug, userId) =>
Glow.apiRequest( Glow.apiRequest(
`/api/teams/${encodeURIComponent(teamSlug)}/members/${encodeURIComponent(userId)}`, `/api/teams/${encodeURIComponent(teamSlug)}/members/${encodeURIComponent(userId)}`,
{ method: "DELETE" } { method: "DELETE" }
); );
Glow.apiCreateTeamInvite = (teamSlug, payload = {}) => Glow.apiCreateTeamInvite = (teamSlug, payload = {}) =>
Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/invites`, { Glow.apiRequest(`/api/teams/${encodeURIComponent(teamSlug)}/invites`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiAcceptTeamInvite = token => Glow.apiAcceptTeamInvite = token =>
Glow.apiRequest(`/api/team-invites/${encodeURIComponent(token)}/accept`, { Glow.apiRequest(`/api/team-invites/${encodeURIComponent(token)}/accept`, {
method: "POST", method: "POST",
@ -271,7 +280,6 @@ Glow.apiCreateRoom = payload =>
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiUpdateRoom = (roomSlug, payload) => Glow.apiUpdateRoom = (roomSlug, payload) =>
Glow.apiRequest(`/api/rooms/${encodeURIComponent(roomSlug)}`, { Glow.apiRequest(`/api/rooms/${encodeURIComponent(roomSlug)}`, {
method: "PATCH", method: "PATCH",
@ -282,14 +290,12 @@ Glow.apiUpdateRoom = (roomSlug, payload) =>
/* reactions */ /* reactions */
Glow.apiGetMessageReactions = messageId => Glow.apiGetMessageReactions = messageId =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/reactions`); Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/reactions`);
Glow.apiAddReaction = (messageId, emoji) => Glow.apiAddReaction = (messageId, emoji) =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/reactions`, { Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/reactions`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ emoji }) body: JSON.stringify({ emoji })
}); });
Glow.apiRemoveReaction = (messageId, emoji) => Glow.apiRemoveReaction = (messageId, emoji) =>
Glow.apiRequest( Glow.apiRequest(
`/api/messages/${encodeURIComponent(messageId)}/reactions/${encodeURIComponent(emoji)}`, `/api/messages/${encodeURIComponent(messageId)}/reactions/${encodeURIComponent(emoji)}`,
@ -303,38 +309,30 @@ Glow.apiEditMessage = (messageId, payload) =>
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiSearch = query => Glow.apiSearch = query =>
Glow.apiRequest(`/api/search?q=${encodeURIComponent(query)}`); Glow.apiRequest(`/api/search?q=${encodeURIComponent(query)}`);
Glow.apiMarkRead = messageIds => Glow.apiMarkRead = messageIds =>
Glow.apiRequest("/api/read-receipts", { Glow.apiRequest("/api/read-receipts", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message_ids: messageIds }) body: JSON.stringify({ message_ids: messageIds })
}); });
Glow.apiGetMessageReceipts = messageId => Glow.apiGetMessageReceipts = messageId =>
Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/receipts`); Glow.apiRequest(`/api/messages/${encodeURIComponent(messageId)}/receipts`);
Glow.apiPingPresence = payload => Glow.apiPingPresence = payload =>
Glow.apiRequest("/api/presence", { Glow.apiRequest("/api/presence", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiGetRoomPresence = roomSlug => Glow.apiGetRoomPresence = roomSlug =>
Glow.apiRequest(`/api/rooms/${encodeURIComponent(roomSlug)}/presence`); Glow.apiRequest(`/api/rooms/${encodeURIComponent(roomSlug)}/presence`);
Glow.apiGetChannelPresence = (teamSlug, channelSlug) => Glow.apiGetChannelPresence = (teamSlug, channelSlug) =>
Glow.apiRequest( Glow.apiRequest(
`/api/teams/${encodeURIComponent(teamSlug)}/channels/${encodeURIComponent(channelSlug)}/presence` `/api/teams/${encodeURIComponent(teamSlug)}/channels/${encodeURIComponent(channelSlug)}/presence`
); );
Glow.apiGetDmPresence = dmId => Glow.apiGetDmPresence = dmId =>
Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/presence`); Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/presence`);
Glow.apiLoadHistory = params => { Glow.apiLoadHistory = params => {
const qs = new URLSearchParams(params); const qs = new URLSearchParams(params);
return Glow.apiRequest(`/api/messages/history?${qs.toString()}`); return Glow.apiRequest(`/api/messages/history?${qs.toString()}`);
@ -342,31 +340,26 @@ Glow.apiLoadHistory = params => {
/* DMs */ /* DMs */
Glow.apiListDms = () => Glow.apiRequest("/api/dms"); Glow.apiListDms = () => Glow.apiRequest("/api/dms");
Glow.apiCreateDm = payload => Glow.apiCreateDm = payload =>
Glow.apiRequest("/api/dms", { Glow.apiRequest("/api/dms", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiGetDmMessages = (dmId, afterId = null) => { Glow.apiGetDmMessages = (dmId, afterId = null) => {
const base = `/api/dms/${encodeURIComponent(dmId)}/messages`; const base = `/api/dms/${encodeURIComponent(dmId)}/messages`;
return Glow.apiRequest( return Glow.apiRequest(
afterId == null ? base : `${base}?after_id=${encodeURIComponent(afterId)}` afterId == null ? base : `${base}?after_id=${encodeURIComponent(afterId)}`
); );
}; };
Glow.apiSendDmMessage = (dmId, payload) => Glow.apiSendDmMessage = (dmId, payload) =>
Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/messages`, { Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/messages`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiGetDmTyping = dmId => Glow.apiGetDmTyping = dmId =>
Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/typing`); Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/typing`);
Glow.apiSetDmTyping = (dmId, typing) => Glow.apiSetDmTyping = (dmId, typing) =>
Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/typing`, { Glow.apiRequest(`/api/dms/${encodeURIComponent(dmId)}/typing`, {
method: "POST", method: "POST",
@ -381,25 +374,21 @@ Glow.apiCreateCall = dmId =>
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({}) body: JSON.stringify({})
}); });
Glow.apiGetCall = callId => Glow.apiGetCall = callId =>
Glow.apiRequest(`/api/calls/${encodeURIComponent(callId)}`); Glow.apiRequest(`/api/calls/${encodeURIComponent(callId)}`);
Glow.apiPostCallSignal = (callId, payload) => Glow.apiPostCallSignal = (callId, payload) =>
Glow.apiRequest(`/api/calls/${encodeURIComponent(callId)}/signal`, { Glow.apiRequest(`/api/calls/${encodeURIComponent(callId)}/signal`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
Glow.apiGetCallSignals = (callId, afterId = 0) => Glow.apiGetCallSignals = (callId, afterId = 0) =>
Glow.apiRequest( Glow.apiRequest(
`/api/calls/${encodeURIComponent(callId)}/signals?after_id=${encodeURIComponent(afterId)}` `/api/calls/${encodeURIComponent(callId)}/signals?after_id=${encodeURIComponent(afterId)}`
); );
Glow.apiEndCall = callId => Glow.apiEndCall = callId =>
Glow.apiRequest(`/api/calls/${encodeURIComponent(callId)}/end`, { Glow.apiRequest(`/api/calls/${encodeURIComponent(callId)}/end`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({}) body: JSON.stringify({})
}); });