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 8ccb9e7..08533cc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

PreVue

@@ -16,34 +16,24 @@ For Vue Developers From Component Architecture to Code Exporting -PreVue allows the user to design/visualize their component architecture by allowing users to : +PreVue allows users to conceptualize and visualize component architecture by allowing them to : -1. Create components and preview their code + 1. Create components and preview their associated code + 2. Set up different routes and views + 3. Establish parent-child component relationships + 4. View application hierarchy in tree format + 5. Export the component architecture as a Vue application created with default Vite settings. -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. +Use PreVue to create projects in single sessions or sign in with GitHub to save projects and update them anytime. +the component architecture as a Vue application created with the default Vue CLI settings.

- +

## Getting Started ---- - -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) - -###### Support for Windows now here! - -- 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. - -If you find any issues, [file issue](https://github.com/teamprevue/PreVue/issues) ## How to use @@ -52,45 +42,49 @@ If you find any issues, [file issue](https://github.com/teamprevue/PreVue/issues #### Adding Components - Double click on the application icon -- Create components by entering a name and clicking the html elements you need - -- Clicked elements will be shown on the right sidebar -- Drag them around to change the order! +- Create components by entering a name and clicking the HTML elements you need +- Clicked elements will be shown in the right sidebar +- Drag the elements to change their order +- Once you're satisfied, click the button to ‘add a component’ and it will show up in the working area. Resize and move components to fit the design you have in mind. -- 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 +- Double click elements to bring up the modal view - 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 +- Establish parent-child component relationships via the 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 +#### Adding Routes - +- Create different routes that represent different Views for your app. +- Any components created on a given route will be automatically saved to that route +- See your application’s hierarchy by clicking the ‘Tree’ icon in the navigation bar + +

+ +

#### Tree View of Application Architecture

- +

#### 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! +- In order to utilize the saving and opening functionality of PreVue, please clone the repo to run on your local machine. +- If you're signed in with GitHub, click the ‘Save Project’ icon to save it to PreVue’s database +- Click ‘Open Project’ to retrieve past projects - Once you're satisfied, click the export project icon to export your awesome project as new Vue application! +- Other users can use PreVue's playground to create and export projects in single sessions. + @@ -112,26 +106,15 @@ src/ UserCreatedRouteComponent2.vue ... ``` - -### Editor Hotkeys: - -- cmd/ctrl + s: save -- cmd/ctrl + o: open -- cmd/ctrl + n: new 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 +git clone https://github.com/oslabs/PreVue.git ``` Install dependencies @@ -139,13 +122,19 @@ Install dependencies ``` npm i ``` +Build the app -Run electron app +``` +npm run build +``` +Run the app ``` -npm run electron:serve +npm run server ``` +Go to http://localhost:8080 to use PreVue! + ## Built With --- @@ -153,25 +142,27 @@ npm run electron:serve - [Vue.js](https://vuejs.org/) - [Vue Router](https://router.vuejs.org/guide/#html) - [Vuex](https://vuex.vuejs.org/) -- [Electron](https://electronjs.org/) -- [Vue-Electron CLI](https://github.com/nklayman/vue-cli-plugin-electron-builder) -- [Buefy](https://buefy.org/) -- [Babel](https://babeljs.io/) +- [Vite](https://vitejs.dev/) +- [Vuetify](https://vuetifyjs.com/) - [Jest](https://jestjs.io/) -- [Travis](https://travis-ci.org/) -- [localForage](https://localforage.github.io/localForage/) -- [Vue D3 Tree](https://github.com/David-Desmaisons/Vue.D3.tree) +- [SuperTest](https://www.npmjs.com/package/supertest) ## 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. +PreVue We encourage you to submit issues for any bugs or ideas for enhancements. Please feel free to fork this repo and submit pull requests to contribute as well. Also follow PreVue on [LinkedIn](https://www.linkedin.com/company/prevue-live/) for more updates. ## Authors --- +PreVue 2.0 +- **Jason Boo** [@jasonboo123](https://github.com/jasonboo123) +- **Robert Drake** [@rmdrake8](https://github.com/rmdrake8) +- **Sean Flynn** [@seanflynn5](http://github.com/seanflynn5) +- **Zach Pestaina** [@zachpestaina](https://github.com/zachpestaina) +PreVue 1.0 - **Hubert Lin** [@hubelin](https://github.com/hubelin) - **Franklin Pinnock** [@pinnockf](https://github.com/pinnockf) - **Annette Lin** [@al2613](https://github.com/al2613) 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/electron-builder.json b/electron-builder.json deleted file mode 100644 index cd66724..0000000 --- a/electron-builder.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "appId": "com.electron.PreVue", - "mac": { - "category": "public.app-category.developer-tools", - "icon": "build/icon.icns" - }, - "files": ["out"], - "nsis": { - "createDesktopShortcut": "always" - }, - "dmg": { - "contents": [ - { - "x": 110, - "y": 150 - }, - { - "x": 240, - "y": 150, - "type": "link", - "path": "/Applications" - } - ] - }, - - "linux": { - "target": ["deb"] - }, - "win": { - "target": "NSIS", - "icon": "build/icon.ico" - }, - - "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 8c9ed87..7d7eebf 100644 --- a/package.json +++ b/package.json @@ -1,59 +1,83 @@ { - "name": "PreVue", - "author": { - "name": "teamprevue", - "email": "teamprevue@gmail.com", - "url": "www.prevue.io" + "module": { + "type": "commonjs" }, - "version": "1.0.0", - "description": "Developer prototyping app built with Vue on Electron", + "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 -mlw --publish never", - "electron:release": "vue-cli-service electron:build -mlw --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" }, "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", + "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", - "vuedraggable": "^2.19.3", - "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-builder-squirrel-windows": "^20.39.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" + "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" + }, + "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..1ff4215 --- /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/3.png b/src/assets/3.png new file mode 100644 index 0000000..3fed9d6 Binary files /dev/null and b/src/assets/3.png differ 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/componentdisplay.png b/src/assets/componentdisplay.png new file mode 100644 index 0000000..693e74c Binary files /dev/null and b/src/assets/componentdisplay.png differ diff --git a/src/assets/homeview.png b/src/assets/homeview.png new file mode 100644 index 0000000..a427ade Binary files /dev/null and b/src/assets/homeview.png differ diff --git a/src/assets/newcomp.png b/src/assets/newcomp.png new file mode 100644 index 0000000..7568648 Binary files /dev/null and b/src/assets/newcomp.png differ diff --git a/src/assets/newcompvue.png b/src/assets/newcompvue.png new file mode 100644 index 0000000..7a299f3 Binary files /dev/null and b/src/assets/newcompvue.png differ diff --git a/src/assets/prevue_color_white.png b/src/assets/prevue_color_white.png index 76bb07d..6f294e2 100644 Binary files a/src/assets/prevue_color_white.png and b/src/assets/prevue_color_white.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/routecreator.png b/src/assets/routecreator.png new file mode 100644 index 0000000..cee98dd Binary files /dev/null and b/src/assets/routecreator.png 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/treeview.png b/src/assets/treeview.png new file mode 100644 index 0000000..e9518d9 Binary files /dev/null and b/src/assets/treeview.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 9104173..eb168bf 100644 --- a/src/components/ChildrenMultiselect.vue +++ b/src/components/ChildrenMultiselect.vue @@ -1,27 +1,34 @@ - - - - + + 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 c33bb1b..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 9d8e292..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 91ba659..c139cd1 100644 --- a/src/components/HomeSidebar.vue +++ b/src/components/HomeSidebar.vue @@ -1,35 +1,76 @@ - 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 @@