Merge branch 'MathMan05:main' into main

This commit is contained in:
greysilly7 2024-09-25 11:10:58 -07:00 committed by GitHub
commit be40162fc5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 431 additions and 77 deletions

View file

@ -102,7 +102,10 @@ app.use("/", async (req: Request, res: Response)=>{
res.sendFile(path.join(__dirname, "webpage", "invite.html"));
return;
}
if(req.path.endsWith("service.js")){
res.send("nope :3");
return;
}
const filePath = path.join(__dirname, "webpage", req.path);
try{
await fs.access(filePath);

277
src/webpage/bot.ts Normal file
View file

@ -0,0 +1,277 @@
import { mainuserjson } from "./jsontypes.js";
import { Localuser } from "./localuser.js";
import { MarkDown } from "./markdown.js";
import { Form, Settings } from "./settings.js";
import { User } from "./user.js";
import {guildjson} from "./jsontypes.js";
import { PermissionToggle } from "./role.js";
import { Permissions } from "./permissions.js";
class Bot{
readonly owner:Localuser;
readonly token:string;
readonly json:mainuserjson;
headers: { "Content-type": string; Authorization: string };
get localuser(){
return this.owner;
}
get info(){
return this.localuser.info;
}
constructor(json:mainuserjson,token:string,owner:Localuser){
this.owner=owner;
this.token=token;
this.json=json;
this.headers={
"Content-type": "application/json; charset=UTF-8",
Authorization: token,
};
}
settings(){
const settings = new Settings("Bot Settings");
const botOptions = settings.addButton("Profile",{ltr:true});
const bot=new User(this.json,this.localuser);
{
const hypotheticalProfile = document.createElement("div");
let file: undefined | File | null;
let newpronouns: string | undefined;
let newbio: string | undefined;
const hypouser = bot.clone();
let color: string;
async function regen(){
hypotheticalProfile.textContent = "";
const hypoprofile = await hypouser.buildprofile(-1, -1);
hypotheticalProfile.appendChild(hypoprofile);
}
regen();
const settingsLeft = botOptions.addOptions("");
const settingsRight = botOptions.addOptions("");
settingsRight.addHTMLArea(hypotheticalProfile);
const finput = settingsLeft.addFileInput(
"Upload pfp:",
_=>{
if(file){
this.updatepfp(file);
}
},
{ clear: true }
);
finput.watchForChange(_=>{
if(!_){
file = null;
hypouser.avatar = null;
hypouser.hypotheticalpfp = true;
regen();
return;
}
if(_.length){
file = _[0];
const blob = URL.createObjectURL(file);
hypouser.avatar = blob;
hypouser.hypotheticalpfp = true;
regen();
}
});
let bfile: undefined | File | null;
const binput = settingsLeft.addFileInput(
"Upload banner:",
_=>{
if(bfile !== undefined){
this.updatebanner(bfile);
}
},
{ clear: true }
);
binput.watchForChange(_=>{
if(!_){
bfile = null;
hypouser.banner = undefined;
hypouser.hypotheticalbanner = true;
regen();
return;
}
if(_.length){
bfile = _[0];
const blob = URL.createObjectURL(bfile);
hypouser.banner = blob;
hypouser.hypotheticalbanner = true;
regen();
}
});
let changed = false;
const pronounbox = settingsLeft.addTextInput(
"Pronouns",
_=>{
if(newpronouns || newbio || changed){
this.updateProfile({
pronouns: newpronouns,
bio: newbio,
accent_color: Number.parseInt("0x" + color.substr(1), 16),
});
}
},
{ initText: bot.pronouns }
);
pronounbox.watchForChange(_=>{
hypouser.pronouns = _;
newpronouns = _;
regen();
});
const bioBox = settingsLeft.addMDInput("Bio:", _=>{}, {
initText: bot.bio.rawString,
});
bioBox.watchForChange(_=>{
newbio = _;
hypouser.bio = new MarkDown(_, this.owner);
regen();
});
if(bot.accent_color){
color = "#" + bot.accent_color.toString(16);
}else{
color = "transparent";
}
const colorPicker = settingsLeft.addColorInput(
"Profile color",
_=>{},
{ initColor: color }
);
colorPicker.watchForChange(_=>{
console.log();
color = _;
hypouser.accent_color = Number.parseInt("0x" + _.substr(1), 16);
changed = true;
regen();
});
}
{
const guildsettings=settings.addButton("Guilds");
guildsettings.addTitle("Guilds bot is in:");
fetch(this.info.api+"/users/@me/guilds/",{
headers:this.headers
}).then(_=>_.json()).then((json:(guildjson["properties"])[])=>{
for(const guild of json){
const content = document.createElement("div");
content.classList.add("discovery-guild");
if(guild.banner){
const banner = document.createElement("img");
banner.classList.add("banner");
banner.crossOrigin = "anonymous";
banner.src = this.info.cdn + "/icons/" + guild.id + "/" + guild.banner + ".png?size=256";
banner.alt = "";
content.appendChild(banner);
}
const nameContainer = document.createElement("div");
nameContainer.classList.add("flex");
const img = document.createElement("img");
img.classList.add("icon");
img.crossOrigin = "anonymous";
img.src = this.info.cdn + (guild.icon? "/icons/" + guild.id + "/" + guild.icon + ".png?size=48": "/embed/avatars/3.png");
img.alt = "";
nameContainer.appendChild(img);
const name = document.createElement("h3");
name.textContent = guild.name;
nameContainer.appendChild(name);
content.appendChild(nameContainer);
const desc = document.createElement("p");
desc.textContent = guild.description;
content.appendChild(desc);
guildsettings.addHTMLArea(content);
content.onclick=()=>{
const guildsetting=guildsettings.addSubOptions(guild.name);
guildsetting.addHTMLArea(content);
guildsetting.addButtonInput("","Leave Guild",()=>{
if(confirm(`Are you sure you want to leave ${guild.name}?`)){
fetch(this.info.api+"/users/@me/guilds/"+guild.id,{
method:"DELETE",
headers:this.headers
})
}
})
}
}
})
}
settings.show();
}
updatepfp(file: Blob): void{
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = ()=>{
fetch(this.info.api + "/users/@me", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
avatar: reader.result,
}),
});
};
}
updatebanner(file: Blob | null): void{
if(file){
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = ()=>{
fetch(this.info.api + "/users/@me", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
banner: reader.result,
}),
});
};
}else{
fetch(this.info.api + "/users/@me", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
banner: null,
}),
});
}
}
updateProfile(json: {
bio?: string;
pronouns?: string;
accent_color?: number;
}){
fetch(this.info.api + "/users/@me/profile", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify(json),
});
}
static InviteMaker(id:string,container:Form,info:Localuser["info"]){
const gen=container.addSubOptions("URL generator",{
noSubmit:true
});
const params = new URLSearchParams("");
params.set("instance", info.wellknown);
params.set("client_id", id);
params.set("scope", "bot");
const url=gen.addText("");
const perms=new Permissions("0");
for(const perm of Permissions.info){
const permsisions=new PermissionToggle(perm,perms,gen);
gen.options.push(permsisions);
gen.generate(permsisions);
}
const cancel=setInterval(()=>{
if(!gen.container.deref()){
clearInterval(cancel);
}
params.set("permissions",perms.allow.toString());
const encoded = params.toString();
url.setText(`${location.origin}/oauth2/authorize?${encoded}`);
},100)
}
}
export {Bot};

