adding invites

This commit is contained in:
MathMan05
2024-08-15 17:05:14 -05:00
parent 3e5435668e
commit 3af371e6ab
16 changed files with 670 additions and 30 deletions

View File

@@ -73,6 +73,63 @@ class Channel{
this.contextmenu.addbutton("Edit channel",function(){
this.editChannel(this);
},null,_=>{return _.isAdmin()});
this.contextmenu.addbutton("Make invite",function(){
this.createInvite();
},null,(_:Channel)=>{
return _.hasPermission("CREATE_INSTANT_INVITE")&&_.type!==4
});
}
createInvite(){
const div=document.createElement("div");
div.classList.add("invitediv");
const text=document.createElement("span");
div.append(text);
let uses=0;
let expires=1800;
const copycontainer=document.createElement("div");
copycontainer.classList.add("copycontainer")
const copy=document.createElement("img");
copy.src="/icons/copy.svg";
copy.classList.add("copybutton","svgtheme");
copycontainer.append(copy);
copycontainer.onclick=_=>{
navigator.clipboard.writeText(text.textContent);
}
div.append(copycontainer);
const update=()=>{
fetch(`${this.info.api}/channels/${this.id}/invites`,{
method:"POST",
headers:this.headers,
body:JSON.stringify({
flags: 0,
target_type: null,
target_user_id: null,
max_age: expires+"",
max_uses: uses,
temporary: uses!==0
})
}).then(_=>_.json()).then(json=>{
const params=new URLSearchParams("");
params.set("instance",this.info.wellknown)
const encoded=params.toString();
text.textContent=`${window.location.protocol}//${window.location.host}/invite/${json.code}?${encoded}`
})
}
update();
new Dialog(["vdiv",
["title","Invite people"],
["text",`to #${this.name} in ${this.guild.properties.name}`],
["select","Expire after:",["30 Minutes","1 Hour","6 Hours","12 Hours","1 Day","7 Days","30 Days","Never"],function(e){
expires=[1800,3600,21600,43200,86400,604800,2592000,0][e.srcElement.selectedIndex];
update();
},0],
["select","Max uses:",["No limit","1 use","5 uses","10 uses","25 uses","50 uses","100 uses"],function(e){
uses=[0,1,5,10,25,50,100][e.srcElement.selectedIndex];
update();
},0],
["html",div]
]).show()
}
generateSettings(){
this.sortPerms();

1
webpage/icons/copy.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180"><g fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width="21.9"><path d="m64 44.5 85.7.3-.5 124.3-85.2-.4.5-124.2Z"/><path d="M31.5 141.6 32 11.5h-.5l89.6.3"/></g></svg>

After

Width:  |  Height:  |  Size: 262 B

22
webpage/invite.html Normal file
View File

@@ -0,0 +1,22 @@
<body>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jank Client</title>
<meta content="Invite" property="og:title" />
<meta content="You shouldn't see this, but this is an invite URL'" property="og:description" />
<meta content="/logo.webp" property="og:image" />
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
<link href="/style.css" rel="stylesheet" type="text/css" />
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/>
</head>
<div>
<div id="invitebody">
<div id="inviteimg"></div>
<h1 id="invitename">Server Name</h1>
<p id="invitedescription">Someone invited you to Server Name</p>
<button id="AcceptInvite">Accept Invite</button>
</div>
</div>
<script type="module" src="/invite.js"></script>
</body>

118
webpage/invite.ts Normal file
View File

@@ -0,0 +1,118 @@
import {getBulkUsers, Specialuser, getapiurls} from "./login.js";
const users=getBulkUsers();
const well=new URLSearchParams(window.location.search).get("instance");
const joinable:Specialuser[]=[];
for(const thing in users.users){
const user:Specialuser = users.users[thing]
if(user.serverurls.wellknown.includes(well)){
joinable.push(user);
}
console.log(users.users[thing]);
}
let urls:{api:string,cdn:string};
if(!joinable.length){
const out=await getapiurls(well);
if(out){
urls=out;
for(const thing in users.users){
const user:Specialuser = users.users[thing]
if(user.serverurls.api.includes(out.api)){
joinable.push(user);
}
console.log(users.users[thing]);
}
}else{
throw Error("someone needs to handle the case where the servers don't exist")
}
}else{
urls=joinable[0].serverurls;
}
if(!joinable.length){
document.getElementById("AcceptInvite").textContent="Create an account to accept the invite"
}
const code=window.location.pathname.split("/")[2];
let guildinfo;
fetch(`${urls.api}/invites/${code}`,{
method:"GET"
}).then(_=>_.json()).then(json=>{
const guildjson=json.guild;
guildinfo=guildjson;
document.getElementById("invitename").textContent=guildjson.name;
document.getElementById("invitedescription").textContent=
`${json.inviter.username} invited you to join ${guildjson.name}`;
if(guildjson.icon){
const img=document.createElement("img");
img.src=`${urls.cdn}/icons/${guildjson.id}/${guildjson.icon}.png`;
img.classList.add("inviteGuild");
document.getElementById("inviteimg").append(img);
}else{
const txt=guildjson.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, "");
const div=document.createElement("div");
div.textContent=txt;
div.classList.add("inviteGuild");
document.getElementById("inviteimg").append(div);
}
})
function showAccounts(){
const table=document.createElement("dialog");
for(const thing of Object.values(joinable)){
const specialuser=thing as Specialuser;
console.log(specialuser.pfpsrc)
const userinfo=document.createElement("div");
userinfo.classList.add("flexltr","switchtable");
const pfp=document.createElement("img");
userinfo.append(pfp);
const user=document.createElement("div");
userinfo.append(user);
user.append(specialuser.username);
user.append(document.createElement("br"));
const span=document.createElement("span");
span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://","");
user.append(span);
user.classList.add("userinfo")
span.classList.add("serverURL")
pfp.src=specialuser.pfpsrc;
pfp.classList.add("pfp");
table.append(userinfo);
userinfo.addEventListener("click",_=>{
console.log(thing);
fetch(`${urls.api}/invites/${code}`,{
method:"POST",
headers:{
Authorization:thing.token
}
}).then(_=>{
users["currentuser"]=specialuser.uid;
localStorage.setItem("userinfos",JSON.stringify(users));
window.location.href="/channels/"+guildinfo.id;
})
})
}
{
const td=document.createElement("div");
td.classList.add("switchtable")
td.append("Login or create an account ⇌");
td.addEventListener("click",_=>{
const l=new URLSearchParams("?")
l.set("goback",window.location.href);
l.set("instance",well);
window.location.href="/login?"+l.toString();
})
if(!joinable.length){
const l=new URLSearchParams("?")
l.set("goback",window.location.href);
l.set("instance",well);
window.location.href="/login?"+l.toString();
}
table.append(td);
}
table.classList.add("accountSwitcher");
console.log(table);
document.body.append(table);
}
document.getElementById("AcceptInvite").addEventListener("click",showAccounts);

