tagging
This commit is contained in:
parent
85643184ea
commit
2112f730a8
|
@ -0,0 +1 @@
|
||||||
|
topButtons: none
|
|
@ -0,0 +1,18 @@
|
||||||
|
admin:
|
||||||
|
text: ADMIN
|
||||||
|
color: "#ff5555"
|
||||||
|
trialmod:
|
||||||
|
text: TRIAL MOD
|
||||||
|
color: "#ffbb00"
|
||||||
|
mod:
|
||||||
|
text: MOD
|
||||||
|
color: "#00aa00"
|
||||||
|
media:
|
||||||
|
text: MEDIA
|
||||||
|
color: "#ff55ff"
|
||||||
|
bot:
|
||||||
|
text: BOT
|
||||||
|
color: "#5555ff"
|
||||||
|
owner:
|
||||||
|
text: OWNER
|
||||||
|
color: "#aa0000"
|
|
@ -11,7 +11,7 @@ defaultFlags:
|
||||||
|
|
||||||
# Whether or not to allow users to change their color.
|
# Whether or not to allow users to change their color.
|
||||||
# Based on some reports, the MPP.com server stopped allowing this around 2016.
|
# Based on some reports, the MPP.com server stopped allowing this around 2016.
|
||||||
enableColorChanging: true
|
enableColorChanging: false
|
||||||
|
|
||||||
# Whether to allow custom data inside note messages.
|
# Whether to allow custom data inside note messages.
|
||||||
# This was in the original server, but not in MPP.net's server do to stricter sanitization.
|
# This was in the original server, but not in MPP.net's server do to stricter sanitization.
|
||||||
|
|
|
@ -12,13 +12,13 @@ datasource db {
|
||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @unique @map("_id")
|
id String @id @unique @map("_id")
|
||||||
name String @default("Anonymous")
|
name String @default("Anonymous")
|
||||||
color String @default("#ffffff")
|
color String @default("#ffffff")
|
||||||
flags String @default("{}") // JSON flags object
|
flags String @default("{}") // JSON flags object
|
||||||
tag String // JSON tag
|
tag String? // JSON tag
|
||||||
tokens String @default("[]") // JSON tokens
|
tokens String @default("[]") // JSON tokens
|
||||||
group String @default("default") // Permission group
|
group String @default("default") // Permission group
|
||||||
}
|
}
|
||||||
|
|
||||||
model ChatHistory {
|
model ChatHistory {
|
||||||
|
@ -34,7 +34,8 @@ model Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
model Role {
|
model Role {
|
||||||
userId String @unique
|
id Int @id @unique @default(autoincrement())
|
||||||
|
userId String
|
||||||
roleId String
|
roleId String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,7 @@ export class Channel extends EventEmitter {
|
||||||
|
|
||||||
this.on("user data update", (user: User) => {
|
this.on("user data update", (user: User) => {
|
||||||
try {
|
try {
|
||||||
|
if (!this.ppl.map(p => p._id).includes(user.id)) return;
|
||||||
if (typeof user.name !== "string") return;
|
if (typeof user.name !== "string") return;
|
||||||
if (typeof user.color !== "string") return;
|
if (typeof user.color !== "string") return;
|
||||||
if (typeof user.id !== "string") return;
|
if (typeof user.id !== "string") return;
|
||||||
|
|
|
@ -15,7 +15,8 @@ export const config = ConfigManager.loadConfig<Record<string, string[]>>(
|
||||||
"usersetOthers",
|
"usersetOthers",
|
||||||
"siteBan",
|
"siteBan",
|
||||||
"siteBanAnyReason",
|
"siteBanAnyReason",
|
||||||
"siteBanAnyDuration"
|
"siteBanAnyDuration",
|
||||||
|
"event.admin.*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
);
|
);
|
|
@ -29,7 +29,7 @@ export async function giveRole(userId: string, roleId: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeRole(userId: string, roleId: string) {
|
export async function removeRole(userId: string, roleId: string) {
|
||||||
return await prisma.role.delete({
|
return await prisma.role.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId,
|
||||||
roleId
|
roleId
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { loadForcedStartupChannels } from "./channel/forceLoad";
|
||||||
import { Logger } from "./util/Logger";
|
import { Logger } from "./util/Logger";
|
||||||
// docker hates this next one
|
// docker hates this next one
|
||||||
import { startReadline } from "./util/readline";
|
import { startReadline } from "./util/readline";
|
||||||
import { loadDefaultPermissions } from "./data/permission";
|
import { loadDefaultPermissions } from "./data/permissions";
|
||||||
|
|
||||||
// wrapper for some reason
|
// wrapper for some reason
|
||||||
export function startServer() {
|
export function startServer() {
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
loadDefaultPermissions,
|
loadDefaultPermissions,
|
||||||
removeAllRolePermissions,
|
removeAllRolePermissions,
|
||||||
removeRolePermission
|
removeRolePermission
|
||||||
} from "~/data/permission";
|
} from "~/data/permissions";
|
||||||
|
import { builtinTags, removeTag, setBuiltinTag } from "../tags";
|
||||||
|
|
||||||
Command.addCommand(
|
Command.addCommand(
|
||||||
new Command(["help", "h", "commands", "cmds"], "help", msg => {
|
new Command(["help", "h", "commands", "cmds"], "help", msg => {
|
||||||
|
@ -94,11 +95,19 @@ Command.addCommand(
|
||||||
|
|
||||||
if (msg.args[1] === "add") {
|
if (msg.args[1] === "add") {
|
||||||
if (!msg.args[3]) return "No role id provided";
|
if (!msg.args[3]) return "No role id provided";
|
||||||
|
|
||||||
await giveRole(msg.args[2], msg.args[3]);
|
await giveRole(msg.args[2], msg.args[3]);
|
||||||
|
await setBuiltinTag(msg.args[2], msg.args[3]);
|
||||||
|
|
||||||
return `Gave user ${msg.args[2]} role ${msg.args[3]}`;
|
return `Gave user ${msg.args[2]} role ${msg.args[3]}`;
|
||||||
} else if (msg.args[1] === "remove") {
|
} else if (msg.args[1] === "remove") {
|
||||||
if (!msg.args[3]) return "No role id provided";
|
if (!msg.args[3]) return "No role id provided";
|
||||||
await removeRole(msg.args[2], msg.args[3]);
|
await removeRole(msg.args[2], msg.args[3]);
|
||||||
|
|
||||||
|
if (Object.keys(builtinTags).includes(msg.args[3])) {
|
||||||
|
await removeTag(msg.args[2]);
|
||||||
|
}
|
||||||
|
|
||||||
return `Removed role ${msg.args[3]} from ${msg.args[2]}`;
|
return `Removed role ${msg.args[3]} from ${msg.args[2]}`;
|
||||||
} else if (msg.args[1] === "list") {
|
} else if (msg.args[1] === "list") {
|
||||||
const roles = await getRoles(msg.args[2]);
|
const roles = await getRoles(msg.args[2]);
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { Socket } from "~/ws/Socket";
|
||||||
|
import { ConfigManager } from "./config";
|
||||||
|
import { Tag } from "./types";
|
||||||
|
import { readUser, updateUser } from "~/data/user";
|
||||||
|
import { prisma } from "~/data/prisma";
|
||||||
|
import { User } from "@prisma/client";
|
||||||
|
import { ChannelList } from "~/channel/ChannelList";
|
||||||
|
|
||||||
|
export const builtinTags = ConfigManager.loadConfig<Record<string, Tag>>(
|
||||||
|
"config/tags.yml",
|
||||||
|
{
|
||||||
|
admin: {
|
||||||
|
text: "ADMIN",
|
||||||
|
color: "#ff5555"
|
||||||
|
},
|
||||||
|
trialmod: {
|
||||||
|
text: "TRIAL MOD",
|
||||||
|
color: "#ffbb00"
|
||||||
|
},
|
||||||
|
mod: {
|
||||||
|
text: "MOD",
|
||||||
|
color: "#00aa00"
|
||||||
|
},
|
||||||
|
media: {
|
||||||
|
text: "MEDIA",
|
||||||
|
color: "#ff55ff"
|
||||||
|
},
|
||||||
|
bot: {
|
||||||
|
text: "BOT",
|
||||||
|
color: "#5555ff"
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
text: "OWNER",
|
||||||
|
color: "#aa0000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function propogateUser(user: User) {
|
||||||
|
const channelList = ChannelList.getList();
|
||||||
|
|
||||||
|
for (const ch of channelList) {
|
||||||
|
ch.emit("user data update", user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setBuiltinTag(userId: string, tagId: string) {
|
||||||
|
const user = await readUser(userId);
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
const tag = builtinTags[tagId];
|
||||||
|
if (!tag) return;
|
||||||
|
|
||||||
|
user.tag = JSON.stringify(tag);
|
||||||
|
await updateUser(user.id, user);
|
||||||
|
|
||||||
|
propogateUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setTag(userId: string, tag: Tag) {
|
||||||
|
const user = await readUser(userId);
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
user.tag = JSON.stringify(tag);
|
||||||
|
await updateUser(user.id, user);
|
||||||
|
|
||||||
|
propogateUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removeTag(userId: string) {
|
||||||
|
const user = await readUser(userId);
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
user.tag = "";
|
||||||
|
await updateUser(user.id, user);
|
||||||
|
|
||||||
|
propogateUser(user);
|
||||||
|
}
|
|
@ -231,6 +231,18 @@ declare interface ServerEvents {
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setcolor: {
|
||||||
|
m: "setcolor";
|
||||||
|
_id: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
setname: {
|
||||||
|
m: "setname";
|
||||||
|
_id: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
user_flag: {
|
user_flag: {
|
||||||
m: "user_flag";
|
m: "user_flag";
|
||||||
_id: string;
|
_id: string;
|
||||||
|
|
|
@ -41,8 +41,9 @@ import {
|
||||||
getUserPermissions,
|
getUserPermissions,
|
||||||
hasPermission,
|
hasPermission,
|
||||||
validatePermission
|
validatePermission
|
||||||
} from "~/data/permission";
|
} from "~/data/permissions";
|
||||||
import { getRoles } from "~/data/role";
|
import { getRoles } from "~/data/role";
|
||||||
|
import { setTag } from "~/util/tags";
|
||||||
|
|
||||||
const logger = new Logger("Sockets");
|
const logger = new Logger("Sockets");
|
||||||
|
|
||||||
|
@ -792,10 +793,8 @@ export class Socket extends EventEmitter {
|
||||||
**/
|
**/
|
||||||
public setTag(text: string, color: string) {
|
public setTag(text: string, color: string) {
|
||||||
//logger.debug("Setting tag:", text, color);
|
//logger.debug("Setting tag:", text, color);
|
||||||
const user = this.getUser();
|
if (!this.user) return;
|
||||||
if (!user) return;
|
setTag(this.user.id, { text, color });
|
||||||
user.tag = JSON.stringify({ text, color });
|
|
||||||
updateUser(this.getUserID(), user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -836,6 +835,11 @@ export class Socket extends EventEmitter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this socket has a given permission
|
||||||
|
* @param perm Permission string
|
||||||
|
* @returns Whether this socket has the given permission
|
||||||
|
*/
|
||||||
public async hasPermission(perm: string) {
|
public async hasPermission(perm: string) {
|
||||||
if (!this.user) return false;
|
if (!this.user) return false;
|
||||||
|
|
||||||
|
@ -844,6 +848,8 @@ export class Socket extends EventEmitter {
|
||||||
for (const permission of permissions) {
|
for (const permission of permissions) {
|
||||||
if (validatePermission(perm, permission)) return true;
|
if (validatePermission(perm, permission)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import type { ServerEventListener, ServerEvents } from "../util/types";
|
import type { EventID, ServerEventListener, ServerEvents } from "../util/types";
|
||||||
|
|
||||||
export class EventGroup {
|
export class EventGroup {
|
||||||
public eventList = new Array<ServerEventListener<keyof ServerEvents>>();
|
public eventList = new Array<ServerEventListener<any>>();
|
||||||
constructor(public id: string) {}
|
constructor(public id: string) {}
|
||||||
|
|
||||||
public add(listener: ServerEventListener<keyof ServerEvents>) {
|
public add(listener: ServerEventListener<any>) {
|
||||||
this.eventList.push(listener);
|
this.eventList.push(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addMany(...listeners: ServerEventListener<keyof ServerEvents>[]) {
|
public addMany(...listeners: ServerEventListener<any>[]) {
|
||||||
for (const l of listeners) this.add(l);
|
for (const l of listeners) this.add(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove(listener: ServerEventListener<keyof ServerEvents>) {
|
public remove(listener: ServerEventListener<any>) {
|
||||||
this.eventList.splice(this.eventList.indexOf(listener), 1);
|
this.eventList.splice(this.eventList.indexOf(listener), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { getUserPermissions } from "~/data/permission";
|
import { getUserPermissions } from "~/data/permissions";
|
||||||
import { Logger } from "~/util/Logger";
|
import { Logger } from "~/util/Logger";
|
||||||
import { getMOTD } from "~/util/motd";
|
import { getMOTD } from "~/util/motd";
|
||||||
import { createToken, getToken, validateToken } from "~/util/token";
|
import { createToken, getToken, validateToken } from "~/util/token";
|
||||||
|
|
|
@ -14,7 +14,7 @@ export function handleMessage(socket: Socket, text: string) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"Received message that isn't an array! --",
|
"Received message that isn't an array! --",
|
||||||
transmission,
|
transmission,
|
||||||
" -- from",
|
"-- from",
|
||||||
socket.getUserID()
|
socket.getUserID()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,6 +8,8 @@ import env from "../util/env";
|
||||||
import { getMOTD } from "../util/motd";
|
import { getMOTD } from "../util/motd";
|
||||||
import nunjucks from "nunjucks";
|
import nunjucks from "nunjucks";
|
||||||
import type { ServerWebSocket } from "bun";
|
import type { ServerWebSocket } from "bun";
|
||||||
|
import { ConfigManager } from "~/util/config";
|
||||||
|
import { config as usersConfig } from "./usersConfig";
|
||||||
|
|
||||||
const logger = new Logger("WebSocket Server");
|
const logger = new Logger("WebSocket Server");
|
||||||
|
|
||||||
|
@ -15,6 +17,17 @@ const logger = new Logger("WebSocket Server");
|
||||||
// for checking if they visited the site and are also connected to the websocket
|
// for checking if they visited the site and are also connected to the websocket
|
||||||
const httpIpCache = new Map<string, number>();
|
const httpIpCache = new Map<string, number>();
|
||||||
|
|
||||||
|
interface IFrontendConfig {
|
||||||
|
topButtons: "original" | "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = ConfigManager.loadConfig<IFrontendConfig>(
|
||||||
|
"config/frontend.yml",
|
||||||
|
{
|
||||||
|
topButtons: "original"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a rendered version of the index file
|
* Get a rendered version of the index file
|
||||||
* @returns Response with html in it
|
* @returns Response with html in it
|
||||||
|
@ -29,7 +42,9 @@ async function getIndex() {
|
||||||
const index = Bun.file("./public/index.html");
|
const index = Bun.file("./public/index.html");
|
||||||
|
|
||||||
const rendered = nunjucks.renderString(await index.text(), {
|
const rendered = nunjucks.renderString(await index.text(), {
|
||||||
motd: getMOTD()
|
motd: getMOTD(),
|
||||||
|
config,
|
||||||
|
usersConfig
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = new Response(rendered);
|
const response = new Response(rendered);
|
||||||
|
@ -38,7 +53,7 @@ async function getIndex() {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerWebSocketMPP = ServerWebSocket<{ ip: string, socket: Socket }>
|
type ServerWebSocketMPP = ServerWebSocket<{ ip: string; socket: Socket }>;
|
||||||
|
|
||||||
export const app = Bun.serve<{ ip: string }>({
|
export const app = Bun.serve<{ ip: string }>({
|
||||||
port: env.PORT,
|
port: env.PORT,
|
||||||
|
|
Loading…
Reference in New Issue