diff --git a/README.md b/README.md index 9e0b738d..010f7b28 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,14 @@ -# databases +# Learn Databases -Fork the repository -Go to https://c0d3.com -Create a username and account +A free site to learn and try different databases. -Ssh into c0d3 server -`ssh [c0d3.com username]@c0d.com -p 221` +**Installation** -Clone your fork on the server -`git clone https://github.com/[github username]/databases.git` - -To run server -1. install nodemon -2. run npm start:dev - -To install nodemon -`npm i -g nodemon` - -To start the server -`npm run start:dev` - -If you need to make changes to the Database run: -`ALTER_DB=true npm run start:dev` +1. Fork the repository. If you're new to github refer to this [guide](https://github.com/garageScript/curriculum/wiki/Engineering-Workflow). +2. Download the fork into your local machine. +3. Install required node modules with `npm i`. +4. Create new .env file, it should look like env.example but with valid credentials instead of `***`. Ask for passwords and api keys on our [chat](https://chat.c0d3.com/c0d3/channels/). +5. Start server with `npm run start:dev` and register a new user. ### Production Phases @@ -34,13 +21,9 @@ Phase 3: API to power user interactions (backend) Phase 4: UI (aka frontend) **We are here!** -What needs to worked on -https://github.com/garageScript/databases/issues +* [Issues](https://github.com/garageScript/databases/issues) -Wiki -https://github.com/garageScript/databases/wiki +* [Wiki](https://github.com/garageScript/databases/wiki) -If you have any questions message us on our chat: -https://chat.c0d3.com/c0d3/channels/ +* If you have any questions message us on our [chat](https://chat.c0d3.com/c0d3/channels/) -__Sequelize credentials are in the chat for privacy__ diff --git a/database/elasticsearch/elastic.js b/database/elasticsearch/elastic.js index 7d808138..a41d5bbd 100644 --- a/database/elasticsearch/elastic.js +++ b/database/elasticsearch/elastic.js @@ -24,7 +24,7 @@ const sendESRequest = (path, method, body) => { }; es.createAccount = async (account) => { - if (!account.username || !account.dbPassword || !account.email) { + if (!account.username || !account.dbPassword) { logger.error("Account data is invalid"); throw new Error("Account data is invalid"); } @@ -87,10 +87,10 @@ es.deleteAccount = async (account) => { if (err || !r1.found || !r2.found) { logger.error("Deleting Elasticsearch user failed"); throw new Error( - `Failed to delete Elasticsearch account for user: ${account.email}` + `Failed to delete Elasticsearch account for user: ${account.id}` ); } - logger.info("Successfully deleted Elasticsearch user", account.email); + logger.info("Successfully deleted Elasticsearch user", account.id); }; es.checkAccount = async (account) => { diff --git a/database/postgres/pg.js b/database/postgres/pg.js index 8c5a5278..221db7e3 100644 --- a/database/postgres/pg.js +++ b/database/postgres/pg.js @@ -20,8 +20,9 @@ pgModule.closePGDB = () => { return client.end(); }; -pgModule.createPgAccount = async (username, password) => { - if (!username || !password) return; +pgModule.createPgAccount = async (user) => { + const { username, dbPassword } = user; + if (!username || !dbPassword) return; try { // Could not escape user input by using $1 $2 // https://github.com/brianc/node-postgres/issues/539 @@ -30,7 +31,7 @@ pgModule.createPgAccount = async (username, password) => { const sqlQuery2 = escape( `create user %s with encrypted password %Q`, username, - password + dbPassword ); const sqlQuery3 = escape( diff --git a/database/postgres/pg.test.js b/database/postgres/pg.test.js index 53b5abe2..63584b30 100644 --- a/database/postgres/pg.test.js +++ b/database/postgres/pg.test.js @@ -47,7 +47,8 @@ describe("Test PG DB", () => { }); describe("Test createPgAccount", () => { it("it should execute all queries if required arguments are passed into createPgAccount", async () => { - await createPgAccount("username", "password"); + const user = { username: "username", dbPassword: "password" }; + await createPgAccount(user); expect(mockClient.query).toHaveBeenCalledTimes(3); expect(mockClient.query.mock.calls[0]).toEqual([ `CREATE DATABASE username;`, @@ -65,16 +66,15 @@ describe("Test PG DB", () => { ]); }); it("it should not execute any queries in createPgAccount if required arguments are not passed in", async () => { - await createPgAccount(); + const user = {}; + await createPgAccount(user); expect(mockClient.query).toHaveBeenCalledTimes(0); }); it("it should check if logger.error is called at throw of createPgAccount", async () => { try { await mockClient.query.mockReturnValue(Promise.reject()); - const resCreatePgAccount = await createPgAccount( - "username", - "password" - ); + const user = { username: "username", dbPassword: "password" }; + const resCreatePgAccount = await createPgAccount(user); expect(resCreatePgAccount).rejects.toThrow(); } catch (err) { expect(logger.error).toHaveBeenCalledTimes(1); diff --git a/env.example b/env.example index edf8144c..83bca08e 100644 --- a/env.example +++ b/env.example @@ -1,9 +1,31 @@ -HOST=databases.com -PORT=3000 -PG_USER=username -PASSWORD=password -DATABASE=database -DIALECT=postgres -ALTER_DB=true -MAILGUN_API_KEY=01234567890123456789 -MAILGUN_DOMAIN=databases.com \ No newline at end of file +#api key for mailing service +MAILGUN_API_KEY=*** +#mailgun domain +MAILGUN_DOMAIN=code3scape.com +#testing port for jest +TEST_PORT=30300 +#sequelize host adress +HOST=104.168.169.204 +#sequelize postgres username +PG_USER=*** +#sequelize postgres database name +DATABASE=*** +#sequelize database password +PASSWORD=*** +#sequelize allow to alter database: true/false +ALTER_DB=true +#password for session-express +SECRET=*** +#Neo4j graph database url +NEO4J_URL=neo4j://104.168.169.204 +#Neo4j username +NEO4J_USER=*** +#Neo4j password +NEO4J_PASSWORD=*** +#production/development flag, in jest tests this varible is "test" by default +NODE_ENV = development +#local port, default value 3052 +PORT = 3052 +#hostname adress, default is https://learndatabases.dev, +#if you want to use localhost you need to specify port, for example http://localhost:4000 +HOSTNAME = https://learndatabases.dev diff --git a/lib/getEnvVar.js b/lib/getEnvVar.js deleted file mode 100644 index 08af531a..00000000 --- a/lib/getEnvVar.js +++ /dev/null @@ -1,8 +0,0 @@ -require('dotenv').config() - -module.exports = (type) => { - if (type === 'mailgun') return { - apiKey: process.env.MAILGUN_API_KEY || '123', - domain: process.env.MAILGUN_DOMAIN - } -} \ No newline at end of file diff --git a/lib/getEnvVar.test.js b/lib/getEnvVar.test.js deleted file mode 100644 index 0eafe3e8..00000000 --- a/lib/getEnvVar.test.js +++ /dev/null @@ -1,16 +0,0 @@ -describe('test getEnvVar', () => { - it('should return mailgun env var', () => { - process.env.MAILGUN_API_KEY = 'test key' - const getEnvVar = require('./getEnvVar') - expect(getEnvVar('mailgun').apiKey).toEqual('test key') - }) - it('should return default mailgun env var', () => { - delete process.env.MAILGUN_API_KEY - const getEnvVar = require('./getEnvVar') - expect(getEnvVar('mailgun').apiKey).toEqual('123') - }) - it('should return nothing without argument', () => { - const getEnvVar = require('./getEnvVar') - expect(getEnvVar()).toEqual(undefined) - }) -}) \ No newline at end of file diff --git a/lib/users.js b/lib/users.js index 742f344b..df03efe4 100644 --- a/lib/users.js +++ b/lib/users.js @@ -14,7 +14,7 @@ const { const users = {}; const schema = yup.object().shape({ - email: yup.string().required().email(), + email: yup.string().nullable().email(), }); users.sendPasswordResetEmail = async (userAccount) => { @@ -38,35 +38,22 @@ users.sendPasswordResetEmail = async (userAccount) => { }; users.signUp = async (userInfo) => { - try { - await schema.validate(userInfo); - } catch (err) { - throw new Error(err); - } - - const { email } = userInfo; - const { Accounts } = db.getModels(); - const userAccount = await Accounts.findOne({ - where: { - email: email, - }, - }); + await schema.validate(userInfo); const username = uniqueNamesGenerator({ length: 2, - dictionaries: [adjectives, colors, animals], + dictionaries: [adjectives, animals], separator: "", }); const dbPassword = genPw(); - if (userAccount) { - logger.info("this account already exists", email); - throw new Error("this account already exists"); - } + const { Accounts } = db.getModels(); const newAccount = await Accounts.create({ - email: email, + email: userInfo.email, username: username, dbPassword: dbPassword, }); - await users.sendPasswordResetEmail(newAccount); + if (userInfo.email) { + await users.sendPasswordResetEmail(newAccount); + } return newAccount; }; diff --git a/lib/users.test.js b/lib/users.test.js index ee3be7e7..afe433c5 100644 --- a/lib/users.test.js +++ b/lib/users.test.js @@ -58,42 +58,47 @@ describe("Sign up", () => { }); it("should throw an error if accounts already exists", () => { - mockFindOne.mockImplementation((query) => { - if (query.where.email) return { email: "1234@gmail.com" }; - if (query.where.username) return false; + mockCreateAccount.mockImplementation(() => { + throw new Error("This account already exists"); }); const obj = { email: "1234@gmail.com", }; - return expect(signUp(obj)).rejects.toThrow("this account already exists"); + return expect(signUp(obj)).rejects.toThrow("This account already exists"); }); it("should create a user account", async () => { - const dataValues = await genUserInfoWithPw("abcd1234"); - mockFindOne.mockImplementation((query) => { - if (query.where.email) return undefined; - if (query.where.username) return false; + const obj = { email: "test.user@databases.com" }; + const dataValues = { ...obj, username: "testuser", dbPassword: "database" }; + mockCreateAccount.mockReturnValue({ + dataValues: dataValues, + update: () => {}, }); + const data = await signUp(obj); + expect(data.dataValues).toEqual(dataValues); + }); + + it("should create a anonymous user account", async () => { + const obj = {}; + const dataValues = { username: "testuser", dbPassword: "database" }; mockCreateAccount.mockReturnValue({ dataValues: dataValues, update: () => {}, }); - const obj = { - email: "test.user@databases.com", - }; const data = await signUp(obj); expect(data.dataValues).toEqual(dataValues); + expect(email.sendPasswordResetEmail).not.toHaveBeenCalled(); }); it("should send a user set Password email", async () => { - const obj = { - id: 4, - email: "em@i.l", - update: jest.fn(), - }; - - await sendPasswordResetEmail(obj); - expect(email.sendPasswordResetEmail.mock.calls.length).toEqual(1); + const obj = { email: "test.user@databases.com" }; + const dataValues = { ...obj, username: "testuser", dbPassword: "database" }; + mockCreateAccount.mockReturnValue({ + dataValues: dataValues, + update: () => {}, + }); + await signUp(obj); + expect(email.sendPasswordResetEmail).toHaveBeenCalled(); }); }); diff --git a/sequelize/db.js b/sequelize/db.js index cb0fcc29..521e4cbd 100644 --- a/sequelize/db.js +++ b/sequelize/db.js @@ -35,6 +35,7 @@ dbModule.start = async () => { email: { type: DataTypes.STRING, unique: true, + allowNull: true, }, dbPassword: { type: DataTypes.STRING, diff --git a/services/__snapshots__/mailer.test.js.snap b/services/__snapshots__/mailer.test.js.snap index fa77bf87..2b44a815 100644 --- a/services/__snapshots__/mailer.test.js.snap +++ b/services/__snapshots__/mailer.test.js.snap @@ -9,7 +9,7 @@ Object {

You have requested a (re)set password token. The button below will redirect you to our website with an autheticated token. Please click the button and set your password.

- Set my Password + Set my Password

Warning: Anyone with access to this email has access to your account. Don't share this email with other people.

diff --git a/services/mailer.js b/services/mailer.js index c5c18eef..6e89e730 100644 --- a/services/mailer.js +++ b/services/mailer.js @@ -1,13 +1,16 @@ const mailgun = require("mailgun-js"); const logger = require("../lib/log")(__filename); -const getEnvVar = require("../lib/getEnvVar"); +require("dotenv").config(); -const mg = mailgun(getEnvVar("mailgun")); +const mg = mailgun({ + apiKey: process.env.MAILGUN_API_KEY, + domain: process.env.MAILGUN_DOMAIN, +}); const mgModule = {}; mgModule.sendPasswordResetEmail = (receiver, token) => { - const link = `https://learndatabases.dev/setPassword/${token}`; + const link = `${process.env.HOSTNAME||"https://learndatabases.dev"}/setPassword/${token}` const data = { from: "admin@learndatabases.dev", to: receiver, @@ -19,7 +22,7 @@ mgModule.sendPasswordResetEmail = (receiver, token) => {

You have requested a (re)set password token. The button below will redirect you to our website with an autheticated token. Please click the button and set your password.

- Set my Password + Set my Password ${link!=`https://learndatabases.dev/setPassword/${token}`?"

DEVELOPMENT MODE IS ON. This link will redirect you to your development server

" : ""}

Warning: Anyone with access to this email has access to your account. Don't share this email with other people.

diff --git a/services/mailer.test.js b/services/mailer.test.js index 6d33473c..c63e3f4b 100644 --- a/services/mailer.test.js +++ b/services/mailer.test.js @@ -1,4 +1,5 @@ jest.mock('../lib/log') +require("dotenv").config(); const logGen = require('../lib/log') const logger = { info: jest.fn(), @@ -19,12 +20,13 @@ mailgun.mockImplementation(() => { const email = require('./mailer'); -describe('Test mailgun', ()=>{ +describe('Test mailgun', () => { beforeEach(() => { jest.clearAllMocks() }) it('should test if mocksend and mailgun is called', async () => { + process.env.HOSTNAME = "" messages.send = jest.fn().mockReturnValue(Promise.resolve('hello')) await email.sendPasswordResetEmail('paul@github.com', 'token123') expect(messages.send).toHaveBeenCalledTimes(1) @@ -34,10 +36,22 @@ describe('Test mailgun', ()=>{ }) it('should call logger.error when function is called with invalid argument', async () => { + process.env.HOSTNAME = "" messages.send = jest.fn().mockReturnValue(Promise.reject('rejected')) await email.sendPasswordResetEmail(null, null) expect(logger.error).toHaveBeenCalledTimes(1) expect(logger.error.mock.calls[0][0]).toEqual('Confirmation Email Error:') }) - + it('should notify that development mode is on in confirmation email', async () => { + process.env.HOSTNAME= "http://localhost:4000" + messages.send = jest.fn().mockReturnValue(Promise.resolve('hello')) + await email.sendPasswordResetEmail('paul@github.com', 'token123') + expect(messages.send.mock.calls[0][0].html.includes('DEVELOPMENT MODE IS ON')).toEqual(true) + }) + it('should redirect to learndatabases.dev in confirmation email if no HOSTNAME was provided in .env file', async () => { + process.env.HOSTNAME = "" + messages.send = jest.fn().mockReturnValue(Promise.resolve('hello')) + await email.sendPasswordResetEmail('paul@github.com', 'token123') + expect(messages.send.mock.calls[0][0].html.includes('https://learndatabases.dev/setPassword')).toEqual(true) + }) }) diff --git a/src/routes/userRoutes.js b/src/routes/userRoutes.js index c22a9900..f96d6da0 100644 --- a/src/routes/userRoutes.js +++ b/src/routes/userRoutes.js @@ -40,6 +40,9 @@ routes.resetPasswordEmail = async (req, res) => { }; routes.createUser = async (req, res) => { + if (!req.body.email) { + return res.status(400).json({ error: { message: "Email is required" } }); + } const userInfo = { email: req.body.email, }; @@ -49,7 +52,13 @@ routes.createUser = async (req, res) => { return res.status(200).json({ ...account.dataValues }); } catch (err) { logger.error("Creating user failed", userInfo.email, err); - return res.status(400).json({ error: { message: err.message } }); + let message; + if (err.toString().includes("SequelizeUniqueConstraintError")) { + message = "This account already exists."; + } else { + message = err.toString(); + } + return res.status(400).json({ error: { message: message } }); } }; @@ -140,41 +149,24 @@ routes.userResetPassword = async (req, res) => { }; routes.createDatabase = async (req, res) => { - if (!req.session.email) { - logger.info("User must be signed in to create database"); - return res.status(403).json({ - error: { message: "You must be signed in to create a database" }, - }); - } - - const { Accounts } = db.getModels(); - const user = await Accounts.findOne({ - where: { id: req.session.userid }, - }); - - const { username, dbPassword } = user; - - if (!dbPassword) { - logger.info("User must use password to create database"); - return res.status(400).json({ - error: { - message: "You must use your database password to create a database", - }, - }); - } - try { - if (req.params.database === "Postgres") { - await pgModule.createPgAccount(username, dbPassword); - return res.json({ - success: { message: "Create Postgres Database success" }, + let user; + if (!req.session.email) { + user = await signUp({ email: null }); + logger.info("Succeded creating anonymous user account", user.id); + } else { + const { Accounts } = db.getModels(); + user = await Accounts.findOne({ + where: { id: req.session.userid }, }); } + if (req.params.database === "Postgres") { + await pgModule.createPgAccount(user); + return res.json({ ...user.dataValues, password: null }); + } if (req.params.database === "Elasticsearch") { await es.createAccount(user); - return res.json({ - success: { message: "Create Elasticsearch Database success" }, - }); + return res.json({ ...user.dataValues, password: null }); } return res .status(400) diff --git a/src/routes/userRoutes.test.js b/src/routes/userRoutes.test.js index 20734f81..fe4eaa75 100644 --- a/src/routes/userRoutes.test.js +++ b/src/routes/userRoutes.test.js @@ -133,6 +133,31 @@ describe("Testing createUser function", () => { beforeEach(() => { jest.clearAllMocks(); }); + it("should send error if email is not provided", async () => { + const req = { + body: {}, + }; + await createUser(req, res); + expect(res.status.mock.calls[0][0]).toEqual(400); + return expect(res.json.mock.calls[0][0].error.message).toEqual( + "Email is required" + ); + }); + it("should send error if email already exists", async () => { + signUp.mockImplementation(() => { + throw new Error("SequelizeUniqueConstraintError"); + }); + const req = { + body: { + email: "em@i.l", + }, + }; + await createUser(req, res); + expect(res.status.mock.calls[0][0]).toEqual(400); + return expect(res.json.mock.calls[0][0].error.message).toEqual( + "This account already exists." + ); + }); it("should send error if sign up fails", async () => { signUp.mockImplementation(() => { throw new Error("Error"); @@ -144,7 +169,9 @@ describe("Testing createUser function", () => { }; await createUser(req, res); expect(res.status.mock.calls[0][0]).toEqual(400); - return expect(res.json.mock.calls[0][0].error.message).toEqual("Error"); + return expect(res.json.mock.calls[0][0].error.message).toEqual( + "Error: Error" + ); }); it("should create user account", async () => { signUp.mockImplementation(() => { @@ -356,50 +383,21 @@ describe("test creating database", () => { beforeEach(() => { jest.clearAllMocks(); }); - it("should return error if there is not a email", async () => { - const req = { - session: { - email: null, - dbPassword: "Google", - }, - }; - - await createDatabase(req, res); - return expect(res.json.mock.calls[0][0].error.message).toEqual( - "You must be signed in to create a database" - ); - }); - it("should return error if there is not a password", async () => { - const req = { - session: { - email: "testm@i.l", - dbPassword: null, - }, - }; - - await createDatabase(req, res); - return expect(res.json.mock.calls[0][0].error.message).toEqual( - "You must use your database password to create a database" - ); - }); it("should return error if database name is not provided", async () => { const req = { - session: { - email: "testm@i.l", - }, - params: { - database: "", - }, + session: { email: null }, + params: { database: "" }, + }; + const user = { + email: "testm@i.l", + dbPassword: "Google", }; db.getModels = () => { return { Accounts: { findOne: () => { - return { - email: "testm@i.l", - dbPassword: "Google", - }; + return { ...user, dataValues: user }; }, }, }; @@ -412,12 +410,12 @@ describe("test creating database", () => { it("should return success if creating postgres database success", async () => { const req = { - session: { - email: "testm@i.l", - }, - params: { - database: "Postgres", - }, + session: { email: "testm@i.l" }, + params: { database: "Postgres" }, + }; + const user = { + email: "testm@i.l", + dbPassword: "Google", }; pgModule.createPgAccount.mockReturnValue(Promise.resolve()); @@ -426,39 +424,31 @@ describe("test creating database", () => { return { Accounts: { findOne: () => { - return { - email: "testm@i.l", - dbPassword: "Google", - }; + return { ...user, dataValues: user }; }, }, }; }; await createDatabase(req, res); - return expect(res.json.mock.calls[0][0].success.message).toEqual( - "Create Postgres Database success" - ); + return expect(res.json.mock.calls[0][0].email).toEqual("testm@i.l"); }); it("should throw and error if pgModule fails to create database", async () => { const req = { - session: { - email: "testm@i.l", - }, - params: { - database: "Postgres", - }, + session: { email: "testm@i.l" }, + params: { database: "Postgres" }, + }; + const user = { + email: "testm@i.l", + dbPassword: "Google", }; db.getModels = () => { return { Accounts: { findOne: () => { - return { - email: "testm@i.l", - dbPassword: "Google", - }; + return { ...user, dataValues: user }; }, }, }; @@ -476,12 +466,12 @@ describe("test creating database", () => { it("should return success if creating elastic database success", async () => { const req = { - session: { - email: "testm@i.l", - }, - params: { - database: "Elasticsearch", - }, + session: { email: "testm@i.l" }, + params: { database: "Elasticsearch" }, + }; + const user = { + email: "testm@i.l", + dbPassword: "Google", }; es.createAccount.mockReturnValue(Promise.resolve()); @@ -490,39 +480,31 @@ describe("test creating database", () => { return { Accounts: { findOne: () => { - return { - email: "testm@i.l", - dbPassword: "Google", - }; + return { ...user, dataValues: user }; }, }, }; }; await createDatabase(req, res); - return expect(res.json.mock.calls[0][0].success.message).toEqual( - "Create Elasticsearch Database success" - ); + return expect(res.json.mock.calls[0][0].email).toEqual("testm@i.l"); }); it("should throw and error if esModule fails to create database", async () => { const req = { - session: { - email: "testm@i.l", - }, - params: { - database: "Elasticsearch", - }, + session: { email: "testm@i.l" }, + params: { database: "Elasticsearch" }, + }; + const user = { + email: "testm@i.l", + dbPassword: "Google", }; db.getModels = () => { return { Accounts: { findOne: () => { - return { - email: "testm@i.l", - dbPassword: "Google", - }; + return { ...user, dataValues: user }; }, }, }; diff --git a/tests/integration/__snapshots__/welcome.test.js.snap b/tests/integration/__snapshots__/welcome.test.js.snap index 4c94a039..905b957c 100644 --- a/tests/integration/__snapshots__/welcome.test.js.snap +++ b/tests/integration/__snapshots__/welcome.test.js.snap @@ -1,16 +1,370 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`test welcome page should render elasticsearch page correctly 1`] = ` +" + + + + + + + + + learndatabases.dev + +
+

Learn Databases

+ + +

Login / Signup

+ +
+ + + +

Learn Elasticsearch

+
+
+
+ + + + + + +" +`; + exports[`test welcome page should render postgres page correctly 1`] = ` -" +" + + + + + + - - -Error - - -
Cannot GET /postgres
- + + learndatabases.dev + +
+

Learn Databases

+ + +

Login / Signup

+ +
+ + +

Learn Postgres

+
+
+
+ + + + + + " `; diff --git a/tests/integration/welcome.test.js b/tests/integration/welcome.test.js index 35fffe63..a7f04962 100644 --- a/tests/integration/welcome.test.js +++ b/tests/integration/welcome.test.js @@ -49,7 +49,16 @@ describe("test welcome page", () => { }); test("should render postgres page correctly", async () => { - const result = await fetch(baseUrl + "postgres").then((r) => r.text()); + const result = await fetch(baseUrl + "tutorial/Postgres").then((r) => + r.text() + ); + expect(result).toMatchSnapshot(); + }); + + test("should render elasticsearch page correctly", async () => { + const result = await fetch(baseUrl + "tutorial/Elasticsearch").then((r) => + r.text() + ); expect(result).toMatchSnapshot(); }); }); diff --git a/views/postgres.ejs b/views/postgres.ejs deleted file mode 100644 index 36209122..00000000 --- a/views/postgres.ejs +++ /dev/null @@ -1,91 +0,0 @@ -<%- include("./partials/head") %> -

Learn PostgreSQL

-
-
-
- - - - - - \ No newline at end of file diff --git a/views/tutorial.ejs b/views/tutorial.ejs index 160d7b3e..e66a0f57 100644 --- a/views/tutorial.ejs +++ b/views/tutorial.ejs @@ -18,75 +18,108 @@ const database = "<%= database %>" const credentials = document.createElement("pre") - credentials.innerHTML = `host: ${dbHost} + const renderCredentials = (username, dbPassword) => { + if (database === "Postgres") { + credentials.innerHTML = `host: ${dbHost} username: ${username} -password: ${dbPassword}` - - const introduction = document.getElementById("introduction") - if (!username) { - introduction.innerHTML = ` -

In this module, you can learn how to use ${database}. Don't have ${database} installed on your local machine yet? Fear not! We can make a ${database} database for you. Please login first to create your database. If you want, you may keep reading this tutorial without login.

` - } else if (!dbExists) { - introduction.innerHTML = ` -

In this module, you can learn how to use ${database}. Don't have ${database} installed on your local machine yet? Fear not! We can make an ${database} database for you. Simply click on the button below to create your ${database} database. Credentials for your database will appear after it is done being created.

-

- ` - } else { - introduction.innerHTML = ` -

In this module, you can learn how to use ${database}. You have already created an ${database} database on our server. Here are the credentials for your database.

- ` +password: ${dbPassword} +database: ${username}
` + } else if (database === "Elasticsearch") { + credentials.innerHTML = `host: ${dbHost} +username: ${username} +password: ${dbPassword} +index: ${username}-*` + } else { + credentials.innerHTML = "" + } introduction.append(credentials) } + const content = document.getElementById("content") + const renderContent = (username, dbPassword) => { + fetch(`/lessons/${database}.md`).then(r => r.text()).then((r) => { + marked.setOptions({ + highlight: function (code) { + return hljs.highlightAuto(code).value + } + }) + const markedHTML = marked(r) + const markedHTMLwithUserData = markedHTML.replace(/@username/gi, username).replace(/@dbPassword/gi, dbPassword) + content.innerHTML = markedHTMLwithUserData + }) + } + let disabled const createDb = () => { if (disabled) return disabled = true - const button = document.getElementById("button") - button.classList.add("disabled") - button.innerText = "Creating..." + createDb_button.classList.add("disabled") + createDb_button.innerText = "Creating..." fetch(`/api/createDatabase/${database}`, { method: "POST" }).then(r => r.json()).then((r) => { if (r.error) { alert(r.error.message) disabled = false - button.classList.remove("disabled") - button.innerText = "Create my database" + createDb_button.classList.remove("disabled") + createDb_button.innerText = "Create my database" } else { - alert(r.success.message) - button.style.opacity = 0 + if (r.email) { + alert("Your database is successfully created!") + } else { + alert("Your temporary database is successfully created!\r\nSince credentials are provided only once, please keep the information somewhere safe.") + } + createDb_button.style.opacity = 0 setTimeout(() => { - button.innerText = "Complete!" - button.style.background = "rgb(10, 170, 75)" - button.style.opacity = 1 + createDb_button.innerText = "Complete!" + createDb_button.style.background = "rgb(10, 170, 75)" + createDb_button.style.opacity = 1 setTimeout(() => { - introduction.append(credentials) + renderCredentials(r.username, r.dbPassword) + renderContent(r.username, r.dbPassword) }, 200) }, 200) } }) } - const content = document.getElementById("content") - fetch(`/lessons/${database}.md`).then(r => r.text()).then((r) => { - marked.setOptions({ - highlight: function (code) { - return hljs.highlightAuto(code).value - } - }) - const markedHTML = marked(r) - const markedHTMLwithUserData = markedHTML.replace(/@username/gi, username).replace(/@dbPassword/gi, dbPassword) - content.innerHTML = markedHTMLwithUserData - }) + const createDb_button = document.createElement("button") + createDb_button.id = "createDb" + createDb_button.innerText = "Create my database" + createDb_button.addEventListener("click", createDb) + + const introduction = document.getElementById("introduction") + if (!username) { + introduction.innerHTML = ` +

In this module, you can learn how to use ${database}. Don't have ${database} installed on your local machine yet? Fear not! We can make a ${database} database for you. Simply click on the button below to create your temporary ${database} database. Credentials for your database will appear after it is done being created.

+

Temporary database credentials will expire in 5 days. If you want, you can sign up with us and get a non-expiring Postgres database!

+ ` + introduction.append(createDb_button) + renderContent("username", "dbPassword") + } else if (!dbExists) { + introduction.innerHTML = ` +

In this module, you can learn how to use ${database}. Don't have ${database} installed on your local machine yet? Fear not! We can make an ${database} database for you. Simply click on the button below to create your ${database} database. Credentials for your database will appear after it is done being created.

+ ` + introduction.append(createDb_button) + renderContent("username", "dbPassword") + } else { + introduction.innerHTML = ` +

In this module, you can learn how to use ${database}. You have already created an ${database} database on our server. Here are the credentials for your database.

+ ` + renderCredentials(username, dbPassword) + renderContent(username, dbPassword) + } +