inital member list support

This commit is contained in:
MathMan05 2024-09-30 15:47:52 -05:00
parent b2a31d7993
commit a1902a912f
8 changed files with 501 additions and 288 deletions

View file

@ -377,7 +377,10 @@ class Channel extends SnowFlake{
if(member.isAdmin()){
return true;
}
for(const thing of member.roles){
const roles=new Set(member.roles);
const everyone=this.guild.roles[this.guild.roles.length-1];
roles.add(everyone)
for(const thing of roles){
const premission = this.permission_overwrites.get(thing.id);
if(premission){
const perm = premission.getPermission(name);
@ -834,6 +837,7 @@ class Channel extends SnowFlake{
Channel.regenLoadingMessages();
loading.classList.add("loading");
this.rendertyping();
this.localuser.getSidePannel();
await this.putmessages();
await prom;
if(id !== Channel.genid){

View file

@ -34,6 +34,7 @@ class Guild extends SnowFlake{
html!: HTMLElement;
emojis!: emojijson[];
large!: boolean;
members=new Set<Member>();
static contextmenu = new Contextmenu<Guild, undefined>("guild menu");
static setupcontextmenu(){
Guild.contextmenu.addbutton("Copy Guild id", function(this: Guild){

View file

@ -56,6 +56,8 @@
<span id="channelname">Channel name</span>
<span id="channelTopic" hidden>Channel topic</span>
</div>
<div class="flexltr">
<div class="flexttb">
<div id="channelw">
<div id="loadingdiv">
</div>
@ -76,6 +78,10 @@
</div>
</div>
</div>
<div class="flexttb" id="sideDiv">
</div>
</div>
</div>
</div>
</body>

View file

@ -145,21 +145,22 @@ pronouns: string;
badge_ids: string[];
};
type memberjson = {
index?: number;
id: string;
user: userjson | null;
guild_id: string;
guild: {
id: string;
} | null;
nick?: string;
roles: string[];
joined_at: string;
premium_since: string;
deaf: boolean;
mute: boolean;
pending: boolean;
last_message_id?: boolean; //What???
index?: number;
id: string;
user: userjson | null;
guild_id: string;
guild: {
id: string;
} | null;
presence?:presencejson
nick?: string;
roles: string[];
joined_at: string;
premium_since: string;
deaf: boolean;
mute: boolean;
pending: boolean;
last_message_id?: boolean; //What???
};
type emojijson = {
name: string;
@ -257,18 +258,18 @@ default_thread_rate_limit_per_user: number;
position: number;
};
type rolesjson = {
id: string;
guild_id: string;
color: number;
hoist: boolean;
managed: boolean;
mentionable: boolean;
name: string;
permissions: string;
position: number;
icon: string;
unicode_emoji: string;
flags: number;
id: string;
guild_id: string;
color: number;
hoist: boolean;
managed: boolean;
mentionable: boolean;
name: string;
permissions: string;
position: number;
icon: string;
unicode_emoji: string;
flags: number;
};
type dirrectjson = {
id: string;
@ -392,20 +393,20 @@ t: "MESSAGE_CREATE";
};
type wsjson =
| {
op: 0;
d: any;
s: number;
t:
| "TYPING_START"
| "USER_UPDATE"
| "CHANNEL_UPDATE"
| "CHANNEL_CREATE"
| "CHANNEL_DELETE"
| "GUILD_DELETE"
| "GUILD_CREATE"
| "MESSAGE_REACTION_REMOVE_ALL"
| "MESSAGE_REACTION_REMOVE_EMOJI";
}
op: 0;
d: any;
s: number;
t:
| "TYPING_START"
| "USER_UPDATE"
| "CHANNEL_UPDATE"
| "CHANNEL_CREATE"
| "CHANNEL_DELETE"
| "GUILD_DELETE"
| "GUILD_CREATE"
| "MESSAGE_REACTION_REMOVE_ALL"
| "MESSAGE_REACTION_REMOVE_EMOJI";
}
| {
op: 0;
t: "GUILD_MEMBERS_CHUNK";
@ -469,7 +470,7 @@ guild_id: string;
emoji: emojijson;
};
s: 3;
};
}|memberlistupdatejson;
type memberChunk = {
guild_id: string;
nonce: string;
@ -479,6 +480,39 @@ chunk_index: number;
chunk_count: number;
not_found: string[];
};
type memberlistupdatejson={
op: 0,
s: number,
t: "GUILD_MEMBER_LIST_UPDATE",
d: {
ops: [
{
items:({
group:{
count:number,
id:string
}
}|{
member:memberjson
})[]
op: "SYNC",
range: [
number,
number
]
}
],
online_count: number,
member_count: number,
id: string,
guild_id: string,
groups: {
count: number,
id: string
}[]
}
}
export{
readyjson,
dirrectjson,
@ -498,4 +532,5 @@ export{
messageCreateJson,
memberChunk,
invitejson,
memberlistupdatejson
};

View file

@ -10,6 +10,7 @@ import{
guildjson,
mainuserjson,
memberjson,
memberlistupdatejson,
messageCreateJson,
presencejson,
readyjson,
@ -20,6 +21,7 @@ import{ Member }from"./member.js";
import{ Form, FormError, Options, Settings }from"./settings.js";
import{ MarkDown }from"./markdown.js";
import { Bot } from "./bot.js";
import { Role } from "./role.js";
const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]);
@ -479,7 +481,13 @@ class Localuser{
case"GUILD_MEMBERS_CHUNK":
this.gotChunk(temp.d);
break;
case"GUILD_MEMBER_LIST_UPDATE":
{
this.memberListUpdate(temp)
break;
}
}
}else if(temp.op === 10){
if(!this.ws)return;
console.log("heartbeat down");
@ -518,6 +526,108 @@ class Localuser{
}
return channel; // Add this line to return the 'channel' variable
}
async memberListUpdate(list:memberlistupdatejson){
const div=document.getElementById("sideDiv") as HTMLDivElement;
div.innerHTML="";
const counts=new Map<string,number>();
const guild=this.lookingguild;
if(!guild) return;
const channel=this.channelfocus;
if(!channel) return;
for(const thing of list.d.ops[0].items){
if("member" in thing){
await Member.new(thing.member,guild);
}else{
counts.set(thing.group.id,thing.group.count);
}
}
const elms:Map<Role|"offline"|"online",Member[]>=new Map([["offline",[]],["online",[]]]);
for(const role of guild.roles){
console.log(guild.roles);
if(role.hoist){
elms.set(role,[]);
}
}
const members=new Set(guild.members);
members.forEach((member)=>{
if(!channel.hasPermission("VIEW_CHANNEL",member)){
members.delete(member);
console.log(member)
return;
}
})
for(const [role, list] of elms){
members.forEach((member)=>{
if(role === "offline"){
if(member.user.status === "offline"){
list.push(member);
members.delete(member);
}
return;
}
if(role !== "online"&&member.hasRole(role.id)){
list.push(member);
members.delete(member);
}
});
if(!list.length) continue;
list.sort((a,b)=>{
return (a.name.toLowerCase()>b.name.toLowerCase())?1:-1;
});
}
const online=[...members];
online.sort((a,b)=>{
return (a.name.toLowerCase()>b.name.toLowerCase())?1:-1;
});
elms.set("online",online);
for(const [role, list] of elms){
if(!list.length) continue;
const category=document.createElement("div");
category.classList.add("memberList");
let title=document.createElement("h3");
if(role==="offline"){
title.textContent="Offline";
category.classList.add("offline");
}else if(role==="online"){
title.textContent="Online";
}else{
title.textContent=role.name;
}
category.append(title);
const membershtml=document.createElement("div");
membershtml.classList.add("flexttb");
for(const member of list){
const memberdiv=document.createElement("div");
const pfp=member.user.buildpfp();
const username=document.createElement("span");
username.textContent=member.name;
member.bind(username)
member.user.bind(memberdiv,member.guild,false);
memberdiv.append(pfp,username);
memberdiv.classList.add("flexltr");
membershtml.append(memberdiv);
}
category.append(membershtml);
div.prepend(category);
}
console.log(elms);
}
async getSidePannel(){
if(this.ws&&this.channelfocus){
this.ws.send(JSON.stringify({
d:{
channels:{[this.channelfocus.id]:[[0,99]]},
guild_id:this.channelfocus.guild.id
},
op:14
}))
}else{
console.log("false? :3")
}
}
gotoid: string | undefined;
async goToChannel(id: string){
const channel = this.channelids.get(id);

View file

@ -11,9 +11,8 @@ class Member extends SnowFlake{
user: User;
roles: Role[] = [];
nick!: string;
[key: string]: any;
private constructor(memberjson: memberjson, owner: Guild){
private constructor(memberjson: memberjson, owner: Guild){
super(memberjson.id);
this.owner = owner;
if(this.localuser.userMap.has(memberjson.id)){
@ -23,9 +22,11 @@ private constructor(memberjson: memberjson, owner: Guild){
}else{
throw new Error("Missing user object of this member");
}
if(this.localuser.userMap.has(this?.id)){
this.user = this.localuser.userMap.get(this?.id) as User;
}
for(const key of Object.keys(memberjson)){
if(key === "guild" || key === "owner"){
if(key === "guild" || key === "owner" || key === "user"){
continue;
}
@ -37,28 +38,30 @@ private constructor(memberjson: memberjson, owner: Guild){
}
continue;
}
if(key === "presence"){
this.getPresence(memberjson.presence);
continue;
}
(this as any)[key] = (memberjson as any)[key];
}
if(this.localuser.userMap.has(this?.id)){
this.user = this.localuser.userMap.get(this?.id) as User;
}
this.roles.sort((a, b)=>{
return this.guild.roles.indexOf(a) - this.guild.roles.indexOf(b);
});
}
get guild(){
}
get guild(){
return this.owner;
}
get localuser(){
}
get localuser(){
return this.guild.localuser;
}
get info(){
}
get info(){
return this.owner.info;
}
static async new(
}
static async new(
memberjson: memberjson,
owner: Guild
): Promise<Member | undefined>{
): Promise<Member | undefined>{
let user: User;
if(owner.localuser.userMap.has(memberjson.id)){
user = owner.localuser.userMap.get(memberjson.id) as User;
@ -72,22 +75,27 @@ static async new(
if(memb === undefined){
memb = new Member(memberjson, owner);
user.members.set(owner, memb);
owner.members.add(memb);
return memb;
}else if(memb instanceof Promise){
return await memb; //I should do something else, though for now this is "good enough"
}else{
if(memberjson.presence){
memb.getPresence(memberjson.presence);
}
return memb;
}
}else{
const memb = new Member(memberjson, owner);
user.members.set(owner, memb);
owner.members.add(memb);
return memb;
}
}
static async resolveMember(
}
static async resolveMember(
user: User,
guild: Guild
): Promise<Member | undefined>{
): Promise<Member | undefined>{
const maybe = user.members.get(guild);
if(!user.members.has(guild)){
const membpromise = guild.localuser.resolvemember(user.id, guild.id);
@ -111,14 +119,14 @@ static async resolveMember(
}else{
return maybe;
}
}
public getPresence(presence: presencejson | undefined){
}
public getPresence(presence: presencejson | undefined){
this.user.getPresence(presence);
}
/**
}
/**
* @todo
*/
highInfo(){
highInfo(){
fetch(
this.info.api +
"/users/" +
@ -127,8 +135,8 @@ highInfo(){
this.guild.id,
{ headers: this.guild.headers }
);
}
hasRole(ID: string){
}
hasRole(ID: string){
console.log(this.roles, ID);
for(const thing of this.roles){
if(thing.id === ID){
@ -136,8 +144,8 @@ hasRole(ID: string){
}
}
return false;
}
getColor(){
}
getColor(){
for(const thing of this.roles){
const color = thing.getColor();
if(color){
@ -145,16 +153,16 @@ getColor(){
}
}
return"";
}
isAdmin(){
}
isAdmin(){
for(const role of this.roles){
if(role.permissions.getPermission("ADMINISTRATOR")){
return true;
}
}
return this.guild.properties.owner_id === this.user.id;
}
bind(html: HTMLElement){
}
bind(html: HTMLElement){
if(html.tagName === "SPAN"){
if(!this){
return;
@ -168,14 +176,14 @@ bind(html: HTMLElement){
}
//this.profileclick(html);
}
profileclick(/* html: HTMLElement */){
}
profileclick(/* html: HTMLElement */){
//to be implemented
}
get name(){
}
get name(){
return this.nick || this.user.username;
}
kick(){
}
kick(){
let reason = "";
const menu = new Dialog([
"vdiv",
@ -199,16 +207,16 @@ kick(){
],
]);
menu.show();
}
kickAPI(reason: string){
}
kickAPI(reason: string){
const headers = structuredClone(this.guild.headers);
(headers as any)["x-audit-log-reason"] = reason;
fetch(`${this.info.api}/guilds/${this.guild.id}/members/${this.id}`, {
method: "DELETE",
headers,
});
}
ban(){
}
ban(){
let reason = "";
const menu = new Dialog([
"vdiv",
@ -232,16 +240,16 @@ ban(){
],
]);
menu.show();
}
banAPI(reason: string){
}
banAPI(reason: string){
const headers = structuredClone(this.guild.headers);
(headers as any)["x-audit-log-reason"] = reason;
fetch(`${this.info.api}/guilds/${this.guild.id}/bans/${this.id}`, {
method: "PUT",
headers,
});
}
hasPermission(name: string): boolean{
}
hasPermission(name: string): boolean{
if(this.isAdmin()){
return true;
}
@ -251,6 +259,6 @@ hasPermission(name: string): boolean{
}
}
return false;
}
}
}
export{ Member };

View file

@ -1379,6 +1379,7 @@ span {
width: 100%;
height: 100dvh;
align-content: space-around;
align-items: stretch;
}
.userflex{
display:flex;
@ -2219,3 +2220,51 @@ form div{
.mentionMD:hover{
background:color-mix(in srgb,var(--mention-md-bg),white 10%);
}
#sideDiv{
flex-grow:0;
flex-shrink:0;
width:2.5in;
box-shadow: -.02in 0 .04in black;
&:empty{
width:0in;
}
;
align-items: stretch;
/* overflow-x: hidden; */
overflow-y: unset;
scrollbar-width: none;
}
.memberList{
padding:.05in;
>div{
width: 100%;
>div{
width:100%;
padding:.04in .02in;
margin: .01in 0.0in;
border-radius:.1in;
&:hover{
background:var(--message-bg-hover);
}
flex-shrink: 1;
cursor: pointer;
box-sizing:border-box;
gap:.05in;
align-items: center;
}
img{
width:40px;
height:40px;
}
box-sizing: border-box;
}
}
.offline{
h3{
color:var(--primary-text)
}
>div{
opacity:.4;
}
}

View file

@ -27,7 +27,7 @@ class User extends SnowFlake{
badge_ids!: string[];
members: WeakMap<Guild, Member | undefined | Promise<Member | undefined>> =
new WeakMap();
private status!: string;
status!: string;
resolving: false | Promise<any> = false;
constructor(userjson: userjson, owner: Localuser, dontclone = false){