[
  {
    "path": ".browserslistrc",
    "content": "> 1%\nlast 2 versions\nnot ie <= 8\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    node: true\n  },\n  extends: [\"plugin:vue/recommended\", \"standard\"],\n  rules: {\n    \"no-console\": process.env.NODE_ENV === \"production\" ? \"error\" : \"off\",\n    \"no-debugger\": process.env.NODE_ENV === \"production\" ? \"error\" : \"off\",\n    \"vue/max-attributes-per-line\": [\"error\", {\n      \"singleline\": 4,\n      \"multiline\": {\n        \"max\": 1,\n        \"allowFirstLine\": false\n      }\n    }]\n  },\n  parserOptions: {\n    parser: \"babel-eslint\"\n  }\n};\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\ndb/user.json\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw*\n"
  },
  {
    "path": "README.md",
    "content": "# authentication_course\n\n## Project setup\n```\nnpm install\n```\n\n### Compiles and hot-reloads for development\n```\nnpm run serve\n```\n### Same as above and start backend server\n```\nnpm run start\n```\n### Compiles and minifies for production\n```\nnpm run build\n```\n\n### Run your tests\n```\nnpm run test\n```\n\n### Lints and fixes files\n```\nnpm run lint\n```\n\n### Customize configuration\nSee [Configuration Reference](https://cli.vuejs.org/config/).\n"
  },
  {
    "path": "_server.js",
    "content": "var express = require('express')\nvar jwt = require('jsonwebtoken')\nvar cors = require('cors')\nvar bodyParser = require('body-parser')\nvar fs = require('fs')\nvar events = require('./db/events.json')\n\nconst app = express()\n\napp.use(cors())\napp.use(bodyParser.json())\n\napp.get('/', (req, res) => {\n  res.json({\n    message: 'Welcome to the API.'\n  })\n})\n\napp.get('/dashboard', verifyToken, (req, res) => {\n  jwt.verify(req.token, 'the_secret_key', err => {\n    if (err) {\n      res.sendStatus(401)\n    } else {\n      res.json({\n        events: events\n      })\n    }\n  })\n})\n\napp.post('/register', (req, res) => {\n  if (req.body) {\n    const user = {\n      name: req.body.name,\n      email: req.body.email,\n      password: req.body.password\n      // You'll want to encrypt the password in a live app\n    }\n\n    var data = JSON.stringify(user, null, 2)\n\n    fs.writeFile('db/user.json', data, err => {\n      if (err) {\n        console.log(err)\n      } else {\n        console.log('Added user to user.json')\n      }\n    })\n    // The secret key should be an evironment variable in a live app\n    const token = jwt.sign({ user }, 'the_secret_key')\n    res.json({\n      token,\n      email: user.email,\n      name: user.name\n    })\n  } else {\n    res.sendStatus(401)\n  }\n})\n\napp.post('/login', (req, res) => {\n  var userDB = fs.readFileSync('./db/user.json')\n  var userInfo = JSON.parse(userDB)\n  if (\n    req.body &&\n    req.body.email === userInfo.email &&\n    req.body.password === userInfo.password\n  ) {\n    // The secret key should be an environment variable in a live app\n    const token = jwt.sign({ userInfo }, 'the_secret_key')\n    res.json({\n      token,\n      email: userInfo.email,\n      name: userInfo.name\n    })\n  } else {\n    res.sendStatus(401)\n  }\n})\n\nfunction verifyToken (req, res, next) {\n  const bearerHeader = req.headers['authorization']\n\n  if (typeof bearerHeader !== 'undefined') {\n    const bearer = bearerHeader.split(' ')\n    const bearerToken = bearer[1]\n    req.token = bearerToken\n    next()\n  } else {\n    res.sendStatus(401)\n  }\n}\n\napp.listen(3000, () => {\n  console.log('Server started on port 3000')\n})\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: [\"@vue/app\"]\n};\n"
  },
  {
    "path": "db/events.json",
    "content": "{\n  \"events\": [\n    {\n      \"id\": \"1234\",\n      \"title\": \"Puppy Parade\",\n      \"time\": \"12:00\",\n      \"date\": \"Feb 22, 2022\"\n    },\n    {\n      \"id\": \"1584\",\n      \"title\": \"Cat Cabaret\",\n      \"time\": \"9:00\",\n      \"date\": \"March 4, 2022\"\n    },\n    {\n      \"id\": \"2794\",\n      \"title\": \"Doggy Day\",\n      \"time\": \"1:00\",\n      \"date\": \"June 12, 2022\"\n    },\n    {\n      \"id\": \"4619\",\n      \"title\": \"Feline Frenzy\",\n      \"time\": \"8:00\",\n      \"date\": \"July 28, 2022\"\n    }\n  ]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"authentication_course\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"vue-cli-service lint\",\n    \"start\": \"nodemon server.js & vue-cli-service serve\"\n  },\n  \"dependencies\": {\n    \"axios\": \"^0.18.0\",\n    \"body-parser\": \"^1.18.3\",\n    \"cors\": \"^2.8.5\",\n    \"eslint-config-standard\": \"^12.0.0\",\n    \"eslint-plugin-import\": \"^2.16.0\",\n    \"express\": \"^4.16.4\",\n    \"jsonwebtoken\": \"^8.4.0\",\n    \"nodemon\": \"^1.18.10\",\n    \"sqlite3\": \"^4.0.6\",\n    \"vue\": \"^2.5.22\",\n    \"vue-router\": \"^3.0.1\",\n    \"vuex\": \"^3.0.1\"\n  },\n  \"devDependencies\": {\n    \"@vue/cli-plugin-babel\": \"^3.4.0\",\n    \"@vue/cli-plugin-eslint\": \"^3.4.0\",\n    \"@vue/cli-service\": \"^3.4.0\",\n    \"@vue/eslint-config-prettier\": \"^4.0.1\",\n    \"babel-eslint\": \"^10.0.1\",\n    \"eslint\": \"^5.8.0\",\n    \"eslint-plugin-node\": \"^8.0.1\",\n    \"eslint-plugin-promise\": \"^4.0.1\",\n    \"eslint-plugin-standard\": \"^4.0.0\",\n    \"eslint-plugin-vue\": \"^5.0.0\",\n    \"node-sass\": \"^4.11.0\",\n    \"sass-loader\": \"^7.1.0\",\n    \"vue-template-compiler\": \"^2.5.21\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    autoprefixer: {}\n  }\n};\n"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title>authentication_course</title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but authentication_course doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "server.js",
    "content": "const express = require('express')\nconst jwt = require('jsonwebtoken')\nconst cors = require('cors')\nconst bodyParser = require('body-parser')\nconst fs = require('fs')\nconst events = require('./db/events.json')\n\nconst app = express()\n\napp.use(cors())\napp.use(bodyParser.json())\n\napp.get('/', (req, res) => {\n  res.json({\n    message: 'Welcome to the API.'\n  })\n})\n\napp.get('/dashboard', verifyToken, (req, res) => {\n  jwt.verify(req.token, 'the_secret_key', err => {\n    if (err) {\n      res.sendStatus(401)\n    } else {\n      res.json({\n        events: events\n      })\n    }\n  })\n})\n\napp.post('/register', (req, res) => {\n  if (req.body) {\n    const user = {\n      name: req.body.name,\n      email: req.body.email,\n      password: req.body.password\n      // In a production app, you'll want to encrypt the password\n    }\n\n    const data = JSON.stringify(user, null, 2)\n    var dbUserEmail = require('./db/user.json').email\n\n    if (dbUserEmail === req.body.email) {\n      res.sendStatus(400)\n    } else {\n      fs.writeFile('./db/user.json', data, err => {\n        if (err) {\n          console.log(err + data)\n        } else {\n          const token = jwt.sign({ user }, 'the_secret_key')\n          // In a production app, you'll want the secret key to be an environment variable\n          res.json({\n            token,\n            email: user.email,\n            name: user.name\n          })\n        }\n      })\n    }\n  } else {\n    res.sendStatus(400)\n  }\n})\n\napp.post('/login', (req, res) => {\n  const userDB = fs.readFileSync('./db/user.json')\n  const userInfo = JSON.parse(userDB)\n  if (\n    req.body &&\n    req.body.email === userInfo.email &&\n    req.body.password === userInfo.password\n  ) {\n    const token = jwt.sign({ userInfo }, 'the_secret_key')\n    // In a production app, you'll want the secret key to be an environment variable\n    res.json({\n      token,\n      email: userInfo.email,\n      name: userInfo.name\n    })\n  } else {\n    res.sendStatus(400)\n  }\n})\n\n// MIDDLEWARE\nfunction verifyToken (req, res, next) {\n  const bearerHeader = req.headers['authorization']\n\n  if (typeof bearerHeader !== 'undefined') {\n    const bearer = bearerHeader.split(' ')\n    const bearerToken = bearer[1]\n    req.token = bearerToken\n    next()\n  } else {\n    res.sendStatus(401)\n  }\n}\n\napp.listen(3000, () => {\n  console.log('Server started on port 3000')\n})\n"
  },
  {
    "path": "src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <app-nav />\n    <router-view class=\"page\" />\n  </div>\n</template>\n\n<script>\nimport AppNav from './components/AppNav'\n\nexport default {\n  components: { AppNav }\n}\n</script>\n\n<style lang=\"scss\">\n@import './assets/styles/global.scss';\n.page {\n  display: flex;\n  justify-content: center;\n  flex-direction: column;\n  align-items: center;\n  min-height: calc(100vh - 56px);\n}\n</style>\n"
  },
  {
    "path": "src/assets/styles/global.scss",
    "content": "body {\n  font-family: 'Avenir', Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: center;\n  color: #2c3e50;\n  padding: 0em;\n  margin: 0em;\n}\n\na:visited {\n  color: #2c3e50;\n}\n\n.button,\nbutton {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 5em;\n  height: 2em;\n  margin: 0.5em;\n  border-radius: 5px;\n  background: linear-gradient(to right, #16c0b0, #84cf6a);\n  font-size: 1em;\n  color: white;\n  border: none;\n  outline: none;\n}\n\nform {\n  display: flex;\n  align-items: center;\n  flex-direction: column;\n  width: 15em;\n  margin-bottom: 2em;\n\n  p {\n    color: red;\n  }\n}\n\ninput {\n  display: block;\n  box-sizing: border-box;\n  width: 100%;\n  height: 2.6em;\n  padding: 0.5em;\n  margin-bottom: 1em;\n  font: 1em 'Avenir', Helvetica, sans-serif;\n}\n\nh1 {\n  margin-top: 0;\n}"
  },
  {
    "path": "src/components/AppNav.vue",
    "content": "<template>\n  <div id=\"nav\">\n    <router-link to=\"/\">\nHome\n</router-link>\n\n    <template v-if=\"user\">\n      <router-link to=\"dashboard\">\nDashboard\n</router-link>\n\n      <span class=\"nav-welcome\">Hello, {{ user.name }}.</span>\n\n      <button type=\"button\" class=\"logoutButton\" @click=\"logout\">\nLog out\n</button>\n    </template>\n\n    <template v-else>\n      <router-link to=\"authenticate\" class=\"button\">\nLogin\n</router-link>\n    </template>\n  </div>\n</template>\n\n<script>\nexport default {\n  computed: {\n    user () {\n      return this.$store.state.user\n    }\n  },\n  methods: {\n    logout () {\n      this.$store.dispatch('logout')\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n#nav {\n  display: flex;\n  align-items: center;\n  min-height: 50px;\n  padding: 0.2em 1em;\n  background: linear-gradient(to right, #16c0b0, #84cf6a);\n}\n\n.nav-welcome {\n  margin-left: auto;\n  margin-right: 1rem;\n  color: white;\n}\n\na {\n  font-weight: bold;\n  color: #2c3e50;\n  margin: auto 0.8em auto 0.4em;\n  text-decoration: none;\n  border-top: 2px solid transparent;\n  border-bottom: 2px solid transparent;\n}\n\n.router-link-exact-active {\n  color: white;\n  border-bottom: 2px solid #fff;\n}\n\nbutton,\n.button {\n  margin-left: auto;\n  background: white;\n  text-decoration: none;\n  color: #2c3e50;\n\n  &.router-link-active {\n    color: #2c3e50;\n  }\n}\n\n.logoutButton {\n  cursor: pointer;\n}\n\n.nav-welcome + button {\n  margin-left: 0;\n}\n</style>\n"
  },
  {
    "path": "src/components/EventCard.vue",
    "content": "<template>\n  <div class=\"event-card\">\n    <span>@{{ event.time }} on {{ event.date }}</span>\n    <h4>{{ event.title }}</h4>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'EventCard',\n  props: {\n    event: {\n      type: Object,\n      default: () => ({})\n    }\n  }\n}\n</script>\n\n<style scoped>\n.event-card {\n  width: 13em;\n  margin: 1em auto 1em auto;\n  padding: 1em;\n  border: solid 1px #2c3e50;\n  cursor: pointer;\n  transition: all 0.2s linear;\n}\n.event-card:hover {\n  transform: scale(1.01);\n  box-shadow: 0 3px 12px 0 rgba(0, 0, 0, 0.2), 0 1px 15px 0 rgba(0, 0, 0, 0.19);\n}\n.event-card h4 {\n  font-size: 1.4em;\n  margin-top: 0.5em;\n  margin-bottom: 0.3em;\n}\n</style>\n"
  },
  {
    "path": "src/components/LoginUser.vue",
    "content": "<template>\n  <form @submit.prevent=\"login\">\n    <label for=\"email\">\n      Email:\n    </label>\n    <input v-model=\"email\" type=\"email\" name=\"email\" value>\n    <label for=\"password\">\n      Password:\n    </label>\n    <input v-model=\"password\" type=\"password\" name value>\n    <p v-if=\"status === 400\">\n      Invalid login info.\n    </p>\n    <button type=\"submit\" name=\"button\">\n      Login\n    </button>\n  </form>\n</template>\n\n<script>\nexport default {\n  name: 'LoginUser',\n  data () {\n    return {\n      email: '',\n      password: '',\n      status: null\n    }\n  },\n  methods: {\n    login () {\n      this.$store\n        .dispatch('login', {\n          email: this.email,\n          password: this.password\n        })\n        .then(() => { this.$router.push({ name: 'dashboard' }) })\n        .catch(err => { this.status = err.response.status })\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "src/components/RegisterUser.vue",
    "content": "<template>\n  <div>\n    <form @submit.prevent=\"register\">\n      <label for=\"name\">\n        Name:\n      </label>\n      <input v-model=\"name\" type=\"text\" name=\"name\" value>\n      <label for=\"email\">\n        Email:\n      </label>\n      <input v-model=\"email\" type=\"email\" name=\"email\" value>\n\n      <label for=\"password\">\n        Password:\n      </label>\n      <input v-model=\"password\" type=\"password\" name value>\n      <p v-if=\"status === 400\">\n        Please enter different info.\n      </p>\n\n      <button type=\"submit\" name=\"button\">\n        Register\n      </button>\n    </form>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'RegisterUser',\n  data () {\n    return {\n      name: '',\n      email: '',\n      password: '',\n      status: null\n    }\n  },\n  methods: {\n    register () {\n      this.$store\n        .dispatch('register', {\n          name: this.name,\n          email: this.email,\n          password: this.password\n        })\n        .then(() => { this.$router.push({ name: 'dashboard' }) })\n        .catch(err => { this.status = err.response.status })\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "src/main.js",
    "content": "import Vue from 'vue'\nimport App from './App.vue'\nimport router from './router'\nimport store from './store'\nimport axios from 'axios'\n\nVue.config.productionTip = false\n\nnew Vue({\n  router,\n  store,\n  render: h => h(App),\n  created() {\n    const userString = localStorage.getItem('user')\n    if (userString) {\n      const userData = JSON.parse(userString)\n      this.$store.commit('SET_USER_DATA', userData)\n    }\n    //\n    axios.interceptors.response.use(\n      response => response,\n      error => {\n        console.log(error.response)\n        if (error.response.status === 401) {\n          this.$router.push('/')\n          this.$store.dispatch('logout')\n        }\n        return Promise.reject(error)\n      }\n    )\n  }\n}).$mount('#app')\n"
  },
  {
    "path": "src/router.js",
    "content": "import Vue from 'vue'\nimport Router from 'vue-router'\nimport Home from './views/Home.vue'\nimport Dashboard from './views/Dashboard.vue'\nimport Authenticate from './views/Authenticate.vue'\n\nVue.use(Router)\n\nconst router = new Router({\n  mode: 'history',\n  base: process.env.BASE_URL,\n  routes: [\n    {\n      path: '/',\n      name: 'home',\n      component: Home\n    },\n    {\n      path: '/dashboard',\n      name: 'dashboard',\n      component: Dashboard\n    },\n    {\n      path: '/authenticate',\n      name: 'authenticate',\n      component: Authenticate\n    }\n  ]\n})\n\nrouter.beforeEach((to, from, next) => {\n  // redirect to login page if user is not logged in and trying to access a restricted page\n  const publicPages = ['/authenticate', '/']\n  const authRequired = !publicPages.includes(to.path)\n  const loggedIn = localStorage.getItem('user')\n\n  if (authRequired && !loggedIn) {\n    return next('/authenticate')\n  }\n\n  next()\n})\n\nexport default router\n"
  },
  {
    "path": "src/store.js",
    "content": "import Vue from 'vue'\nimport Vuex from 'vuex'\nimport axios from 'axios'\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n  state: {\n    user: null,\n    isNewUser: true\n  },\n  mutations: {\n    SET_USER_DATA (state, userData) {\n      localStorage.setItem('user', JSON.stringify(userData))\n      axios.defaults.headers.common['Authorization'] = `Bearer ${\n        userData.token\n      }`\n      state.user = userData\n    },\n    LOGOUT () {\n      localStorage.removeItem('user')\n      location.reload()\n    },\n    IS_NEW_USER (state, isNewUser) {\n      state.isNewUser = isNewUser\n    }\n  },\n  actions: {\n    register ({ commit }, credentials) {\n      return axios\n        .post('//localhost:3000/register', credentials)\n        .then(({ data }) => {\n          commit('SET_USER_DATA', data)\n        })\n    },\n    login ({ commit }, credentials) {\n      return axios\n        .post('//localhost:3000/login', credentials)\n        .then(({ data }) => {\n          commit('SET_USER_DATA', data)\n        })\n    },\n    logout ({ commit }) {\n      commit('LOGOUT')\n    },\n    isNewUser ({ commit }, isNewUser) {\n      commit('IS_NEW_USER', isNewUser)\n    }\n  }\n})\n"
  },
  {
    "path": "src/views/Authenticate.vue",
    "content": "<template>\n  <div>\n    <component :is=\"loginOrRegister\" />\n    <a\n      v-show=\"isNewUser\"\n      class=\"auth-link\"\n      @click=\"toggleComponent\"\n    >Don't have an account? Create one.</a>\n    <a\n      v-show=\"!isNewUser\"\n      class=\"auth-link\"\n      @click=\"toggleComponent\"\n    >Already have an account? Login.</a>\n  </div>\n</template>\n\n<script>\nimport RegisterUser from '../components/RegisterUser'\nimport LoginUser from '../components/LoginUser'\n\nexport default {\n  components: { RegisterUser, LoginUser },\n  computed: {\n    isNewUser () {\n      return this.$store.state.isNewUser\n    },\n    loginOrRegister () {\n      return this.isNewUser ? 'LoginUser' : 'RegisterUser'\n    }\n  },\n  methods: {\n    toggleComponent () {\n      this.$store.dispatch('isNewUser', !this.isNewUser)\n    }\n  }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.auth-link {\n  font-size: 0.8em;\n  text-decoration: underline;\n  color: #2c3e50;\n  cursor: pointer;\n}\n</style>\n"
  },
  {
    "path": "src/views/Dashboard.vue",
    "content": "<template>\n  <div>\n    <h1>Dashboard</h1>\n    <template v-if=\"events !== 'Loading events...'\">\n      <EventCard v-for=\"event in events\" :key=\"event.id\" :event=\"event\" />\n    </template>\n  </div>\n</template>\n\n<script>\nimport axios from 'axios'\nimport EventCard from '../components/EventCard'\n\nexport default {\n  components: { EventCard },\n  data () {\n    return { events: 'Loading events...' }\n  },\n  created () {\n    axios.get('//localhost:3000/dashboard').then(({ data }) => {\n      this.events = data.events.events\n    })\n  }\n}\n</script>\n"
  },
  {
    "path": "src/views/Home.vue",
    "content": "<template>\n  <div class=\"home\">\n    <h1>Welcome to the App!</h1>\n    <template v-if=\"!this.$store.state.user\">\n      <div>\n        To use the app, you'll need to\n        <router-link to=\"authenticate\" @click.native=\"isNew(false)\">\n          Login\n        </router-link>\n        or\n        <router-link to=\"authenticate\" @click.native=\"isNew(true)\">\n          Register\n        </router-link>\n      </div>\n    </template>\n  </div>\n</template>\n\n<script>\nexport default {\n  methods: {\n    isNew (isNewUser) { this.$store.dispatch('isNewUser', !isNewUser) }\n  }\n}\n</script>\n"
  },
  {
    "path": "vue.config.js",
    "content": "const path = require(\"path\");\n\nmodule.exports = {\n  pluginOptions: {\n    \"style-resources-loader\": {\n      preProcessor: \"scss\",\n      patterns: [path.resolve(__dirname, \"./src/styles/global.scss\")]\n    }\n  }\n};"
  }
]