View File

@@ -29,7 +29,7 @@
</div>
<button type="submit">Login</button>
</form>
<a href="/register.html">Don't have an account?</a>
<a href="/register.html" id="switch">Don't have an account?</a>
</div>
<script src="/login.js" type="module"></script>
<script src="/login.js" type="module" ></script>
</body>

View File

@@ -1,12 +1,13 @@
import { Dialog } from "./dialog.js";
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
export {mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser}
export {mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser,getapiurls,adduser}
function setTheme(){
const name=localStorage.getItem("theme");
let name=localStorage.getItem("theme");
if(!name){
document.body.className="Dark-theme";
localStorage.setItem("theme","Dark");
name="Dark";
}
document.body.className=name+"-theme";
}
@@ -18,6 +19,7 @@ function getBulkUsers(){
}
return json;
}
function getBulkInfo(){
return JSON.parse(localStorage.getItem("userinfos"));
}
@@ -115,12 +117,39 @@ function adduser(user){
info.users[user.uid]=user;
info.currentuser=user.uid;
localStorage.setItem("userinfos",JSON.stringify(info));
return user;
}
const instancein=document.getElementById("instancein");
const instancein=document.getElementById("instancein") as HTMLInputElement;
let timeout;
let instanceinfo;
async function checkInstance(e){
const verify=document.getElementById("verify");;
async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:string,wellknown:string}|false>{
if(str[str.length-1]!=="/"){
str+="/"
}
let api:string;
try{
const info=await fetch(`${str}/.well-known/spacebar`).then((x) => x.json());
api=info.api;
}catch{
return false
}
const url = new URL(api);
try{
const info=await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then((x) => x.json());
return {
api: info.apiEndpoint,
gateway: info.gateway,
cdn: info.cdn,
wellknown: str,
};
}catch{
}
}
async function checkInstance(e:string){
const verify=document.getElementById("verify");
try{
verify.textContent="Checking Instance";
const instanceinfo=await setInstance((instancein as HTMLInputElement).value);
@@ -150,8 +179,8 @@ if(instancein){
}else{
checkInstance("https://spacebar.chat/");
}
}
}
async function login(username:string, password:string, captcha:string){
if(captcha===""){
@@ -215,15 +244,27 @@ async function login(username:string, password:string, captcha:string){
if(response.message){
alert(response.message)
}else{
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token});
window.location.href = '/channels/@me';
console.warn(response);
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token}).username=username;
const redir=new URLSearchParams(window.location.search).get("goback");
if(redir){
window.location.href = redir;
}else{
window.location.href = '/channels/@me';
}
}
})
}]]).show();
}else{
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token});
window.location.href = '/channels/@me';
return response.token;
console.warn(response);
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token}).username=username;
const redir=new URLSearchParams(window.location.search).get("goback");
if(redir){
window.location.href = redir;
}else{
window.location.href = '/channels/@me';
}
return "";
}
}
})
@@ -292,4 +333,14 @@ if ("serviceWorker" in navigator){
})
}
*/
const switchurl=document.getElementById("switch") as HTMLAreaElement;
if(switchurl){
switchurl.href+=window.location.search;
const instance=new URLSearchParams(window.location.search).get("instance");
console.log(instance);
if(instance){
instancein.value=instance;
checkInstance("");
}
}
export {checkInstance};

