diff --git a/.gitignore b/.gitignore
index c51ef9ba..5fbe08ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
+backups
+build
+dist
+node_modules
+storage
+uploads
.env.json
-build/
-dist/
-node_modules/
.idea
.vscode
diff --git a/Dockerfile b/Dockerfile
index af8a7f08..e7008681 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -29,7 +29,7 @@ RUN ln -s /var/skychat/storage ./storage
RUN ln -s /var/skychat/uploads ./uploads
# Copy build configuration
-COPY package*.json gulpfile.js tsconfig.*.json webpack.config.js ./
+COPY package*.json gulpfile.js tsconfig.json webpack.config.js ./
# Copy application .env file
COPY .env.json ./
diff --git a/README.md b/README.md
index 0d482ce6..dd030f21 100644
--- a/README.md
+++ b/README.md
@@ -61,38 +61,32 @@ This is not all, but to discover all features, you may as well launch an instanc
## How to install
-### Install and run
+### Install in 30 seconds
If using docker you need:
-- docker & docker-compose
+- docker
+- docker-compose
If not using docker, ensure you have the following installed on your system:
-- nodejs >= 10 and npm
-- sqlite3
+- nodejs >= 10
+- sqlite3, zip, ffmpeg (e.g. `apt install -y sqlite3 zip ffmpeg`)
-Then, follow these steps:
+Then, follow these 2 steps:
```bash
-# 1. Clone the repository
-git clone https://github.com/skychatorg/skychat.git
-cd skychat
+# 1. Use the autoinstall script (Clones the repository then executes scripts/setup.sh)
+bash <(wget -q https://raw.githubusercontent.com/skychatorg/skychat/master/scripts/autoinstall.sh -O -) && cd skychat
-# 2. Generates the .env.json and config files in config/
-bash scripts/setup.sh
-
-# 3. (Choose only one) Run the app
-# Run with docker:
+# 2.A. Run the app in docker
bash scripts/docker-start.sh
-# Run on current host
-npm i && npm run start
+# 2.B. Run the app on your local host
+npm i && npm start
```
### Application setup
-By default, the application will be listening to `localhost:8080` and assume it is accessed from `http://localhost:8080`. In order to customize the domain name of your SkyChat application, you will need to edit the `.env.json` file. The fields in the .env.json contain private information related to the application.
-
-The semantic of these fields are defined below:
+By default, the application will be listening to `localhost:8080` and assume it is accessed from `http://localhost:8080`. In order to customize the domain name of your SkyChat application, edit the `.env.json` file. The fields in the .env.json contain the private variables of the application, listed below:
| field | type | default | semantic |
@@ -127,15 +121,15 @@ Using the Youtube API is free but there is a daily quota, which when exceeded bl
npm run dev
```
-This will start a static file server & websocket server on http://localhost:8080
-When the source files change, the build processes runs automatically
+This will start a static file server & websocket server, available under the location specified in the `.env.json` file.
+When the source files change, the build processes runs automatically.
## Customize
### Customize preferences
-The preferences.json file specifies application preferences. The available fields are detailed below.
+The `config/preferences.json` file specifies application preferences. The available fields are detailed below.
| field | type | default | description |
@@ -153,21 +147,23 @@ The preferences.json file specifies application preferences. The available field
### Customize plugins
-Enabled plugins. Must only define classes exported by `app/server/skychat/commands/impl/index.ts`
+The `config/plugins.txt` contains the list of enabled plugins.
+To add a custom plugin, create a plugin object in `app/server/skychat/plugins/user_defined/` then add its name to `config/plugins.txt`.
### Customize ranks
-Rank definition (xp threshold and image path). Must be sorted by descending limit. The fields for each rank are:
+`config/ranks.json` contains the rank definition (xp threshold and rank icon paths). Must be sorted by descending limit. The fields for each rank are:
- limit: XP limit to have this rank. The last rank definition must have `0` as the limit, otherwise new users will not have any rank.
- images: Image path corresponding to the rank icon for each 18 and 26px sizes. Image paths should be relative to `/assets/images/`.
### Customize the fake message history
-This file contains the fake raw messages that are displayed to users whose right level is less than `minRightForMessageHistory` defined in `preferences.json`.
+`config/fakemessages.txt` contains the fake messages shown to users whose right level is less than `minRightForMessageHistory` defined in `preferences.json`. If `minRightForMessageHistory` is set to -1, you do not need to modify the fake messages since not one will see them.
### Customize guest names
+`config/guestnames.txt` is the pool of non-logged usernames.
When a guest logs in, a random name is associated to its session. These names are randomly used from this file. If you want to change these names, keep in mind that they should not contain whitespace characters (anything matched by \s so newline, tab, space, ..). Default random names are animal names.
diff --git a/app/client/assets/assets/images/icons/twitch.png b/app/client/assets/assets/images/icons/twitch.png
new file mode 100644
index 00000000..4819726b
Binary files /dev/null and b/app/client/assets/assets/images/icons/twitch.png differ
diff --git a/app/client/src/SkyChatClient.js b/app/client/src/SkyChatClient.js
index c5228b06..74ea8ece 100644
--- a/app/client/src/SkyChatClient.js
+++ b/app/client/src/SkyChatClient.js
@@ -45,8 +45,12 @@ export class SkyChatClient extends EventEmitter {
this.on('auth-token', this.onAuthToken.bind(this));
this.on('typing-list', this.onTypingList.bind(this));
this.on('cursor', this.onCursor.bind(this));
+ this.on('info', this.onInfo.bind(this));
this.on('error', this.onError.bind(this));
this.on('roll', this.onRoll.bind(this));
+
+ this.on('file-list', this.onFileList.bind(this));
+ this.on('file-content', this.onFileContent.bind(this));
this.on('gallery', this.onGallery.bind(this));
this.on('gallery-search', this.onGallerySearchResults.bind(this));
@@ -452,6 +456,20 @@ export class SkyChatClient extends EventEmitter {
this.store.commit("SET_ROLL_STATE", roll.state);
}
+ /**
+ *
+ */
+ onFileList(files) {
+ this.store.commit("SET_FILE_LIST", files)
+ }
+
+ /**
+ *
+ */
+ onFileContent(data) {
+ this.store.commit("SET_FILE_CONTENT", data);
+ }
+
/**
*
*/
@@ -481,6 +499,19 @@ export class SkyChatClient extends EventEmitter {
this.store.commit('SET_PLAYER_CHANNEL', channelId);
}
+ /**
+ *
+ */
+ onInfo(info) {
+ new Noty({
+ type: 'info',
+ layout: 'topCenter',
+ theme: 'nest',
+ text: info,
+ timeout: 10 * 1000
+ }).show();
+ }
+
/**
*
*/
diff --git a/app/client/src/store.js b/app/client/src/store.js
index 1286d470..515345f5 100644
--- a/app/client/src/store.js
+++ b/app/client/src/store.js
@@ -82,16 +82,47 @@ const store = {
gallerySearchResults: null,
isGalleryVisible: false,
+ /**
+ * List of current shown cursors on the screen
+ */
cursors: {},
+
+ rollState: null,
+
+ /**
+ * List of files that can be edited
+ */
+ files: [],
+
+ /**
+ * Currently edited file
+ * @type {null | { filePath: string, content: string }}
+ */
+ file: null,
+
+ /**
+ *
+ */
messages: [],
- playerEnabled: false,
+
+ /**
+ * Current list of typing users
+ */
typingList: [],
+ /**
+ * Whether the player is on/off on the client side
+ */
+ playerEnabled: false,
+
/**
* List of on-going polls
*/
polls: {},
-
+
+ /**
+ * Player state
+ */
playerApiSearchResult: {},
playerChannels: [],
playerChannel: null,
@@ -332,6 +363,12 @@ const store = {
rollEndSound.play();
}
},
+ SET_FILE_LIST(state, files) {
+ state.files = files;
+ },
+ SET_FILE_CONTENT(state, data) {
+ state.file = data;
+ },
SET_PLAYER_API_SEARCH_RESULTS(state, result) {
state.playerApiSearchResult = result;
},
diff --git a/app/client/src/vue/components/form/QuickActions.vue b/app/client/src/vue/components/form/QuickActions.vue
index 1378c848..04b2bb70 100644
--- a/app/client/src/vue/components/form/QuickActions.vue
+++ b/app/client/src/vue/components/form/QuickActions.vue
@@ -3,15 +3,21 @@
Quick actions
+ v-show="isGroupShown(group)">
@@ -28,17 +34,20 @@
+
+
diff --git a/app/client/src/vue/components/user/UserListRow.vue b/app/client/src/vue/components/user/UserListRow.vue
index 6bc3ab80..5d69c5a5 100644
--- a/app/client/src/vue/components/user/UserListRow.vue
+++ b/app/client/src/vue/components/user/UserListRow.vue
@@ -6,7 +6,6 @@
:class="{
'disconnected': session.connectionCount === 0,
}"
- @click.native="joinChannel(channel.id)"
>
+
@@ -10,10 +11,11 @@
+
+
diff --git a/app/server/skychat/Connection.ts b/app/server/skychat/Connection.ts
index 2c84bdba..e61b840d 100644
--- a/app/server/skychat/Connection.ts
+++ b/app/server/skychat/Connection.ts
@@ -185,7 +185,15 @@ export class Connection extends EventEmitter implements IBroadcaster {
}
/**
- * Send an error back to the websocket
+ * Send an info message to the websocket
+ * @param message
+ */
+ public sendInfo(message: string): void {
+ this.webSocket.send(JSON.stringify({ event: 'info', data: message }));
+ }
+
+ /**
+ * Send an error to the websocket
* @param error
*/
public sendError(error: Error): void {
diff --git a/app/server/skychat/MessageFormatter.ts b/app/server/skychat/MessageFormatter.ts
index edbe0c07..6e686c86 100644
--- a/app/server/skychat/MessageFormatter.ts
+++ b/app/server/skychat/MessageFormatter.ts
@@ -9,12 +9,6 @@ import { StickerManager } from './StickerManager';
*/
export class MessageFormatter {
- public static readonly IMAGE_REPLACE_LIMIT: number = Config.PREFERENCES.maxReplacedImagesPerMessage;
-
- public static readonly STICKER_REPLACE_LIMIT: number = Config.PREFERENCES.maxReplacedStickersPerMessage;
-
- public static readonly MAX_NEWLINES_PER_MESSAGE: number = Config.PREFERENCES.maxNewlinesPerMessage;
-
public static readonly LINK_REGEXP: RegExp = /(^|[ \n]|
)((http|https):\/\/[\w?=&.\/-;#~%+@,\[\]:!-]+(?![\w\s?&.\/;#~%"=+@,\[\]:!-]*>))/ig;
private static instance?: MessageFormatter;
@@ -75,7 +69,7 @@ export class MessageFormatter {
let count = 0;
return message.replace(/\n/g, () => {
// If limit reached
- if (++ count > MessageFormatter.MAX_NEWLINES_PER_MESSAGE) {
+ if (++ count > Config.PREFERENCES.maxNewlinesPerMessage) {
return "\n";
}
// Otherwise, replace with br
@@ -153,14 +147,14 @@ export class MessageFormatter {
// If replacing images by html, replace within limit
message = message.replace(new RegExp(imageUrl, 'g'), () => {
++ replacedCount;
- if (! trusted && replacedCount > MessageFormatter.IMAGE_REPLACE_LIMIT) {
+ if (! trusted && replacedCount > Config.PREFERENCES.maxReplacedImagesPerMessage) {
return imageUrl;
}
return html;
});
}
// If limit was reached when replacing this image, do not replace the next ones
- if (! trusted && replacedCount > MessageFormatter.IMAGE_REPLACE_LIMIT) {
+ if (! trusted && replacedCount > Config.PREFERENCES.maxReplacedImagesPerMessage) {
break;
}
}
@@ -194,12 +188,12 @@ export class MessageFormatter {
message = message.replace(new RegExp(MessageFormatter.escapeRegExp(code), 'g'), () => {
++ replacedCount;
- if (replacedCount > MessageFormatter.STICKER_REPLACE_LIMIT) {
+ if (replacedCount > Config.PREFERENCES.maxReplacedStickersPerMessage) {
return code;
}
return `
`;
});
- if (replacedCount > MessageFormatter.STICKER_REPLACE_LIMIT) {
+ if (replacedCount > Config.PREFERENCES.maxReplacedStickersPerMessage) {
break;
}
}
diff --git a/app/server/skychat/User.ts b/app/server/skychat/User.ts
index c0687f9b..6f3907e0 100644
--- a/app/server/skychat/User.ts
+++ b/app/server/skychat/User.ts
@@ -36,16 +36,13 @@ export class User {
plugins: {}
};
- public static readonly RANK_LIMITS: {limit: number, images: {[size: string]: string}}[] = Config.RANKS;
-
/**
* Get the rank image of this user from an xp amount
*/
static getRankByXp(xp: number): {limit: number, images: {[size: string]: string}} {
- const entry = User
- .RANK_LIMITS
+ const entry = Config.RANKS
.filter(entry => xp >= entry.limit)[0];
- return entry ? entry : User.RANK_LIMITS[User.RANK_LIMITS.length - 1];
+ return entry ? entry : Config.RANKS[Config.RANKS.length - 1];
}
/**
diff --git a/app/server/skychat/UserController.ts b/app/server/skychat/UserController.ts
index 4e90442b..927bcdf2 100644
--- a/app/server/skychat/UserController.ts
+++ b/app/server/skychat/UserController.ts
@@ -4,7 +4,6 @@ import {Config} from "./Config";
import {DatabaseHelper} from "./DatabaseHelper";
import {AuthToken, User} from "./User";
import SQL from "sql-template-strings";
-import {Plugin} from "./Plugin";
import {Message, MessageConstructorOptions, MessageMeta} from "./Message";
import * as _ from "lodash"
@@ -18,6 +17,7 @@ export class UserController {
/**
* Object containing default storage data for each plugin
+ * @TODO update when configuration is hot-reloaded
*/
private static pluginDefaultStorages: {[name: string]: any} = PluginManager.getPluginsDefaultDataStorageValues(Config.PLUGINS);
diff --git a/app/server/skychat/plugins/core/FileEditorPlugin.ts b/app/server/skychat/plugins/core/FileEditorPlugin.ts
new file mode 100644
index 00000000..79e7cc0f
--- /dev/null
+++ b/app/server/skychat/plugins/core/FileEditorPlugin.ts
@@ -0,0 +1,96 @@
+import * as fs from "fs";
+import { Config } from "../../Config";
+import { Connection } from "../../Connection";
+import { GlobalPlugin } from "../../GlobalPlugin";
+
+
+export class FileEditorPlugin extends GlobalPlugin {
+
+ static readonly commandName = 'filelist';
+
+ static readonly commandAliases = ['fileget', 'fileset'];
+
+ static readonly ALLOWED_FILES = [
+ 'config/fakemessages.txt',
+ 'config/guestnames.txt',
+ 'config/plugins.txt',
+ 'config/preferences.json',
+ 'config/ranks.json',
+ 'config/stickers.json',
+ ];
+
+ readonly opOnly = true;
+
+ readonly rules = {
+ filelist: {
+ maxCount: 0,
+ },
+ fileget: {
+ minCount: 1,
+ maxCount: 1,
+ },
+ fileset: {
+ minCount: 2,
+ },
+ };
+
+ async run(alias: string, param: string, connection: Connection): Promise
{
+
+ if (alias === 'filelist') {
+ return await this.handleFileList(param, connection);
+ }
+
+ if (alias === 'fileget') {
+ return await this.handleFileGet(param, connection);
+ }
+
+ if (alias === 'fileset') {
+ return await this.handleFileSet(param, connection);
+ }
+ }
+
+ /**
+ *
+ * @param param
+ * @param connection
+ */
+ public async handleFileList(param: string, connection: Connection): Promise {
+ connection.send('file-list', FileEditorPlugin.ALLOWED_FILES);
+ }
+
+ /**
+ *
+ * @param filePath
+ * @param connection
+ */
+ public async handleFileGet(filePath: string, connection: Connection): Promise {
+ if (FileEditorPlugin.ALLOWED_FILES.indexOf(filePath) === -1) {
+ throw new Error('Unable to edit this file');
+ }
+ connection.send(
+ 'file-content',
+ {
+ filePath,
+ content: fs.readFileSync(filePath).toString(),
+ }
+ );
+ }
+
+ /**
+ *
+ * @param param
+ * @param connection
+ */
+ public async handleFileSet(param: string, connection: Connection): Promise {
+ const [filePath, ...contentParts] = param.split(' ');
+ if (FileEditorPlugin.ALLOWED_FILES.indexOf(filePath) === -1) {
+ throw new Error('Unable to edit this file');
+ }
+ const content = contentParts.join(' ');
+ fs.writeFileSync(filePath, content);
+ Config.initialize();
+ connection.sendInfo('File has been edited');
+ // Send file back to the user
+ await this.handleFileGet(filePath, connection);
+ }
+}
diff --git a/app/server/skychat/plugins/entertainment/PointsCollectorPlugin.ts b/app/server/skychat/plugins/entertainment/PointsCollectorPlugin.ts
index 8a677c91..d6927a2d 100644
--- a/app/server/skychat/plugins/entertainment/PointsCollectorPlugin.ts
+++ b/app/server/skychat/plugins/entertainment/PointsCollectorPlugin.ts
@@ -64,7 +64,7 @@ export class PointsCollectorPlugin extends RoomPlugin {
}
// Get a reference to the cursor plugin
- const cursorPlugin = this.room.getPlugin('cursor') as CursorPlugin;
+ const cursorPlugin = this.room.manager.getPlugin('cursor') as CursorPlugin;
// Initialize game object
this.currentGame = {
diff --git a/app/server/skychat/plugins/moderation/StickerPlugin.ts b/app/server/skychat/plugins/moderation/StickerPlugin.ts
index 726e79de..267f55a4 100644
--- a/app/server/skychat/plugins/moderation/StickerPlugin.ts
+++ b/app/server/skychat/plugins/moderation/StickerPlugin.ts
@@ -13,7 +13,7 @@ export class StickerPlugin extends GlobalPlugin {
static readonly commandAliases = ['stickeradd', 'stickerdel'];
- readonly minRight = 40;
+ readonly opOnly = true;
readonly rules = {
sticker: { maxCount: 0 },
diff --git a/app/server/skychat/plugins/player/PlayerChannel.ts b/app/server/skychat/plugins/player/PlayerChannel.ts
index 9d365327..513b9749 100644
--- a/app/server/skychat/plugins/player/PlayerChannel.ts
+++ b/app/server/skychat/plugins/player/PlayerChannel.ts
@@ -16,7 +16,7 @@ export type VideoInfo = {
/**
* Video type (currently only youtube supported)
*/
- type: 'youtube' | 'embed';
+ type: 'youtube' | 'twitch' | 'embed';
/**
* Video data (for youtube, video id)
@@ -240,7 +240,7 @@ export class PlayerChannel {
}
// If media owner left
const ownerSession = Session.getSessionByIdentifier(owner);
- if (! ownerSession || ownerSession.isAlive()) {
+ if (! ownerSession || ! ownerSession.isAlive()) {
return true;
}
}
diff --git a/app/server/skychat/plugins/player/PlayerPlugin.ts b/app/server/skychat/plugins/player/PlayerPlugin.ts
index d34ff0e4..f9798e98 100644
--- a/app/server/skychat/plugins/player/PlayerPlugin.ts
+++ b/app/server/skychat/plugins/player/PlayerPlugin.ts
@@ -1,4 +1,3 @@
-import { Config } from "../../Config";
import { Connection } from "../../Connection";
import { GlobalPlugin } from "../../GlobalPlugin";
import { RoomManager } from "../../RoomManager";
@@ -7,6 +6,7 @@ import { YoutubeFetcher } from "./fetcher/YoutubeFetcher";
import { PluginCommandRules } from "../../Plugin";
import { LinkFetcher } from "./fetcher/LinkFetcher";
import { VideoFetcher } from "./VideoFetcher";
+import { TwitchFetcher } from "./fetcher/TwitchFetcher";
@@ -19,6 +19,7 @@ export class PlayerPlugin extends GlobalPlugin {
static readonly FETCHERS: {[fetcherName: string]: VideoFetcher} = {
'yt': new YoutubeFetcher(),
+ 'twitch': new TwitchFetcher(),
'embed': new LinkFetcher(),
};
diff --git a/app/server/skychat/plugins/player/fetcher/TwitchFetcher.ts b/app/server/skychat/plugins/player/fetcher/TwitchFetcher.ts
new file mode 100644
index 00000000..6b1ff0b7
--- /dev/null
+++ b/app/server/skychat/plugins/player/fetcher/TwitchFetcher.ts
@@ -0,0 +1,29 @@
+import { VideoInfo } from "../PlayerChannel";
+import { VideoFetcher } from "../VideoFetcher";
+
+
+//
+
+export class TwitchFetcher implements VideoFetcher {
+
+
+ async get(channelName: string): Promise {
+ channelName = channelName.toLowerCase();
+ if (! channelName.match(/^[a-z0-9-_]+$/)) {
+ throw new Error('Invalid channel name');
+ }
+ const videoInfo: VideoInfo = {
+ type: 'twitch',
+ id: channelName,
+ duration: 0,
+ startCursor: 0,
+ title: `${channelName}'s twitch`,
+ thumb: 'assets/images/icons/twitch.png'
+ };
+ return [videoInfo];
+ }
+
+ search(type: string, search: string, limit: number): Promise {
+ throw new Error("Method not implemented.");
+ }
+}
diff --git a/backups/.gitignore b/backups/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/backups/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/config/plugins.txt.template b/config/plugins.txt.template
index 98b29a56..b8087296 100644
--- a/config/plugins.txt.template
+++ b/config/plugins.txt.template
@@ -5,6 +5,7 @@ AvatarPlugin
BackupPlugin
ColorPlugin
ConnectedListPlugin
+FileEditorPlugin
GiveMoneyPlugin
CursorPlugin
OPPlugin
diff --git a/docker-compose.yml b/docker-compose.yml
index 8c4337a0..9ed72af8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -12,8 +12,8 @@ services:
GID: ${DOCKER_GID}
DOCKER_TZ: "${DOCKER_TZ}"
volumes:
- - ./config:/var/skychat/config:ro
- ./scripts:/var/skychat/scripts:ro
+ - ./config:/var/skychat/config
- ./backups:/var/skychat/backups
- ./storage:/var/skychat/storage
- ./uploads:/var/skychat/uploads
diff --git a/gulpfile.js b/gulpfile.js
index c5a3d864..e27a2a04 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -5,7 +5,7 @@ const cleanCSS = require('gulp-clean-css');
const htmlmin = require('gulp-htmlmin');
const pug = require('gulp-pug');
const ts = require('gulp-typescript');
-const tsProject = ts.createProject('tsconfig.server.json');
+const tsProject = ts.createProject('tsconfig.json');
const nodemon = require('gulp-nodemon');
const webpack = require('webpack-stream');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
diff --git a/package.json b/package.json
index ced9d520..a57aacb8 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"types": "build/index.d.ts",
"main": "build/index.js",
"scripts": {
+ "destroy": "bash scripts/destroy.sh",
"setup": "bash scripts/setup.sh",
"clean:client": "rm -rf dist",
"clean:server": "rm -rf build",
diff --git a/scripts/autoinstall.sh b/scripts/autoinstall.sh
new file mode 100644
index 00000000..30342a7b
--- /dev/null
+++ b/scripts/autoinstall.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+
+# 1. Clone the repository
+git clone https://github.com/skychatorg/skychat.git
+cd skychat
+
+# 2. Generates the .env.json and config files in config/
+bash scripts/setup.sh
diff --git a/scripts/backup.sh b/scripts/backup.sh
index df2488fa..3d39673c 100755
--- a/scripts/backup.sh
+++ b/scripts/backup.sh
@@ -2,7 +2,7 @@
# Constants
-BACKUP_DIRS="config scripts database storage uploads"
+BACKUP_DIRS="config scripts storage uploads"
BACKUP_LOCATION="backups"
diff --git a/scripts/destroy.sh b/scripts/destroy.sh
new file mode 100644
index 00000000..4a631176
--- /dev/null
+++ b/scripts/destroy.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# Remove all configuration files
+rm config/*.{txt,json} .env.json
+
+# Clear storage
+rm -r storage uploads
diff --git a/scripts/setup.sh b/scripts/setup.sh
index dd840642..4b80ffab 100644
--- a/scripts/setup.sh
+++ b/scripts/setup.sh
@@ -1,5 +1,17 @@
#!/usr/bin/env bash
+
+# Create empty directories if they do not exist
+if [[ ! -e backups ]]; then
+ mkdir backups;
+fi
+if [[ ! -e uploads ]]; then
+ mkdir -p uploads/{all,avatars,gallery,stickers};
+fi
+if [[ ! -e storage ]]; then
+ mkdir -p storage/{plugins,rooms};
+fi
+
# Initialize .env.json
if [[ ! -e .env.json ]]; then
cp .env.json.template .env.json;
diff --git a/storage/.gitignore b/storage/.gitignore
deleted file mode 100644
index 64d89aa3..00000000
--- a/storage/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*
-!plugins
-!rooms
-!.gitignore
diff --git a/storage/plugins/.gitignore b/storage/plugins/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/storage/plugins/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/storage/rooms/.gitignore b/storage/rooms/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/storage/rooms/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/test/test.ts b/test/test.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/tsconfig.json b/tsconfig.json
index b2bcd653..3f007e68 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,14 +1,20 @@
{
"compilerOptions": {
- "outDir": "./build/",
- "sourceMap": true,
+ "module": "commonjs",
"strict": true,
- "noImplicitReturns": true,
- "module": "es2015",
+ "declaration": true,
+ "removeComments": true,
+ "outDir": "./build/",
+ "target": "es5",
+ "lib": ["ES2019"],
"moduleResolution": "node",
- "target": "es5"
+ "sourceMap": true
},
"include": [
- "app/client/src/**/*"
+ "app/server/**/*"
],
+ "exclude": [
+ "node_modules",
+ "dist"
+ ]
}
diff --git a/tsconfig.server.json b/tsconfig.server.json
deleted file mode 100644
index 3f007e68..00000000
--- a/tsconfig.server.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "compilerOptions": {
- "module": "commonjs",
- "strict": true,
- "declaration": true,
- "removeComments": true,
- "outDir": "./build/",
- "target": "es5",
- "lib": ["ES2019"],
- "moduleResolution": "node",
- "sourceMap": true
- },
- "include": [
- "app/server/**/*"
- ],
- "exclude": [
- "node_modules",
- "dist"
- ]
-}
diff --git a/uploads/all/.gitignore b/uploads/all/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/uploads/all/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/uploads/avatars/.gitignore b/uploads/avatars/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/uploads/avatars/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/uploads/gallery/.gitignore b/uploads/gallery/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/uploads/gallery/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/uploads/stickers/.gitignore b/uploads/stickers/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/uploads/stickers/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore