diff --git a/css/oi.css b/css/oi.css
index 7736ddb47a..d0a7240a25 100644
--- a/css/oi.css
+++ b/css/oi.css
@@ -156,3 +156,7 @@ input::placeholder {
z-index: 1000;
outline: none;
}
+
+.cactus-editor {
+ display: none!important;
+}
\ No newline at end of file
diff --git a/db/Ideas.db.backup b/db/Ideas.db.backup
index d5dadd159e..a14bde24b2 100644
Binary files a/db/Ideas.db.backup and b/db/Ideas.db.backup differ
diff --git a/media/favicon.png b/media/favicon.png
new file mode 100644
index 0000000000..eaec21b5de
Binary files /dev/null and b/media/favicon.png differ
diff --git a/myServer.js b/myServer.js
index f4d5859fb7..5a6772e867 100644
--- a/myServer.js
+++ b/myServer.js
@@ -7,28 +7,26 @@ const express = require("express");
const fs = require("fs");
const sqlite3 = require("sqlite3").verbose();
const https = require("https");
-var path = require("path");
-var bcrypt = require("bcrypt");
-const sdk = require("matrix-js-sdk");
-var request = require('request');
+const path = require("path");
+const bcrypt = require("bcrypt");
+const request = require("request");
const passport = require("passport");
const flash = require("express-flash");
const session = require("express-session");
-const methodOverride = require('method-override');
+const methodOverride = require("method-override");
+const matrix = require("./src/oi/matrix");
+// const db = require("./src/oi/sqliteDb");
const app = express();
const http = express();
const port = process.argv[2] || 80;
const portSSL = process.argv[3] || 443;
-//matrix login
-const client = sdk.createClient("https://matrix.org");
-client.login("m.login.password", {"user": "openidea", "password": process.env.MATRIX_PASSWORD}).then((response) => {
- console.log(response.access_token);
-});
+matrix.loginOpenIdea();
//usermanagement using passport
const initializePassport = require("./passport-config");
+// initializePassport(passport, async db.getUserByEmail);
initializePassport(passport, async function getUserByEmail(email) {
return new Promise((resolve) => {
let sql = `SELECT name, email, pwHash password FROM User WHERE email is ?`;
@@ -41,8 +39,7 @@ initializePassport(passport, async function getUserByEmail(email) {
if (err) throw err;
resolve(rows);
});
- }
- else resolve(rows);
+ } else resolve(rows);
});
});
});
@@ -91,15 +88,14 @@ app.use((req, res, next) => {
app.use(passport.initialize());
app.use(passport.session());
-app.use(methodOverride('_method'));
+app.use(methodOverride("_method"));
//app start page
app.get("/", checkAuthenticated, function (req, res) {
- if(req.session.isNew) {
- if(req.query.Idea) res.redirect('/?user=new&Idea='+req.query.Idea);
- else res.redirect('/?user=new');
- }
- else {
+ if (req.session.isNew) {
+ if (req.query.Idea) res.redirect("/?user=new&Idea=" + req.query.Idea);
+ else res.redirect("/?user=new");
+ } else {
try {
console.log(req.user.name + " visited us");
} catch (error) {
@@ -109,7 +105,6 @@ app.get("/", checkAuthenticated, function (req, res) {
}
});
-
//respond with topics
app.get("/getTopics", function (req, res) {
//read all topics from Database
@@ -135,10 +130,10 @@ app.get("/getSkills", function (req, res) {
});
//respond to getIdeas GET request
-app.get("/getIdeas", checkAuthenticated, function(req, res) {
+app.get("/getIdeas", checkAuthenticated, function (req, res) {
//read all places from Database
var idearows;
- db.serialize(function() {
+ db.serialize(function () {
let sql = `SELECT lon, lat, IdeaID, upvotes, downvotes FROM v_PlacesVotes ORDER BY lat`;
db.all(sql, [], async (err, rows) => {
if (err) throw err;
@@ -148,16 +143,16 @@ app.get("/getIdeas", checkAuthenticated, function(req, res) {
idearows[key].tags = tmp.tags;
idearows[key].skills = tmp.skills;
idearows[key].user = tmp.user;
- };
+ }
res.json(idearows);
});
});
});
function addTagsSkillsUsers(id) {
- var idearows = {tags: [], skills: [], user: []};
+ var idearows = { tags: [], skills: [], user: [] };
return new Promise((resolve) => {
- db.serialize(function() {
+ db.serialize(function () {
let sql = `SELECT Tag FROM Idea_Tags WHERE Idea is ?`;
db.all(sql, [id], (err, rows) => {
if (err) throw err;
@@ -188,17 +183,17 @@ function addTagsSkillsUsers(id) {
});
});
});
-};
+}
//get svgs
-app.get("/svgTest", function(req,res) {
+app.get("/svgTest", function (req, res) {
let _id = req.query.IdeaID;
let _title = "";
db.serialize(function () {
let sql = `SELECT ID, title FROM Idea WHERE ID is ?`;
db.get(sql, [_id], (err, row) => {
if (err) throw err;
- if(row) _title = row.title;
+ if (row) _title = row.title;
else _title = "title not found";
// console.log("test query " + _id + " title " + _title);
var testSVG = `
@@ -220,12 +215,21 @@ app.get("/svgTest", function(req,res) {
${_title}
`;
- res.type('svg');
+ res.type("svg");
res.send(testSVG);
});
});
});
+//endpoint for new comments
+app.post("/submitComment", checkAuthenticated, async function (req, res, next) {
+ if(res._headers.login !== "false")
+ console.log(await matrix.sendMessage(res._headers.login, req.body.IdeaID, req.body.comment, db));
+ //elso only if we want to let people comment without login in!
+ //else console.log(await matrix.sendMessage('guest', req.body.IdeaID, req.body.comment, db));
+ res.json({msg: "comment saved"});
+});
+
//respond to getIdea POST request
app.post("/getIdea", checkAuthenticated, function (req, res) {
if (!req.body.IdeaID) res.json();
@@ -294,7 +298,7 @@ app.post("/submitVote", checkAuthenticatedCancel, function (req, res) {
1: req.body.IdeaID,
2: req.body.upvote,
3: datenow,
- 4: req.user.name
+ 4: req.user.name,
},
function (err) {
if (err) return console.log(err.message);
@@ -330,7 +334,7 @@ app.post("/submitIdea", checkAuthenticatedCancel, function (req, res) {
);
var tags = req.body.tags.split(",");
tags.forEach(function (item, index) {
- if(item.trim() != ""){
+ if (item.trim() != "") {
db.run(
"INSERT OR IGNORE INTO Tags(Name) VALUES(?1)",
{
@@ -354,7 +358,7 @@ app.post("/submitIdea", checkAuthenticatedCancel, function (req, res) {
});
var skills = req.body.skills.split(",");
skills.forEach(function (item, index) {
- if(item.trim() != ""){
+ if (item.trim() != "") {
db.run(
"INSERT OR IGNORE INTO Skills(Name) VALUES(?1)",
{
@@ -381,7 +385,7 @@ app.post("/submitIdea", checkAuthenticatedCancel, function (req, res) {
{
1: lastID,
2: req.user.name,
- 3: 0
+ 3: 0,
},
function (err) {
if (err) return console.log(err.message);
@@ -391,17 +395,17 @@ app.post("/submitIdea", checkAuthenticatedCancel, function (req, res) {
/*****************************|
| mastodon part start |
|*****************************/
- if(req.body.mastodon == "true"){
+ if (req.body.mastodon == "true") {
console.log("publish on mastodon: " + req.body.mastodon);
var tagsBody = "";
- tags.some(function(item, index) {
- if(item.trim() != "") {
- tagsBody += ("#" + item.trim() + " ");
+ tags.some(function (item, index) {
+ if (item.trim() != "") {
+ tagsBody += "#" + item.trim() + " ";
console.log("item: " + index + "tag: " + "#" + item.trim() + " ");
}
//if 3 tags written stop function
- if(index >= 2) return true;
+ if (index >= 2) return true;
else return false;
});
@@ -411,25 +415,26 @@ app.post("/submitIdea", checkAuthenticatedCancel, function (req, res) {
+ "\n" + "https://openidea.io/?Idea=" + lastID + "\n"
+ tagsBody;
- var jsonBody = {'status': truncate(statusText, 425),
- 'visibility': 'unlisted'}// public, unlisted, private, direct
- ;
+ var jsonBody = {
+ status: truncate(statusText, 425),
+ visibility: "unlisted",
+ }; // public, unlisted, private, direct
var clientServerOptions = {
- url: 'https://botsin.space/api/v1/statuses',
+ url: "https://botsin.space/api/v1/statuses",
body: JSON.stringify(jsonBody),
- method: 'POST',
+ method: "POST",
headers: {
- 'Content-Type': 'application/json',
- 'Authorization' : 'Bearer ' + process.env.MASTODON_ACCESS_TOKEN
- }
+ "Content-Type": "application/json",
+ Authorization: "Bearer " + process.env.MASTODON_ACCESS_TOKEN,
+ },
};
- request(clientServerOptions, function(error, response, body){
+ request(clientServerOptions, function (error, response, body) {
// console.log(body);
});
- function truncate(str, n){
- return (str.length > n) ? str.substr(0, n-3) + '...' : str;
- };
+ function truncate(str, n) {
+ return str.length > n ? str.substr(0, n - 3) + "..." : str;
+ }
}
/*****************************|
| mastodon part end |
@@ -440,27 +445,9 @@ app.post("/submitIdea", checkAuthenticatedCancel, function (req, res) {
});
});
-
//support request to matrix room
app.post("/submitSupportRequest", function (req, res, next) {
- client.startClient();
-
- var testRoomId = "!HTcpkpXWLaaunauYsD:cactus.chat";
-
- var content = {
- "body": "#" + req.body.IdeaID + "\n" + req.body.text + "\n\nsend from: ",
- "msgtype": "m.text"
- };
- if(req.user){
- content.body += req.user.email;
- }
- else {content.body += "anonymous";}
-
- client.sendEvent(testRoomId, "m.room.message", content, "").then((res) => {
- // message sent successfully
- }).catch((err) => {
- console.log(err);
- });
+ matrix.sendSupportRequest(req);
res.send("Message send to support");
});
@@ -469,23 +456,23 @@ app.post("/submitSupportRequest", function (req, res, next) {
app.post("/submitLogin", function (req, res, next) {
passport.authenticate("local", (err, user, info) => {
//if authenticate failed respond with info
- if(!user) return res.json(info);
+ if (!user) return res.json(info);
else {
//start user session
- req.logIn(user, function(err) {
- if (err) { return next(err); }
+ req.logIn(user, function (err) {
+ if (err) {
+ return next(err);
+ }
return res.json(user.name);
});
}
- })(req,res,next)
- }
-);
+ })(req, res, next);
+});
app.delete("/SubmitLogout", function (req, res) {
req.logOut();
res.json();
-}
- );
+});
//handle register POST request
app.post("/submitRegister", async function (req, res) {
@@ -494,31 +481,41 @@ app.post("/submitRegister", async function (req, res) {
res.json({
email: req.user.email,
});
- } catch {}
+ } catch(e) {}
+
+ //reject username if it uses not allowed character
+ const regex = /[^A-Za-z0-9 ]+/g;
+ if(regex.test(req.body.name)) {
+ res.json({message: "username not allowed"});
+ return;
+ }
+
console.log(req.body.name);
console.log(req.body.email);
- console.log(req.body.password);
try {
const hashedPassword = await bcrypt.hash(req.body.password, 10);
console.log(hashedPassword);
+ const matrixUser = await matrix.createUser(req.body.name);
db.serialize(function () {
db.run(
- "INSERT INTO User(name,email,pwHash) VALUES(?1,?2,?3)",
+ "INSERT INTO User(name,email,pwHash,matrixname,matrixpw) VALUES(?1,?2,?3,?4,?5)",
{
1: req.body.name,
2: req.body.email,
3: hashedPassword,
+ 4: matrixUser.matrixname,
+ 5: matrixUser.matrixpw,
},
function (err) {
if (err) {
console.log(err.message);
- res.json({"message": err.message});
+ res.json({ message: err.message });
}
res.json("success");
}
);
});
- } catch {
+ } catch(e) {
console.log("error while user registered");
}
});
@@ -550,11 +547,11 @@ function checkAuthenticated(req, res, next) {
function checkAuthenticatedCancel(req, res, next) {
if (req.isAuthenticated()) {
- res.append('login', req.user.name);
+ res.append("login", req.user.name);
console.log("checkAuthenticated " + req.user.name);
next();
} else {
- res.append('login', false);
+ res.append("login", false);
res.json("error");
}
}
diff --git a/package.json b/package.json
index 38a9f436e9..3501fd50ae 100644
--- a/package.json
+++ b/package.json
@@ -36,15 +36,16 @@
"express": "^4.17.1",
"express-flash": "0.0.2",
"express-session": "^1.17.1",
+ "generate-password": "^1.6.0",
"material-design-icons": "^3.0.1",
"materialize-css": "^1.0.0",
"matrix-js-sdk": "^9.9.0",
"method-override": "^3.0.0",
+ "msdf-bmfont-xml": "^2.5.4",
"nodemon": "^2.0.7",
"passport": "^0.4.1",
"passport-local": "^1.0.0",
- "sqlite3": "^5.0.2",
- "msdf-bmfont-xml": "^2.5.4"
+ "sqlite3": "^5.0.2"
},
"exports": {
".": "./src/og/index.js",
diff --git a/src/oi/SideLoginRegister.js b/src/oi/SideLoginRegister.js
index 494ce51a04..52ab426ece 100644
--- a/src/oi/SideLoginRegister.js
+++ b/src/oi/SideLoginRegister.js
@@ -128,7 +128,8 @@ function showRegister() {
@@ -141,7 +142,7 @@ function showRegister() {
-
diff --git a/src/oi/SideShowIdea.js b/src/oi/SideShowIdea.js
index c9989d02f0..9955cb3f0a 100644
--- a/src/oi/SideShowIdea.js
+++ b/src/oi/SideShowIdea.js
@@ -17,6 +17,8 @@ function show(IdeaID) {
document.getElementById("up-btn").onclick = function () {SideLoginRegister.showLogin();};
document.getElementById("down-btn").style.opacity = "0.4";
document.getElementById("down-btn").onclick = function () {SideLoginRegister.showLogin();};
+ document.getElementById("commentForm").textContent = "Comments:";
+ document.getElementById("commentForm").classList.add("cactus-comment");
}
//cactus chat
@@ -64,7 +66,23 @@ function show(IdeaID) {
+
+
+
+
+
Vote this idea
@@ -88,6 +106,13 @@ function show(IdeaID) {
`;
SidePanel.show(html);
+ //send comment when hitting enter in comment field
+ document.getElementById('comment').addEventListener('keydown', (event) => {
+ if (event.code === 'Enter') {
+ event.preventDefault();
+ SideShowIdea.sendComment(IdeaID);
+ }
+ });
var LoginRegister = `
Login
@@ -131,19 +156,41 @@ function sendSupportRequest(IdeaID){
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
- // var obj = JSON.parse(this.responseText);
- // if(obj) {
- // if(obj == "error") alert("error - are you still logged in?");
- // else {
- // myCreateIdea(lon,lat,obj,0);
- // SidePanel.hide();
- // }
- // }
+ SidePanel.hide();
}};
- var _testText = document.getElementById("text").value;
+ var _message = document.getElementById("text").value;
xhttp.open("POST", "submitSupportRequest", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- xhttp.send("text="+_testText+"&IdeaID="+IdeaID);
+ xhttp.send("text="+_message+"&IdeaID="+IdeaID);
}
export { sendSupportRequest };
+
+function sendComment(IdeaID) {
+ if(!document.forms.comment_form.comment.checkValidity()) {
+ return false;
+ }
+ var xhttp = new XMLHttpRequest();
+ xhttp.onreadystatechange = function() {
+ if (this.readyState == 4 && this.status == 200) {
+ document.forms.comment_form.comment.value = "";
+
+ //cactus chat - update
+ let comsec = document.getElementsByClassName("cactus-container");
+ comsec[0].innerHTML = "";
+ comsec[0].id = "comment-section";
+ comsec[0].classList.remove("cactus-container");
+ initComments({
+ node: document.getElementById("comment-section"),
+ defaultHomeserverUrl: "https://matrix.cactus.chat:8448",
+ serverName: "cactus.chat",
+ siteName: "openidea.io",
+ commentSectionId: "Idea#" + IdeaID
+ });
+ //cactus chat end
+ }};
+ xhttp.open("POST", "submitComment", true);
+ xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ xhttp.send("comment="+document.getElementById("comment").value+"&IdeaID="+IdeaID);
+};
+export { sendComment };
\ No newline at end of file
diff --git a/src/oi/matrix-wo-cactus.js b/src/oi/matrix-wo-cactus.js
new file mode 100644
index 0000000000..a418d8657f
--- /dev/null
+++ b/src/oi/matrix-wo-cactus.js
@@ -0,0 +1,157 @@
+
+/** Function not in use - this is done by cactus comments
+ * function to create comment rooms for ideas
+ * @param {number} IdeaID - IdeaID for which a room should be created
+ * @param {string} [forCreation] - Display name of room, if not provided room will be namend 'comments for Idea #IdeaID'
+ * @returns {Room} - room object
+ */
+function createRoom(IdeaID, roomName){
+ if(!openideaClient) loginOpenIdea();
+ roomName = roomName || 'comments for Idea #' + IdeaID;
+ var options = {
+ name: roomName,
+ room_alias_name: RoomAlias(IdeaID, true),
+ visibility: "public"
+ };
+
+ console.log(options);
+
+ return openideaClient.createRoom(options);
+}
+
+
+//TODO
+/**
+ * function to fetch (num) last messages of room
+ * @param {number} IdeaID - IdeaID to fetch messages from
+ * @param {number} num - number of fetched messages
+ * @returns {(string|string[])} - returns num messages of matrix room asocciated with IdeaID
+ */
+async function getLastMessages(IdeaID, num){
+ if(!openideaClient) loginOpenIdea();
+
+ await openideaClient.startClient({initialSyncLimit: 10});
+// await openideaClient.once('sync', function(state, prevState, res) {
+// if(state === 'PREPARED') {
+// console.log("prepared");
+// } else {
+// console.log(state);
+// process.exit(1);
+// }
+// });
+
+var roomID = await openideaClient.joinRoom(RoomAlias(IdeaID));
+// try{
+// var room = await openideaClient.getRoom(roomID.roomId);
+// } catch (e) {console.log(e);}
+
+var iTest = 0;
+
+await openideaClient.on("Room.timeline", function(event, room, toStartOfTimeline) {
+ if (event.getType() !== "m.room.message") {
+ return; // only use messages
+ }
+ //if(room.name == RoomAlias(IdeaID)) console.log(room);
+ if(room.roomId == roomID.roomId) console.log("finaly");
+ console.log(iTest++);
+ console.log(room.roomId);
+ console.log(event.event.content.body);
+});
+
+// var scrollback = await openideaClient.scrollback(roomID);
+// Object.keys(openideaClient.store.rooms).forEach((roomId) => {
+// client.getRoom(roomId).timeline.forEach(t => {
+// console.log(t.event);
+// });
+// });
+
+ let messages;
+ //join room (even if joined already returns the roomID which is needed to write to it)
+ // var roomID = await openideaClient.joinRoom(RoomAlias(IdeaID));
+ // try{
+ // openideaClient.getRoom(roomID.roomId).timeline.forEach(t => {
+ // console.log(t.event);
+ // });
+
+ // // messages = openideaClient.scrollback(roomID.roomId, num);
+ // // console.log(messages);
+ // } catch (e) {console.log(e);}
+
+ return messages;
+}
+
+/**
+ * function to create consistant roomAliases
+ * @param {number} IdeaID - IdeaID which needs a room
+ * @param {boolean} [forCreation=false] - if true switches to only local part as return (like Idea_IdeaID)
+ * @returns {string} - roomAlias looks like this: #Idea_IdeaID:dohm.work
+ */
+function RoomAlias(IdeaID, forCreation=false){
+ var roomAlias = 'Idea_' + IdeaID;
+ if(!forCreation) roomAlias = '#' + roomAlias + ':' + matrixGroupUrl;
+ return roomAlias;
+}
+
+/**
+ * function to send usermessage to idea room
+ * @param {string} user - user which sends the message
+ * @param {number} IdeaID - number of idea hosting the room
+ * @param {string} message - usermessage
+ * @param {*} db - opened sqlite database to fetch users matrix data from
+ * @returns {string} - errormessage or undefined at success
+ */
+async function sendMessage(user, IdeaID, message, db) {
+ //get matrixname and matrixpw from database (db)
+ let matrix = await getMatrixUserByName(user, db);
+ console.log(matrix);
+ if(matrix == null || !matrix.matrixname || !matrix.matrixpw) return 'username not found';
+ //matrix login
+ const client = sdk.createClient(matrixServer);
+ await client
+ .login("m.login.password", {
+ user: matrix.matrixname,
+ password: matrix.matrixpw,
+ })
+ .then((response) => {
+ // console.log(response.access_token);
+ });
+ await client.startClient();
+
+ //join room (even if joined already returns the roomID which is needed to write to it)
+ var roomID
+ try {
+ roomID = await client.joinRoom(RoomAlias(IdeaID));
+ roomID = roomID.roomId;
+ } catch (e) {
+ if(e.errcode == 'M_NOT_FOUND')
+ {
+ try {
+ await createRoom(IdeaID);
+ roomID = await client.joinRoom(RoomAlias(IdeaID));
+ roomID = roomID.roomId;
+ }
+ catch (e) {return "room coudn't be joined or created"}
+ }
+ }
+ try {
+ //create content for message to be send
+ var content = {
+ body: message,
+ msgtype: "m.text",
+ };
+ //matrix send message to room
+ client
+ .sendEvent(roomID, "m.room.message", content, "")
+ .then((res) => {
+ // message sent successfully
+ return;
+ })
+ .catch((err) => {
+ console.log(err);
+ return err;
+ });
+ }
+ catch (e) {
+ return e;
+ }
+};
\ No newline at end of file
diff --git a/src/oi/matrix.js b/src/oi/matrix.js
new file mode 100644
index 0000000000..51f0094a21
--- /dev/null
+++ b/src/oi/matrix.js
@@ -0,0 +1,267 @@
+/**
+ * @fileOverview
+ * @name matrix.js
+ * @author Jannis Dohm
+ * @license MIT
+ */
+const https = require("https");
+const generator = require("generate-password");
+const crypto = require("crypto");
+const sdk = require("matrix-js-sdk");
+const { exitCode } = require("process");
+const db = require("./sqliteDb");
+const { RoomState } = require("matrix-js-sdk");
+const { resolve } = require("path");
+const { promiseMapSeries } = require("matrix-js-sdk/lib/utils");
+
+/* url to the matrix server for crating new users
+ often uses matrix.example.com
+ */
+const matrixServer = "matrix.dohm.work";
+/* url to append on matrix rooms
+ often uses example.com
+ */
+const matrixGroupUrl = "cactus.chat";
+
+let urldata = {
+ host: matrixServer,
+ path: "/_synapse/admin/v1/register",
+ method: "GET",
+};
+let urlRegData = {
+ nonce: "",
+ username: "",
+ displayname: "",
+ password: "",
+ mac: "",
+};
+let matrix = {
+ matrixname: "",
+ matrixpw: "",
+};
+
+let openideaClient;
+
+/**
+ * This function creates a matrix account for a given user.
+ * The username will be transformed to all lowercase and spaces will be replaced with underscores
+ * for more informations visit: https://github.com/matrix-org/synapse/blob/master/docs/admin_api/register_api.rst
+ * @param {string} username - wanted username of matrix user
+ * @returns {object} - matrix object
+ * @property {string} matrixname - the given matrix username
+ * @property {string} matrixpw - the automatically created matrix pw
+ */
+async function createUser(username) {
+ return new Promise((resolve) => {
+ //generate lowercase only charakters and underscores matrix name!
+ //make username lowercase
+ matrix.matrixname = username.toLowerCase();
+ //replace spaces with underscores
+ matrix.matrixname = matrix.matrixname.replace(/\s+/g, "_");
+ //delete all non alphanumeric and not underscore (shoudn't be necessary since they are not allowed as usernames anyway)
+ matrix.matrixname = matrix.matrixname.replace(/\W/g, "");
+ urlRegData.username = matrix.matrixname;
+ urlRegData.displayname = username;
+ var password = generator.generate({
+ length: 24,
+ numbers: true,
+ });
+ urlRegData.password = password;
+ matrix.matrixpw = password;
+ //for debugging and not loosing users in the beginning
+ console.log("matrixname: \t" + matrix.matrixname);
+ console.log("pw: \t" + password);
+
+ function OnResponse(response) {
+ console.log(`statusCode 1: ${response.statusCode}`);
+ var data = ""; //This will store the page we're downloading.
+ response.on("data", function (chunk) {
+ //Executed whenever a chunk is received.
+ data += chunk; //Append each chunk to the data variable.
+ });
+
+ response.on("end", function () {
+ urlRegData.nonce = JSON.parse(data).nonce;
+ urlRegData.mac = generate_mac(
+ urlRegData.nonce,
+ urlRegData.username,
+ urlRegData.password
+ );
+
+ let urlPostData = {
+ host: "matrix.dohm.work",
+ path: "/_synapse/admin/v1/register",
+ port: 443,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Content-Length": JSON.stringify(urlRegData).length,
+ },
+ };
+
+ let postreq = https.request(urlPostData, (res) => {
+ console.log(`statusCode: ${res.statusCode}`);
+ console.log("res: " + res.statusMessage);
+
+ resolve( matrix );
+
+ // res.on("data", (d) => {
+ // console.log(d);
+ // });
+ });
+
+ console.log(urlRegData);
+ postreq.write(JSON.stringify(urlRegData));
+ postreq.end();
+ });
+ }
+
+ console.log(urldata);
+ https.request(urldata, OnResponse).end();
+});
+}
+
+/**
+ * function to generate mac for user creation via shared secret
+ * @param {number} nonce - nonce which is a one time key to generate the mac. Can be requested from the matrix-synapse server.
+ * @param {string} user - user to be created
+ * @param {strin} password - password of user
+ * @param {boolean} [somebody=false] - wether or not the user should get admin rights
+ * @returns {number} - mac in HEX
+ */
+function generate_mac(nonce, user, password, admin = false) {
+ var mac = crypto.createHmac("sha1", process.env.DOHMWORK_MATRIX_SS);
+
+ mac.update(nonce.toString());
+ mac.update("\x00");
+ mac.update(user.toString());
+ mac.update("\x00");
+ mac.update(password.toString());
+ mac.update("\x00");
+ if (admin) mac.update("admin");
+ else mac.update("notadmin");
+ return mac.digest("hex");
+}
+
+/**
+ * function to send usermessage to idea room
+ * @param {string} user - user which sends the message
+ * @param {number} IdeaID - number of idea hosting the room
+ * @param {string} message - usermessage
+ * @param {*} dbOpened - opened sqlite database to fetch users matrix data from
+ * @returns {string} - errormessage or undefined at success
+ */
+async function sendMessage(user, IdeaID, message, dbOpened) {
+ //get matrixname and matrixpw from database (db)
+ let matrix = await db.getMatrixUserByName(user, dbOpened);
+ console.log(matrix);
+ if (matrix == null || !matrix.matrixname || !matrix.matrixpw)
+ return "username not found";
+ //matrix login
+ const client = sdk.createClient("https://" + matrixServer);
+ await client
+ .login("m.login.password", {
+ user: matrix.matrixname,
+ password: matrix.matrixpw,
+ })
+ .then((response) => {
+ // console.log(response.access_token);
+ });
+ await client.startClient();
+
+ //join room (even if joined already returns the roomID which is needed to write to it)
+ var roomID;
+ try {
+ roomID = await client.joinRoom(RoomAlias(IdeaID));
+ roomID = roomID.roomId;
+ } catch (e) {
+ console.log(e);
+ }
+ try {
+ //create content for message to be send
+ var content = {
+ body: message,
+ msgtype: "m.text",
+ };
+ //matrix send message to room
+ client
+ .sendEvent(roomID, "m.room.message", content, "")
+ .then((res) => {
+ // message sent successfully
+ return;
+ })
+ .catch((err) => {
+ console.log(err);
+ return err;
+ });
+ } catch (e) {
+ return e;
+ }
+}
+
+/**
+ * function to create consistant roomAliases
+ * @param {number} IdeaID - IdeaID which needs a room
+ * @returns {string} - roomAlias looks like this: #comments_openidea.io_Idea#IdeaId:cactus.chat
+ */
+function RoomAlias(IdeaID) {
+ var roomAlias = "#comments_openidea.io_Idea#" + IdeaID + ":" + matrixGroupUrl;
+ return roomAlias;
+}
+
+/**
+ * function to get link to comment room of given IdeaID
+ * @param {number} IdeaID - IdearID of idea of which the url is requested
+ * @returns {string} - url to join room looks like this: https://matrix.to/#/#Idea_IdeaID:dohm.work
+ */
+function getJoinUrl(IdeaID) {
+ let url = "https://matrix.to/#/" + RoomAlias(IdeaID);
+ return url;
+}
+
+/**
+ * function to call on init.
+ * This function handels the login of the openidea user which is used for reports etc.
+ */
+function loginOpenIdea() {
+ //return if openideaClint was already set
+ if (openideaClient) return;
+ openideaClient = sdk.createClient("https://" + matrixServer);
+ openideaClient
+ .login("m.login.password", {
+ user: process.env.MATRIX_DW_USER,
+ password: process.env.MATRIX_DW_PASSWORD,
+ })
+ .then((response) => {
+ console.log(response.access_token);
+ });
+}
+
+/**
+ * function to send support message to support chat
+ * @param {Object} req - req object, this functions reads the body.IdeaID, body.text, req.user
+ */
+function sendSupportRequest(req) {
+ if(!openideaClient) loginOpenIdea();
+ openideaClient.startClient();
+
+ var RoomId = "!HTcpkpXWLaaunauYsD:cactus.chat";
+
+ var content = {
+ body: "#" + req.body.IdeaID + "\n" + req.body.text + "\n\nsend from: ",
+ msgtype: "m.text",
+ };
+ if (req.user) {
+ content.body += req.user.email;
+ } else {
+ content.body += "anonymous";
+ }
+
+ openideaClient
+ .sendEvent(RoomId, "m.room.message", content, "")
+ .catch((err) => {
+ console.log(err);
+ });
+}
+
+module.exports = { createUser, sendMessage, getJoinUrl, loginOpenIdea, sendSupportRequest};
\ No newline at end of file
diff --git a/src/oi/sqliteDb.js b/src/oi/sqliteDb.js
new file mode 100644
index 0000000000..22b15064f0
--- /dev/null
+++ b/src/oi/sqliteDb.js
@@ -0,0 +1,70 @@
+/**
+ * @fileOverview
+ * @name sqliteDb.js
+ * @author Jannis Dohm
+ * @license MIT
+ */
+
+const sqlite3 = require("sqlite3").verbose();
+
+
+// Start sqlite3 database connection
+function startDb(){
+let db = new sqlite3.Database("./db/Ideas.db", (err) => {
+ if (err) {
+ return console.error(err.message);
+ }
+ console.log("Connected to the SQlite database.");
+ return db;
+});
+}
+
+
+
+
+/**
+ * function to get matrixname and matrixpw of given user
+ * @param {string} username - username to fetch matrix data for
+ * @param {*} db - opened sqlite database to fetch data from
+ * @returns {Object} - matrix user data
+ * @property {string} matrixname - matrix username
+ * @property {string} matrixpw - matrix password
+ */
+async function getMatrixUserByName(username, db) {
+ return new Promise((resolve) => {
+ let sql = `SELECT name, matrixname, matrixpw FROM User WHERE name is ?`;
+ db.get(sql, [username], (err, rows) => {
+ if (err) throw err;
+ console.log(rows);
+ resolve(rows);
+ });
+ });
+}
+
+/**
+ * function to get user object by email or username
+ * @param {string} email - email of searched user
+ * @param {boolean} [alsoCheckUserName=true] - if set to true (default) this function will check if the given email was a username and return data for this user.
+ * @returns {Object} - user object
+ * @property {string} name - username
+ * @property {string} email - users email
+ * @property {string} pwHash - hashed password of the user
+ */
+async function getUserByEmail(email, alsoCheckUserName=true) {
+ return new Promise((resolve) => {
+ let sql = `SELECT name, email, pwHash password FROM User WHERE email is ?`;
+ db.get(sql, [email], (err, rows) => {
+ if (err) throw err;
+ //if no user with this email was found, check if a username with this string exists
+ if (rows == null && alsoCheckUserName) {
+ sql = `SELECT name, email, pwHash password FROM User WHERE name is ?`;
+ db.get(sql, [email], (err, rows) => {
+ if (err) throw err;
+ resolve(rows);
+ });
+ } else resolve(rows);
+ });
+ });
+}
+
+module.exports = {getMatrixUserByName, getUserByEmail, startDb};
\ No newline at end of file