diff --git a/.eslintrc.js b/.eslintrc.js index 893a5e8..0f2dd4e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,18 +1,20 @@ module.exports = { root: true, env: { + es2021: true, node: true }, extends: [ 'plugin:vue/essential', 'plugin:prettier/recommended', - '@vue/prettier' + '@vue/prettier', + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended' ], + parser: 'vue-eslint-parser', + plugins: ['@typescript-eslint, vue'], rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' - }, - parserOptions: { - parser: 'babel-eslint' } }; diff --git a/.gitignore b/.gitignore index 4b8f7bc..2c3ef21 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,12 @@ node_modules /dist -# local env files +# dotenv environment variables files (local env files) .env.local .env.*.local .env +.env.test + # Log files npm-debug.log* @@ -22,7 +24,5 @@ yarn-error.log* *.sln *.sw* -#Electron-builder output -/dist_electron package-lock.json \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e8fbc9e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +# base image that provides runtime environment for the application +FROM node:16.13 +# where the application code will be copied to in the docker container +WORKDIR /usr/src/app +# copies all files from the current directory (where the Dockerfile is located) to the working directory in the docker image (which we set on line 4) +COPY . . +RUN npm install +RUN npm run build +# Exposes port 4173 to the host machine, so that it can access the Node.js application running inside the Docker container +EXPOSE 8080 +# Specifies the command to run when the Docker container starts +ENTRYPOINT npm run server diff --git a/README.md b/README.md index dde498c..8ccb9e7 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,100 @@

- +

PreVue

[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/teamprevue/PreVue/pulls) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE LINK GOES HERE) +![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)

-An open source Vue application prototyping tool for developers and designers. +All in One Prototyping Tool +For Vue Developers +

-PreVue allows the user to design/visualize their component architecture - previewing component template HTML structure, setting up views/routes, establishing parent-child component relationships - and then export their component architecture as a Vue application created with the default Vue CLi settings. +

+From Component Architecture to Code Exporting +

+ +PreVue allows the user to design/visualize their component architecture by allowing users to : + +1. Create components and preview their code + +2. Set up different views/routes + +3. Establish parent-child component relationships + +4. See their application architecture in tree format + +5. Export the component architecture as a Vue application created with the default Vue CLI settings. + +

+ + +

## Getting Started -If you are looking for the executable version of PreVue, you can download it at [prevue.io](https://www.prevue.io/) +--- -These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. +Download for [MacOS](https://s3.amazonaws.com/prevue-app/PreVue-1.0.0.dmg), [Linux](https://s3.amazonaws.com/prevue-app/PreVue_1.0.0_amd64.deb), or [Windows](https://s3.amazonaws.com/prevue-app/PreVue+Setup+1.0.0.exe) -### Prerequisites +###### Support for Windows now here! -PreVue was developed using node runtime @ v10.15.0. You should make sure you at least have that version installed to ensure full compatibility. You can download the latest version of node [here](https://nodejs.org/en/) +- Mac users only: for now you might need to go to your security settings to allow the app run on your system as we do not have an Apple license yet. -### Setup +If you find any issues, [file issue](https://github.com/teamprevue/PreVue/issues) -Clone this repo +## How to use -``` -git clone https://github.com/teamprevue/PreVue.git -``` +--- -Install dependencies +#### Adding Components -``` -npm i -``` +- Double click on the application icon +- Create components by entering a name and clicking the html elements you need -Run electron app +- Clicked elements will be shown on the right sidebar +- Drag them around to change the order! -``` -npm run electron:serve -``` +- Once you're satisfied, click the button to add a component and it will show up in the center stage, with the ability to resize! + + + +#### Editing Components + +- Edit components by double clicking for the edit modal to show +- Add additional elements to a component with a live preview of the component code +- Drag elements on the right side bar to nest elements +- Establish parent-child component relationships via a dropdown menu when creating or editing components + + + +#### Adding Routes/Projects + +- Create different routes for your application by entering a new route name and pressing enter +- Any components created on a certain route will be automatically saved to that route +- Play with multiple projects by clicking the add project icon! +- Display a tree view of entire application component architecture when the tree icon on navbar is clicked + + + +#### Tree View of Application Architecture -## Features +

+ + +

+ +#### Saving/Opening/Exporting Projects + +- If you ever need to save your current project, click the save project icon to save a json to your local directory +- Next time the application is started, open the project again by clicking the open project icon! +- Once you're satisfied, click the export project icon to export your awesome project as new Vue application! -- Create components using 'Create a Component' form -- Edit components by double clicking on them -- Add standard html elements to template of a component that is created or being edited -- Draggable editing of component HTML template code structure -- Live updating of component HTML template code structure display -- Establish parent-child component relationships via dropdown menu when creating or editng components -- Create route components using 'Routes' form that allows for designing of multiple views of a SPA at once. -- Components will automatically save to the route that they are created in -- Display tree view of entire Vue application component architecture when tree icon on navbar is clicked -- Project Open/Save -- Hotkeys for opening and saving projects, and opening and closing tabs -- Export project as Vue application! + -### Code Exporting +##### Code Exporting Below is the generated directory structure of the Vue application that is created when you export your design. @@ -81,10 +118,38 @@ src/ - cmd/ctrl + s: save - cmd/ctrl + o: open - cmd/ctrl + n: new project tab -- cmd/ctrl + t: close project tab +- cmd/ctrl + w: close project tab + +## Running your own local version + +--- + +PreVue was developed using node runtime @ v10.15.0. You should make sure you at least have that version installed to ensure full compatibility. You can download the latest version of node [here](https://nodejs.org/en/) + +### Setup + +Clone this repo + +``` +git clone https://github.com/teamprevue/PreVue.git +``` + +Install dependencies + +``` +npm i +``` + +Run electron app + +``` +npm run electron:serve +``` ## Built With +--- + - [Vue.js](https://vuejs.org/) - [Vue Router](https://router.vuejs.org/guide/#html) - [Vuex](https://vuex.vuejs.org/) @@ -99,10 +164,14 @@ src/ ## Contributing +--- + PreVue is currently in beta release. We encourage you to submit issues for any bugs or ideas for enhancements. Also feel free to fork this repo and submit pull requests to contribute as well. ## Authors +--- + - **Hubert Lin** [@hubelin](https://github.com/hubelin) - **Franklin Pinnock** [@pinnockf](https://github.com/pinnockf) - **Annette Lin** [@al2613](https://github.com/al2613) @@ -110,4 +179,6 @@ PreVue is currently in beta release. We encourage you to submit issues for any b ## License +--- + This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 3490e08..0000000 --- a/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: ['@vue/app'] -}; diff --git a/build/icon.ico b/build/icon.ico new file mode 100644 index 0000000..939755e Binary files /dev/null and b/build/icon.ico differ diff --git a/electron-builder.json b/electron-builder.json deleted file mode 100644 index 949816a..0000000 --- a/electron-builder.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "appId": "com.electron.PreVue", - "mac": { - "category": "public.app-category.developer-tools", - "icon": "dist/icon.icns" - }, - "files": ["out"], - "nsis": { - "createDesktopShortcut": "always" - }, - "dmg": { - "contents": [ - { - "x": 110, - "y": 150 - }, - { - "x": 240, - "y": 150, - "type": "link", - "path": "/Applications" - } - ] - }, - - "publish": [ - { - "provider": "s3", - "bucket": "prevue-app" - } - ] -} diff --git a/public/favicon.ico b/favicon.ico similarity index 100% rename from public/favicon.ico rename to favicon.ico diff --git a/public/index.html b/index.html similarity index 81% rename from public/index.html rename to index.html index 7aaf018..3c37552 100644 --- a/public/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + - PreVue @@ -29,5 +25,7 @@
+ + diff --git a/jest.config.js b/jest.config.js index 9701826..60d54a6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,15 +4,18 @@ module.exports = { '^.+\\.vue$': 'vue-jest', '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', - '^.+\\.jsx?$': 'babel-jest' + '^.+\\.jsx?$': 'babel-jest', }, transformIgnorePatterns: ['/node_modules/'], moduleNameMapper: { - '^@/(.*)$': '/src/$1' + '^@/(.*)$': '/src/$1', }, snapshotSerializers: ['jest-serializer-vue'], testMatch: [ - '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' + '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)', ], - testURL: 'http://localhost/' + testEnvironmentOptions: { + url: 'http://localhost:5174', // replace with your test URL + }, + testEnvironment: 'node', }; diff --git a/package.json b/package.json index 86ae82d..7d7eebf 100644 --- a/package.json +++ b/package.json @@ -1,54 +1,83 @@ { - "name": "PreVue", - "version": "1.0.0", - "description": "Developer prototyping app built with Vue on Electron", + "module": { + "type": "commonjs" + }, + "name": "prevue", + "author": "teamprevue (www.prevue.io)", + "version": "2.0.0", + "description": "Developer prototyping app built with Vue", "scripts": { - "serve": "vue-cli-service serve", - "build": "vue-cli-service build", - "lint": "vue-cli-service lint", - "electron:build": "vue-cli-service electron:build --publish never", - "electron:release": "vue-cli-service electron:build --publish always", - "electron:serve": "vue-cli-service electron:serve", - "postinstall": "electron-builder install-app-deps", - "postuninstall": "electron-builder install-app-deps", - "test:unit": "vue-cli-service test:unit" + "dev": "concurrently \"npm run vite\" \"npm run server\"", + "build": "vite build", + "serve": "vite preview", + "vite": "npm run server", + "server": "node server/server.js", + "test": "NODE_ENV=test vitest", + "coverage": "vitest run --coverage" }, - "author": "team prevue", - "license": "ISC", + "license": "MIT", "dependencies": { - "buefy": "^0.7.3", + "@he-tree/vue": "^2.2.7", + "@progress/jszip-esm": "^1.0.3", + "@ssthouse/vue3-tree-chart": "^0.2.6", + "axios": "^1.3.4", + "concurrently": "^7.6.0", + "connect-history-api-fallback": "^2.0.0", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "express": "^4.18.2", + "file-saver": "^2.0.5", "fs-extra": "^7.0.1", - "localforage": "^1.7.3", - "lodash.throttle": "^4.1.1", + "handlebars": "^4.7.7", + "happy-dom": "^8.9.0", + "he-tree-vue": "^3.1.2", + "jsonwebtoken": "^9.0.0", + "mongodb": "^5.1.0", + "mongodb-connection-string-url": "^2.6.0", + "mongoose": "^6.10.0", "mousetrap": "^1.6.3", - "vue": "^2.6.6", - "vue-draggable-nested-tree": "^2.2.8", - "vue-draggable-resizable": "^2.0.0-rc1", - "vue-multiselect": "^2.1.4", - "vue-router": "^3.0.1", + "sass": "^1.58.3", + "vue": "^3.2.47", + "vue-multiselect": "^3.0.0-alpha.2", + "vue-router": "^4.1.6", + "vue-template-compiler": "^2.6.11", + "vue3-draggable-resizable": "^1.6.5", "vued3tree": "^3.6.4", - "vuex": "^3.0.1" + "vuedraggable": "^4.1.0", + "vuetify": "^3.1.6" }, "devDependencies": { - "@vue/cli-plugin-babel": "^3.5.1", - "@vue/cli-plugin-eslint": "^3.4.0", - "@vue/cli-plugin-unit-jest": "^3.5.1", - "@vue/cli-service": "^3.5.1", + "@typescript-eslint/eslint-plugin": "^5.54.0", + "@typescript-eslint/parser": "^5.54.0", + "@vitejs/plugin-vue": "^4.0.0", "@vue/eslint-config-prettier": "^4.0.1", - "@vue/test-utils": "1.0.0-beta.29", - "babel-core": "^7.0.0-bridge.0", - "babel-eslint": "^10.0.1", - "babel-jest": "^23.6.0", - "electron": "^3.0.0", - "electron-compile": "^6.4.4", - "electron-compilers": "^5.9.0", - "electron-prebuilt-compile": "^4.0.0", - "eslint": "^5.8.0", - "eslint-plugin-vue": "^5.0.0", - "node-sass": "^4.11.0", - "sass-loader": "^7.1.0", - "vue-cli-plugin-electron-builder": "^1.0.4", - "vue-template-compiler": "^2.5.21" + "@vue/test-utils": "^2.3.1", + "dotenv": "^16.0.3", + "eslint": "^8.35.0", + "eslint-plugin-typescript": "^0.14.0", + "eslint-plugin-vue": "^8.7.1", + "jest": "^29.5.0", + "jsdom": "^21.1.0", + "sinon": "^15.0.1", + "supertest": "^6.3.3", + "typescript": "^4.9.5", + "vite": "^4.1.4", + "vitest": "^0.29.2", + "vue-eslint-parser": "^9.1.0", + "vue-template-compiler": "^2.5.21", + "vue-tsc": "^1.0.24", + "vuex": "^4.1.0" + }, + "main": "background.js", + "directories": { + "test": "tests" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/oslabs-beta/PreVue.git" + }, + "bugs": { + "url": "https://github.com/oslabs-beta/PreVue/issues" }, - "main": "background.js" + "homepage": "https://github.com/oslabs-beta/PreVue#readme" } diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index 5bfb8f6..0000000 --- a/postcss.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - plugins: { - autoprefixer: {} - } -}; diff --git a/prevue-prod.zip b/prevue-prod.zip new file mode 100644 index 0000000..020b68d Binary files /dev/null and b/prevue-prod.zip differ diff --git a/server/controllers/accountController.js b/server/controllers/accountController.js new file mode 100644 index 0000000..f8645c2 --- /dev/null +++ b/server/controllers/accountController.js @@ -0,0 +1,63 @@ +const Users = require('../models/accountModels'); +const accountController = {}; + +// enters a user into the database after GitHub OAuth if an entry +// does not already exist +accountController.createUser = (req, res, next) => { + const { username, id } = res.locals; + //Making sure username does not exist + Users.findOne({ username }) + .then(data => { + if (!data) { + Users.create({ username, id }).then(data => { + //data here is full entry, includes _id key + res.locals.id = data._id; // sending ID for cookie auth + return next(); + }); + } else { + return next(); + } + }) + .catch(err => { + next({ + log: `accountController.createUser failed: ${err}`, + message: `User already exists!` + }); + }); +}; + +// showing the logged in user's projects before the mounting +// of the home page +accountController.userProjects = (req, res, next) => { + Users.findOne({ username: res.locals.username }) + .then(data => { + res.locals.userProjects = data.project_ids; + return next(); + }) + .catch(err => { + next({ + log: 'accountController.userProjects failed', + message: `could not find projects for user` + }); + }); +}; + +// just for test purposes; returns all users in the database +accountController.findUser = (req, res, next) => { + // write code here + // const { username } = req.body; + Users.find({}) + .then(data => { + res.locals.username = data; + return next(); + }) + .catch(err => { + // if (err.message === `Username Doesn't Exist`) res.redirect("/signup"); + return next({ + log: err, + error: `error found in userController.findUser` + }); + }); +}; + +module.exports = accountController; diff --git a/server/controllers/authController.js b/server/controllers/authController.js new file mode 100644 index 0000000..08227c7 --- /dev/null +++ b/server/controllers/authController.js @@ -0,0 +1,45 @@ +const jwt = require('jsonwebtoken'); +require('dotenv').config(); + +// the secret key generated when integrating your app with Github OAuth +const privateKey = process.env.SECRET_KEY; + +const authController = {}; + +// authenticates user base on info stored on the JWT +authController.authenticate = (req, res, next) => { + try { + const { ssid } = req.cookies; + //decoded becomes {id,username} + const decoded = jwt.verify(ssid, privateKey); + res.locals.username = decoded.username; + res.locals.id = decoded.id; + return next(); + } catch (err) { + return next({ + log: `authController.authenticate failed: ${err}`, + message: `An authentication error occured.` + }); + } +}; + +// assigns a JWT to a user upon login +authController.sign = (req, res, next) => { + try { + const { username, id } = res.locals; + const token = jwt.sign( + { + username, + id + }, + privateKey, + { expiresIn: '6h' } + ); + res.locals.token = token; + return next(); + } catch (err) { + return next(err); + } +}; + +module.exports = authController; diff --git a/server/controllers/cookieController.js b/server/controllers/cookieController.js new file mode 100644 index 0000000..ca63e50 --- /dev/null +++ b/server/controllers/cookieController.js @@ -0,0 +1,15 @@ +const cookieController = {}; + +// sets cookie with key of 'ssid' and value of generated JWT +cookieController.setSSIDCookie = (req, res, next) => { + res.cookie('ssid', res.locals.token, { httpOnly: true }); + return next(); +}; + +// used to log out a user +cookieController.deleteCookie = (req, res, next) => { + res.clearCookie('ssid'); + return next(); +}; + +module.exports = cookieController; diff --git a/server/controllers/oAuthController.js b/server/controllers/oAuthController.js new file mode 100644 index 0000000..51fefc1 --- /dev/null +++ b/server/controllers/oAuthController.js @@ -0,0 +1,107 @@ +require('dotenv').config(); +const axios = require('axios'); + +const oAuthController = {}; +const GITHUB_OAUTH_CLIENT_ID = process.env.GITHUB_OAUTH_CLIENT_ID; +const GITHUB_OAUTH_CLIENT_SECRET = process.env.GITHUB_OAUTH_CLIENT_SECRET; +const GITHUB_ACCESS_TOKEN_REQUEST_URL = `https://github.com/login/oauth/access_token`; +const GITHUB_REDIRECT_URI = process.env.GITHUB_REDIRECT_URI; +let str = GITHUB_OAUTH_CLIENT_ID.toString(); +let newStr = GITHUB_REDIRECT_URI.toString(); + +// first step of OAuth; redirects user to github with specific client id and redirect uri's concatenated +oAuthController.oAuthLogin = async (req, res, next) => { + try { + console.log('sending get request to github '); + let redirectStr = + `https://github.com/login/oauth/authorize?` + + 'client_id=' + + str + + '&redirect_uri=' + + newStr; + let redirectURL = new URL(redirectStr); + res.locals.url = redirectURL; + console.log('res.locals', res.locals.url); + return next(); + } catch (error) { + return next({ + log: 'Error occurred in the oauthController.oAuthLogin middleware', + status: 400, // bad request + err: { + err: 'Error occurred in sending user to login to GitHub to login' + } + }); + } +}; + +// Get temporary "code" from Github (in req.query) in oauthController and AWAIT post request it back to exchange it for an access token (to Github API for user data) +oAuthController.requestGitHubIdentity = async (req, res, next) => { + try { + console.log('reached requestGitHubIdentity controller'); + const { code } = req.query; + const { data } = await axios.post( + GITHUB_ACCESS_TOKEN_REQUEST_URL, + { + client_id: GITHUB_OAUTH_CLIENT_ID, + client_secret: GITHUB_OAUTH_CLIENT_SECRET, + code + }, + { + headers: { + Accept: 'application/json' + } + } + ); + console.log(data); + + // if all's good, attach access_token to res.locals and move on! + res.locals.access_token = data.access_token; + return next(); + } catch (error) { + console.log(error); + return next({ + log: `Error occurred in the oauthController.requestGitHubIdentity middleware\n Error: ${error.message}`, + status: 400, // bad request + err: { err: 'Error occurred in getting your Github user identity' } + }); + } +}; + +// how a given user is actually authenticated +// https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-the-authenticated-user +oAuthController.queryGitHubAPIWithAccessToken = async (req, res, next) => { + try { + const auth = res.locals.access_token; + const { data } = await axios.get('https://api.github.com/user', { + headers: { Authorization: `Bearer ${auth}` } + }); + console.log('response from the api'); + console.log(data); + + // set info from api to res.locals + res.locals = { + ...res.locals, + ...processGitHubData(data) + }; + + return next(); + } catch (error) { + return next({ + log: `Error occurred in the oauthController.queryGitHubAPIWithAccessToken middleware\n Error: ${error.message}`, + status: 400, // bad request + err: { err: 'Error occurred in querying Github API with access token' } + }); + } +}; + +// // Helper function for converting Github API data to fields for database input +function processGitHubData(data) { + const { login, id } = data; + // only works with two names + return { + username: login, + id: id + }; +} + +module.exports = oAuthController; diff --git a/server/controllers/projectController.js b/server/controllers/projectController.js new file mode 100644 index 0000000..141aa6a --- /dev/null +++ b/server/controllers/projectController.js @@ -0,0 +1,103 @@ +const Project = require('../models/projectModels'); +const User = require('../models/accountModels'); +const projectController = {}; + +// saving a project +// we query the database to see if a project with the name on the req.body already exists +// if not, create a project; if so, update the project under that name with req.body.projectObject +projectController.saveProject = (req, res, next) => { + const { project_name, projectObject } = req.body; + Project.findOne({ project_name }).then(data => { + if (!data) { + Project.create({ + project_name, + projectObject, + projectOwner: res.locals.username + }) + .then(data => { + res.locals.newProject = data.projectObject; + res.locals.projectName = data.project_name; + return next(); + }) + .catch(err => { + next({ + log: `projectController.saveProject failed, ${err}`, + message: `Can't save new project!` + }); + }); + } else { + // if the project already exists, it is updated with the new state + Project.findOneAndUpdate( + { project_name }, + { projectObject: req.body.projectObject } + ) + .then(data => { + res.locals.newProject = data.projectObject; + res.locals.projectName = data.project_name; + return next(); + }) + .catch(err => { + next({ + log: `projectController.saveProject failed, ${err}`, + message: `Can't update project!` + }); + }); + } + }); +}; + +// updates project_ids of of User who is saving a project +// if it already exists in their projects array, it is not added +projectController.userQuery = (req, res, next) => { + User.findOneAndUpdate( + { username: res.locals.username }, + { $addToSet: { project_ids: res.locals.projectName } }, + { new: true } + ) + .then(data => { + res.locals.user = data; + return next(); + }) + .catch(err => { + next({ + log: `projectController.userQuery failed, ${err}`, + message: `user already exists!` + }); + }); +}; + +// for retrieving projects ('open project' on frontend) +projectController.getProject = (req, res, next) => { + Project.findOne({ + project_name: req.body.project_name, + projectOwner: res.locals.username + }) + .then(data => { + res.locals.project = data.projectObject; + return next(); + }) + .catch(err => { + next({ + log: `projectController.getProject failed, ${err}`, + message: `Can't find project!` + }); + }); +}; + +// general query to find all projects; not used in app itself +projectController.findProject = (req, res, next) => { + Project.find({}) + .then(data => { + res.locals.username = data; + return next(); + }) + .catch(err => { + // if (err.message === `Username Doesn't Exist`) res.redirect("/signup"); + return next({ + log: err, + error: `error found in userController.verifyUser` + }); + }); +}; + +module.exports = projectController; diff --git a/server/models/accountModels.js b/server/models/accountModels.js new file mode 100644 index 0000000..46e7b2b --- /dev/null +++ b/server/models/accountModels.js @@ -0,0 +1,13 @@ +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +// schema for users stored in database +const userSchema = new Schema({ + username: { type: String, required: true }, + id: { type: String, required: true }, + project_ids: { type: Array } +}); + +const Users = mongoose.model('Users', userSchema); +module.exports = Users; diff --git a/server/models/projectModels.js b/server/models/projectModels.js new file mode 100644 index 0000000..5d53563 --- /dev/null +++ b/server/models/projectModels.js @@ -0,0 +1,13 @@ +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +// schema for projects stored in database +const projectSchema = new Schema({ + project_name: { type: String, required: true }, + projectObject: { type: Object, required: true }, + projectOwner: { type: String, required: true } +}); + +const Project = mongoose.model('Project', projectSchema); +module.exports = Project; diff --git a/server/routes/accountRouter.js b/server/routes/accountRouter.js new file mode 100644 index 0000000..895a489 --- /dev/null +++ b/server/routes/accountRouter.js @@ -0,0 +1,69 @@ +const express = require('express'); +const accountController = require('../controllers/accountController'); +const cookieController = require('../controllers/cookieController'); +const oAuthController = require('../controllers/oAuthController'); +const authController = require('../controllers/authController'); +const accountRouter = express.Router(); + +// route for GitHub OAuth +accountRouter.get( + '/oauth', + oAuthController.oAuthLogin, + // oAuthController.requestGitHubIdentity, + (req, res) => { + console.log('Oauth Router console log'); + return res.status(200).json(res.locals.url); + } +); + +// retrieves specific user projects +accountRouter.get( + '/userProjects', + authController.authenticate, + accountController.userProjects, + (req, res) => { + return res.status(200).json(res.locals.userProjects); + } +); + +// github OAuth route +accountRouter.get( + '/oauth/access_token/redirect', + oAuthController.requestGitHubIdentity, + oAuthController.queryGitHubAPIWithAccessToken, + accountController.createUser, + authController.sign, + cookieController.setSSIDCookie, + (req, res) => { + console.log('after requestGitHUbIdentity'), + console.log('res.locals.access_token', res.locals.access_token), + console.log('final redirect to homepage'); + res.redirect('/'); + } +); + +// validates user on login +accountRouter.get( + '/validateSession', + authController.authenticate, + (req, res) => { + res.status(200).json(res.locals.username); + } +); + +// logs out user by deleting cookie +accountRouter.get('/logout', cookieController.deleteCookie, (req, res) => { + return res.sendStatus(200); +}); + +// general route for querying to find all users in database +accountRouter.get( + '/find', + accountController.findUser, + // oAuthController.requestGitHubIdentity, + (req, res) => { + return res.status(200).json(res.locals.username); + } +); + +module.exports = accountRouter; diff --git a/server/routes/projectRouter.js b/server/routes/projectRouter.js new file mode 100644 index 0000000..bc5f1d6 --- /dev/null +++ b/server/routes/projectRouter.js @@ -0,0 +1,40 @@ +const express = require('express'); +const projectController = require('../controllers/projectController'); +const authController = require('../controllers/authController'); +const projectRouter = express.Router(); + +// signup route +// endpoint : /projects/saveProject +projectRouter.post( + '/saveProject', + authController.authenticate, + projectController.saveProject, + projectController.userQuery, + (req, res) => { + return res.status(201).json(res.locals.user); + } +); + +projectRouter.post( + '/getProject', + authController.authenticate, + projectController.getProject, + (req, res) => { + console.log('testing route'); + return res.status(201).json(res.locals.project); + } +); + +// used to test Supertest functionality; not used in actual app +projectRouter.get( + '/find', + projectController.findProject, + // oAuthController.requestGitHubIdentity, + (req, res) => { + return res + .status(200) + .json({ hello: test, 'res.locals.usename': res.locals.username }); + } +); + +module.exports = projectRouter; diff --git a/server/server.js b/server/server.js new file mode 100644 index 0000000..6871c90 --- /dev/null +++ b/server/server.js @@ -0,0 +1,66 @@ +const express = require('express'); +const path = require('path'); +const cookieParser = require('cookie-parser'); +const app = express(); +const PORT = 8080; + +const cors = require('cors'); +const corsOptions = { + origin: process.env.CORS_ORIGIN, + methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', + credentials: true, +}; +const accountRouter = require('./routes/accountRouter'); +const projectRouter = require('./routes/projectRouter'); + +// connecting to MongoDB +const mongoose = require('mongoose'); +const myURI = process.env.MONGO_URI; +const { MongoClient } = require('mongodb'); +mongoose + .connect(myURI, { + // options for the connect method to parse the URI + useNewUrlParser: true, + useUnifiedTopology: true, + // sets the name of the DB that our collections are part of + dbName: 'prevueDB', + }) + .then(() => console.log('Connected to Mongo DB.')) + .catch((err) => console.log(err)); + +// Global Middleware +app.use(express.json()); +app.use(cookieParser()); +app.use(cors(corsOptions)); +app.use(express.urlencoded({ extended: true })); + +app.use(express.static(path.join(__dirname, '..', '/dist'))); + +// Routers +app.use('/users', accountRouter); +app.use('/projects', projectRouter); + +app.get('*', (req, res) => { + return res.sendFile(path.join(__dirname, '..', '/dist/index.html')); +}); + +app.use((req, res) => res.sendStatus(404)); + +// Global error handler +app.use((err, req, res, next) => { + const defaultErr = { + log: 'Express error handler caught unknown middleware error', + status: 400, + message: { err: 'An error occurred' }, + }; + const errorObj = Object.assign({}, defaultErr, err); + console.log(errorObj.log); + return res.status(errorObj.status).json(errorObj.message); +}); + +// starts server +app.listen(PORT, () => { + console.log(`Server listening on port: ${PORT}`); +}); + +module.exports = app; diff --git a/src/App.vue b/src/App.vue index d3684e1..d087fb0 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,11 +1,15 @@ diff --git a/src/assets/PreVueDemo.mp4 b/src/assets/PreVueDemo.mp4 new file mode 100644 index 0000000..162bb55 Binary files /dev/null and b/src/assets/PreVueDemo.mp4 differ diff --git a/src/assets/background.jpg b/src/assets/background.jpg new file mode 100644 index 0000000..4e67d21 Binary files /dev/null and b/src/assets/background.jpg differ diff --git a/src/assets/prevue-logo.png b/src/assets/prevue-logo.png new file mode 100644 index 0000000..aa8738d Binary files /dev/null and b/src/assets/prevue-logo.png differ diff --git a/src/assets/prevue.png b/src/assets/prevue.png new file mode 100644 index 0000000..bf25675 Binary files /dev/null and b/src/assets/prevue.png differ diff --git a/src/assets/robert-photo.jpeg b/src/assets/robert-photo.jpeg new file mode 100644 index 0000000..66fd273 Binary files /dev/null and b/src/assets/robert-photo.jpeg differ diff --git a/src/assets/sean-photo.jpeg b/src/assets/sean-photo.jpeg new file mode 100644 index 0000000..d20654c Binary files /dev/null and b/src/assets/sean-photo.jpeg differ diff --git a/src/assets/tree-demo.png b/src/assets/tree-demo.png new file mode 100644 index 0000000..e326e98 Binary files /dev/null and b/src/assets/tree-demo.png differ diff --git a/src/assets/zach-photo.jpeg b/src/assets/zach-photo.jpeg new file mode 100644 index 0000000..dadb412 Binary files /dev/null and b/src/assets/zach-photo.jpeg differ diff --git a/src/background.js b/src/background.js deleted file mode 100644 index 7d3507a..0000000 --- a/src/background.js +++ /dev/null @@ -1,145 +0,0 @@ -'use strict'; - -const { app, protocol, BrowserWindow, dialog } = require('electron'); -const ipc = require('electron').ipcMain; - -const { - createProtocol, - installVueDevtools -} = require('vue-cli-plugin-electron-builder/lib'); - -const isDevelopment = process.env.NODE_ENV !== 'production'; - -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the JavaScript object is garbage collected. -let win; - -// Standard scheme must be registered before the app is ready -protocol.registerStandardSchemes(['app'], { secure: true }); -function createWindow() { - // Create the browser window. - win = new BrowserWindow({ width: 800, height: 600 }); - - if (process.env.WEBPACK_DEV_SERVER_URL) { - // Load the url of the dev server if in development mode - win.loadURL(process.env.WEBPACK_DEV_SERVER_URL); - if (!process.env.IS_TEST) win.webContents.openDevTools(); - } else { - createProtocol('app'); - // Load the index.html when not in development - win.loadURL('app://./index.html'); - } - - win.on('closed', () => { - win = null; - }); -} - -// Quit when all windows are closed. -app.on('window-all-closed', () => { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -app.on('activate', () => { - // On macOS it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (win === null) { - createWindow(); - } -}); - -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.on('ready', async () => { - if (isDevelopment && !process.env.IS_TEST) { - // Install Vue Devtools - try { - await installVueDevtools(); - } catch (e) { - console.error('Vue Devtools failed to install:', e.toString()); - } - } - createWindow(); -}); - -// Exit cleanly on request from parent process in development mode. -if (isDevelopment) { - if (process.platform === 'win32') { - process.on('message', data => { - if (data === 'graceful-exit') { - app.quit(); - } - }); - } else { - process.on('SIGTERM', () => { - app.quit(); - }); - } -} - -function showExportDialog(event) { - dialog.showSaveDialog( - { - title: 'Choose location to save folder in', - defaultPath: app.getPath('desktop'), - message: 'Choose location to save folder in', - nameFieldLabel: 'Application Name' - }, - result => { - // console.log(result); - // if (nameLabel === 'JSON Name') event.sender.send('json-location', result); - event.sender.send('export-project-location', result); - } - ); -} - -function showSaveJsonDialog(event) { - dialog.showSaveDialog( - { - title: 'Choose location to save JSON object in', - defaultPath: app.getPath('desktop'), - message: 'Choose location to save JSON object in', - nameFieldLabel: 'Application State Name', - filters: [ - { - name: 'JSON Files', - extensions: ['json'] - } - ] - }, - result => { - event.sender.send('save-json-location', result); - } - ); -} - -ipc.on('show-open-dialog', event => { - dialog.showOpenDialog( - { - properties: ['openFile'], - filters: [ - { - name: 'JSON Files', - extensions: ['json'] - } - // { name: 'Text Files', extensions: ['txt', 'text'] }, - ] - }, - result => { - event.sender.send('open-json-location', result); - } - ); -}); - -ipc.on('show-save-json-dialog', event => { - showSaveJsonDialog(event); -}); - -ipc.on('show-export-dialog', event => { - showExportDialog(event); -}); diff --git a/src/components/ChildrenMultiselect.vue b/src/components/ChildrenMultiselect.vue index 27dc96f..eb168bf 100644 --- a/src/components/ChildrenMultiselect.vue +++ b/src/components/ChildrenMultiselect.vue @@ -1,52 +1,70 @@ - - - - + + diff --git a/src/components/Component.vue b/src/components/Component.vue new file mode 100644 index 0000000..d0d1943 --- /dev/null +++ b/src/components/Component.vue @@ -0,0 +1,57 @@ + + + diff --git a/src/components/ComponentDisplay.vue b/src/components/ComponentDisplay.vue index ed6365f..1debb6e 100644 --- a/src/components/ComponentDisplay.vue +++ b/src/components/ComponentDisplay.vue @@ -1,40 +1,60 @@ - - diff --git a/src/components/ExportProjectComponent.vue b/src/components/ExportProjectComponent.vue index 34f7c48..4eedeca 100644 --- a/src/components/ExportProjectComponent.vue +++ b/src/components/ExportProjectComponent.vue @@ -1,94 +1,94 @@ - + diff --git a/src/components/HomeQueue.vue b/src/components/HomeQueue.vue index fce93dd..ca82466 100644 --- a/src/components/HomeQueue.vue +++ b/src/components/HomeQueue.vue @@ -1,62 +1,107 @@ diff --git a/src/components/HomeSidebar.vue b/src/components/HomeSidebar.vue index cb5e59d..c139cd1 100644 --- a/src/components/HomeSidebar.vue +++ b/src/components/HomeSidebar.vue @@ -1,51 +1,103 @@ - diff --git a/src/components/Icons.vue b/src/components/Icons.vue index 9290efa..3d47a97 100644 --- a/src/components/Icons.vue +++ b/src/components/Icons.vue @@ -1,7 +1,13 @@