diff --git a/README.md b/README.md
index 7e08b13..15e2423 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,252 @@
-# fancy-todo
\ No newline at end of file
+# fancy-todo
+
+All the APIs endpoint using base URL:
+```javascript
+http://localhost:3000
+```
+
+## Index of Reference:
+* [User]()
+* [Todo]()
+
+## User API
+| HTTP | Endpoint | Headers | Body | Description |
+|--------|----------|---------|------|-------------|
+| POST | /user/signup | none | name: string
email: string
password: string | Register new user |
+| POST | /user/signin | none | email: string
password: string | Login user |
+| POST | /user/signInGoogle | none | log in using user google account | Login user |
+
+## Todo API
+| HTTP | Endpoint | Headers | Body | Description |
+|--------|----------|---------|------|-------------|
+| GET | /todo | {token: JWT token} | none | get user todo list |
+| POST | /todo| {token: JWT token} | todo : string
description : string
dueDate : date | create todo list |
+| GET | /todo/search | {token: JWT token, id : userId, todo : string} | none | find user todo and display |
+| GET | /todo/:id | {token: JWT token, id:todoId} | none | find user todo for to be display for update requirements |
+| PUT | /todo/:id | {token: JWT token, id : todoId} | {todo :string, description :string, dueDate :date} | update todo that matches with |
+| DELETE | /todo/:id | {token: JWT token, id : userId} | none | get global published articles |
+
+# Request & Response Details
+
+## User
++ ### Register
+ method: `POST`
+ endpoint: `/user/signup`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ name: String, required
+ email: String, required
+ password: String, required
+ ```
+
+ #### _Response_ :
+ - 201
+ ```javascript
+ {code: 201, message: "Berhasil SignUp"}
+
+ ```
+ - 400
+ ```javascript
+ {
+ "code": 400,
+ "message": "Mohon Maaf Nama Harus di Isi"
+ }
+ ```
+
+ + ### Login
+ method: `POST`
+ endpoint: `/users/login`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ email: String, required
+ password: String, required
+ ```
+
+ #### _Response_ :
+ - 200
+ ```javascript
+ Get an access token (JWT Token)
+ {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Z…DIxfQ.rCDMqKOnNie3UktVbTbwayGzUiN3_SoHT6qlk15RYvI"}
+ ```
+ - 401
+ ```javascript
+ {"code":401,"message":"Mohon Maaf Password Salah"}
+ ```
+
+ ## Todo
++ ### find all Todo
+ method: `GET`
+ endpoint: `/todo`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ todo: "foo",
+ desc: "bar,
+ due_date: "2019-10-10",
+ token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJiYWR1IiwiZW1haWwiOiJiYWR1QG1haWwuY29tIiwiaWF0IjoxNTY0OTkzNzgxfQ.Q4JKT7BRNCPOGUgTF-9NQTU2YASPRg7a3kO72fpPRY8
+ ```
+
+ #### _Response_ :
+ - 201
+ ```javascript
+ status: false,
+ _id: 5d757aed076a72e08de1817e,
+ userId: 5d757585076a72e08de1817b,
+ todo: 'cemilan',
+ description: 'macaroni maicih',
+ dueDate: 2019-09-16T00:00:00.000Z,
+ createdAt: 2019-09-08T22:04:29.632Z,
+ updatedAt: 2019-09-08T22:04:29.632Z
+ ```
+ - 400
+ ```javascript
+ {
+ "code": 403
+ }
+ ```
+
+ + ### create Todo
+ method: `POST`
+ endpoint: `/todo`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ todo: 'halooo',
+ description: 'asfqwreqwr',
+ dueDate: '2019-09-10'
+ ```
+
+ #### _Response_ :
+ - 201
+ ```javascript
+ createdAt: "2019-09-08T23:21:52.329Z"
+description: "asfqwreqwr"
+dueDate: "2019-09-10T00:00:00.000Z"
+status: false
+todo: "halooo"
+updatedAt: "2019-09-08T23:21:52.329Z"
+userId: "5d757585076a72e08de1817b"
+_id: "5d758d10a528cb008eb62228"
+ ```
+ - 400
+ ```javascript
+ {
+ "code": 401
+ }
+ ```
++ ### create Todo
+ method: `POST`
+ endpoint: `/todo`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ todo: 'halooo',
+ description: 'asfqwreqwr',
+ dueDate: '2019-09-10'
+ ```
+
+ #### _Response_ :
+ - 201
+ ```javascript
+ createdAt: "2019-09-08T23:21:52.329Z"
+ description: "asfqwreqwr"
+ dueDate: "2019-09-10T00:00:00.000Z"
+ status: false
+ todo: "halooo"
+ updatedAt: "2019-09-08T23:21:52.329Z"
+ userId: "5d757585076a72e08de1817b"
+ _id: "5d758d10a528cb008eb62228"
+ ```
+ - 400
+ ```javascript
+ {
+ "code": 401
+ }
+ ```
++ ### search Todo
+ method: `GET`
+ endpoint: `/todo/search`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ {todo: todo}
+ ```
+
+ #### _Response_ :
+ - 201
+ ```javascript
+ createdAt: "2019-09-08T23:12:41.959Z"
+ description: "suryaaa"
+ dueDate: "2019-09-23T00:00:00.000Z"
+ status: false
+ todo: "fadhil"
+ updatedAt: "2019-09-08T23:12:41.959Z"
+ userId: "5d757585076a72e08de1817b"
+ _id: "5d758ae9560c27fb8b3141e0"
+ ```
+ - 403
+ ```javascript
+ {
+ "code": 403
+ }
+ ```
+
+ + ### update Todo
+ method: `PUT`
+ endpoint: `/todo/:id`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ {id: todoId}
+ ```
+
+ #### _Response_ :
+ - 201
+ ```javascript
+ n: 1
+ nModified: 1
+ ok: 1
+ ```
+ - 403
+ ```javascript
+ {
+ "code": 401
+ }
+ ```
+ + ### delete Todo
+ method: `DELETE`
+ endpoint: `/todo/:id`
+
+ #### _Request_ :
+ * body:
+ ```javascript
+ {id: todoId}
+ ```
+
+ #### _Response_ :
+ - 201
+ ```javascript
+ n: 1
+ nModified: 1
+ ok: 1
+ ```
+ - 403
+ ```javascript
+ {
+ "code": 401
+ }
+ ```
+
+
+
+
+
diff --git a/client/css/main.css b/client/css/main.css
new file mode 100644
index 0000000..9d590ca
--- /dev/null
+++ b/client/css/main.css
@@ -0,0 +1,14 @@
+body {
+ min-height: 100vh;
+ position: relative;
+ margin: 0;
+}
+
+footer {
+ position: absolute;
+ bottom: 0;
+}
+
+thead {
+ background-color: grey;
+}
\ No newline at end of file
diff --git a/client/index.html b/client/index.html
new file mode 100644
index 0000000..6ef7a6d
--- /dev/null
+++ b/client/index.html
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fadhil Todos
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/index.js b/client/index.js
new file mode 100644
index 0000000..16a4a8b
--- /dev/null
+++ b/client/index.js
@@ -0,0 +1,634 @@
+const baseUrl = `34.87.84.247 `
+
+
+$(document).ready(_ => {
+ register()
+ loginPage()
+ login()
+ signout()
+ // todoMainPage()
+ deleteTodo()
+ update()
+ inputUpdate()
+ search()
+
+})
+
+
+//
+if (localStorage.getItem('token')) {
+ console.log
+ // console.log(localStorage.getItem('token'))
+ $('#logOut').show()
+ $('.g-signin2').hide()
+ // todoMainPage()
+ $('#login').hide()
+ todoMainPage()
+ showTodoList()
+ createTodo()
+ deleteTodo()
+ $('.formbar').show()
+ $('.home-btn').hide()
+
+} else {
+ $('.g-signin2').show()
+ // signOut()
+ $('.formbar').hide()
+ $('signin-form').show()
+ $('.btn-logout').hide()
+ $('.home-btn').hide()
+ // todoMainPage().hide()
+}
+
+
+function register() {
+ $('.btn-register').click(function (event) {
+ event.preventDefault()
+ console.log('masuk ke register')
+
+ $.ajax({
+ method: 'POST',
+ url: `${baseUrl}/user/signup`,
+ data: {
+ name: $('#name').val(),
+ email: $('#email').val(),
+ password: $('#password').val()
+ }
+ })
+
+ .done(data => {
+ console.log(data)
+ console.log('masukkkkk <<<<<<<')
+
+ // console.log(data, '<<<<<< BERHASIL BRO')
+ console.log('MASUK KE BERHASIL CEK KE DATABASE')
+ })
+ .fail(err => {
+ console.log(err, '<<<<<< TIDAK BERHASIL BRO')
+ console.log('TIDAK MASUK KE BERHASIL CEK KE DATABASE')
+ })
+ })
+}
+
+function loginPage() {
+ console.log('masuk ke login page')
+ $('.btn-login').click(function (event) {
+
+ event.preventDefault()
+
+ $('.homepage').empty().append(`
+ `)
+ $('.home-btn').show()
+ $('.signin-form').hide()
+ })
+}
+
+function homeBtn() {
+ $(document).on('click', '.home-btn', function (event) {
+ event.preventDefault()
+ $('.homepage').empty()
+ todoMainPage()
+ })
+}
+
+function login() {
+ $(document).on('click', '.btn-loginId', function (event) {
+ event.preventDefault()
+ console.log('masuk berhasil login coy')
+ const dataLogin = {
+ email: $('#email').val(),
+ password: $('#password').val()
+ }
+
+ console.log(dataLogin, 'ini data login <<<<')
+ $.ajax({
+ method: 'POST',
+ url: `${baseUrl}/user/signin`,
+ data: dataLogin
+ })
+
+ .done(data => {
+ console.log(data, '<<< BERHASIL MASUK BRO')
+ localStorage.setItem('token', data.token)
+ todoMainPage()
+ $('.formbar').show()
+ $('.btn-logout').show()
+ $('signin-form').hide()
+
+ $('.homepage').empty().append(`
+
+ `)
+
+ })
+ .fail(err => {
+ console.log(err, '<<< OOPS ERORNYA TUH DISINI')
+ })
+ })
+
+}
+
+function onSignIn(googleUser) {
+ let googleToken = googleUser.getAuthResponse().id_token
+ console.log(googleToken, '<<<<<<< INI TOKEN GOOGLENYA')
+ $.ajax({
+ method: 'post',
+ url: `${baseUrl}/user/signInGoogle`,
+ data: {
+ token: googleToken
+ }
+ })
+ .done(data => {
+ console.log('masuk kesini bro')
+ localStorage.setItem('token', data.token)
+ $('#logOut').show()
+ $('.g-signin2').hide()
+ $('#login').hide()
+ todoMainPage()
+ $('.formbar').show()
+
+
+ })
+ .fail(err => {
+ console.log(err, '<<<<< ini Errornya')
+ })
+}
+
+function signOut() {
+ const auth2 = gapi.auth2.getAuthInstance();
+ auth2.signOut().then(function () {
+ console.log('User signed out.');
+ localStorage.clear()
+ $('#logOut').hide()
+ $('.g-signin2').show()
+ $('#login').show()
+ $('.formbar').hide()
+ });
+}
+
+function todoMainPage(e) {
+ console.log('masuk ke main todo page')
+ // e.preventDefault()
+ $('.homepage').empty().append(
+ `
+ `)
+ $('.home-btn').hide()
+}
+
+function signout() {
+ $(document).on('click', '.btn-logout', function (event) {
+ event.preventDefault()
+ $('.homepage').empty()
+ .append(`
+ `)
+ $('.g-signin2').show()
+
+ })
+
+}
+
+function getTodos() {
+ $.ajax({
+ method: 'GET',
+ url: `${baseUrl}/todo`,
+ headers: {
+ token: localStorage.getItem('token')
+ }
+ })
+ .done(data => {
+ console.log(data)
+ $('.table-body').empty()
+ for (let i = 0; i < data.length; i++) {
+ // console.log(data.length, 'masuk datanya')
+ $('.table-body').append(`
+
+
+ ${data[i].todo}
+ |
+
+ ${data[i].description}
+ |
+
+ ${data[i].dueDate.substr(0, 10)}
+ |
+
+
+ TRUE
+ FALSE
+ |
+
+ Edit
+ Delete
+ |
+
+ `)
+ if (data[i].status == false) {
+ $('.btn-status-true').hide()
+ $('.btn-status-false').show()
+
+ } else {
+ $('.btn-status-false').hide()
+ $('.btn-status-true').show()
+ }
+ }
+ })
+ .fail(err => {
+ console.log(err, '<<< ini errornya broh')
+ })
+}
+
+function showTodoList() {
+ $(document).on('click', '.btn-showtodo', function (event) {
+ console.log('masuk ke showToDoList')
+ event.preventDefault()
+ getTodos()
+ })
+}
+
+function createTodo() {
+ $(document).on('click', '.btn-submittodo', function (event) {
+ console.log('masuk kesini createTodo')
+ event.preventDefault()
+
+ let result = {
+ todo: $('#todo').val(),
+ description: $('#description').val(),
+ dueDate: $('#duedate').val()
+ }
+
+ $.ajax({
+ method: 'POST',
+ url: `${baseUrl}/todo`,
+ data: result,
+ headers: {
+ token: localStorage.getItem('token')
+ }
+ })
+ .done(data => {
+ console.log(data, 'ini datanya broh yang masukan')
+ console.log(data)
+ $('.table-body').append(`
+
+
+
+ ${data.todo}
+ |
+
+ ${data.description}
+ |
+
+ ${data.dueDate.substr(0, 10)}
+ |
+
+ TRUE
+ FALSE
+ |
+
+ Edit
+ Delete
+ |
+
+
+ `)
+ $('.btn-status-true').hide()
+ })
+ .fail(err => {
+ console.log(`failed to create >>>>`, err)
+ })
+ })
+}
+
+function deleteTodo() {
+ console.log('masuk ke delete broo')
+ $(document).on('click', '.btn-deletetodo', function (event) {
+ event.preventDefault()
+ let todoId = $(this).attr('id')
+ // console.log(todoId, 'ini todo idnyaaa')
+
+ $.ajax({
+ method: 'DELETE',
+ url: `${baseUrl}/todo/${todoId}`,
+ headers: {
+ token: localStorage.getItem('token')
+ }
+ })
+ .done(data => {
+ // console.log('Berhasil Gan')
+ $('.table-body').empty()
+ getTodos()
+ })
+ .fail(err => {
+ console.log(err, '<<< ini errornya di client')
+ // console.log('gagaaaal adooh')
+ })
+ })
+}
+
+function inputUpdate() {
+ console.log('masuk tahap 1 input update')
+ $(document).on('click', '.btn-submitupdate', function (event) {
+ event.preventDefault()
+ let todoId = $(this).attr('id')
+ console.log(todoId)
+
+ let obj = {
+ todo: $('#updateTodo').val(),
+ description: $('#updateDescription').val(),
+ dueDate: $('#updateDueDate').val()
+ }
+ console.log(obj)
+ // console.log($('#updateTodo').val(), '<<<<<<< INI DATANYAAAA')
+ $.ajax({
+ method: 'PUT',
+ url: `${baseUrl}/todo/${todoId}`,
+ headers: {
+ token: localStorage.getItem('token')
+ },
+ data: obj
+ })
+ .done(data => {
+ console.log('disini brooh <<<<<<<<<')
+ console.log(data, 'berhasil bro')
+ $('.homepage').empty()
+ todoMainPage()
+ })
+ .fail(err => {
+ console.log(err, 'tidak berhasil bro')
+ })
+
+ })
+
+}
+
+function update() {
+
+ $(document).on('click', '.btn-edittodo', function (event) {
+ event.preventDefault()
+ console.log('masuk ke edit')
+ // $('.homepage').empty().append(`
+ let todoId = $(this).attr('id')
+ console.log(todoId)
+ // `)
+ $.ajax({
+ method: 'GET',
+ url: `${baseUrl}/todo/${todoId}`,
+ headers: {
+ token: localStorage.getItem('token')
+ }
+ })
+ .done(data => {
+ $('.homepage').empty().append(`
+
+
Update Your Priorities
+
ready to Organized your life?
+
+
+
+
+
`)
+
+ })
+ .fail(err => {
+ console.log(err, '<<< ini errornya di client')
+ })
+ })
+}
+
+function search() {
+ // console.log('masuk search')
+ $(document).on('click', '.searchButton', function (event) {
+ event.preventDefault()
+ let value = $('.searchbar').val()
+
+ // console.log(value, '<<<< INI VALIENYA')
+ // console.log('masuk kesini dong')
+ $.ajax({
+ method: 'GET',
+ url: `${baseUrl}/todo/search?todo=${value}`,
+ headers: {
+ token: localStorage.getItem('token')
+ }
+ })
+ .done(data => {
+ console.log(data)
+ // console.log(data)
+ // console.log('masuk dan berhasil')
+ $('.table-body').empty()
+ for (let i = 0; i < data.length; i++) {
+ // console.log(data.length, 'masuk datanya')
+ $('.table-body').append(`
+
+
+ ${data[i].todo}
+ |
+
+ ${data[i].description}
+ |
+
+ ${data[i].dueDate.substr(0, 10)}
+ |
+
+
+ TRUE
+ FALSE
+ |
+
+ Edit
+ Delete
+ |
+
`)
+ if (data[i].status == false) {
+ $('.btn-status-true').hide()
+ $('.btn-status-false').show()
+
+ } else {
+ $('.btn-status-false').hide()
+ $('.btn-status-true').show()
+ }
+ }
+ })
+ .fail(err => {
+ console.log('wah searchnya gagal nih')
+ })
+ })
+}
\ No newline at end of file
diff --git a/sandbox.html b/sandbox.html
new file mode 100644
index 0000000..fd700fa
--- /dev/null
+++ b/sandbox.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+ id |
+
+ Todo |
+ Description |
+ Due Date |
+ Status |
+ Action |
+
+
+
+
+
+
+
+
+
+ 1
+ |
+
+
+ Kelarin Hacktiv8
+ |
+
+
+ Bisa Kok Gas Pol Bro
+ |
+
+
+ 3/3/2019
+ |
+
+
+
+ TRUE
+ FALSE
+
+
+ |
+
+
+ Edit
+ Delete
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/.gitignore b/server/.gitignore
new file mode 100644
index 0000000..1dcef2d
--- /dev/null
+++ b/server/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+.env
\ No newline at end of file
diff --git a/server/app.js b/server/app.js
new file mode 100644
index 0000000..53e1e56
--- /dev/null
+++ b/server/app.js
@@ -0,0 +1,36 @@
+require('dotenv').config()
+const morgan = require('morgan')
+
+const express = require('express')
+const cors = require('cors')
+const mongoose = require('mongoose')
+
+const app = express()
+const port = 3000
+
+mongoose.connect('mongodb+srv://fadhilsurya:@fadhilsurya-6770g.gcp.mongodb.net/test?retryWrites=true&w=majority', {
+ useNewUrlParser: true
+});
+// mongoose.connect(process.env.MONGOATLAS, {
+// useNewUrlParser: true
+// });
+
+app.use(morgan())
+app.use(cors())
+
+app.use(express.json())
+app.use(express.urlencoded({
+ extended: false
+}))
+
+const userRoutes = require('./routes/signRoutes')
+const todoRoutes = require('./routes/todoRoutes')
+
+app.use('/user', userRoutes)
+app.use('/todo', todoRoutes)
+
+const errHandler = require('./middleware/errHandler')
+
+
+app.use(errHandler)
+app.listen(port, () => console.log(`Example app listening on port port!`))
\ No newline at end of file
diff --git a/server/controller/todos.js b/server/controller/todos.js
new file mode 100644
index 0000000..4fcea27
--- /dev/null
+++ b/server/controller/todos.js
@@ -0,0 +1,96 @@
+const todosModel = require('../model/todos')
+
+class Todo {
+
+ static create(req, res, next) {
+ // console.log('masuk ke create di server')
+ console.log(req.body, ' <<<<< ini masukkkkk')
+ const {
+ todo,
+ description,
+ dueDate
+ } = req.body
+ todosModel.create({
+ userId: req.payload._id,
+ todo,
+ description,
+ dueDate
+ })
+ .then(data => {
+ res.status(201).json(data)
+ })
+ .catch(next)
+ }
+ static update(req, res, next) {
+ const {
+ todo,
+ description,
+ dueDate
+ } = req.body
+ todosModel.updateOne({
+ _id: req.params.id,
+ }, {
+ todo,
+ description,
+ dueDate
+ })
+ .then(data => {
+ res.status(200).json(data)
+ })
+ .catch(next)
+ }
+
+ static findAll(req, res, next) {
+ todosModel.find({
+ userId: req.payload._id
+ })
+ .then(data => {
+ console.log(data)
+ res.status(200).json(data)
+ })
+ .catch(next)
+ }
+ static delete(req, res, next) {
+ console.log('masuk ke delete')
+ todosModel.deleteOne({
+ _id: req.params.id
+ })
+ .then(data => {
+ console.log('berhasil ke delete')
+ res.status(200).json(data)
+ })
+ .catch(next)
+ }
+ static findById(req, res, next) {
+ console.log('pasti bisa aku pasti bisa ku tak mau berputus asa')
+ todosModel.findById({
+ _id: req.params.id
+ })
+ .then(data => {
+ console.log('berhasil ke update')
+ res.status(200).json(data)
+
+ })
+ .catch(next)
+ }
+ static search(req, res, next) {
+ console.log(req, 'ini bagian request')
+ console.log('goooooo ini search')
+ todosModel.find()
+ .then(data => {
+ console.log(data, '<<<< bagian search')
+ console.log(req.query.todo, '<<<< Ini Searchnyaaa looh')
+ let searched = data.filter(data1 => {
+ let regex = new RegExp(`${req.query.todo}`, 'i')
+ return regex.test(data1)
+ // console.log(regex.test(data1.name))
+ })
+ res.status(200).json(searched)
+
+ })
+ .catch(next)
+ }
+
+}
+
+module.exports = Todo
\ No newline at end of file
diff --git a/server/controller/user.js b/server/controller/user.js
new file mode 100644
index 0000000..074d878
--- /dev/null
+++ b/server/controller/user.js
@@ -0,0 +1,111 @@
+const user = require('../model/user')
+const {
+ generateToken,
+ verToken
+} = require('../helper/jwt')
+const {
+ OAuth2Client
+} = require('google-auth-library');
+const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);
+const {
+ checkHash
+} = require('../helper/hashpass')
+
+// const axios = require('axios')
+
+class UserController {
+
+ static signInGoogle(req, res, next) {
+ // console.log('masuk')
+ client.verifyIdToken({
+ idToken: req.body.token,
+ audience: process.env.GOOGLE_CLIENT_ID,
+ })
+ .then(profile => {
+ // console.log('tahap1')
+ let payload = profile.payload
+ let userOne = user.findOne({
+ email: payload.email
+ })
+ return Promise.all([payload, userOne])
+ })
+ .then(arr => {
+ // console.log('tahap2')
+ if (!arr[1]) {
+ return user.create({
+ name: arr[0].name,
+ email: arr[0].email,
+ password: process.env.PASSWORD
+ })
+ } else {
+ return arr[1]
+ }
+ })
+ .then(data => {
+ // console.log('tahap3')
+ let obj = {
+ _id: data._id,
+ name: data.name,
+ email: data.email
+ }
+ res.status(201).json({
+ token: generateToken(obj)
+ })
+ })
+ .catch(next)
+
+ }
+
+ static signIn(req, res, next) {
+ console.log('masuk ke sign in')
+ user.findOne({
+ email: req.body.email
+ })
+ .then(data => {
+ console.log('berhasil generate token')
+ if (checkHash(req.body.password, data.password)) {
+ res.status(200).json({
+ token: generateToken({
+ _id: data._id,
+ name: data.name,
+ email: data.email
+ })
+ })
+
+ console.log('berhasil untuk generate dan dikirim')
+ } else {
+ next({
+ code: 401,
+ message: 'Mohon Maaf Password Salah'
+ })
+ }
+ })
+ .catch(next)
+ }
+
+ static signUp(req, res, next) {
+ // console.log
+ const {
+ name,
+ email,
+ password
+ } = req.body
+
+ user.create({
+ name,
+ email,
+ password
+ })
+ .then(_ => {
+
+ res.status(201).json({
+ code: 201,
+ message: 'Berhasil SignUp'
+ })
+ })
+ .catch(next)
+ }
+
+}
+
+module.exports = UserController
\ No newline at end of file
diff --git a/server/helper/hashpass.js b/server/helper/hashpass.js
new file mode 100644
index 0000000..4cd71fb
--- /dev/null
+++ b/server/helper/hashpass.js
@@ -0,0 +1,16 @@
+var bcrypt = require('bcryptjs');
+
+function hash(params) {
+ let salt = bcrypt.genSaltSync(10);
+ let hash = bcrypt.hashSync(params, salt);
+ return hash
+}
+
+function checkHash(inputPass, hashPass) {
+ let check = bcrypt.compareSync(inputPass, hashPass)
+ return check
+}
+module.exports = {
+ hash,
+ checkHash
+}
\ No newline at end of file
diff --git a/server/helper/jwt.js b/server/helper/jwt.js
new file mode 100644
index 0000000..fa262bd
--- /dev/null
+++ b/server/helper/jwt.js
@@ -0,0 +1,17 @@
+const jwt = require('jsonwebtoken');
+const secret = process.env.JWT_SALT
+
+function generateToken(input) {
+ let token = jwt.sign(input, secret);
+ return token
+}
+
+function verToken(token) {
+ let data = jwt.verify(token, secret);
+ return data
+}
+
+module.exports = {
+ generateToken,
+ verToken
+}
\ No newline at end of file
diff --git a/server/middleware/authentication.js b/server/middleware/authentication.js
new file mode 100644
index 0000000..6d45777
--- /dev/null
+++ b/server/middleware/authentication.js
@@ -0,0 +1,18 @@
+const {
+ verToken
+} = require('../helper/jwt')
+module.exports =
+ function authenticate(req, res, next) {
+ // console.log('halooo broooo')
+ // console.log(req.headers, '<<<<<< INI HEADERSNYA')
+ // console.log(req.headers.token, '<<<<<< INI HEADERS TOKENNYA')
+ try {
+ req.payload = verToken(req.headers.token)
+ next()
+ } catch {
+ next({
+ code: 401,
+ message: 'Unauthenticate User'
+ })
+ }
+ }
\ No newline at end of file
diff --git a/server/middleware/authorized.js b/server/middleware/authorized.js
new file mode 100644
index 0000000..673743e
--- /dev/null
+++ b/server/middleware/authorized.js
@@ -0,0 +1,26 @@
+const todo = require('../model/todos')
+module.exports =
+ function authorized(req, res, next) {
+ console.log('masuk authorized')
+ console.log(req.params.id, '<<<<< ini idnya')
+ todo.findById(req.params.id)
+ .then(data => {
+ console.log('authorized jalan bro')
+ console.log(data, '<<< INI DATANYA')
+ // console.log(data.userId, '<<<<<<<<< userIdnya ini')
+ // console.log(req.payload._id, '<<<<<<<<<< payload')
+ if (data.userId == req.payload._id) {
+ console.log('lancar kok')
+ next()
+ } else {
+ console.log('authorizednya error')
+ next({
+ code: 401,
+ message: 'UnAuthorized User'
+ })
+ }
+
+ })
+ .catch(next)
+
+ }
\ No newline at end of file
diff --git a/server/middleware/errHandler.js b/server/middleware/errHandler.js
new file mode 100644
index 0000000..1e0335d
--- /dev/null
+++ b/server/middleware/errHandler.js
@@ -0,0 +1,27 @@
+function errorHandler(err, req, res, next) {
+ if (err.name == 'JsonWebTokenError') {
+ console.log('Masuk Ke JWT Error')
+ res.status(401).json({
+ message: err.message
+ })
+ } else if (err.name == 'ValidationError') {
+ let budleErr = []
+ for (let key in err.errors) {
+ budleErr.push(err.errors[key].message)
+ }
+ res.status(400).json({
+
+ message: budleErr
+ })
+ } else {
+ res.status(err.code || 500).json({
+ code: err.code || 500,
+ message: err.message
+ })
+ }
+ console.log(JSON.stringify(err, null, 2))
+
+
+}
+
+module.exports = errorHandler
\ No newline at end of file
diff --git a/server/model/todos.js b/server/model/todos.js
new file mode 100644
index 0000000..207e32a
--- /dev/null
+++ b/server/model/todos.js
@@ -0,0 +1,34 @@
+const mongoose = require('mongoose')
+
+const todoSchema = new mongoose.Schema({
+ userId: {
+ type: mongoose.Schema.Types.ObjectId,
+ require: [true, 'userId required']
+ },
+ todo: {
+ type: String,
+ required: [true, 'Todo Name Required']
+ },
+ status: {
+ type: Boolean,
+ default: false
+ },
+ description: {
+ type: String
+ },
+ dueDate: {
+ type: Date,
+ required: [true, 'Due Date Required']
+
+ }
+}, {
+ timestamps: true,
+ versionKey: false
+})
+
+
+
+
+const todo = mongoose.model('Todo', todoSchema)
+
+module.exports = todo
\ No newline at end of file
diff --git a/server/model/user.js b/server/model/user.js
new file mode 100644
index 0000000..b09c938
--- /dev/null
+++ b/server/model/user.js
@@ -0,0 +1,49 @@
+const mongoose = require('mongoose')
+const {
+ hash
+} = require('../helper/hashpass')
+
+const userSchema = new mongoose.Schema({
+ name: {
+ type: String,
+ required: [true, 'Mohon Maaf Nama Harus Diisi']
+ },
+ email: {
+ type: String,
+ required: [true, 'Mohon Maaf Email Harus Diisi']
+ },
+ password: {
+ type: String,
+ required: [true, 'Mohon Maaf Password Harus Diisi']
+ }
+}, {
+ timestamps: true,
+ versionKey: false
+})
+
+
+
+// ENCRYPT PASSWORD
+userSchema.pre('save', function () {
+ console.log('masuk')
+ let password = hash(this.password)
+ this.password = password
+ console.log(password)
+})
+
+userSchema.pre('save', function (next) {
+ return user.findOne({
+ email: this.email
+ })
+ .then(user => {
+ if (user) {
+ throw new Error('Email Regitered')
+ } else {
+ next()
+ }
+ })
+})
+
+const user = mongoose.model('User', userSchema)
+
+module.exports = user
\ No newline at end of file
diff --git a/server/package-lock.json b/server/package-lock.json
new file mode 100644
index 0000000..ecf633a
--- /dev/null
+++ b/server/package-lock.json
@@ -0,0 +1,854 @@
+{
+ "name": "server",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "requires": {
+ "event-target-shim": "^5.0.0"
+ }
+ },
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "agent-base": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+ "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "arrify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
+ },
+ "async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
+ "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
+ "requires": {
+ "lodash": "^4.17.11"
+ }
+ },
+ "base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
+ },
+ "basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "bcryptjs": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+ "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
+ },
+ "bignumber.js": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz",
+ "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ=="
+ },
+ "bluebird": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ }
+ },
+ "bson": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz",
+ "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg=="
+ },
+ "buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+ },
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "requires": {
+ "object-assign": "^4",
+ "vary": "^1"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "dotenv": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz",
+ "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA=="
+ },
+ "ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+ },
+ "es6-promisify": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+ "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+ "requires": {
+ "es6-promise": "^4.0.3"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
+ },
+ "express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "requires": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "fast-text-encoding": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz",
+ "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ=="
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "gaxios": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.0.1.tgz",
+ "integrity": "sha512-c1NXovTxkgRJTIgB2FrFmOFg4YIV6N/bAa4f/FZ4jIw13Ql9ya/82x69CswvotJhbV3DiGnlTZwoq2NVXk2Irg==",
+ "requires": {
+ "abort-controller": "^3.0.0",
+ "extend": "^3.0.2",
+ "https-proxy-agent": "^2.2.1",
+ "node-fetch": "^2.3.0"
+ }
+ },
+ "gcp-metadata": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-2.0.2.tgz",
+ "integrity": "sha512-dxPXBvjyfz5qFEBXzEwNmuZXwsGYfuASGYeg3CKZDaQRXdiWti9J3/Ezmtyon1OrCNpDO2YekyoSjEqMtsrcXw==",
+ "requires": {
+ "gaxios": "^2.0.1",
+ "json-bigint": "^0.3.0"
+ }
+ },
+ "google-auth-library": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.2.1.tgz",
+ "integrity": "sha512-p9vO6UcRIK/zD3PxoMijaUfFYu6tvzaQwvag1K/82O42NBeAnmllyQUgqaBhcAh9FzFAVlN4bQIaO8+prpE7Vg==",
+ "requires": {
+ "arrify": "^2.0.0",
+ "base64-js": "^1.3.0",
+ "fast-text-encoding": "^1.0.0",
+ "gaxios": "^2.0.0",
+ "gcp-metadata": "^2.0.0",
+ "gtoken": "^4.0.0",
+ "jws": "^3.1.5",
+ "lru-cache": "^5.0.0"
+ }
+ },
+ "google-p12-pem": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.2.tgz",
+ "integrity": "sha512-UfnEARfJKI6pbmC1hfFFm+UAcZxeIwTiEcHfqKe/drMsXD/ilnVjF7zgOGpHXyhuvX6jNJK3S8A0hOQjwtFxEw==",
+ "requires": {
+ "node-forge": "^0.9.0"
+ }
+ },
+ "gtoken": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.0.0.tgz",
+ "integrity": "sha512-XaRCfHJxhj06LmnWNBzVTAr85NfAErq0W1oabkdqwbq3uL/QTB1kyvGog361Uu2FMG/8e3115sIy/97Rnd4GjQ==",
+ "requires": {
+ "gaxios": "^2.0.0",
+ "google-p12-pem": "^2.0.0",
+ "jws": "^3.1.5",
+ "mime": "^2.2.0"
+ },
+ "dependencies": {
+ "mime": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
+ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA=="
+ }
+ }
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ }
+ },
+ "https-proxy-agent": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
+ "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
+ "requires": {
+ "agent-base": "^4.3.0",
+ "debug": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ipaddr.js": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
+ "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
+ },
+ "json-bigint": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz",
+ "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=",
+ "requires": {
+ "bignumber.js": "^7.0.0"
+ }
+ },
+ "jsonwebtoken": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+ "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+ "requires": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^5.6.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "requires": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "requires": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "kareem": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
+ "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw=="
+ },
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+ },
+ "lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+ },
+ "lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+ },
+ "lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+ },
+ "lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+ },
+ "lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+ },
+ "lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+ },
+ "lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "memory-pager": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
+ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
+ "optional": true
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ },
+ "mongodb": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.2.7.tgz",
+ "integrity": "sha512-2YdWrdf1PJgxcCrT1tWoL6nHuk6hCxhddAAaEh8QJL231ci4+P9FLyqopbTm2Z2sAU6mhCri+wd9r1hOcHdoMw==",
+ "requires": {
+ "mongodb-core": "3.2.7",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "mongodb-core": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.2.7.tgz",
+ "integrity": "sha512-WypKdLxFNPOH/Jy6i9z47IjG2wIldA54iDZBmHMINcgKOUcWJh8og+Wix76oGd7EyYkHJKssQ2FAOw5Su/n4XQ==",
+ "requires": {
+ "bson": "^1.1.1",
+ "require_optional": "^1.0.1",
+ "safe-buffer": "^5.1.2",
+ "saslprep": "^1.0.0"
+ }
+ },
+ "mongoose": {
+ "version": "5.6.13",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.6.13.tgz",
+ "integrity": "sha512-MGV2qSED8JFFwRXtR8ETxLRSaF15u5rAJQ0ejmp7/Z0gy6wFit32pKBQKvuEuYRoNYQmSsctUDngFnOByNPH4g==",
+ "requires": {
+ "async": "2.6.2",
+ "bson": "~1.1.1",
+ "kareem": "2.3.1",
+ "mongodb": "3.2.7",
+ "mongodb-core": "3.2.7",
+ "mongoose-legacy-pluralize": "1.0.2",
+ "mpath": "0.6.0",
+ "mquery": "3.2.1",
+ "ms": "2.1.2",
+ "regexp-clone": "1.0.0",
+ "safe-buffer": "5.1.2",
+ "sift": "7.0.1",
+ "sliced": "1.0.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "mongoose-legacy-pluralize": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
+ "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
+ },
+ "morgan": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
+ "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==",
+ "requires": {
+ "basic-auth": "~2.0.0",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "on-headers": "~1.0.1"
+ }
+ },
+ "mpath": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.6.0.tgz",
+ "integrity": "sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw=="
+ },
+ "mquery": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.1.tgz",
+ "integrity": "sha512-kY/K8QToZWTTocm0U+r8rqcJCp5PRl6e8tPmoDs5OeSO3DInZE2rAL6AYH+V406JTo8305LdASOQcxRDqHojyw==",
+ "requires": {
+ "bluebird": "3.5.1",
+ "debug": "3.1.0",
+ "regexp-clone": "^1.0.0",
+ "safe-buffer": "5.1.2",
+ "sliced": "1.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+ },
+ "node-fetch": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
+ "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
+ },
+ "node-forge": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
+ "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ=="
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "proxy-addr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
+ "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.0"
+ }
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "regexp-clone": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
+ "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
+ },
+ "require_optional": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
+ "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
+ "requires": {
+ "resolve-from": "^2.0.0",
+ "semver": "^5.1.0"
+ }
+ },
+ "resolve-from": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
+ "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "saslprep": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
+ "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
+ "optional": true,
+ "requires": {
+ "sparse-bitfield": "^3.0.3"
+ }
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ },
+ "send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+ },
+ "sift": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
+ "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
+ },
+ "sliced": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
+ "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
+ },
+ "sparse-bitfield": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
+ "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
+ "optional": true,
+ "requires": {
+ "memory-pager": "^1.0.2"
+ }
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+ }
+ }
+}
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 0000000..7d27ea4
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "server",
+ "version": "1.0.0",
+ "description": "",
+ "main": "app.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "bcryptjs": "^2.4.3",
+ "cors": "^2.8.5",
+ "dotenv": "^8.1.0",
+ "express": "^4.17.1",
+ "google-auth-library": "^5.2.1",
+ "jsonwebtoken": "^8.5.1",
+ "mongoose": "^5.6.13",
+ "morgan": "^1.9.1"
+ }
+}
diff --git a/server/routes/signRoutes.js b/server/routes/signRoutes.js
new file mode 100644
index 0000000..e57bcf2
--- /dev/null
+++ b/server/routes/signRoutes.js
@@ -0,0 +1,10 @@
+const router = require('express').Router()
+
+
+const user = require('../controller/user')
+
+router.post('/signInGoogle', user.signInGoogle)
+router.post('/signin', user.signIn)
+router.post('/signup', user.signUp)
+
+module.exports = router
\ No newline at end of file
diff --git a/server/routes/todoRoutes.js b/server/routes/todoRoutes.js
new file mode 100644
index 0000000..51cd280
--- /dev/null
+++ b/server/routes/todoRoutes.js
@@ -0,0 +1,18 @@
+const router = require('express').Router()
+const authentication = require('../middleware/authentication')
+const authorized = require('../middleware/authorized')
+
+const todoController = require('../controller/todos')
+
+// seluruh kegiatan dalam todo hanya bisa diakses apabila sudah signIn
+
+router.use(authentication)
+router.get('/', todoController.findAll)
+router.post('/', todoController.create)
+router.get('/search', todoController.search)
+
+router.get('/:id', todoController.findById)
+router.put('/:id', authorized, todoController.update)
+router.delete('/:id', authorized, todoController.delete)
+
+module.exports = router
\ No newline at end of file