View File

@@ -53,7 +53,7 @@
</div>
<button type="submit" class="dontgrow">Create account</button>
</form>
<a href="/login.html">Already have an account?</a>
<a href="/login.html" id="switch">Already have an account?</a>
</div>
<script src="/register.js" type="module"></script>
</body>

View File

@@ -1,4 +1,4 @@
import {checkInstance} from "./login.js";
import {checkInstance, adduser} from "./login.js";
if(document.getElementById("register")){
document.getElementById("register").addEventListener("submit", registertry);
}
@@ -63,8 +63,14 @@ async function registertry(e){
document.getElementById("wrong").textContent=e.errors[Object.keys(e.errors)[0]]._errors[0].message;
}
}else{
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:email,token:e.token}).username=username;
localStorage.setItem("token",e.token);
window.location.href = '/channels/@me';
const redir=new URLSearchParams(window.location.search).get("goback");
if(redir){
window.location.href = redir;
}else{
window.location.href = '/channels/@me';
}
}
})
})

View File

@@ -1751,4 +1751,71 @@ form div{
}
.reactiondiv{
margin-left: .45in;
}
#invitebody{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--dialog-bg);
border-radius: .1in;
border: solid .03in var(--black);
padding:.2in;
box-sizing:border-box;
display:flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: .5in .2in;
gap: .1in;
width: 5.in;
}
#AcceptInvite{
padding: .1in .2in;
width: 100%;
text-align: center;
margin-top: .5in;
}
.invitediv{
height: .35in;
width: 3in;
border: solid .03in var(--black);
border-radius: .1in;
background: var(--textarea-bg);
span{
text-wrap:nowrap;
}
;
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
}
.inviteGuild{
width: .75in;
height:.75in;
background-color:var(--blank-bg);
display:flex;
justify-content: center;
align-items: center;
user-select: none;
font-size:.3in;
border-radius:.2in;
border:solid .03in var(--black);
}
.copybutton{
width:.25in;
}
.copycontainer{
position:absolute;
right:0;
background:var(--blank-bg);
padding:.05in;
border-radius:.1in;
border:solid .03in var(--black);
box-sizing:border-box;
box-shadow: .02in 0 .03in var(--black);
cursor:pointer;
}

View File

@@ -49,8 +49,8 @@ class User{
}
static contextmenu:Contextmenu=new Contextmenu("User Menu");
static setUpContextMenu(){
this.contextmenu.addbutton("Copy user id",function(){
navigator.clipboard.writeText(this.id.id);
this.contextmenu.addbutton("Copy user id",function(this:User){
navigator.clipboard.writeText(this.id);
});
this.contextmenu.addbutton("Message user",function(){
fetch(this.info.api+"/users/@me/channels",