implement very basic connections & applications

This commit is contained in:
TomatoCake 2024-07-20 19:19:23 +02:00
parent 97c264d888
commit 1a3ce1e3ff
4 changed files with 303 additions and 14 deletions

View file

@ -37,7 +37,12 @@
<p id="status">STATUS</p> <p id="status">STATUS</p>
</div> </div>
</div> </div>
<h2 id="settings"></h2>
<div id="user-actions">
<h2 id="settings"></h2>
<h2 id="connections">🔗</h2>
<h2 id="dev-portal">🤖</h2>
</div>
</div> </div>
</div> </div>
<div class="flexttb messageflex"> <div class="flexttb messageflex">

View file

@ -245,6 +245,17 @@ function userSettings(){
thisuser.usersettings.show(); thisuser.usersettings.show();
} }
document.getElementById("settings").onclick=userSettings; document.getElementById("settings").onclick=userSettings;
function userConnections(){
thisuser.userConnections.show();
}
document.getElementById("connections").onclick=userConnections;
function devPortal(){
thisuser.devPortal.show();
}
document.getElementById("dev-portal").onclick=devPortal;
let triggered=false; let triggered=false;
document.getElementById("messagecontainer").addEventListener("scroll",(e)=>{ document.getElementById("messagecontainer").addEventListener("scroll",(e)=>{
const messagecontainer=document.getElementById("messagecontainer") const messagecontainer=document.getElementById("messagecontainer")

View file

@ -19,6 +19,8 @@ class Localuser{
info; info;
headers:{"Content-type":string,Authorization:string}; headers:{"Content-type":string,Authorization:string};
usersettings:Fullscreen; usersettings:Fullscreen;
userConnections:Fullscreen;
devPortal:Fullscreen;
ready; ready;
guilds:Guild[]; guilds:Guild[];
guildids:{ [key: string]: Guild }; guildids:{ [key: string]: Guild };
@ -671,6 +673,262 @@ class Localuser{
newprouns=null; newprouns=null;
newbio=null; newbio=null;
}.bind(this)) }.bind(this))
}
const connectionContainer=document.createElement("div");
connectionContainer.id="connection-container";
this.userConnections=new Fullscreen(
["html",
connectionContainer
], () => {}, async () => {
connectionContainer.innerHTML="";
const res=await fetch(this.info.api.toString()+"/v9/connections", {
headers: this.headers
});
const json=await res.json();
Object.keys(json).sort(key => json[key].enabled ? -1 : 1).forEach(key => {
const connection=json[key];
const container=document.createElement("div");
container.textContent=key.charAt(0).toUpperCase() + key.slice(1);
if (connection.enabled) {
container.addEventListener("click", async () => {
const connectionRes=await fetch(this.info.api.toString()+"/v9/connections/" + key + "/authorize", {
headers: this.headers
});
const connectionJSON=await connectionRes.json();
window.open(connectionJSON.url, "_blank", "noopener noreferrer");
})
} else {
container.classList.add("disabled")
container.title="This connection has been disabled server-side."
}
connectionContainer.appendChild(container);
})
}
);
let appName="";
const appListContainer=document.createElement("div");
appListContainer.id="app-list-container";
this.devPortal=new Fullscreen(
["vdiv",
["hdiv",
["textbox", "Name:", appName, event => {
appName=event.target.value;
}],
["button",
"",
"Create application",
async () => {
if (appName.trim().length == 0) return alert("Please enter a name for the application.");
const res=await fetch(this.info.api.toString()+"/v9/applications", {
method: "POST",
headers: this.headers,
body: JSON.stringify({
name: appName
})
});
const json=await res.json();
this.manageApplication(json.id);
this.devPortal.hide();
}
]
],
["html",
appListContainer
]
], () => {}, async () => {
appListContainer.innerHTML="";
const res=await fetch(this.info.api.toString()+"/v9/applications", {
headers: this.headers
});
const json=await res.json();
json.forEach(application => {
const container=document.createElement("div");
if (application.cover_image) {
const cover=document.createElement("img");
cover.crossOrigin="anonymous";
cover.src=this.info.cdn.toString()+"/app-icons/" + application.id + "/" + application.cover_image + ".png?size=256";
cover.alt="";
cover.loading="lazy";
container.appendChild(cover);
}
const name=document.createElement("h2");
name.textContent=application.name + (application.bot ? " (Bot)" : "");
container.appendChild(name);
container.addEventListener("click", async () => {
this.devPortal.hide();
this.manageApplication(application.id);
});
appListContainer.appendChild(container);
})
}
)
}
async manageApplication(appId="") {
const res=await fetch(this.info.api.toString()+"/v9/applications/" + appId, {
headers: this.headers
});
const json=await res.json();
const fields: any={};
const appDialog=new Fullscreen(
["vdiv",
["title",
"Editing " + json.name
],
["hdiv",
["textbox", "Application name:", json.name, event => {
fields.name=event.target.value;
}],
["mdbox", "Description:", json.description, event => {
fields.description=event.target.value;
}],
["vdiv",
json.icon ? ["img", this.info.cdn.toString()+"/app-icons/" + appId + "/" + json.icon + ".png?size=128", [128, 128]] : ["text", "No icon"],
["fileupload", "Application icon:", event => {
const reader=new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload=() => {
fields.icon=reader.result;
}
}]
]
],
["hdiv",
["textbox", "Privacy policy URL:", json.privacy_policy_url || "", event => {
fields.privacy_policy_url=event.target.value;
}],
["textbox", "Terms of Service URL:", json.terms_of_service_url || "", event => {
fields.terms_of_service_url=event.target.value;
}]
],
["hdiv",
["checkbox", "Make bot publicly inviteable?", json.bot_public, event => {
fields.bot_public=event.target.checked;
}],
["checkbox", "Require code grant to invite the bot?", json.bot_require_code_grant, event => {
fields.bot_require_code_grant=event.target.checked;
}]
],
["hdiv",
["button",
"",
"Save changes",
async () => {
const updateRes=await fetch(this.info.api.toString()+"/v9/applications/" + appId, {
method: "PATCH",
headers: this.headers,
body: JSON.stringify(fields)
});
if (updateRes.ok) appDialog.hide();
else {
const updateJSON=await updateRes.json();
alert("An error occurred: " + updateJSON.message);
}
}
],
["button",
"",
(json.bot ? "Manage" : "Add") + " bot",
async () => {
if (!json.bot) {
if (!confirm("Are you sure you want to add a bot to this application? There's no going back.")) return;
const updateRes=await fetch(this.info.api.toString()+"/v9/applications/" + appId + "/bot", {
method: "POST",
headers: this.headers
});
const updateJSON=await updateRes.json();
alert("Bot token:\n" + updateJSON.token);
}
appDialog.hide();
this.manageBot(appId);
}
]
]
]
)
appDialog.show();
}
async manageBot(appId="") {
const res=await fetch(this.info.api.toString()+"/v9/applications/" + appId, {
headers: this.headers
});
const json=await res.json();
if (!json.bot) return alert("For some reason, this application doesn't have a bot (yet).");
const fields: any={
username: json.bot.username,
avatar: json.bot.avatar ? (this.info.cdn.toString()+"/app-icons/" + appId + "/" + json.bot.avatar + ".png?size=256") : ""
};
const botDialog=new Fullscreen(
["vdiv",
["title",
"Editing bot: " + json.bot.username
],
["hdiv",
["textbox", "Bot username:", json.bot.username, event => {
fields.username=event.target.value
}],
["vdiv",
fields.avatar ? ["img", fields.avatar, [128, 128]] : ["text", "No avatar"],
["fileupload", "Bot avatar:", event => {
const reader=new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload=() => {
fields.avatar=reader.result;
}
}]
]
],
["hdiv",
["button",
"",
"Save changes",
async () => {
const updateRes=await fetch(this.info.api.toString()+"/v9/applications/" + appId + "/bot", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify(fields)
});
if (updateRes.ok) botDialog.hide();
else {
const updateJSON=await updateRes.json();
alert("An error occurred: " + updateJSON.message);
}
}
],
["button",
"",
"Reset token",
async () => {
if (!confirm("Are you sure you want to reset the bot token? Your bot will stop working until you update it.")) return;
const updateRes=await fetch(this.info.api.toString()+"/v9/applications/" + appId + "/bot/reset", {
method: "POST",
headers: this.headers
});
const updateJSON=await updateRes.json();
alert("New token:\n" + updateJSON.token);
botDialog.hide();
}
]
]
]
);
botDialog.show();
}
} }
export {Localuser}; export {Localuser};

View file

@ -699,22 +699,20 @@ textarea {
flex-shrink: 1; flex-shrink: 1;
} }
#settings { #user-actions {
display: flex;
flex-wrap: wrap;
}
#user-actions h2 {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
border-radius: .3in; border-radius: .1in;
transition: background 1s; transition: color .5s;
text-align: center; text-align: center;
font-size: .25in;
width: .3in;
height: .3in;
overflow: visible; overflow: visible;
} }
#user-actions h2:hover, #user-actions h2:focus {
#settings:hover { color: var(--timestamp-color);
background-color: var(--settings-hover);
cursor: pointer;
user-select: none;
} }
#userinfo { #userinfo {
@ -1352,4 +1350,21 @@ span {
width: 100%; width: 100%;
flex-direction: row; flex-direction: row;
max-height:100in; max-height:100in;
} }
#connection-container, #app-list-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
max-width: 700px;
}
#connection-container div, #app-list-container div {
padding: 5px 10px;
border-radius: 5px;
background-color: var(--textarea-bg);
cursor: pointer;
}
#connection-container .disabled {
background-color: var(--embed-fallback);
cursor: not-allowed;
}