Fixed Voice Channels type and display, updated vulnerable modules, fully re-worked dev docker compose file. Production usage not ready.
This commit is contained in:
parent
24ea281650
commit
ba9e975e10
@ -1,20 +1,36 @@
|
|||||||
FROM node:16-alpine3.14
|
# Use Node.js 18 with Alpine Linux as the base image
|
||||||
RUN addgroup app && adduser -SG app app
|
FROM node:18-alpine
|
||||||
RUN mkdir /app && chown app:app /app
|
RUN apk add --no-cache python3 make g++ && ln -sf python3 /usr/bin/python
|
||||||
|
|
||||||
|
# Create a new user and group for better security
|
||||||
|
RUN addgroup app && adduser -SG app app \
|
||||||
|
&& mkdir -p /app/frontend /app/backend /app/shared \
|
||||||
|
&& chown -R app:app /app
|
||||||
|
|
||||||
|
# Switch to the new user
|
||||||
USER app
|
USER app
|
||||||
|
|
||||||
|
# Set up the frontend environment
|
||||||
WORKDIR /app/frontend
|
WORKDIR /app/frontend
|
||||||
COPY --chown=app:app ./frontend/package*.json ./
|
COPY --chown=app:app ./frontend/package*.json ./
|
||||||
RUN ln -s ./frontend/src/types /app
|
RUN ln -s /app/frontend/src/types /app/shared/types \
|
||||||
RUN npm i
|
&& npm install --legacy-peer-deps --unsafe-perm
|
||||||
|
|
||||||
|
# Set up the backend environment
|
||||||
WORKDIR /app/backend
|
WORKDIR /app/backend
|
||||||
COPY --chown=app:app ./backend/package*.json ./
|
COPY --chown=app:app ./backend/package*.json ./
|
||||||
RUN npm i
|
RUN npm install --legacy-peer-deps --unsafe-perm
|
||||||
|
|
||||||
|
# Copy the remaining application files
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --chown=app:app . .
|
COPY --chown=app:app . .
|
||||||
|
RUN chown -R app:app /app
|
||||||
|
RUN chmod -R 777 /app/backend/upload
|
||||||
|
|
||||||
|
|
||||||
|
# Expose ports for frontend and backend applications
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
EXPOSE 4200
|
EXPOSE 3001
|
||||||
CMD ./bin/start-dev.sh
|
|
||||||
|
# Start the application
|
||||||
|
CMD ["sh", "./bin/start-dev.sh"]
|
||||||
|
51
README.md
51
README.md
@ -1,6 +1,6 @@
|
|||||||
# PVTChat - Messaging Made Simple.
|
# PVTChat - Messaging Made Simple.
|
||||||
PVTChat is an app, similar to Discord, but cooler.
|
PVTChat is an app, similar to Discord, but cooler.
|
||||||
Built with React, TypeScript, and Node.js.
|
Built with React, TypeScript, and Node.js (18).
|
||||||
Main point of PVT Chat is to fix accord bugs and continue maintenance for said app.
|
Main point of PVT Chat is to fix accord bugs and continue maintenance for said app.
|
||||||
|
|
||||||
**PVTChat is based on [acrd.app](https://github.com/theADAMJR/acrd.app), leave a star to original creator!**
|
**PVTChat is based on [acrd.app](https://github.com/theADAMJR/acrd.app), leave a star to original creator!**
|
||||||
@ -34,7 +34,17 @@ Main point of PVT Chat is to fix accord bugs and continue maintenance for said a
|
|||||||
mkdir -p assets/upload
|
mkdir -p assets/upload
|
||||||
```
|
```
|
||||||
5. In `backend` directory, configure `.env.example` and rename the file to `.env`
|
5. In `backend` directory, configure `.env.example` and rename the file to `.env`
|
||||||
|
6. In `frontend/env` directory, configure `.env.dev` and `.env.prod` file.
|
||||||
|
7. To run application in dev or production mode move back to project root directory and type:
|
||||||
|
```
|
||||||
|
# for development
|
||||||
|
docker-compose -f docker-compose.dev.yml up
|
||||||
|
# for production
|
||||||
|
docker-compose -f docker-compose.prod.yml up
|
||||||
|
# use -d tag to run it in the background
|
||||||
|
# use --build tag to build app
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@ -59,43 +69,10 @@ Main point of PVT Chat is to fix accord bugs and continue maintenance for said a
|
|||||||
- Delete your user and prevent it from being used to login
|
- Delete your user and prevent it from being used to login
|
||||||
- **and more** (of course)
|
- **and more** (of course)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
`backend/.env`
|
|
||||||
(dev with Docker)
|
|
||||||
|
|
||||||
```
|
|
||||||
EMAIL_ADDRESS="...@gmail.com"
|
|
||||||
EMAIL_PASSWORD="..."
|
|
||||||
MONGO_URI="mongodb://database/accord"
|
|
||||||
NODE_ENV="dev"
|
|
||||||
PORT=3000
|
|
||||||
WEBSITE_URL="http://localhost:4200"
|
|
||||||
SESSION_SECRET="Please ⭐ this repository."
|
|
||||||
```
|
|
||||||
|
|
||||||
`backend/test/.env`
|
|
||||||
(test without Docker)
|
|
||||||
|
|
||||||
```
|
|
||||||
API_URL="http://localhost:3001/api"
|
|
||||||
EMAIL_ADDRESS="...@gmail.com"
|
|
||||||
EMAIL_PASSWORD="..."
|
|
||||||
MONGO_URI="mongodb://localhost/accord-test"
|
|
||||||
NODE_ENV="dev"
|
|
||||||
PORT=3001
|
|
||||||
ROOT_ENDPOINT="http://localhost:3001"
|
|
||||||
WEBSITE_URL="http://localhost:4200"
|
|
||||||
SESSION_SECRET="Please ⭐ this repository."
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### App does not connect to MongoDB on Windows?
|
### App does not connect to MongoDB in Docker?
|
||||||
- Ensure MongoDB is installed.
|
- Ensure MongoDB is installed.
|
||||||
- If localhost does not work, use `mongodb://127.0.0.1:27017/accord`.
|
- If localhost does not work, use `mongodb://database/accord`.
|
||||||
- https://stackoverflow.com/a/73139137/8304458
|
|
||||||
|
@ -3,6 +3,6 @@ EMAIL_PASSWORD="password"
|
|||||||
MONGO_URI="mongodb://localhost/accord"
|
MONGO_URI="mongodb://localhost/accord"
|
||||||
NODE_ENV="dev"
|
NODE_ENV="dev"
|
||||||
PORT=3000
|
PORT=3000
|
||||||
WEBSITE_URL="http://localhost:4200"
|
WEBSITE_URL="http://localhost:3001"
|
||||||
SESSION_SECRET="Please ⭐ this repository."
|
SESSION_SECRET="Please ⭐ this repository."
|
||||||
RECAPTCHA_SECRET=""
|
RECAPTCHA_SECRET=""
|
2985
backend/package-lock.json
generated
2985
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -22,36 +22,52 @@ export default class Channels extends DBWrapper<string, ChannelDocument> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async create(options: Partial<Entity.Channel>): Promise<ChannelDocument> {
|
public async create(options: Partial<Entity.Channel>): Promise<ChannelDocument> {
|
||||||
|
const isVoice = options.type === 'VOICE';
|
||||||
return Channel.create({
|
return Channel.create({
|
||||||
_id: options.id ?? generateSnowflake(),
|
_id: options.id ?? generateSnowflake(),
|
||||||
name: 'chat',
|
name: options.name || (isVoice ? 'Voice Channel' : 'chat'),
|
||||||
position: await Channel.countDocuments({ guildId: options.guildId }),
|
position: await Channel.countDocuments({ guildId: options.guildId }),
|
||||||
type: 'TEXT',
|
type: options.type || 'TEXT',
|
||||||
|
userIds: isVoice ? [] : undefined,
|
||||||
...options as any,
|
...options as any,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createDM(userIds: string[]) {
|
public async createDM(userIds: string[]) {
|
||||||
return this.create({ userIds }) as Promise<DMChannelDocument>;
|
return this.create({ userIds, type: 'DM' }) as Promise<DMChannelDocument>;
|
||||||
}
|
}
|
||||||
public async createText(guildId: string) {
|
|
||||||
return this.create({ guildId }) as Promise<TextChannelDocument>;
|
public async createText(guildId: string, name?: string) {
|
||||||
|
return this.create({
|
||||||
|
guildId,
|
||||||
|
type: 'TEXT',
|
||||||
|
name: name || 'chat'
|
||||||
|
}) as Promise<TextChannelDocument>;
|
||||||
}
|
}
|
||||||
public async createVoice(guildId: string) {
|
|
||||||
return this.create({ guildId, type: 'VOICE' }) as Promise<VoiceChannelDocument>;
|
public async createVoice(guildId: string, name?: string) {
|
||||||
|
return this.create({
|
||||||
|
guildId,
|
||||||
|
type: 'VOICE',
|
||||||
|
name: name || 'Voice Channel',
|
||||||
|
userIds: []
|
||||||
|
}) as Promise<VoiceChannelDocument>;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async joinVC(channel: VoiceChannelDocument, userId: string) {
|
public async joinVC(channel: VoiceChannelDocument, userId: string) {
|
||||||
|
if (!channel.userIds) channel.userIds = [];
|
||||||
channel.userIds.push(userId);
|
channel.userIds.push(userId);
|
||||||
return await channel.save();
|
return await channel.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async leaveVC(channel: VoiceChannelDocument, userId: string) {
|
public async leaveVC(channel: VoiceChannelDocument, userId: string) {
|
||||||
|
if (!channel.userIds) return channel;
|
||||||
const index = channel.userIds.indexOf(userId);
|
const index = channel.userIds.indexOf(userId);
|
||||||
channel.userIds.splice(index, 1);
|
if (index > -1) channel.userIds.splice(index, 1);
|
||||||
return await channel.save();
|
return await channel.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSystem(guildId: string) {
|
public async getSystem(guildId: string) {
|
||||||
return await Channel.findOne({ guildId, type: 'TEXT' });
|
return await Channel.findOne({ guildId, type: 'TEXT' });
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -114,8 +114,8 @@ export const User = model<UserDocument>('user', new Schema({
|
|||||||
AttemptTooSoonError: 'Account is currently locked. Try again later',
|
AttemptTooSoonError: 'Account is currently locked. Try again later',
|
||||||
TooManyAttemptsError: 'Account locked due to too many failed login attempts',
|
TooManyAttemptsError: 'Account locked due to too many failed login attempts',
|
||||||
NoSaltValueStoredError: 'Authentication not possible. No salt value stored',
|
NoSaltValueStoredError: 'Authentication not possible. No salt value stored',
|
||||||
IncorrectPasswordError: 'Password or username are incorrect',
|
IncorrectPasswordError: 'Password is incorrect',
|
||||||
IncorrectUsernameError: 'Password or username are incorrect',
|
IncorrectUsernameError: 'Username is incorrect',
|
||||||
MissingUsernameError: 'No username was given',
|
MissingUsernameError: 'No username was given',
|
||||||
UserExistsError: 'Email is already in use',
|
UserExistsError: 'Email is already in use',
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ export class REST {
|
|||||||
applyRoutes(app, prefix);
|
applyRoutes(app, prefix);
|
||||||
applyErrorHandling(app, prefix);
|
applyErrorHandling(app, prefix);
|
||||||
|
|
||||||
const port = process.env.PORT || 8080;
|
const port = process.env.PORT || 3000;
|
||||||
const server = app.listen(port, async () => {
|
const server = app.listen(port, async () => {
|
||||||
log.info(`API is running on port ${port}`);
|
log.info(`API is running on port ${port}`);
|
||||||
await deps.webSocket.init(server);
|
await deps.webSocket.init(server);
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
"strictPropertyInitialization": false,
|
"strictPropertyInitialization": false,
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"watch": true,
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src",
|
"src",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
cd /app/backend && npm run start:dev &
|
cd /app/backend && PORT=3000 NODE_ENV=dev npm run start:dev &
|
||||||
cd /app/frontend && npm run start:dev
|
cd /app/frontend && DISABLE_ESLINT_PLUGIN=true NODE_ENV=dev PORT=3001 WDS_SOCKET_PORT=3001 npm run start:dev
|
||||||
|
|
||||||
fg %1
|
wait
|
@ -1,22 +1,24 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
container_name: accord_database
|
container_name: pvtchat_database
|
||||||
image: mongo:5-focal
|
image: mongo:5-focal
|
||||||
ports: [27018:27017]
|
ports: [27018:27017]
|
||||||
volumes: [accord:/data/db]
|
volumes: [pvtchat:/data/db]
|
||||||
|
restart: unless-stopped
|
||||||
app:
|
app:
|
||||||
container_name: accord_app
|
container_name: pvtchat_app
|
||||||
depends_on: [database]
|
depends_on: [database]
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: Dockerfile.dev
|
dockerfile: Dockerfile.dev
|
||||||
ports: [3000:3000, 4200:4200]
|
ports: [3000:3000, 3001:3001]
|
||||||
env_file: [./backend/.env, ./frontend/env/.env.dev]
|
env_file: [./backend/.env, ./frontend/env/.env.dev]
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/src:/app/backend/src
|
- ./backend/src:/app/backend/src
|
||||||
- ./backend/assets:/app/backend/assets
|
- ./backend/assets:/app/backend/assets
|
||||||
- ./backend/logs:/app/backend/logs
|
- ./backend/logs:/app/backend/logs
|
||||||
- ./frontend/src:/app/frontend/src
|
- ./frontend/src:/app/frontend/src
|
||||||
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
accord:
|
pvtchat:
|
@ -1,13 +1,13 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
container_name: accord_database
|
container_name: pvtchat_database
|
||||||
image: mongo:5-focal
|
image: mongo:5-focal
|
||||||
ports: [27017:27017]
|
ports: [27017:27017]
|
||||||
volumes: [accord:/data/db]
|
volumes: [pvtchat:/data/db]
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
app:
|
app:
|
||||||
container_name: accord_app
|
container_name: pvtchat_app
|
||||||
depends_on: [database]
|
depends_on: [database]
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
@ -21,4 +21,4 @@ services:
|
|||||||
- ./frontend/src:/app/frontend/src
|
- ./frontend/src:/app/frontend/src
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
accord:
|
pvtchat:
|
Loading…
x
Reference in New Issue
Block a user