update
10
.env.example
|
@ -1,10 +0,0 @@
|
|||
VUE_APP_VERSION=[AIV]{version}[/AIV]
|
||||
VUE_APP_BUILD_DATE=[AIV]{date}[/AIV]
|
||||
VUE_APP_SENTRY_DSN=https://c82c997e304148cf8deed40fef8912ea@o444992.ingest.sentry.io/6307174
|
||||
VUE_APP_MATOMO_SITE_ID=5
|
||||
VUE_APP_MATOMO_URL=https://analytics.flowinity.com
|
||||
VUE_APP_MATOMO_TRACKER=flow
|
||||
VUE_APP_MATOMO_DOMAINS=*.troplo.com
|
||||
VUE_APP_MATOMO_ENABLED=true
|
||||
VUE_APP_SENTRY_ENABLED=true
|
||||
VUE_APP_BASE_URL=
|
30
.gitignore
vendored
|
@ -1,29 +1 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
.env
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
.sentryclirc
|
||||
|
||||
backend/node_modules
|
||||
backend/config/config.json
|
||||
backend/.env
|
||||
.idea
|
||||
|
|
45
README.md
|
@ -2,13 +2,56 @@
|
|||
|
||||
![Wakatime](https://wakatime.troplo.com/api/badge/Troplo/interval:any/project:Colubrina?label=wakatime)
|
||||
|
||||
Colubrina is a simple chatting platform written in Vue, and Vuetify for the frontend, and Node.js, Sequelize and Socket.io for the backend.
|
||||
|
||||
### Checklist
|
||||
- [x] Messaging
|
||||
- [x] Authentication
|
||||
- [x] Admin panel
|
||||
- [x] CLI (cli)
|
||||
- [ ] Message history
|
||||
- [x] User profile cards
|
||||
- [x] Group creation and modification
|
||||
- [x] Friending
|
||||
- [x] Searching
|
||||
|
||||
<img src="https://i.troplo.com/i/d608273e066c.png" alt="Chat" width="45%"></img>
|
||||
<img src="https://i.troplo.com/i/e8e2c9d6e349.png" alt="Friends" width="45%"></img>
|
||||
<img src="https://i.troplo.com/i/e958b8e58c5e.png" alt="Chat with AMOLED theme" width="45%"></img>
|
||||
<img src="https://i.troplo.com/i/279376da3f1d.png" alt="Chat with profile card and light theme" width="45%"></img>
|
||||
<img src="https://i.troplo.com/i/59b63d5aa167.png" alt="QuickSwitcher" width="45%"></img>
|
||||
<img src="https://i.troplo.com/i/b2d6dd14c6b6.png" alt="QuickSwitcher with AMOLED theme" width="45%"></img>
|
||||
## Project setup
|
||||
## Backend setup
|
||||
First, configure a database and user (MariaDB strongly recommended) for Colubrina.<br>
|
||||
Please navigate to the `cli` folder, and run the following commands:
|
||||
|
||||
```
|
||||
yarn
|
||||
```
|
||||
to install dependencies, and then
|
||||
```
|
||||
node .
|
||||
```
|
||||
which should result in an interactive CLI prompt looking like the following:
|
||||
```
|
||||
Troplo/Colubrina CLI
|
||||
Colubrina version 1.0.1
|
||||
Failed to check for updates, ensure you are connected to the internet, and services.troplo.com is whitelisted behind any potential firewalls.
|
||||
? Please select an option (Use arrow keys)
|
||||
❯ Setup
|
||||
Create user
|
||||
Run migrations
|
||||
Update/create config file
|
||||
Check for updates
|
||||
Build frontend for production
|
||||
Exit
|
||||
```
|
||||
Select setup, and go through the steps. After completing the initial setup, you may run `yarn build` in the frontend folder, or select "Build frontend for production" in the CLI.<br>
|
||||
The CLI will populate the database with some default data which are essential for operation.<br>
|
||||
The backend service can now be started with `node .` in the `backend` folder which will run on port `23998`.
|
||||
|
||||
A systemd service example config file can be found at `colubrina.service`
|
||||
## Frontend setup
|
||||
|
||||
Rename .env.example to .env and fill it out with your own information.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Colubrina Backend
|
||||
|
||||
## Setup instructions
|
||||
Setup instructions can be found in the root README.md document.
|
||||
## Manual Setup instructions (not using Colubrina CLI)
|
||||
|
||||
- Run `yarn install` to install the dependencies.
|
||||
- Configure the MariaDB database connection in `config/config.json` using the
|
||||
|
@ -11,4 +11,4 @@
|
|||
- Run `yarn serve` to start the proxy with nodemon which automatically restarts
|
||||
on file-change for development.
|
||||
- Run `yarn start` or `node .` to start the proxy in production.
|
||||
- Colubrina Proxy runs on port 23998.
|
||||
- Colubrina Backend runs on port 23998.
|
||||
|
|
|
@ -27,7 +27,7 @@ app.get("/api/v1/state", async (req, res) => {
|
|||
loading: true,
|
||||
notification: process.env.NOTIFICATION,
|
||||
notificationType: process.env.NOTIFICATION_TYPE,
|
||||
latestVersion: require("../package.json").version,
|
||||
latestVersion: require("../frontend/package.json").version,
|
||||
name: process.env.SITE_NAME,
|
||||
allowRegistrations: JSON.parse(process.env.ALLOW_REGISTRATIONS)
|
||||
})
|
||||
|
|
|
@ -22,7 +22,7 @@ module.exports = {
|
|||
release: process.env.RELEASE,
|
||||
notification: process.env.NOTIFICATION,
|
||||
notificationType: process.env.NOTIFICATION_TYPE,
|
||||
latestVersion: require("../../package.json").version
|
||||
latestVersion: require("../../frontend/package.json").version
|
||||
})
|
||||
const friends = await Friend.findAll({
|
||||
where: {
|
||||
|
@ -114,7 +114,7 @@ module.exports = {
|
|||
release: process.env.RELEASE,
|
||||
notification: process.env.NOTIFICATION,
|
||||
notificationType: process.env.NOTIFICATION_TYPE,
|
||||
latestVersion: require("../../package.json").version
|
||||
latestVersion: require("../../frontend/package.json").version
|
||||
})
|
||||
socket.emit("unauthorized", {
|
||||
message: "Please reauth."
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"constantinople": "3.1.1",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"crypto-random-string": "3.3.1",
|
||||
"dayjs": "^1.11.4",
|
||||
"debug": "~2.6.9",
|
||||
"dotenv": "^16.0.0",
|
||||
"express": "^4.17.1",
|
||||
|
|
|
@ -229,7 +229,7 @@ router.put("/state", auth, async (req, res, next) => {
|
|||
io.emit("siteState", {
|
||||
notification: req.body.notification,
|
||||
notificationType: req.body.notificationType,
|
||||
latestVersion: require("../../package.json").version,
|
||||
latestVersion: require("../../frontend/package.json").version,
|
||||
allowRegistrations: req.body.allowRegistrations
|
||||
})
|
||||
res.sendStatus(204)
|
||||
|
|
|
@ -1023,6 +1023,11 @@ dashdash@^1.12.0:
|
|||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
dayjs@^1.11.4:
|
||||
version "1.11.4"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.4.tgz#3b3c10ca378140d8917e06ebc13a4922af4f433e"
|
||||
integrity sha512-Zj/lPM5hOvQ1Bf7uAvewDaUcsJoI6JmNqmHhHl3nyumwe0XHwt8sWdOVAPACJzCebL8gQCi+K49w7iKWnGwX9g==
|
||||
|
||||
debug@2.6.9, debug@~2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
|
|
82
cli/.gitignore
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
<<<<<<< HEAD
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# temp directory
|
||||
tmp
|
||||
=======
|
||||
.DS_Store
|
||||
node_modules/
|
||||
dist/
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Config folder
|
||||
config/config.json
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
>>>>>>> frontend
|
||||
frontend/dist1/
|
||||
rendering/global
|
||||
rendering/global/5c2f8896a2b7169d4e253944f3b733e2.png
|
||||
rendering/global/81df1ac4d303319a79db19f45c5c475c.png
|
||||
rendering/global/d24b3e361c4fc6263e0276f52ada9694.png
|
||||
rendering/marketplacecontent
|
||||
rendering/usercontent
|
||||
nodeinfo.json
|
||||
|
||||
.env
|
||||
|
||||
usercontent
|
|
@ -4,13 +4,13 @@ const path = require("path")
|
|||
const { Umzug, SequelizeStorage } = require("umzug")
|
||||
const { Sequelize } = require("sequelize")
|
||||
const argon2 = require("argon2")
|
||||
const { production: config } = require("../config/config.json")
|
||||
const { User } = require("../models")
|
||||
const { User } = require("../backend/models")
|
||||
const axios = require("axios")
|
||||
const os = require("os")
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
console.log("Troplo/Colubrina CLI")
|
||||
console.log("Colubrina version", require("../../package.json").version)
|
||||
console.log("Colubrina version", require("../frontend/package.json").version)
|
||||
async function checkForUpdates() {
|
||||
await axios
|
||||
.get("https://services.troplo.com/api/v1/state", {
|
||||
|
@ -20,7 +20,7 @@ async function checkForUpdates() {
|
|||
timeout: 800
|
||||
})
|
||||
.then((res) => {
|
||||
if (require("../../package.json").version !== res.data.latestVersion) {
|
||||
if (require("frontend/package.json").version !== res.data.latestVersion) {
|
||||
console.log("A new version of Colubrina is available!")
|
||||
console.log("Latest version:", res.data.latestVersion)
|
||||
} else {
|
||||
|
@ -40,7 +40,8 @@ let state = {
|
|||
username: "colubrina",
|
||||
password: null,
|
||||
database: "colubrina",
|
||||
storage: "./storage.db"
|
||||
storage: "../backend/storage.db",
|
||||
dialect: "mariadb"
|
||||
},
|
||||
dbConfig: {}
|
||||
}
|
||||
|
@ -127,18 +128,18 @@ async function testDB() {
|
|||
async function dbSetup() {
|
||||
await doSetupDB()
|
||||
fs.writeFileSync(
|
||||
path.join(__dirname, "../config/config.json"),
|
||||
path.join(__dirname, "../backend/config/config.json"),
|
||||
JSON.stringify(state.dbConfig)
|
||||
)
|
||||
console.log("config/config.json overwritten")
|
||||
}
|
||||
async function runMigrations() {
|
||||
console.log("Running migrations")
|
||||
const config = require("../config/config.json").production
|
||||
const config = require("../backend/config/config.json").production
|
||||
const sequelize = new Sequelize(config)
|
||||
|
||||
const umzug = new Umzug({
|
||||
migrations: { glob: "../migrations/*.js" },
|
||||
migrations: { glob: "../backend/migrations/*.js" },
|
||||
context: sequelize.getQueryInterface(),
|
||||
storage: new SequelizeStorage({ sequelize }),
|
||||
logger: console,
|
||||
|
@ -170,7 +171,7 @@ async function createUser() {
|
|||
}
|
||||
async function configureDotEnv() {
|
||||
function setEnvValue(key, value) {
|
||||
const ENV_VARS = fs.readFileSync("../.env", "utf8").split(os.EOL)
|
||||
const ENV_VARS = fs.readFileSync("../backend/.env", "utf8").split(os.EOL)
|
||||
|
||||
// find the env we want based on the key
|
||||
const target = ENV_VARS.indexOf(
|
||||
|
@ -197,8 +198,8 @@ async function configureDotEnv() {
|
|||
// write everything back to the file system
|
||||
fs.writeFileSync("../.env", ENV_VARS.join(os.EOL))
|
||||
}
|
||||
if (!fs.existsSync("../.env")) {
|
||||
fs.writeFileSync("../.env", "")
|
||||
if (!fs.existsSync("../backend/.env")) {
|
||||
fs.writeFileSync("../backend/.env", "")
|
||||
}
|
||||
setEnvValue(
|
||||
"HOSTNAME",
|
||||
|
@ -236,10 +237,19 @@ async function init() {
|
|||
"Run migrations",
|
||||
"Update/create config file",
|
||||
"Check for updates",
|
||||
"Build frontend for production",
|
||||
"Exit"
|
||||
])
|
||||
|
||||
if (option === "Setup") {
|
||||
// run yarn install in ../backend
|
||||
console.log("Running yarn install")
|
||||
execSync("cd ../backend && yarn install --frozen-lockfile", () => {
|
||||
console.log("yarn install complete (backend)")
|
||||
})
|
||||
execSync("cd ../frontend && yarn install --frozen-lockfile", () => {
|
||||
console.log("yarn install complete (frontend)")
|
||||
})
|
||||
if (fs.existsSync(path.join(__dirname, "../.env"))) {
|
||||
const option = await input.confirm(".env already exists, overwrite?", {
|
||||
default: false
|
||||
|
@ -250,7 +260,7 @@ async function init() {
|
|||
} else {
|
||||
await configureDotEnv()
|
||||
}
|
||||
if (fs.existsSync(path.join(__dirname, "../config/config.json"))) {
|
||||
if (fs.existsSync(path.join(__dirname, "../backend/config/config.json"))) {
|
||||
const option = await input.select(
|
||||
`config/config.json already exists. Do you want to overwrite it?`,
|
||||
["Yes", "No"]
|
||||
|
@ -262,7 +272,7 @@ async function init() {
|
|||
await dbSetup()
|
||||
}
|
||||
await runMigrations()
|
||||
const { User, Theme } = require("../models")
|
||||
const { User, Theme } = require("../backend/models")
|
||||
try {
|
||||
await Theme.bulkCreate(
|
||||
JSON.parse(
|
||||
|
@ -313,6 +323,11 @@ async function init() {
|
|||
await runMigrations()
|
||||
} else if (option === "Check for updates") {
|
||||
await checkForUpdates()
|
||||
} else if(option === "Build frontend for production") {
|
||||
console.log("Building...")
|
||||
execSync("cd ../frontend && yarn install --frozen-lockfile && yarn build", () => {
|
||||
console.log("yarn build complete")
|
||||
})
|
||||
} else if (option === "Exit") {
|
||||
process.exit(0)
|
||||
}
|
14
cli/package.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name" : "colubrina-cli",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"argon2": "^0.28.7",
|
||||
"axios": "^0.27.2",
|
||||
"input": "^1.0.1",
|
||||
"mariadb": "^3.0.1",
|
||||
"pg": "^8.7.3",
|
||||
"sequelize": "^6.21.3",
|
||||
"sqlite3": "^5.0.10",
|
||||
"umzug": "^3.1.1"
|
||||
}
|
||||
}
|
1332
cli/yarn.lock
Normal file
17
colubrina.service
Normal file
|
@ -0,0 +1,17 @@
|
|||
[Unit]
|
||||
Description=Colubrina
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
RestartSec=2s
|
||||
Type=simple
|
||||
User=colubrina
|
||||
Group=colubrina
|
||||
WorkingDirectory=/home/colubrina/colubrina/backend
|
||||
ExecStart=node /home/colubrina/colubrina/backend/index.js
|
||||
Restart=always
|
||||
EnvironmentFile=/home/colubrina/colubrina/backend/.env
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
3
frontend/.env
Normal file
|
@ -0,0 +1,3 @@
|
|||
VUE_APP_VERSION=[AIV]{version}[/AIV]
|
||||
VUE_APP_BUILD_DATE=[AIV]{date}[/AIV]
|
||||
VUE_APP_BASE_URL=
|
3
frontend/.env.example
Normal file
|
@ -0,0 +1,3 @@
|
|||
VUE_APP_VERSION=[AIV]{version}[/AIV]
|
||||
VUE_APP_BUILD_DATE=[AIV]{date}[/AIV]
|
||||
VUE_APP_BASE_URL=
|
23
frontend/.gitignore
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
.sentryclirc
|
||||
|
||||
backend/node_modules
|
||||
backend/config/config.json
|
||||
backend/.env
|
|
@ -2,10 +2,11 @@
|
|||
"name": "colubrina-chat",
|
||||
"version": "1.0.1",
|
||||
"private": true,
|
||||
"author": "Troplo <troplo@troplo.com>",
|
||||
"license": "GPL-3.0",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build --no-clean",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"postinstall": "patch-package"
|
||||
},
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 555 B After Width: | Height: | Size: 555 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 262 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 539 B |
|
@ -1,7 +1,6 @@
|
|||
const WebpackAutoInject = require("webpack-auto-inject-version-next")
|
||||
const Dotenv = require("dotenv-webpack")
|
||||
//const SentryPlugin = require("@sentry/webpack-plugin")
|
||||
const version = require("./package.json").version
|
||||
let plugins
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
|
@ -91,10 +90,6 @@ module.exports = {
|
|||
},
|
||||
productionSourceMap: true,
|
||||
configureWebpack: {
|
||||
output: {
|
||||
filename: `[name].[hash].${version}.js`,
|
||||
chunkFilename: `[name].[hash].${version}.js`
|
||||
},
|
||||
plugins
|
||||
},
|
||||
pwa: {
|