View file

@ -168,60 +168,60 @@ animated?: boolean;
};
type guildjson = {
application_command_counts: { [key: string]: number };
channels: channeljson[];
data_mode: string;
emojis: emojijson[];
guild_scheduled_events: [];
id: string;
large: boolean;
lazy: boolean;
member_count: number;
premium_subscription_count: number;
properties: {
region: string | null;
name: string;
description: string;
icon: string;
splash: string;
banner: string;
features: string[];
preferred_locale: string;
owner_id: string;
application_id: string;
afk_channel_id: string;
afk_timeout: number;
member_count: number;
system_channel_id: string;
verification_level: number;
explicit_content_filter: number;
default_message_notifications: number;
mfa_level: number;
vanity_url_code: number;
premium_tier: number;
premium_progress_bar_enabled: boolean;
system_channel_flags: number;
discovery_splash: string;
rules_channel_id: string;
public_updates_channel_id: string;
max_video_channel_users: number;
max_members: number;
nsfw_level: number;
hub_type: null;
home_header: null;
id: string;
latest_onboarding_question_id: string;
max_stage_video_channel_users: number;
nsfw: boolean;
safety_alerts_channel_id: string;
};
roles: rolesjson[];
stage_instances: [];
stickers: [];
threads: [];
version: string;
guild_hashes: {};
joined_at: string;
application_command_counts: { [key: string]: number };
channels: channeljson[];
data_mode: string;
emojis: emojijson[];
guild_scheduled_events: [];
id: string;
large: boolean;
lazy: boolean;
member_count: number;
premium_subscription_count: number;
properties: {
region: string | null;
name: string;
description: string;
icon: string;
splash: string;
banner: string;
features: string[];
preferred_locale: string;
owner_id: string;
application_id: string;
afk_channel_id: string;
afk_timeout: number;
member_count: number;
system_channel_id: string;
verification_level: number;
explicit_content_filter: number;
default_message_notifications: number;
mfa_level: number;
vanity_url_code: number;
premium_tier: number;
premium_progress_bar_enabled: boolean;
system_channel_flags: number;
discovery_splash: string;
rules_channel_id: string;
public_updates_channel_id: string;
max_video_channel_users: number;
max_members: number;
nsfw_level: number;
hub_type: null;
home_header: null;
id: string;
latest_onboarding_question_id: string;
max_stage_video_channel_users: number;
nsfw: boolean;
safety_alerts_channel_id: string;
};
roles: rolesjson[];
stage_instances: [];
stickers: [];
threads: [];
version: string;
guild_hashes: {};
joined_at: string;
};
type startTypingjson = {
d: {

View file

@ -19,6 +19,7 @@ import{
import{ Member }from"./member.js";
import{ Form, FormError, Options, Settings }from"./settings.js";
import{ MarkDown }from"./markdown.js";
import { Bot } from "./bot.js";
const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]);
@ -1370,6 +1371,11 @@ class Localuser{
}
readonly botTokens:Map<string,string>=new Map();
async manageApplication(appId = "", container:Options){
if(this.perminfo.applications){
for(const item of Object.keys(this.perminfo.applications)){
this.botTokens.set(item,this.perminfo.applications[item]);
}
}
const res = await fetch(this.info.api + "/applications/" + appId, {
headers: this.headers,
});
@ -1436,10 +1442,43 @@ class Localuser{
const updateJSON = await updateRes.json();
text.setText("Token: "+updateJSON.token);
this.botTokens.set(appId,updateJSON.token);
if(this.perminfo.applications[appId]){
this.perminfo.applications[appId]=updateJSON.token;
this.userinfo.updateLocal();
}
});
const text=form.addText(this.botTokens.has(appId)?"Token: "+this.botTokens.get(appId):"Token: *****************")
const text=form.addText(this.botTokens.has(appId)?"Token: "+this.botTokens.get(appId):"Token: *****************");
const check=form.addOptions("",{noSubmit:true});
if(!this.perminfo.applications){
this.perminfo.applications={};
this.userinfo.updateLocal();
}
const checkbox=check.addCheckboxInput("Save token to localStorage",()=>{},{initState:!!this.perminfo.applications[appId]});
checkbox.watchForChange(_=>{
if(_){
if(this.botTokens.has(appId)){
this.perminfo.applications[appId]=this.botTokens.get(appId);
this.userinfo.updateLocal();
}else{
alert("Don't know token so can't save it to localStorage, sorry");
checkbox.setState(false);
}
}else{
delete this.perminfo.applications[appId];
this.userinfo.updateLocal();
}
});
form.addButtonInput("","Advanced bot settings",()=>{
const token=this.botTokens.get(appId);
if(token){
const botc=new Bot(bot,token,this);
botc.settings();
}
});
form.addButtonInput("","Bot Invite Creator",()=>{
Bot.InviteMaker(appId,form,this.info);
})
}
//---------- resolving members code -----------
readonly waitingmembers: Map<
string,

View file

@ -296,6 +296,9 @@ class Permissions{
}
}
getPermission(name: string): number{
if(undefined===Permissions.map[name]){
console.error(name +" is not found in map",Permissions.map);
}
if(this.getPermissionbit(Permissions.map[name] as number, this.allow)){
return 1;
}else if(
@ -319,7 +322,7 @@ class Permissions{
}
setPermission(name: string, setto: number): void{
const bit = Permissions.map[name] as number;
if(!bit){
if(bit===undefined){
return console.error(
"Tried to set permission to " +
setto +

View file

@ -44,9 +44,9 @@ export{ Role };
import{ Options }from"./settings.js";
class PermissionToggle implements OptionsElement<number>{
readonly rolejson: {
name: string;
readableName: string;
description: string;
name: string;
readableName: string;
description: string;
};
permissions: Permissions;
owner: Options;
@ -177,4 +177,4 @@ class RoleList extends Buttons{
this.onchange(this.curid, this.permission);
}
}
export{ RoleList };
export{ RoleList, PermissionToggle };

View file

@ -206,6 +206,15 @@ class CheckboxInput implements OptionsElement<boolean>{
this.value = value;
}
}
setState(state:boolean){
if(this.input){
const checkbox=this.input.deref();
if(checkbox){
checkbox.checked=state;
this.value=state;
}
}
}
onchange: (str: boolean) => void = _=>{};
watchForChange(func: (str: boolean) => void){
this.onchange = func;
@ -494,20 +503,21 @@ class Options implements OptionsElement<void>{
readonly owner: Buttons | Options | Form;
readonly ltr: boolean;
value!: void;
readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> =
new WeakMap();
readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> = new WeakMap();
readonly noSubmit:boolean=false;
container: WeakRef<HTMLDivElement> = new WeakRef(
document.createElement("div")
);
constructor(
name: string,
owner: Buttons | Options | Form,
{ ltr = false } = {}
{ ltr = false, noSubmit=false} = {}
){
this.name = name;
this.options = [];
this.owner = owner;
this.ltr = ltr;
this.noSubmit=noSubmit;
}
removeAll(){
while(this.options.length){
@ -519,8 +529,8 @@ class Options implements OptionsElement<void>{
}
}
watchForChange(){}
addOptions(name: string, { ltr = false } = {}){
const options = new Options(name, this, { ltr });
addOptions(name: string, { ltr = false,noSubmit=false } = {}){
const options = new Options(name, this, { ltr,noSubmit });
this.options.push(options);
this.generate(options);
return options;
@ -542,8 +552,8 @@ class Options implements OptionsElement<void>{
);
}
}
addSubOptions(name: string, { ltr = false } = {}){
const options = new Options(name, this, { ltr });
addSubOptions(name: string, { ltr = false,noSubmit=false } = {}){
const options = new Options(name, this, { ltr,noSubmit });
this.subOptions = options;
this.genTop();
return options;
@ -788,7 +798,10 @@ class Options implements OptionsElement<void>{
}
}
changed(){
if(this.owner instanceof Options || this.owner instanceof Form){
if(this.noSubmit){
return;
}
if(this.owner instanceof Options || this.owner instanceof Form ){
this.owner.changed();
return;
}
@ -877,11 +890,11 @@ class Form implements OptionsElement<object>{
//the value can't really be anything, but I don't care enough to fix this
this.values[key] = value;
}
addSubOptions(name: string, { ltr = false } = {}){
addSubOptions(name: string, { ltr = false,noSubmit=false } = {}){
if(this.button&&this.button.deref()){
(this.button.deref() as HTMLElement).hidden=true;
}
return this.options.addSubOptions(name,{ltr});
return this.options.addSubOptions(name,{ltr, noSubmit});
}
addSubForm(
name: string,
@ -981,9 +994,20 @@ class Form implements OptionsElement<object>{
}
return mdInput;
}
/**
* This function does not integrate with the form, so be aware of that
*
*/
addButtonInput(label:string,textContent:string,onSubmit:()=>void){
return this.options.addButtonInput(label,textContent,onSubmit);
}
/**
* This function does not integrate with the form, so be aware of that
*
*/
addOptions(name: string, { ltr = false,noSubmit=false } = {}){
return this.options.addOptions(name, {ltr,noSubmit});
}
addCheckboxInput(
label: string,
formName: string,

View file

@ -452,6 +452,7 @@ p {
/* display: flex; */
width: 100%;
background: transparent;
flex-shrink: 0;
}
hr {
border-style: solid;
@ -538,9 +539,11 @@ hr {
flex-direction: column;
flex-shrink: 1;
min-height: 0;
height: 100vh;
/* height: 100vh; */
/* width: 100%; */
position: relative;
height: 1in;
flex-grow: 1;
}
.timestamp {
@ -1268,7 +1271,7 @@ span {
.flexttb{
display: flex;
flex-direction: column;
max-height: 100vh;
/* max-height: 100vh; */
overflow: auto;
/* margin-bottom: 1in; */
/* padding-bottom: .1in; */
@ -1371,6 +1374,8 @@ span {
display:flex;
justify-content: space-between;
width: 100%;
height: 100dvh;
align-content: space-around;
}
.userflex{
display:flex;
@ -1427,7 +1432,10 @@ span {
}
.discovery-guild img.banner {
width: 215px;
width: 100%;
height: .6in;
border-radius: .04in;
margin-bottom: .03in;
}
.discovery-guild img.icon {
@ -1526,6 +1534,7 @@ span {
.scroller{
padding-bottom: .2in;
flex-grow: 0;
flex-shrink: 1;
}
.suberror{
animation: goout 6s forwards;
@ -1875,7 +1884,6 @@ form div{
background:var(--primary-bg);
}
.banner{
position:absolute;
top:0;
left:0;
width:100%;
@ -2205,4 +2213,4 @@ form div{
}
.mentionMD:hover{
background:color-mix(in srgb,var(--mention-md-bg),white 10%);
}
}