working group controller
This commit is contained in:
parent
bac7b6f275
commit
22340d8a96
19 changed files with 253 additions and 12 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -146,3 +146,4 @@ dist
|
|||
# misc
|
||||
.DS_Store
|
||||
|
||||
.idea
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# chatbridge
|
||||
|
||||
Testing running
|
||||
|
||||
Invite people to a bridged nextcloud chat with a token
|
||||
|
||||
Using matterbridge - https://github.com/42wim/matterbridge
|
||||
|
|
11
config/custom-environment-variables.ts
Executable file
11
config/custom-environment-variables.ts
Executable file
|
@ -0,0 +1,11 @@
|
|||
export default {
|
||||
port: 'PORT',
|
||||
postgresConfig: {
|
||||
host: 'POSTGRES_HOST',
|
||||
port: 'POSTGRES_PORT',
|
||||
username: 'POSTGRES_USER',
|
||||
password: 'POSTGRES_PASSWORD',
|
||||
database: 'POSTGRES_DB',
|
||||
},
|
||||
admin_token: 'ADMIN_TOKEN'
|
||||
}
|
7
config/defaults.ts
Normal file → Executable file
7
config/defaults.ts
Normal file → Executable file
|
@ -1,10 +1,3 @@
|
|||
export default {
|
||||
port: '8999',
|
||||
postgresConfig: {
|
||||
host: '127.0.0.1',
|
||||
port: '6500',
|
||||
username: 'POSTGRES_USER',
|
||||
password: 'POSTGRES_PASSWORD',
|
||||
database: 'POSTGRES_DB',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -6,3 +6,5 @@ POSTGRES_PORT=6500
|
|||
POSTGRES_USER=
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_DB=
|
||||
|
||||
ADMIN_TOKEN=
|
|
@ -7,7 +7,7 @@
|
|||
"author": "sneakers-the-rat <JLSaunders987@gmail.com>",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
"start": "ts-node-dev --respawn --transpile-only --exit-child src/app.ts",
|
||||
"start": "ts-node-dev --respawn --transpile-only --exit-child server/app.ts",
|
||||
"build": "tsc -p .",
|
||||
"typeorm": "typeorm-ts-node-commonjs",
|
||||
"migrate": "rm -rf build && yarn build && yarn typeorm migration:generate ./src/migrations/added-user-entity -d ./src/utils/data-source.ts",
|
||||
|
@ -32,6 +32,7 @@
|
|||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"redis": "^4.6.7",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"typeorm": "^0.3.17",
|
||||
"typescript": "^5.1.6",
|
||||
"zod": "^3.21.4"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
require('dotenv').config();
|
||||
import express, { NextFunction, Request, Response } from 'express';
|
||||
import config from 'config';
|
||||
|
@ -5,6 +7,7 @@ import cors from 'cors';
|
|||
import { AppDataSource } from './db/data-source';
|
||||
import AppError from './errors/appError';
|
||||
|
||||
import groupRoutes from "./routes/group.routes";
|
||||
|
||||
|
||||
|
||||
|
@ -12,9 +15,23 @@ AppDataSource.initialize()
|
|||
.then(async () => {
|
||||
|
||||
const app = express();
|
||||
app.use(express.json({limit: "10kb"}));
|
||||
|
||||
app.get('/healthcheck', async (_, res: Response) => {
|
||||
res.status(200).json({
|
||||
status: "online!!!!"
|
||||
})
|
||||
})
|
||||
|
||||
app.use('/groups', groupRoutes);
|
||||
|
||||
app.all('*', (req: Request, res: Response, next: NextFunction) => {
|
||||
next(new AppError(404, `Route ${req.originalUrl} not found`));
|
||||
});
|
||||
|
||||
const port = config.get<number>('port');
|
||||
app.listen(port);
|
||||
|
||||
console.log(`Server started on port: ${port}`)
|
||||
|
||||
})
|
||||
|
|
0
server/controllers/bridge.controller.ts
Normal file
0
server/controllers/bridge.controller.ts
Normal file
0
server/controllers/channel.controller.ts
Normal file
0
server/controllers/channel.controller.ts
Normal file
52
server/controllers/group.controller.ts
Normal file
52
server/controllers/group.controller.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import {NextFunction, Request, Response} from 'express';
|
||||
import {CreateGroupInput, GetGroupInput, getGroupSchema} from "../schemas/group.schema";
|
||||
import config from 'config';
|
||||
import {Group} from "../entities/group.entity";
|
||||
import AppError from "../errors/appError";
|
||||
|
||||
import {AppDataSource} from "../db/data-source";
|
||||
|
||||
const groupRepository = AppDataSource.getRepository(Group)
|
||||
|
||||
export const createGroupHandler = async(
|
||||
req: Request<{}, {}, CreateGroupInput>,
|
||||
res: Response
|
||||
) => {
|
||||
console.log(req.body);
|
||||
const admin_token = config.get<string>('admin_token');
|
||||
if (req.body.token !== admin_token){
|
||||
return res.status(403).json({
|
||||
status: 'fail',
|
||||
message: 'Not authorized to create group without correct admin token'
|
||||
})
|
||||
}
|
||||
|
||||
let group = await groupRepository.create({...req.body})
|
||||
let result = await groupRepository.save(group)
|
||||
return res.send(result)
|
||||
|
||||
}
|
||||
|
||||
export const getGroupHandler = async(
|
||||
req: Request<GetGroupInput>,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
try {
|
||||
let group = await groupRepository.findOneBy({name: req.params.name})
|
||||
|
||||
if (!group) {
|
||||
return next(new AppError(404, "No group with matching name exists"))
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
status: 'success',
|
||||
data: {
|
||||
group
|
||||
}
|
||||
})
|
||||
|
||||
} catch (err: any) {
|
||||
next(err);
|
||||
}
|
||||
};
|
|
@ -14,7 +14,7 @@ const postgresConfig = config.get<{
|
|||
export const AppDataSource = new DataSource({
|
||||
...postgresConfig,
|
||||
type: 'postgres',
|
||||
synchronize: false,
|
||||
synchronize: true,
|
||||
logging: false,
|
||||
entities: ['server/entities/**/*.entity{.ts,.js}'],
|
||||
migrations: ['server/migrations/**/*{.ts,.js}'],
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
import { Entity, Column, Index, OneToMany, TableInheritance, ChildEntity } from 'typeorm';
|
||||
import Model from './model.entity';
|
||||
import { Channel } from "./channel.entity";
|
||||
|
||||
export enum BridgeEnumType {
|
||||
SLACK = 'slack',
|
||||
DISCORD = 'discord',
|
||||
MATRIX = 'matrix'
|
||||
}
|
||||
|
||||
@Entity('bridges')
|
||||
@TableInheritance({column: { type: "varchar", name: "type" }})
|
||||
export class Bridge extends Model {
|
||||
@Column({
|
||||
type: "enum",
|
||||
enum: BridgeEnumType
|
||||
})
|
||||
Protocol: string;
|
||||
|
||||
@Column()
|
||||
Label: string;
|
||||
|
||||
@Column({
|
||||
default: true
|
||||
})
|
||||
PrefixMessagesWithNick: boolean;
|
||||
|
||||
// See https://github.com/42wim/matterbridge/wiki/Settings#prefixmessageswithnick
|
||||
@Column({
|
||||
default: "[{LABEL}] <{NICK}> "
|
||||
})
|
||||
RemoteNickFormat: string;
|
||||
|
||||
@Column({
|
||||
unique: true
|
||||
})
|
||||
Token: string;
|
||||
|
||||
@OneToMany(() => Channel, (channel) => channel.bridge)
|
||||
channels: Channel[]
|
||||
|
||||
}
|
||||
|
||||
@ChildEntity()
|
||||
export class MatrixBridge extends Bridge {
|
||||
// Matrix-specific
|
||||
@Column()
|
||||
Server: string;
|
||||
|
||||
@Column()
|
||||
Login: string;
|
||||
|
||||
@Column()
|
||||
Password: string;
|
||||
}
|
18
server/entities/channel.entity.ts
Normal file
18
server/entities/channel.entity.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { Entity, Column, Index, ManyToOne, OneToOne } from 'typeorm';
|
||||
import Model from './model.entity';
|
||||
import { Bridge } from "./bridge.entity";
|
||||
import { Group } from "./group.entity";
|
||||
|
||||
@Entity('channels')
|
||||
export class Channel extends Model {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToOne(() => Bridge, (bridge) => bridge.channels)
|
||||
bridge: Bridge
|
||||
|
||||
@ManyToOne(() => Group, (group) => group.channels)
|
||||
group: Group
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Entity, Column, Index, OneToMany } from 'typeorm';
|
||||
import Model from './model.entity';
|
||||
import { Channel } from "./channel.entity";
|
||||
|
||||
@Entity('groups')
|
||||
export class Group extends Model {
|
||||
@Column({
|
||||
unique: true
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column({
|
||||
default: true
|
||||
})
|
||||
enable: boolean;
|
||||
|
||||
@OneToMany(() => Channel, (channel) => channel.bridge)
|
||||
channels: Channel[]
|
||||
|
||||
}
|
|
@ -14,4 +14,6 @@ export default abstract class Model extends BaseEntity {
|
|||
|
||||
@UpdateDateColumn()
|
||||
updated_at: Date;
|
||||
|
||||
|
||||
}
|
||||
|
|
24
server/middleware/validate.ts
Normal file
24
server/middleware/validate.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { Request, Response, NextFunction } from 'express';
|
||||
import { AnyZodObject, ZodError } from 'zod';
|
||||
|
||||
export const validate =
|
||||
(schema: AnyZodObject) =>
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
schema.parse({
|
||||
params: req.params,
|
||||
query: req.query,
|
||||
body: req.body,
|
||||
});
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
status: 'fail',
|
||||
errors: error.errors,
|
||||
});
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
};
|
21
server/routes/group.routes.ts
Normal file
21
server/routes/group.routes.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import express from 'express';
|
||||
|
||||
import {
|
||||
createGroupHandler,
|
||||
getGroupHandler
|
||||
} from "../controllers/group.controller";
|
||||
|
||||
import {
|
||||
createGroupSchema
|
||||
} from "../schemas/group.schema";
|
||||
|
||||
import { validate } from "../middleware/validate";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router
|
||||
.route('/')
|
||||
.post(createGroupHandler)
|
||||
.get(getGroupHandler)
|
||||
|
||||
export default router
|
21
server/schemas/group.schema.ts
Normal file
21
server/schemas/group.schema.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { object, string, TypeOf } from 'zod';
|
||||
|
||||
export const createGroupSchema = object({
|
||||
body: object({
|
||||
name: string({
|
||||
required_error: "Name for group required"
|
||||
}),
|
||||
token: string({
|
||||
required_error: "Administration token required for creating groups"
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
export const getGroupSchema = object({
|
||||
name: string({
|
||||
required_error: "Name of group required to get group"
|
||||
})
|
||||
})
|
||||
|
||||
export type CreateGroupInput = TypeOf<typeof createGroupSchema>['body'];
|
||||
export type GetGroupInput = TypeOf<typeof getGroupSchema>;
|
|
@ -11,7 +11,8 @@
|
|||
"skipLibCheck": true,
|
||||
"outDir": "./build",
|
||||
"rootDir": ".",
|
||||
"include": ["server/**/*"],
|
||||
"exclude": ["node_modules", "roles"]
|
||||
}
|
||||
|
||||
},
|
||||
"include": ["server/**/*"],
|
||||
"exclude": ["node_modules", "roles"]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue