adds support for role settings and various fixes

This commit is contained in:
MathMan05 2024-06-30 22:05:14 -05:00
parent 96b2dbb21c
commit 8fe0c9f46b
20 changed files with 1199 additions and 183 deletions

View file

@ -5,6 +5,8 @@ import { Contextmenu } from "./contextmenu.js";
import { Fullscreen } from "./fullscreen.js";
import { markdown } from "./markdown.js";
import { Permissions } from "./permissions.js";
import { Settings, RoleList } from "./settings.js";
Settings;
class Channel {
editing;
type;
@ -19,6 +21,7 @@ class Channel {
guild_id;
messageids;
permission_overwrites;
permission_overwritesar;
topic;
nsfw;
position;
@ -33,22 +36,38 @@ class Channel {
static contextmenu = new Contextmenu("channel menu");
replyingto;
static setupcontextmenu() {
Channel.contextmenu.addbutton("Copy channel id", function () {
this.contextmenu.addbutton("Copy channel id", function () {
console.log(this);
navigator.clipboard.writeText(this.id);
});
Channel.contextmenu.addbutton("Mark as read", function () {
this.contextmenu.addbutton("Mark as read", function () {
console.log(this);
this.readbottom();
});
Channel.contextmenu.addbutton("Delete channel", function () {
this.contextmenu.addbutton("Settings[temp]", function () {
this.generateSettings();
});
this.contextmenu.addbutton("Delete channel", function () {
console.log(this);
this.deleteChannel();
}, null, _ => { console.log(_); return _.isAdmin(); });
Channel.contextmenu.addbutton("Edit channel", function () {
this.contextmenu.addbutton("Edit channel", function () {
this.editChannel(this);
}, null, _ => { return _.isAdmin(); });
}
generateSettings() {
this.sortPerms();
const settings = new Settings("Settings for " + this.name);
const s1 = settings.addButton("roles");
s1.options.push(new RoleList(this.permission_overwritesar, this.guild, this.updateRolePermissions.bind(this), true));
settings.show();
}
sortPerms() {
this.permission_overwritesar.sort((a, b) => {
const order = this.guild.roles.findIndex(_ => _.id === a[0]) - this.guild.roles.findIndex(_ => _.id === b[0]);
return order;
});
}
constructor(JSON, owner) {
if (JSON === -1) {
return;
@ -66,8 +85,15 @@ class Channel {
this.guild_id = JSON.guild_id;
this.messageids = {};
this.permission_overwrites = {};
this.permission_overwritesar = [];
for (const thing of JSON.permission_overwrites) {
console.log(thing);
if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") {
continue;
}
;
this.permission_overwrites[thing.id] = new Permissions(thing.allow, thing.deny);
this.permission_overwritesar.push([thing.id, this.permission_overwrites[thing.id]]);
}
this.topic = JSON.topic;
this.nsfw = JSON.nsfw;
@ -117,6 +143,9 @@ class Channel {
return false;
}
get canMessage() {
if ((0 === this.permission_overwritesar.length) && this.hasPermission("MANAGE_CHANNELS")) {
this.addRoleToPerms(this.guild.roles.find(_ => _.name === "@everyone"));
}
return this.hasPermission("SEND_MESSAGES");
}
sortchildren() {
@ -726,6 +755,36 @@ class Channel {
});
}
}
async addRoleToPerms(role) {
await fetch(this.info.api.toString() + "/channels/" + this.id + "/permissions/" + role.id, {
method: "PUT",
headers: this.headers,
body: JSON.stringify({
allow: "0",
deny: "0",
id: role.id,
type: 0
})
});
const perm = new Permissions("0", "0");
this.permission_overwrites[role.id] = perm;
this.permission_overwritesar.push([role.id, perm]);
}
async updateRolePermissions(id, perms) {
const permision = this.permission_overwrites[id];
permision.allow = perms.allow;
permision.deny = perms.deny;
await fetch(this.info.api.toString() + "/channels/" + this.id + "/permissions/" + id, {
method: "PUT",
headers: this.headers,
body: JSON.stringify({
allow: permision.allow.toString(),
deny: permision.deny.toString(),
id: id,
type: 0
})
});
}
}
Channel.setupcontextmenu();
export { Channel };

View file

@ -3,6 +3,7 @@ import { Contextmenu } from "./contextmenu.js";
import { Role } from "./role.js";
import { Fullscreen } from "./fullscreen.js";
import { Member } from "./member.js";
import { Settings, RoleList } from "./settings.js";
class Guild {
owner;
headers;
@ -42,6 +43,9 @@ class Guild {
Guild.contextmenu.addbutton("Create invite", function () {
console.log(this);
}, null, _ => true, _ => false);
Guild.contextmenu.addbutton("Settings[temp]", function () {
this.generateSettings();
});
/* -----things left for later-----
guild.contextmenu.addbutton("Leave Guild",function(){
console.log(this)
@ -53,6 +57,16 @@ class Guild {
},null,_=>{return thisuser.isAdmin()})
*/
}
generateSettings() {
const settings = new Settings("Settings for " + this.properties.name);
const s1 = settings.addButton("roles");
const permlist = [];
for (const thing of this.roles) {
permlist.push([thing.id, thing.permissions]);
}
s1.options.push(new RoleList(permlist, this, this.updateRolePermissions.bind(this)));
settings.show();
}
constructor(JSON, owner, member) {
if (JSON === -1) {
return;
@ -481,6 +495,40 @@ class Guild {
body: JSON.stringify({ name: name, type: type })
});
}
async createRole(name) {
const fetched = await fetch(this.info.api.toString() + "/guilds/" + this.id + "roles", {
method: "POST",
headers: this.headers,
body: JSON.stringify({
name: name,
color: 0,
permissions: "0"
})
});
const json = await fetched.json();
const role = new Role(json, this);
this.roleids[role.id] = role;
this.roles.push(role);
return role;
}
async updateRolePermissions(id, perms) {
const role = this.roleids[id];
role.permissions.allow = perms.allow;
role.permissions.deny = perms.deny;
await fetch(this.info.api.toString() + "/guilds/" + this.id + "/roles/" + this.id, {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
color: role.color,
hoist: role.hoist,
icon: role.icon,
mentionable: role.mentionable,
name: role.name,
permissions: role.permissions.allow.toString(),
unicode_emoji: role.unicode_emoji,
})
});
}
}
Guild.setupcontextmenu();
export { Guild };

View file

@ -10,17 +10,6 @@ async function waitforload() {
await res;
}
await waitforload();
function setDynamicHeight() {
var servertdHeight = document.getElementById('servertd').offsetHeight + document.getElementById('typediv').offsetHeight + document.getElementById('pasteimage').offsetHeight;
document.documentElement.style.setProperty('--servertd-height', servertdHeight + 'px');
}
const resizeObserver = new ResizeObserver(() => {
setDynamicHeight();
});
resizeObserver.observe(document.getElementById('servertd'));
resizeObserver.observe(document.getElementById('replybox'));
resizeObserver.observe(document.getElementById('pasteimage'));
setDynamicHeight();
const users = getBulkUsers();
if (!users.currentuser) {
window.location.href = '/login.html';
@ -101,7 +90,7 @@ thisuser.initwebsocket().then(_ => {
}
Contextmenu.currentmenu = table;
console.log(table);
userdock.append(table);
userdock.before(table);
event.stopImmediatePropagation();
});
}

View file

@ -1,11 +1,24 @@
import { User } from "./user.js";
import { Guild } from "./guild.js";
import { Contextmenu } from "./contextmenu.js";
class Member {
static already = {};
owner;
user;
roles;
error;
static contextmenu = new Contextmenu("User Menu");
static setUpContextMenu() {
this.contextmenu.addbutton("Copy user id", function () {
navigator.clipboard.writeText(this.id);
});
this.contextmenu.addbutton("Message user", function () {
fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST",
body: JSON.stringify({ "recipients": [this.id] }),
headers: this.headers
});
});
}
constructor(memberjson, owner, error = false) {
this.error = error;
this.owner = owner;
@ -54,8 +67,13 @@ class Member {
console.error(guild);
}
let user;
let id = "";
if (unkown instanceof User) {
user = unkown;
id = user.id;
}
else if (typeof unkown === typeof "") {
id = unkown;
}
else {
return new Member(unkown, guild);
@ -66,26 +84,26 @@ class Member {
if (!Member.already[guild.id]) {
Member.already[guild.id] = {};
}
else if (Member.already[guild.id][user.id]) {
const memb = Member.already[guild.id][user.id];
else if (Member.already[guild.id][id]) {
const memb = Member.already[guild.id][id];
if (memb instanceof Promise) {
return await memb;
}
return memb;
}
const promoise = fetch(guild.info.api.toString() + "/v9/users/" + user.id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.id, { headers: guild.headers }).then(_ => _.json()).then(json => {
const promoise = fetch(guild.info.api.toString() + "/v9/users/" + id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.id, { headers: guild.headers }).then(_ => _.json()).then(json => {
const memb = new Member(json, guild);
Member.already[guild.id][user.id] = memb;
Member.already[guild.id][id] = memb;
console.log("resolved");
return memb;
});
Member.already[guild.id][user.id] = promoise;
Member.already[guild.id][id] = promoise;
try {
return await promoise;
}
catch (_) {
const memb = new Member(user, guild, true);
Member.already[guild.id][user.id] = memb;
Member.already[guild.id][id] = memb;
return memb;
}
}
@ -115,5 +133,28 @@ class Member {
}
return this.guild.properties.owner_id === this.user.id;
}
bind(html) {
if (html.tagName === "SPAN") {
if (!this) {
return;
}
;
console.log(this.error);
if (this.error) {
const error = document.createElement("span");
error.textContent = "!";
error.classList.add("membererror");
html.after(error);
return;
}
html.style.color = this.getColor();
}
this.profileclick(html);
Member.contextmenu.bind(html);
}
profileclick(html) {
//to be implemented
}
}
Member.setUpContextMenu();
export { Member };

View file

@ -41,15 +41,6 @@ class Message {
Message.contextmenu.addbutton("Copy message id", function () {
navigator.clipboard.writeText(this.id);
});
Message.contextmenu.addbutton("Copy user id", function () {
navigator.clipboard.writeText(this.author.id);
});
Message.contextmenu.addbutton("Message user", function () {
fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST",
body: JSON.stringify({ "recipients": [this.author.id] }),
headers: this.headers
});
});
Message.contextmenu.addbutton("Edit", function () {
this.channel.editing = this;
document.getElementById("typebox").value = this.content;
@ -174,25 +165,26 @@ class Message {
replyline.appendChild(username);
const reply = document.createElement("div");
username.classList.add("username");
Member.resolve(this.author, this.guild).then(_ => {
if (!_) {
return;
}
;
this.author.bind(username, this.guild);
/*
Member.resolve(this.author,this.guild).then(_=>{
if(!_) {return};
console.log(_.error);
if (_.error) {
username.textContent += "Error";
alert("Should've gotten here");
const error = document.createElement("span");
error.textContent = "!";
if(_.error){
username.textContent+="Error";
alert("Should've gotten here")
const error=document.createElement("span");
error.textContent="!";
error.classList.add("membererror");
username.after(error);
return;
}
username.style.color = _.getColor();
}).catch(_ => {
console.log(_);
username.style.color=_.getColor();
}).catch(_=>{
console.log(_)
});
*/
reply.classList.add("replytext");
replyline.appendChild(reply);
const line2 = document.createElement("hr");
@ -204,9 +196,9 @@ class Message {
const author = message.author;
reply.appendChild(markdown(message.content, { stdsize: true }));
minipfp.src = author.getpfpsrc();
author.profileclick(minipfp);
author.bind(minipfp);
username.textContent = author.username;
author.profileclick(username);
author.bind(username);
});
div.appendChild(replyline);
}
@ -227,7 +219,7 @@ class Message {
const combine = (premessage?.author?.id != this.author.id) || (current) || this.message_reference;
if (combine) {
const pfp = this.author.buildpfp();
this.author.profileclick(pfp);
this.author.bind(pfp);
pfpRow.appendChild(pfp);
}
else {
@ -242,21 +234,7 @@ class Message {
if (combine) {
const username = document.createElement("span");
username.classList.add("username");
this.author.profileclick(username);
Member.resolve(this.author, this.guild).then(_ => {
if (!_) {
return;
}
;
if (_.error) {
const error = document.createElement("span");
error.textContent = "!";
error.classList.add("membererror");
username.after(error);
return;
}
username.style.color = _.getColor();
});
this.author.bind(username, this.guild);
username.textContent = this.author.username;
const userwrap = document.createElement("tr");
userwrap.appendChild(username);

View file

@ -2,7 +2,9 @@ export { Permissions };
class Permissions {
allow;
deny;
hasDeny;
constructor(allow, deny = "") {
this.hasDeny = !!deny;
this.allow = BigInt(allow);
this.deny = BigInt(deny);
}
@ -84,7 +86,7 @@ class Permissions {
},
{
name: "MANAGE_MESSAGES",
readableName: "Manager messages",
readableName: "Manage messages",
description: "Allows the user to delete messages that aren't their own"
},
{
@ -242,5 +244,23 @@ class Permissions {
return 0;
}
}
setPermision(name, setto) {
const bit = Permissions.map[name];
if (setto === 0) {
this.deny = this.setPermisionbit(bit, false, this.deny);
this.allow = this.setPermisionbit(bit, false, this.allow);
}
else if (setto === 1) {
this.deny = this.setPermisionbit(bit, false, this.deny);
this.allow = this.setPermisionbit(bit, true, this.allow);
}
else if (setto === -1) {
this.deny = this.setPermisionbit(bit, true, this.deny);
this.allow = this.setPermisionbit(bit, false, this.allow);
}
else {
console.error("invalid number entered:" + setto);
}
}
}
Permissions.makeMap();

View file

@ -5,7 +5,16 @@ class Role {
owner;
color;
id;
name;
info;
hoist;
icon;
mentionable;
unicode_emoji;
headers;
constructor(JSON, owner) {
this.headers = owner.headers;
this.info = owner.info;
for (const thing of Object.keys(JSON)) {
this[thing] = JSON[thing];
}

254
.dist/settings.js Normal file
View file

@ -0,0 +1,254 @@
import { Permissions } from "./permissions.js";
class Buttons {
name;
buttons;
bigtable;
warndiv;
constructor(name) {
this.buttons = [];
this.name = name;
}
add(name, thing = undefined) {
if (!thing) {
thing = new Options(name, this);
}
this.buttons.push([name, thing]);
return thing;
}
generateHTML() {
const bigtable = document.createElement("div");
bigtable.classList.add("Buttons");
bigtable.classList.add("flexltr");
this.bigtable = bigtable;
const htmlarea = document.createElement("div");
const buttonTable = document.createElement("div");
buttonTable.classList.add("flexttb", "settingbuttons");
for (const thing of this.buttons) {
const button = document.createElement("button");
button.classList.add("SettingsButton");
button.textContent = thing[0];
button.onclick = _ => {
this.generateHTMLArea(thing[1], htmlarea);
if (this.warndiv) {
this.warndiv.remove();
}
};
buttonTable.append(button);
}
this.generateHTMLArea(this.buttons[0][1], htmlarea);
bigtable.append(buttonTable);
bigtable.append(htmlarea);
return bigtable;
}
handleString(str) {
const div = document.createElement("div");
div.textContent = str;
return div;
}
generateHTMLArea(genation, htmlarea) {
let html;
if (genation instanceof Options) {
html = genation.generateHTML();
}
else {
html = this.handleString(genation);
}
htmlarea.innerHTML = "";
htmlarea.append(html);
}
changed(html) {
this.warndiv = html;
this.bigtable.append(html);
}
save() { }
}
class PermisionToggle {
rolejson;
permissions;
owner;
constructor(roleJSON, permissions, owner) {
this.rolejson = roleJSON;
this.permissions = permissions;
this.owner = owner;
}
generateHTML() {
const div = document.createElement("div");
div.classList.add("setting");
const name = document.createElement("span");
name.textContent = this.rolejson.readableName;
name.classList.add("settingsname");
div.append(name);
div.append(this.generateCheckbox());
const p = document.createElement("p");
p.innerText = this.rolejson.description;
div.appendChild(p);
return div;
}
generateCheckbox() {
const div = document.createElement("div");
div.classList.add("tritoggle");
const state = this.permissions.getPermision(this.rolejson.name);
const on = document.createElement("input");
on.type = "radio";
on.name = this.rolejson.name;
div.append(on);
if (state === 1) {
on.checked = true;
}
;
on.onclick = _ => {
this.permissions.setPermision(this.rolejson.name, 1);
this.owner.changed();
};
const no = document.createElement("input");
no.type = "radio";
no.name = this.rolejson.name;
div.append(no);
if (state === 0) {
no.checked = true;
}
;
no.onclick = _ => {
this.permissions.setPermision(this.rolejson.name, 0);
this.owner.changed();
};
if (this.permissions.hasDeny) {
const off = document.createElement("input");
off.type = "radio";
off.name = this.rolejson.name;
div.append(off);
if (state === -1) {
off.checked = true;
}
;
off.onclick = _ => {
this.permissions.setPermision(this.rolejson.name, -1);
this.owner.changed();
};
}
return div;
}
}
class RoleList extends Buttons {
permissions;
permission;
guild;
channel;
options;
onchange;
curid;
constructor(permissions, guild, onchange, channel = false) {
super("Roles");
this.guild = guild;
this.permissions = permissions;
this.channel = channel;
this.onchange = onchange;
const options = new Options("", this);
if (channel) {
this.permission = new Permissions("0", "0");
}
else {
this.permission = new Permissions("0");
}
for (const thing of Permissions.info) {
options.addPermisionToggle(thing, this.permission); //
}
for (const i of permissions) {
this.buttons.push([guild.getRole(i[0]).name, i[0]]); //
}
this.options = options;
}
handleString(str) {
this.curid = str;
const perm = this.permissions.find(_ => _[0] === str)[1];
this.permission.deny = perm.deny;
this.permission.allow = perm.allow;
this.options.name = this.guild.getRole(str).name;
this.options.haschanged = false;
return this.options.generateHTML();
}
save() {
this.onchange(this.curid, this.permission);
}
}
class Options {
name;
haschanged = false;
options;
owner;
constructor(name, owner) {
this.name = name;
this.options = [];
this.owner = owner;
}
addPermisionToggle(roleJSON, permissions) {
this.options.push(new PermisionToggle(roleJSON, permissions, this));
}
generateHTML() {
const div = document.createElement("div");
div.classList.add("titlediv");
const title = document.createElement("h2");
title.textContent = this.name;
div.append(title);
title.classList.add("settingstitle");
const table = document.createElement("div");
table.classList.add("flexttb", "flexspace");
for (const thing of this.options) {
table.append(thing.generateHTML());
}
div.append(table);
return div;
}
changed() {
if (!this.haschanged) {
const div = document.createElement("div");
div.classList.add("flexltr", "savediv");
const span = document.createElement("span");
div.append(span);
span.textContent = "Careful, you have unsaved changes";
const button = document.createElement("button");
button.textContent = "Save changes";
div.append(button);
this.haschanged = true;
this.owner.changed(div);
button.onclick = _ => {
this.owner.save();
div.remove();
};
}
}
}
class Settings extends Buttons {
static Buttons = Buttons;
static Options = Options;
html;
constructor(name) {
super(name);
}
addButton(name) {
const options = new Options(name, this);
this.add(name, options);
return options;
}
show() {
const background = document.createElement("div");
background.classList.add("background");
const title = document.createElement("h2");
title.textContent = this.name;
title.classList.add("settingstitle");
background.append(title);
background.append(this.generateHTML());
const exit = document.createElement("span");
exit.textContent = "✖";
exit.classList.add("exitsettings");
background.append(exit);
exit.onclick = _ => { this.hide(); };
document.body.append(background);
this.html = background;
}
hide() {
this.html.remove();
this.html = null;
}
}
export { Settings, RoleList };

View file

@ -13,6 +13,18 @@ class User {
discriminator;
pronouns;
bot;
static contextmenu = new Contextmenu("User Menu");
static setUpContextMenu() {
this.contextmenu.addbutton("Copy user id", function () {
navigator.clipboard.writeText(this.id);
});
this.contextmenu.addbutton("Message user", function () {
fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST",
body: JSON.stringify({ "recipients": [this.id] }),
headers: this.headers
});
});
}
static checkuser(userjson, owner) {
if (User.userids[userjson.id]) {
return User.userids[userjson.id];
@ -60,6 +72,21 @@ class User {
this.changepfp(json.avatar);
}
}
bind(html, guild = null) {
if (guild && guild.id !== "@me") {
Member.resolve(this, guild).then(_ => {
_.bind(html);
}).catch(_ => {
console.log(_);
});
}
this.profileclick(html);
User.contextmenu.bind(html, this);
}
static async resolve(id, localuser) {
const json = await fetch(localuser.info.api.toString() + "/v9/users/" + id + "/profile", { headers: localuser.headers }).then(_ => _.json());
return new User(json, localuser);
}
changepfp(update) {
this.avatar = update;
this.hypotheticalpfp = false;
@ -137,4 +164,5 @@ class User {
};
}
}
User.setUpContextMenu();
export { User };