mirror of
https://github.com/Troplo/Colubrina.git
synced 2024-11-25 12:46:42 +11:00
1.0.19
This commit is contained in:
parent
b292277ec4
commit
0d6e209fc6
22 changed files with 424 additions and 207 deletions
|
@ -1,15 +1,3 @@
|
||||||
HOSTNAME=localhost
|
.ENV is no longer in use, replaced with:
|
||||||
CORS_HOSTNAME=http://localhost:8080
|
- config/database.json - Database credentials
|
||||||
RELEASE=stable
|
- config/config.json - Colubrina configuration (used to be .env)
|
||||||
NOTIFICATION=
|
|
||||||
NOTIFICATION_TYPE=info
|
|
||||||
SITE_NAME=Colubrina
|
|
||||||
ALLOW_REGISTRATIONS=true
|
|
||||||
PUBLIC_USERS=false
|
|
||||||
EMAIL_VERIFICATION=false
|
|
||||||
EMAIL_SMTP_HOST=smtp.myhost.com
|
|
||||||
EMAIL_SMTP_PORT=587
|
|
||||||
EMAIL_SMTP_USER=colubrina@myhost.com
|
|
||||||
EMAIL_SMTP_FROM=colubrina@myhost.com
|
|
||||||
EMAIL_SMTP_PASSWORD=myPassword
|
|
||||||
EMAIL_SMTP_SECURE=false
|
|
1
backend/.gitignore
vendored
1
backend/.gitignore
vendored
|
@ -61,6 +61,7 @@ yarn-error.log*
|
||||||
|
|
||||||
# Config folder
|
# Config folder
|
||||||
config/config.json
|
config/config.json
|
||||||
|
config/database.json
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.idea
|
.idea
|
||||||
*.suo
|
*.suo
|
||||||
|
|
5
backend/.sequelizerc
Normal file
5
backend/.sequelizerc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
var path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
'config': path.resolve('config/database.json'),
|
||||||
|
}
|
|
@ -1,23 +1,18 @@
|
||||||
{
|
{
|
||||||
"development": {
|
"hostname": "localhost",
|
||||||
"username": "username",
|
"corsHostname": "http://localhost:8080",
|
||||||
"password": "password",
|
"siteName": "Colubrina",
|
||||||
"database": "database",
|
"allowRegistrations": true,
|
||||||
"host": "host",
|
"notification": "",
|
||||||
"dialect": "mariadb"
|
"notificationType": "",
|
||||||
},
|
"release": "stable",
|
||||||
"test": {
|
"publicUsers": true,
|
||||||
"username": "username",
|
"emailVerification": false,
|
||||||
"password": "password",
|
"emailSMTPHost": "mail.example.com",
|
||||||
"database": "database",
|
"emailSMTPPort": 587,
|
||||||
"host": "host",
|
"emailSMTPUser": "colubrina@example.com",
|
||||||
"dialect": "mariadb"
|
"emailSMTPFrom": "colubrina@example.com",
|
||||||
},
|
"emailSMTPPassword": "",
|
||||||
"production": {
|
"emailSMTPSecure": false,
|
||||||
"username": "username",
|
"rules": "Write your instance rules here."
|
||||||
"password": "password",
|
|
||||||
"database": "database",
|
|
||||||
"host": "host",
|
|
||||||
"dialect": "mariadb"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
23
backend/config/database.example.json
Normal file
23
backend/config/database.example.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"development": {
|
||||||
|
"username": "username",
|
||||||
|
"password": "password",
|
||||||
|
"database": "database",
|
||||||
|
"host": "host",
|
||||||
|
"dialect": "mariadb"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"username": "username",
|
||||||
|
"password": "password",
|
||||||
|
"database": "database",
|
||||||
|
"host": "host",
|
||||||
|
"dialect": "mariadb"
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"username": "username",
|
||||||
|
"password": "password",
|
||||||
|
"database": "database",
|
||||||
|
"host": "host",
|
||||||
|
"dialect": "mariadb"
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ let app = express()
|
||||||
let bodyParser = require("body-parser")
|
let bodyParser = require("body-parser")
|
||||||
let os = require("os")
|
let os = require("os")
|
||||||
app.set("trust proxy", true)
|
app.set("trust proxy", true)
|
||||||
|
app.locals.config = require("./config/config.json")
|
||||||
const socket = require("./lib/socket")
|
const socket = require("./lib/socket")
|
||||||
const server = require("http").createServer(app)
|
const server = require("http").createServer(app)
|
||||||
|
|
||||||
|
@ -22,15 +23,17 @@ app.use("/api/v1/mediaproxy", require("./routes/mediaproxy.js"))
|
||||||
app.use("/api/v1/associations", require("./routes/associations.js"))
|
app.use("/api/v1/associations", require("./routes/associations.js"))
|
||||||
app.get("/api/v1/state", async (req, res) => {
|
app.get("/api/v1/state", async (req, res) => {
|
||||||
res.json({
|
res.json({
|
||||||
release: process.env.RELEASE,
|
release: req.app.locals.config.release,
|
||||||
loading: true,
|
notification: req.app.locals.config.notification,
|
||||||
notification: process.env.NOTIFICATION,
|
notificationType: req.app.locals.config.notificationType,
|
||||||
notificationType: process.env.NOTIFICATION_TYPE,
|
|
||||||
latestVersion: require("../frontend/package.json").version,
|
latestVersion: require("../frontend/package.json").version,
|
||||||
name: process.env.SITE_NAME,
|
allowRegistrations: req.app.locals.config.allowRegistrations,
|
||||||
allowRegistrations: process.env.ALLOW_REGISTRATIONS === "true",
|
publicUsers: req.app.locals.config.publicUsers,
|
||||||
publicUsers: process.env.PUBLIC_USERS === "true",
|
emailVerification: req.app.locals.config.emailVerification,
|
||||||
emailVerification: process.env.EMAIL_VERIFICATION === "true"
|
rules: req.app.locals.config.rules,
|
||||||
|
name: req.app.locals.config.siteName,
|
||||||
|
loading: true,
|
||||||
|
isColubrinaServer: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ module.exports = {
|
||||||
init(app, server) {
|
init(app, server) {
|
||||||
const io = require("socket.io")(server, {
|
const io = require("socket.io")(server, {
|
||||||
cors: {
|
cors: {
|
||||||
origin: [process.env.CORS_HOSTNAME],
|
origin: [app.locals.config.corsHostname],
|
||||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
|
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -19,10 +19,15 @@ module.exports = {
|
||||||
console.log(socket.user.id)
|
console.log(socket.user.id)
|
||||||
socket.join(user.id)
|
socket.join(user.id)
|
||||||
socket.emit("siteState", {
|
socket.emit("siteState", {
|
||||||
release: process.env.RELEASE,
|
release: app.locals.config.release,
|
||||||
notification: process.env.NOTIFICATION,
|
notification: app.locals.config.notification,
|
||||||
notificationType: process.env.NOTIFICATION_TYPE,
|
notificationType: app.locals.config.notificationType,
|
||||||
latestVersion: require("../../frontend/package.json").version
|
latestVersion: require("../../frontend/package.json").version,
|
||||||
|
allowRegistrations: app.locals.config.allowRegistrations,
|
||||||
|
publicUsers: app.locals.config.publicUsers,
|
||||||
|
emailVerification: app.locals.config.emailVerification,
|
||||||
|
rules: app.locals.config.rules,
|
||||||
|
name: app.locals.config.siteName
|
||||||
})
|
})
|
||||||
const friends = await Friend.findAll({
|
const friends = await Friend.findAll({
|
||||||
where: {
|
where: {
|
||||||
|
@ -114,10 +119,15 @@ module.exports = {
|
||||||
} else {
|
} else {
|
||||||
socket.join(-1)
|
socket.join(-1)
|
||||||
socket.emit("siteState", {
|
socket.emit("siteState", {
|
||||||
release: process.env.RELEASE,
|
release: app.locals.config.release,
|
||||||
notification: process.env.NOTIFICATION,
|
notification: app.locals.config.notification,
|
||||||
notificationType: process.env.NOTIFICATION_TYPE,
|
notificationType: app.locals.config.notificationType,
|
||||||
latestVersion: require("../../frontend/package.json").version
|
latestVersion: require("../../frontend/package.json").version,
|
||||||
|
allowRegistrations: app.locals.config.allowRegistrations,
|
||||||
|
publicUsers: app.locals.config.publicUsers,
|
||||||
|
emailVerification: app.locals.config.emailVerification,
|
||||||
|
rules: app.locals.config.rules,
|
||||||
|
name: app.locals.config.siteName
|
||||||
})
|
})
|
||||||
socket.emit("unauthorized", {
|
socket.emit("unauthorized", {
|
||||||
message: "Please reauth."
|
message: "Please reauth."
|
||||||
|
|
|
@ -5,7 +5,7 @@ const path = require("path")
|
||||||
const Sequelize = require("sequelize")
|
const Sequelize = require("sequelize")
|
||||||
const basename = path.basename(__filename)
|
const basename = path.basename(__filename)
|
||||||
const env = process.env.NODE_ENV || "development"
|
const env = process.env.NODE_ENV || "development"
|
||||||
const config = require(__dirname + "/../config/config.json")[env]
|
const config = require(__dirname + "/../config/database.json")[env]
|
||||||
const db = {}
|
const db = {}
|
||||||
|
|
||||||
let sequelize
|
let sequelize
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node .",
|
"start": "node .",
|
||||||
"serve": "nodemon"
|
"serve": "nodemon . --ignore config"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argon2": "^0.28.7",
|
"argon2": "^0.28.7",
|
||||||
|
|
|
@ -7,6 +7,7 @@ const { Op } = require("sequelize")
|
||||||
const dayjs = require("dayjs")
|
const dayjs = require("dayjs")
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
const os = require("os")
|
const os = require("os")
|
||||||
|
const argon2 = require("argon2")
|
||||||
|
|
||||||
router.all("*", auth, async (req, res, next) => {
|
router.all("*", auth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
|
@ -22,7 +23,7 @@ router.all("*", auth, async (req, res, next) => {
|
||||||
|
|
||||||
router.all("*", auth, async (req, res, next) => {
|
router.all("*", auth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (!req.user.emailVerified && process.env.EMAIL_VERIFICATION === "true") {
|
if (!req.user.emailVerified && req.app.locals.config.emailVerification) {
|
||||||
throw Errors.emailVerificationRequired
|
throw Errors.emailVerificationRequired
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
|
@ -53,8 +54,45 @@ router.get("/", auth, async (req, res, next) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (e) {
|
||||||
return next(err)
|
next(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.put("/user/:id", auth, async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const user = await User.findOne({
|
||||||
|
where: {
|
||||||
|
id: req.params.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!user) {
|
||||||
|
throw Errors.communicationsUserNotFound
|
||||||
|
} else {
|
||||||
|
await user.update({
|
||||||
|
banned: req.body.banned
|
||||||
|
})
|
||||||
|
res.json(user)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
next(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post("/user", auth, async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const user = await User.create({
|
||||||
|
username: req.body.username,
|
||||||
|
password: await argon2.hash(req.body.password),
|
||||||
|
email: req.body.email,
|
||||||
|
emailVerified: req.body.emailVerified,
|
||||||
|
admin: false,
|
||||||
|
banned: false,
|
||||||
|
lastSeenAt: new Date()
|
||||||
|
})
|
||||||
|
res.json(user)
|
||||||
|
} catch (e) {
|
||||||
|
next(e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -231,19 +269,23 @@ router.put("/state", auth, async (req, res, next) => {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const io = req.app.get("io")
|
const io = req.app.get("io")
|
||||||
setEnvValue("ALLOW_REGISTRATIONS", req.body.allowRegistrations)
|
req.app.locals.config.allowRegistrations = req.body.allowRegistrations
|
||||||
|
req.app.locals.config.rules = req.body.rules
|
||||||
if (req.body.broadcastType === "permanent") {
|
if (req.body.broadcastType === "permanent") {
|
||||||
setEnvValue("NOTIFICATION", req.body.notification)
|
req.app.locals.config.notification = req.body.notification
|
||||||
setEnvValue("NOTIFICATION_TYPE", req.body.notificationType)
|
req.app.locals.config.notificationType = req.body.notificationType
|
||||||
process.env.NOTIFICATION = req.body.notification
|
|
||||||
process.env.NOTIFICATION_TYPE = req.body.notificationType
|
|
||||||
}
|
}
|
||||||
io.emit("siteState", {
|
io.emit("siteState", {
|
||||||
notification: req.body.notification,
|
notification: req.body.notification,
|
||||||
notificationType: req.body.notificationType,
|
notificationType: req.body.notificationType,
|
||||||
latestVersion: require("../../frontend/package.json").version,
|
latestVersion: require("../../frontend/package.json").version,
|
||||||
allowRegistrations: req.body.allowRegistrations
|
allowRegistrations: req.body.allowRegistrations,
|
||||||
|
rules: req.body.rules
|
||||||
})
|
})
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./config/config.json",
|
||||||
|
JSON.stringify(req.app.locals.config, null, 2)
|
||||||
|
)
|
||||||
res.sendStatus(204)
|
res.sendStatus(204)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return next(err)
|
return next(err)
|
||||||
|
|
|
@ -13,7 +13,7 @@ const {
|
||||||
|
|
||||||
router.all("*", auth, async (req, res, next) => {
|
router.all("*", auth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (!req.user.emailVerified && process.env.EMAIL_VERIFICATION === "true") {
|
if (!req.user.emailVerified && req.app.locals.config.emailVerification) {
|
||||||
throw Errors.emailVerificationRequired
|
throw Errors.emailVerificationRequired
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
|
|
|
@ -155,7 +155,7 @@ async function createMessage(req, type, content, association, userId) {
|
||||||
|
|
||||||
router.all("*", auth, async (req, res, next) => {
|
router.all("*", auth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (!req.user.emailVerified && process.env.EMAIL_VERIFICATION === "true") {
|
if (!req.user.emailVerified && req.app.locals.config.emailVerification) {
|
||||||
throw Errors.emailVerificationRequired
|
throw Errors.emailVerificationRequired
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
|
@ -376,7 +376,7 @@ router.get("/mutual/:id/groups", auth, async (req, res, next) => {
|
||||||
|
|
||||||
router.get("/users", auth, async (req, res, next) => {
|
router.get("/users", auth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (process.env.PUBLIC_USERS === "true") {
|
if (req.app.locals.config.publicUsers) {
|
||||||
const users = await User.findAll({
|
const users = await User.findAll({
|
||||||
attributes: [
|
attributes: [
|
||||||
"id",
|
"id",
|
||||||
|
|
|
@ -6,7 +6,7 @@ const router = express.Router()
|
||||||
|
|
||||||
router.all("*", auth, async (req, res, next) => {
|
router.all("*", auth, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (!req.user.emailVerified && process.env.EMAIL_VERIFICATION === "true") {
|
if (!req.user.emailVerified && req.app.locals.config.emailVerification) {
|
||||||
throw Errors.emailVerificationRequired
|
throw Errors.emailVerificationRequired
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
|
|
|
@ -72,7 +72,7 @@ const upload = multer({
|
||||||
|
|
||||||
router.post("/verify/resend", auth, mailLimiter, async (req, res, next) => {
|
router.post("/verify/resend", auth, mailLimiter, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (process.env.EMAIL_VERIFICATION !== "true") {
|
if (!req.app.locals.config.emailVerification) {
|
||||||
throw Errors.invalidParameter("Email verification is disabled")
|
throw Errors.invalidParameter("Email verification is disabled")
|
||||||
}
|
}
|
||||||
if (req.user.emailVerified) {
|
if (req.user.emailVerified) {
|
||||||
|
@ -85,20 +85,20 @@ router.post("/verify/resend", auth, mailLimiter, async (req, res, next) => {
|
||||||
const mailGenerator = new Mailgen({
|
const mailGenerator = new Mailgen({
|
||||||
theme: "default",
|
theme: "default",
|
||||||
product: {
|
product: {
|
||||||
name: process.env.SITE_NAME,
|
name: req.app.locals.config.siteName,
|
||||||
link: process.env.CORS_HOSTNAME
|
link: req.app.locals.config.corsHostname
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const email = {
|
const email = {
|
||||||
body: {
|
body: {
|
||||||
name: req.user.username,
|
name: req.user.username,
|
||||||
intro: `${process.env.SITE_NAME} Account Verification`,
|
intro: `${req.app.locals.config.siteName} Account Verification`,
|
||||||
action: {
|
action: {
|
||||||
instructions: `You are receiving this email because you registered on ${process.env.SITE_NAME}, please use the link below to verify your account.`,
|
instructions: `You are receiving this email because you registered on ${req.app.locals.config.siteName}, please use the link below to verify your account.`,
|
||||||
button: {
|
button: {
|
||||||
color: "#1A97FF",
|
color: "#1A97FF",
|
||||||
text: "Account Verification",
|
text: "Account Verification",
|
||||||
link: process.env.CORS_HOSTNAME + "/email/confirm/" + token
|
link: req.app.locals.config.corsHostname + "/email/confirm/" + token
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
outro: "If you did not register, please disregard this email."
|
outro: "If you did not register, please disregard this email."
|
||||||
|
@ -108,18 +108,18 @@ router.post("/verify/resend", auth, mailLimiter, async (req, res, next) => {
|
||||||
|
|
||||||
const emailText = mailGenerator.generatePlaintext(email)
|
const emailText = mailGenerator.generatePlaintext(email)
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
host: process.env.EMAIL_SMTP_HOST,
|
host: req.app.locals.config.emailSMTPHost,
|
||||||
port: process.env.EMAIL_SMTP_PORT,
|
port: req.app.locals.config.emailSMTPPort,
|
||||||
secure: JSON.parse(process.env.EMAIL_SMTP_SECURE.toLowerCase()),
|
secure: req.app.locals.config.emailSMTPSecure,
|
||||||
auth: {
|
auth: {
|
||||||
user: process.env.EMAIL_SMTP_USER,
|
user: req.app.locals.config.emailSMTPUser,
|
||||||
pass: process.env.EMAIL_SMTP_PASSWORD
|
pass: req.app.locals.config.emailSMTPPassword
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let info = await transporter.sendMail({
|
let info = await transporter.sendMail({
|
||||||
from: process.env.EMAIL_SMTP_FROM,
|
from: req.app.locals.config.emailSMTPFrom,
|
||||||
to: req.user.email,
|
to: req.user.email,
|
||||||
subject: "Email Verification - " + process.env.SITE_NAME,
|
subject: "Email Verification - " + req.app.locals.config.siteName,
|
||||||
text: emailText,
|
text: emailText,
|
||||||
html: emailBody
|
html: emailBody
|
||||||
})
|
})
|
||||||
|
@ -135,7 +135,7 @@ router.post("/verify/resend", auth, mailLimiter, async (req, res, next) => {
|
||||||
|
|
||||||
router.post("/verify/confirm/:token", async (req, res, next) => {
|
router.post("/verify/confirm/:token", async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (process.env.EMAIL_VERIFICATION !== "true") {
|
if (!req.app.locals.config.emailVerification) {
|
||||||
throw Errors.invalidParameter("Email verification is disabled")
|
throw Errors.invalidParameter("Email verification is disabled")
|
||||||
}
|
}
|
||||||
if (!req.params.token) {
|
if (!req.params.token) {
|
||||||
|
@ -294,7 +294,7 @@ router.post("/register", limiter, async (req, res, next) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (process.env.ALLOW_REGISTRATIONS !== "true") {
|
if (!req.app.locals.config.allowRegistrations) {
|
||||||
throw Errors.registrationsDisabled
|
throw Errors.registrationsDisabled
|
||||||
}
|
}
|
||||||
if (req.body.password.length < 8) {
|
if (req.body.password.length < 8) {
|
||||||
|
|
165
cli/index.js
165
cli/index.js
|
@ -9,6 +9,11 @@ const os = require("os")
|
||||||
const { execSync } = require("child_process")
|
const { execSync } = require("child_process")
|
||||||
|
|
||||||
console.log("Troplo/Colubrina CLI")
|
console.log("Troplo/Colubrina CLI")
|
||||||
|
if (fs.existsSync("../backend/config/config.json")) {
|
||||||
|
console.log(
|
||||||
|
"Want to modify either the Colubrina, or database config? Check out the config files in backend/config."
|
||||||
|
)
|
||||||
|
}
|
||||||
console.log("Colubrina version", require("../frontend/package.json").version)
|
console.log("Colubrina version", require("../frontend/package.json").version)
|
||||||
async function checkForUpdates() {
|
async function checkForUpdates() {
|
||||||
if (!process.argv.includes("--skip-update")) {
|
if (!process.argv.includes("--skip-update")) {
|
||||||
|
@ -139,10 +144,10 @@ async function testDB() {
|
||||||
async function dbSetup() {
|
async function dbSetup() {
|
||||||
await doSetupDB()
|
await doSetupDB()
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(__dirname, "../backend/config/config.json"),
|
path.join(__dirname, "../backend/config/database.json"),
|
||||||
JSON.stringify(state.dbConfig)
|
JSON.stringify(state.dbConfig, null, 2)
|
||||||
)
|
)
|
||||||
console.log("config/config.json overwritten")
|
console.log("config/database.json overwritten")
|
||||||
}
|
}
|
||||||
async function runMigrations() {
|
async function runMigrations() {
|
||||||
console.log("Running migrations")
|
console.log("Running migrations")
|
||||||
|
@ -171,116 +176,61 @@ async function createUser() {
|
||||||
console.log("User created")
|
console.log("User created")
|
||||||
}
|
}
|
||||||
async function configureDotEnv() {
|
async function configureDotEnv() {
|
||||||
function setEnvValue(key, value) {
|
if (!fs.existsSync("../backend/config/config.json")) {
|
||||||
const ENV_VARS = fs.readFileSync("../backend/.env", "utf8").split(os.EOL)
|
fs.writeFileSync("../backend/config/config.json", "{}")
|
||||||
|
|
||||||
// find the env we want based on the key
|
|
||||||
const target = ENV_VARS.indexOf(
|
|
||||||
ENV_VARS.find((line) => {
|
|
||||||
// (?<!#\s*) Negative lookbehind to avoid matching comments (lines that starts with #).
|
|
||||||
// There is a double slash in the RegExp constructor to escape it.
|
|
||||||
// (?==) Positive lookahead to check if there is an equal sign right after the key.
|
|
||||||
// This is to prevent matching keys prefixed with the key of the env var to update.
|
|
||||||
const keyValRegex = new RegExp(`(?<!#\\s*)${key}(?==)`)
|
|
||||||
|
|
||||||
return line.match(keyValRegex)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// if key-value pair exists in the .env file,
|
|
||||||
if (target !== -1) {
|
|
||||||
// replace the key/value with the new value
|
|
||||||
ENV_VARS.splice(target, 1, `${key}=${value}`)
|
|
||||||
} else {
|
|
||||||
// if it doesn't exist, add it instead
|
|
||||||
ENV_VARS.push(`${key}=${value}`)
|
|
||||||
}
|
}
|
||||||
|
let config = require("../backend/config/config.json")
|
||||||
// write everything back to the file system
|
config.hostname = await input.text("Public Domain", {
|
||||||
fs.writeFileSync("../backend/.env", ENV_VARS.join(os.EOL))
|
|
||||||
}
|
|
||||||
if (!fs.existsSync("../backend/.env")) {
|
|
||||||
fs.writeFileSync("../backend/.env", "")
|
|
||||||
}
|
|
||||||
setEnvValue(
|
|
||||||
"HOSTNAME",
|
|
||||||
await input.text("Public Domain", {
|
|
||||||
default: "localhost"
|
default: "localhost"
|
||||||
})
|
})
|
||||||
)
|
config.corsHostname = await input.text("CORS Hostname", {
|
||||||
setEnvValue(
|
default: "http://localhost"
|
||||||
"CORS_HOSTNAME",
|
|
||||||
await input.text("Public Hostname", {
|
|
||||||
default: "http://localhost:8080"
|
|
||||||
})
|
})
|
||||||
)
|
config.siteName = await input.text("Site Name", {
|
||||||
setEnvValue(
|
|
||||||
"SITE_NAME",
|
|
||||||
await input.text("Site Name", {
|
|
||||||
default: "Colubrina"
|
default: "Colubrina"
|
||||||
})
|
})
|
||||||
)
|
config.allowRegistrations = await input.text("Allow Registrations", {
|
||||||
setEnvValue(
|
default: true
|
||||||
"ALLOW_REGISTRATIONS",
|
})
|
||||||
await input.text("Permit Public Registrations", {
|
config.publicUsers = await input.text("Show instance users publicly?", {
|
||||||
|
default: true
|
||||||
|
})
|
||||||
|
config.emailVerify = await input.text("Enforce email verification?", {
|
||||||
default: false
|
default: false
|
||||||
})
|
})
|
||||||
)
|
if (config.emailVerify) {
|
||||||
setEnvValue(
|
config.emailSMTPHost = await input.text("SMTP Host", {
|
||||||
"PUBLIC_USERS",
|
default: "mail.example.com"
|
||||||
await input.text("Show instance users publicly", {
|
|
||||||
default: false
|
|
||||||
})
|
})
|
||||||
)
|
config.emailSMTPPort = await input.text("SMTP Port", {
|
||||||
const emailVerify = await input.text("Enforce email verification?", {
|
|
||||||
default: false
|
|
||||||
})
|
|
||||||
if (emailVerify) {
|
|
||||||
setEnvValue("EMAIL_VERIFICATION", true)
|
|
||||||
setEnvValue(
|
|
||||||
"EMAIL_SMTP_HOST",
|
|
||||||
await input.text("SMTP Host", {
|
|
||||||
default: "smtp.myhost.com"
|
|
||||||
})
|
|
||||||
)
|
|
||||||
setEnvValue(
|
|
||||||
"EMAIL_SMTP_PORT",
|
|
||||||
await input.text("SMTP Port", {
|
|
||||||
default: 587
|
default: 587
|
||||||
})
|
})
|
||||||
)
|
config.emailSMTPUsername = await input.text("SMTP Username", {
|
||||||
setEnvValue(
|
default: "colubrina@example.com"
|
||||||
"EMAIL_SMTP_USER",
|
|
||||||
await input.text("SMTP User", {
|
|
||||||
default: "colubrina@myhost.com"
|
|
||||||
})
|
})
|
||||||
)
|
config.emailSMTPPassword = await input.text("SMTP Password", {})
|
||||||
setEnvValue(
|
config.emailSMTPFrom = await input.text("SMTP From Address", {
|
||||||
"EMAIL_SMTP_FROM",
|
default: "colubrina@example.com"
|
||||||
await input.text("SMTP From Address", {
|
|
||||||
default: "colubrina@myhost.com"
|
|
||||||
})
|
})
|
||||||
)
|
config.emailSMTPSecure = await input.text("SMTP Secure", {
|
||||||
setEnvValue("EMAIL_SMTP_PASSWORD", await input.text("SMTP Password", {}))
|
default: true
|
||||||
setEnvValue(
|
|
||||||
"EMAIL_SMTP_SECURE",
|
|
||||||
await input.text("SMTP Secure", {
|
|
||||||
default: false
|
|
||||||
})
|
})
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
setEnvValue("EMAIL_VERIFICATION", false)
|
config.emailSMTPHost = "smtp.myhost.com"
|
||||||
setEnvValue("EMAIL_SMTP_HOST", "smtp.myhost.com")
|
config.emailSMTPPort = 587
|
||||||
setEnvValue("EMAIL_SMTP_PORT", "587")
|
config.emailSMTPUsername = "colubrina@example.com"
|
||||||
setEnvValue("EMAIL_SMTP_USER", "colubrina@myhost.com")
|
config.emailSMTPFrom = "colubrina@example.com"
|
||||||
setEnvValue("EMAIL_SMTP_FROM", "colubrina@myhost.com")
|
config.emailSMTPPassword = ""
|
||||||
setEnvValue("EMAIL_SMTP_PASSWORD", "myPassword")
|
config.emailSMTPSecure = true
|
||||||
setEnvValue("EMAIL_SMTP_SECURE", false)
|
|
||||||
}
|
}
|
||||||
setEnvValue("PUBLIC_USERS")
|
config.notification = ""
|
||||||
setEnvValue("NOTIFICATION", "")
|
config.notificationType = "info"
|
||||||
setEnvValue("NOTIFICATION_TYPE", "info")
|
config.release = "stable"
|
||||||
setEnvValue("RELEASE", "stable")
|
config.rules = "Write your instance rules here."
|
||||||
|
fs.writeFileSync(
|
||||||
|
"../backend/config/config.json",
|
||||||
|
JSON.stringify(config, null, 2)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
async function init() {
|
async function init() {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -288,7 +238,7 @@ async function init() {
|
||||||
"First-time setup",
|
"First-time setup",
|
||||||
"Create user",
|
"Create user",
|
||||||
"Run migrations",
|
"Run migrations",
|
||||||
"Update/create config file",
|
"Update/create database config file",
|
||||||
"Check for updates",
|
"Check for updates",
|
||||||
"Build frontend for production",
|
"Build frontend for production",
|
||||||
"Exit"
|
"Exit"
|
||||||
|
@ -303,10 +253,15 @@ async function init() {
|
||||||
execSync("cd ../frontend && yarn install --frozen-lockfile", () => {
|
execSync("cd ../frontend && yarn install --frozen-lockfile", () => {
|
||||||
console.log("yarn install complete (frontend)")
|
console.log("yarn install complete (frontend)")
|
||||||
})
|
})
|
||||||
if (fs.existsSync(path.join(__dirname, "../backend/.env"))) {
|
if (
|
||||||
const option = await input.confirm(".env already exists, overwrite?", {
|
fs.existsSync(path.join(__dirname, "../backend/config/config.json"))
|
||||||
|
) {
|
||||||
|
const option = await input.confirm(
|
||||||
|
"Colubrina config already exists, overwrite?",
|
||||||
|
{
|
||||||
default: false
|
default: false
|
||||||
})
|
}
|
||||||
|
)
|
||||||
if (option) {
|
if (option) {
|
||||||
await configureDotEnv()
|
await configureDotEnv()
|
||||||
}
|
}
|
||||||
|
@ -314,10 +269,10 @@ async function init() {
|
||||||
await configureDotEnv()
|
await configureDotEnv()
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
fs.existsSync(path.join(__dirname, "../backend/config/config.json"))
|
fs.existsSync(path.join(__dirname, "../backend/config/database.json"))
|
||||||
) {
|
) {
|
||||||
const option = await input.select(
|
const option = await input.select(
|
||||||
`config/config.json already exists. Do you want to overwrite it?`,
|
`config/database.json already exists. Do you want to overwrite it?`,
|
||||||
["Yes", "No"]
|
["Yes", "No"]
|
||||||
)
|
)
|
||||||
if (option === "Yes") {
|
if (option === "Yes") {
|
||||||
|
@ -368,9 +323,9 @@ async function init() {
|
||||||
console.log(
|
console.log(
|
||||||
"The Colubrina frontend can be built with `yarn build` in the root project directory, and is recommended to be served via NGINX, with a proxy_pass to the backend on /api and /socket.io."
|
"The Colubrina frontend can be built with `yarn build` in the root project directory, and is recommended to be served via NGINX, with a proxy_pass to the backend on /api and /socket.io."
|
||||||
)
|
)
|
||||||
} else if (option === "Update/create config file") {
|
} else if (option === "Update/create database config file") {
|
||||||
await dbSetup()
|
await dbSetup()
|
||||||
console.log("config/config.json overwritten or created")
|
console.log("config/database.json overwritten or created")
|
||||||
} else if (option === "Create user") {
|
} else if (option === "Create user") {
|
||||||
await createUser()
|
await createUser()
|
||||||
} else if (option === "Run migrations") {
|
} else if (option === "Run migrations") {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "colubrina",
|
"name": "colubrina",
|
||||||
"version": "1.0.18",
|
"version": "1.0.19",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Troplo <troplo@troplo.com>",
|
"author": "Troplo <troplo@troplo.com>",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -624,6 +624,9 @@ export default {
|
||||||
this.$store.state.site.latestVersion = state.latestVersion
|
this.$store.state.site.latestVersion = state.latestVersion
|
||||||
this.$store.state.site.notification = state.notification
|
this.$store.state.site.notification = state.notification
|
||||||
this.$store.state.site.notificationType = state.notificationType
|
this.$store.state.site.notificationType = state.notificationType
|
||||||
|
this.$store.state.site.allowRegistrations = state.allowRegistrations
|
||||||
|
this.$store.state.site.rules = state.rules
|
||||||
|
this.$store.state.site.emailVerification = state.emailVerification
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
this.$store.dispatch("updateQuickSwitch")
|
this.$store.dispatch("updateQuickSwitch")
|
||||||
|
|
|
@ -32,6 +32,14 @@
|
||||||
label="Allow registrations"
|
label="Allow registrations"
|
||||||
v-model="allowRegistrations"
|
v-model="allowRegistrations"
|
||||||
></v-switch>
|
></v-switch>
|
||||||
|
<v-textarea ref="rules" label="Instance Rules" v-model="rules" class="mx-3">
|
||||||
|
</v-textarea>
|
||||||
|
<v-card-title>
|
||||||
|
<v-icon class="mr-1">mdi-language-markdown</v-icon>Rules Preview:
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<span v-markdown class="mx-3" :key="rules">{{ rules }}</span>
|
||||||
|
</v-card-text>
|
||||||
<v-btn text class="mx-3 mb-3" color="primary" @click="updateState"
|
<v-btn text class="mx-3 mb-3" color="primary" @click="updateState"
|
||||||
>Save</v-btn
|
>Save</v-btn
|
||||||
>
|
>
|
||||||
|
@ -47,6 +55,7 @@ export default {
|
||||||
notification: "",
|
notification: "",
|
||||||
notificationType: "info",
|
notificationType: "info",
|
||||||
allowRegistrations: true,
|
allowRegistrations: true,
|
||||||
|
rules: "",
|
||||||
notificationTypes: [
|
notificationTypes: [
|
||||||
{ text: "Info", value: "info" },
|
{ text: "Info", value: "info" },
|
||||||
{ text: "Success", value: "success" },
|
{ text: "Success", value: "success" },
|
||||||
|
@ -73,7 +82,8 @@ export default {
|
||||||
notification: this.notification,
|
notification: this.notification,
|
||||||
notificationType: this.notificationType,
|
notificationType: this.notificationType,
|
||||||
broadcastType: this.broadcastType,
|
broadcastType: this.broadcastType,
|
||||||
allowRegistrations: this.allowRegistrations
|
allowRegistrations: this.allowRegistrations,
|
||||||
|
rules: this.rules
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$toast.success("State updated")
|
this.$toast.success("State updated")
|
||||||
|
@ -87,6 +97,7 @@ export default {
|
||||||
this.notification = this.$store.state.site.notification
|
this.notification = this.$store.state.site.notification
|
||||||
this.notificationType = this.$store.state.site.notificationType
|
this.notificationType = this.$store.state.site.notificationType
|
||||||
this.allowRegistrations = this.$store.state.site.allowRegistrations
|
this.allowRegistrations = this.$store.state.site.allowRegistrations
|
||||||
|
this.rules = this.$store.state.site.rules
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="admin-users">
|
<div id="admin-users">
|
||||||
|
<v-dialog width="500" v-model="create.dialog">
|
||||||
|
<v-card color="card">
|
||||||
|
<v-toolbar color="toolbar">
|
||||||
|
<v-toolbar-title>Create User</v-toolbar-title>
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-form @submit.prevent="createUser">
|
||||||
|
<v-text-field
|
||||||
|
label="Username"
|
||||||
|
v-model="create.username"
|
||||||
|
></v-text-field>
|
||||||
|
<v-text-field label="Email" v-model="create.email"></v-text-field>
|
||||||
|
<v-text-field
|
||||||
|
label="Password"
|
||||||
|
type="password"
|
||||||
|
v-model="create.password"
|
||||||
|
></v-text-field>
|
||||||
|
<v-switch
|
||||||
|
inset
|
||||||
|
label="Email Verified?"
|
||||||
|
v-model="create.emailVerified"
|
||||||
|
></v-switch>
|
||||||
|
<v-btn text type="submit" color="primary">Create</v-btn>
|
||||||
|
</v-form>
|
||||||
|
</v-container>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
<v-toolbar color="toolbar">
|
<v-toolbar color="toolbar">
|
||||||
<v-toolbar-title>Users ({{ users.count }})</v-toolbar-title>
|
<v-toolbar-title>Users ({{ users.count }})</v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn @click="create.dialog = true" icon>
|
||||||
|
<v-icon>mdi-plus</v-icon>
|
||||||
|
</v-btn>
|
||||||
<v-btn @click="getUsers" icon>
|
<v-btn @click="getUsers" icon>
|
||||||
<v-icon>mdi-refresh</v-icon>
|
<v-icon>mdi-refresh</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
@ -19,6 +49,21 @@
|
||||||
<template v-slot:item.index="{ index }">
|
<template v-slot:item.index="{ index }">
|
||||||
{{ index }}
|
{{ index }}
|
||||||
</template>
|
</template>
|
||||||
|
<template v-slot:item.actions="{ item }">
|
||||||
|
<v-tooltip top>
|
||||||
|
<template v-slot:activator="{ on }">
|
||||||
|
<v-btn
|
||||||
|
v-on="on"
|
||||||
|
icon
|
||||||
|
@click="banUser(item)"
|
||||||
|
:disabled="item.id === $store.state.user.id || item.admin"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-gavel</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<span>Ban</span>
|
||||||
|
</v-tooltip>
|
||||||
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -31,6 +76,13 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
users: [],
|
users: [],
|
||||||
|
create: {
|
||||||
|
dialog: false,
|
||||||
|
username: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
emailVerified: false
|
||||||
|
},
|
||||||
headers: [
|
headers: [
|
||||||
{
|
{
|
||||||
text: "Index",
|
text: "Index",
|
||||||
|
@ -68,11 +120,59 @@ export default {
|
||||||
{
|
{
|
||||||
text: "Last Seen At",
|
text: "Last Seen At",
|
||||||
value: "lastSeenAt"
|
value: "lastSeenAt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Admin",
|
||||||
|
value: "admin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Banned",
|
||||||
|
value: "banned"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Email Verified",
|
||||||
|
value: "emailVerified"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Actions",
|
||||||
|
value: "actions",
|
||||||
|
sortable: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
createUser() {
|
||||||
|
this.axios
|
||||||
|
.post(`/api/v1/admin/user`, this.create)
|
||||||
|
.then(() => {
|
||||||
|
this.getUsers()
|
||||||
|
this.$toast.success("Action performed successfully.")
|
||||||
|
this.create = {
|
||||||
|
dialog: false,
|
||||||
|
username: "",
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
emailVerified: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
AjaxErrorHandler(this.$store)(e)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
banUser(item) {
|
||||||
|
this.axios
|
||||||
|
.put(`/api/v1/admin/user/${item.id}`, {
|
||||||
|
banned: !item.banned
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.getUsers()
|
||||||
|
this.$toast.success("Action performed successfully.")
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
AjaxErrorHandler(this.$store)(e)
|
||||||
|
})
|
||||||
|
},
|
||||||
getUsers() {
|
getUsers() {
|
||||||
this.axios
|
this.axios
|
||||||
.get("/api/v1/admin/users")
|
.get("/api/v1/admin/users")
|
||||||
|
|
|
@ -30,8 +30,7 @@
|
||||||
<v-form ref="form" class="pa-4 pt-6">
|
<v-form ref="form" class="pa-4 pt-6">
|
||||||
<p class="text-center text-h4">
|
<p class="text-center text-h4">
|
||||||
Login to
|
Login to
|
||||||
<span class="troplo-title">{{ $store.state.site.name }}</span
|
<span class="troplo-title">{{ $store.state.site.name }}</span>
|
||||||
><small style="font-size: 15px">beta</small>
|
|
||||||
</p>
|
</p>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@keyup.enter="doLogin()"
|
@keyup.enter="doLogin()"
|
||||||
|
|
|
@ -1,5 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="login" v-if="!$store.state.user?.bcUser?.id">
|
<div id="login" v-if="!$store.state.user?.id">
|
||||||
|
<v-dialog v-model="rulesDialog" max-width="700px">
|
||||||
|
<v-card color="card">
|
||||||
|
<v-toolbar color="toolbar">
|
||||||
|
<v-toolbar-title>
|
||||||
|
{{ $store.state.site.name }} Rules
|
||||||
|
</v-toolbar-title>
|
||||||
|
</v-toolbar>
|
||||||
|
<v-card-text class="mt-3" style="color: unset">
|
||||||
|
<span v-markdown :key="$store.state.site.rules">{{
|
||||||
|
$store.state.site.rules
|
||||||
|
}}</span>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
<div :class="{ outer: !$vuetify.breakpoint.mobile }">
|
<div :class="{ outer: !$vuetify.breakpoint.mobile }">
|
||||||
<div :class="{ middle: !$vuetify.breakpoint.mobile }">
|
<div :class="{ middle: !$vuetify.breakpoint.mobile }">
|
||||||
<div :class="{ innerLogin: !$vuetify.breakpoint.mobile }">
|
<div :class="{ innerLogin: !$vuetify.breakpoint.mobile }">
|
||||||
|
@ -8,8 +22,7 @@
|
||||||
<v-form ref="form" class="pa-4 pt-6">
|
<v-form ref="form" class="pa-4 pt-6">
|
||||||
<p class="text-center text-h4">
|
<p class="text-center text-h4">
|
||||||
Register to
|
Register to
|
||||||
<span class="troplo-title">{{ $store.state.site.name }}</span
|
<span class="troplo-title">{{ $store.state.site.name }}</span>
|
||||||
><small style="font-size: 15px">beta</small>
|
|
||||||
</p>
|
</p>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@keyup.enter="doRegister()"
|
@keyup.enter="doRegister()"
|
||||||
|
@ -52,6 +65,38 @@
|
||||||
>This instance has email verification enforced, ensure your
|
>This instance has email verification enforced, ensure your
|
||||||
email is correct.</small
|
email is correct.</small
|
||||||
>
|
>
|
||||||
|
<v-row align="center">
|
||||||
|
<v-tooltip top v-if="!rulesOpenedOnce">
|
||||||
|
<template v-slot:activator="{ on }">
|
||||||
|
<div v-on="on">
|
||||||
|
<v-switch
|
||||||
|
class="ml-4 mt-5"
|
||||||
|
inset
|
||||||
|
v-model="rules"
|
||||||
|
:disabled="!rulesOpenedOnce"
|
||||||
|
></v-switch>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<span>You need to view the rules first.</span>
|
||||||
|
</v-tooltip>
|
||||||
|
<v-switch
|
||||||
|
class="ml-4 mt-5"
|
||||||
|
inset
|
||||||
|
v-model="rules"
|
||||||
|
v-else
|
||||||
|
:disabled="!rulesOpenedOnce"
|
||||||
|
></v-switch>
|
||||||
|
I have read and agree to the
|
||||||
|
<a
|
||||||
|
@click="
|
||||||
|
rulesDialog = true
|
||||||
|
rulesOpenedOnce = true
|
||||||
|
"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
instance rules </a
|
||||||
|
>.
|
||||||
|
</v-row>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn
|
<v-btn
|
||||||
|
@ -96,6 +141,9 @@ export default {
|
||||||
totp: "",
|
totp: "",
|
||||||
totpDialog: false,
|
totpDialog: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
rules: false,
|
||||||
|
rulesDialog: false,
|
||||||
|
rulesOpenedOnce: false,
|
||||||
instance:
|
instance:
|
||||||
localStorage.getItem("instance") || "https://colubrina.troplo.com",
|
localStorage.getItem("instance") || "https://colubrina.troplo.com",
|
||||||
instanceString: ""
|
instanceString: ""
|
||||||
|
@ -123,6 +171,12 @@ export default {
|
||||||
return window.innerHeight
|
return window.innerHeight
|
||||||
},
|
},
|
||||||
doRegister() {
|
doRegister() {
|
||||||
|
if (!this.rules) {
|
||||||
|
this.$toast.error(
|
||||||
|
"You need to accept the rules before you can register."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.axios
|
this.axios
|
||||||
.post("/api/v1/user/register", {
|
.post("/api/v1/user/register", {
|
||||||
|
|
|
@ -94,9 +94,37 @@ module.exports = {
|
||||||
builderOptions: {
|
builderOptions: {
|
||||||
appId: "com.troplo.colubrina",
|
appId: "com.troplo.colubrina",
|
||||||
win: {
|
win: {
|
||||||
|
target: [
|
||||||
|
{
|
||||||
|
target: "nsis",
|
||||||
|
arch: ["x64", "ia32", "armv7l", "arm64"]
|
||||||
|
}
|
||||||
|
],
|
||||||
publish: ["github"]
|
publish: ["github"]
|
||||||
},
|
},
|
||||||
linux: {
|
linux: {
|
||||||
|
target: [
|
||||||
|
{
|
||||||
|
target: "AppImage",
|
||||||
|
arch: ["x64", "ia32", "armv7l", "arm64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: "deb",
|
||||||
|
arch: ["x64", "ia32", "armv7l", "arm64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: "snap",
|
||||||
|
arch: ["x64", "ia32", "armv7l", "arm64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: "pacman",
|
||||||
|
arch: ["x64", "ia32", "armv7l", "arm64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: "tar.gz",
|
||||||
|
arch: ["x64", "ia32", "armv7l", "arm64"]
|
||||||
|
}
|
||||||
|
],
|
||||||
publish: ["github"],
|
publish: ["github"],
|
||||||
category: "Network",
|
category: "Network",
|
||||||
synopsis: "Instant Messaging",
|
synopsis: "Instant Messaging",
|
||||||
|
|
Loading…
Reference in a new issue