Code Monkey home page Code Monkey logo

mycv's People

Contributors

trietpham96 avatar

Watchers

 avatar

mycv's Issues

add

Add product Add Clear Back <script> import { TiptapVuetify, Heading, Bold, Italic, Strike, Underline, Code, Paragraph, BulletList, OrderedList, ListItem, Link, Blockquote, HardBreak, HorizontalRule, History } from "tiptap-vuetify"; export default { name: "ProductAddNew", components: { TiptapVuetify }, data: function() { return { extensions: [ History, Blockquote, Link, Underline, Strike, Italic, ListItem, BulletList, OrderedList, [ Heading, { options: { levels: [1, 2, 3] } } ], Bold, Code, HorizontalRule, Paragraph, HardBreak ], valid: true, product: {}, nameRules: [ v => !!v || "Name is required", v => (v && v.length <= 50) || "Name must be less than 50 characters" ], titleRules: [ v => !!v || "Title is required", v => (v && v.length <= 250) || "Title must be less than 250 characters" ], contentRules: [ v => !!v || "Content is required", v => (v && v.length <= 500) || "Content must be less than 500 characters" ], userIds: [1, 2, 3, 4] }; }, computed: { canClear() { if ( this.product !== undefined && this.product !== null && ((this.product.name !== undefined && this.product.name !== "") || (this.product.userId !== undefined && this.product.userId !== "") || (this.product.title !== undefined && this.product.title !== "") || (this.product.content !== undefined && this.product.content !== "") || (this.product.mainContent !== undefined && this.product.mainContent !== "")) ) { return false; } return true; } }, methods: { addItem() { this.$axios.post("/posts", this.product).then(() => { this.$router.push("Product"); }); }, reset() { this.$refs.form.reset(); } } }; </script>

authenticate

//server
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const fs = require('fs');
const cors = require('cors');
const basicAuth = require('./routes/user/_helpers/basic-auth');
const errorHandler = require('./routes/user/_helpers/error-handler');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors())
// use basic HTTP auth to secure the api
// app.use(basicAuth);
const routes = require('./routes/routes.js')(app, fs);
// global error handler
app.use(errorHandler);
const server = app.listen(3001, () => {
console.log('listening on port %s...', server.address().port);
});

//routes
// import other routes
const userRoutes = require('./user/users');
const postRoutes = require('./post/posts');

const appRouter = (app, fs) => {

// default route
app.get('/', (req, res) => {
    res.send('welcome to the development api-server');
});

// // other routes
userRoutes(app, fs);
postRoutes(app, fs);

};

module.exports = appRouter;

//usersjs
const userRoutes = (app, fs) => {
// variables
const dataPath = './data/users.json'
const userService = require('./users/user.service')
// helper methods
const readFile = (
callback,
returnJson = false,
filePath = dataPath,
encoding = 'utf8'
) => {
fs.readFile(filePath, encoding, (err, data) => {
if (err) {
throw err
}

  callback(returnJson ? JSON.parse(data) : data)
})

}

const writeFile = (
fileData,
callback,
filePath = dataPath,
encoding = 'utf8'
) => {
fs.writeFile(filePath, fileData, encoding, err => {
if (err) {
throw err
}

  callback()
})

}

// AUTHENTICATE USER
app.post('/users/authenticate', authenticate)
function authenticate(req, res, next) {
userService
.authenticate(req.body)
.then(user =>
user
? res.json(user)
: res
.status(400)
.json({ message: 'Username or password is incorrect' })
)
.catch(err => next(err))
}
// READ
app.get('/users', (req, res) => {
fs.readFile(dataPath, 'utf8', (err, data) => {
if (err) {
throw err
}

  res.send(JSON.parse(data))
})

})

// CREATE
app.post('/users', (req, res) => {
readFile(data => {
const newUserId = Object.keys(data).length + 1

  // add the new user
  data[newUserId.toString()] = req.body

  writeFile(JSON.stringify(data, null, 2), () => {
    res.status(200).send('new user added')
  })
}, true)

})

// UPDATE
app.put('/users/:id', (req, res) => {
readFile(data => {
// add the new user
const userId = req.params['id']
data[userId] = req.body

  writeFile(JSON.stringify(data, null, 2), () => {
    res.status(200).send(`users id:${userId} updated`)
  })
}, true)

})

// DELETE
app.delete('/users/:id', (req, res) => {
readFile(data => {
// add the new user
const userId = req.params['id']
delete data[userId]

  writeFile(JSON.stringify(data, null, 2), () => {
    res.status(200).send(`users id:${userId} removed`)
  })
}, true)

})
}

module.exports = userRoutes

//userservice
const dataPath = './data/users.json'
// helper methods
// const readFile = (
// callback,
// returnJson = false,
// filePath = dataPath,
// encoding = 'utf8'
// ) => {
// fs.readFile(filePath, encoding, (err, data) => {
// if (err) {
// throw err
// }

// callback(returnJson ? JSON.parse(data) : data)
// })
// }
// users hardcoded for simplicity, store in a db for production applications
const users = [{ id: 1, username: 'test', password: 'test', firstName: 'Test', lastName: 'User' }];

module.exports = {
authenticate,
getAll
}

async function authenticate({ username, password }) {
const user = users.find(
u => u.username === username && u.password === password
)
if (user) {
const { password, ...userWithoutPassword } = user
return userWithoutPassword
}
}

async function getAll() {
return users.map(u => {
const { password, ...userWithoutPassword } = u
return userWithoutPassword
})
}

//basic-auth
const userService = require('../users/user.service');

module.exports = basicAuth;

async function basicAuth(req, res, next) {
// make authenticate path public
if (req.path === '/users/authenticate') {
return next();
}

// check for basic auth header
if (!req.headers.authorization || req.headers.authorization.indexOf('Basic ') === -1) {
    return res.status(401).json({ message: 'Missing Authorization Header' });
}

// verify auth credentials
const base64Credentials =  req.headers.authorization.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
const user = await userService.authenticate({ username, password });
if (!user) {
    return res.status(401).json({ message: 'Invalid Authentication Credentials' });
}

// attach user to request object
req.user = user

next();

}

edit

Edit product
Edit Clear Back
<script> import { Image, TiptapVuetify, Heading, Bold, Italic, Strike, Underline, Code, Paragraph, BulletList, OrderedList, ListItem, Link, Blockquote, HardBreak, HorizontalRule, History } from "tiptap-vuetify"; export default { name: "ProductEdit", components: { TiptapVuetify }, data: function() { return { extensions: [ History, Blockquote, Link, Underline, Strike, Italic, ListItem, BulletList, OrderedList, [ Heading, { options: { levels: [1, 2, 3] } } ], Bold, Code, HorizontalRule, Paragraph, Image, HardBreak ], proId: this.$route.params.id, valid: true, product: {}, nameRules: [ v => !!v || "Name is required", v => (v && v.length <= 50) || "Name must be less than 50 characters" ], titleRules: [ v => !!v || "Title is required", v => (v && v.length <= 250) || "Title must be less than 250 characters" ], contentRules: [ v => !!v || "Content is required", v => (v && v.length <= 500) || "Content must be less than 500 characters" ], userIds: [1, 2, 3, 4] }; }, created() { this.$axios .get(`/posts/${this.proId}`) .then(response => { this.product = response.data; }) .catch(e => { this.errors.push(e); }); }, computed: { canClear() { if ( this.product !== undefined && this.product !== null && ((this.product.name !== undefined && this.product.name !== "") || (this.product.userId !== undefined && this.product.userId !== "") || (this.product.title !== undefined && this.product.title !== "") || (this.product.content !== undefined && this.product.content !== "") || (this.product.mainContent !== undefined && this.product.mainContent !== "")) ) { return false; } return true; } }, methods: { reset() { this.$refs.form.reset(); }, editItem() { this.$axios.put(`/posts/${this.proId}`, this.product).then(() => { this.$router.push({ name: "ProductTable" }); }); }, back() { this.$router.push({ name: "ProductTable" }); } } }; </script>

table list

Add product Product list edit delete <script> export default { name: "ProductTable", data() { return { loading: true, products: [], search: "", headers: [ { text: "Id", align: "left", value: "id" }, { text: "Name", value: "name" }, { text: "UserId", value: "userId" }, { text: "Title", value: "title" }, { text: "Actions", value: "action", sortable: false } ] }; }, created() { this.$axios .get("/posts") .then(response => { this.products = response.data; this.loading = false; }) .catch(e => { this.errors.push(e); }); } }; </script> <style scoped> </style>

fix bug modal

<template>
  <v-dialog :value="value" @input="$emit('input')" max-width="600" persistent>
    <v-card>
      <v-card-title class="headline grey lighten-2" primary-title>
        <v-tabs background-color="grey lighten-2" v-model="tabs">
          <v-tab>Sign In</v-tab>
          <v-tab>Sign Up</v-tab>
        </v-tabs>
      </v-card-title>
      <v-tabs-items v-model="tabs">
        <v-tab-item>
          <v-form ref="form" v-model="signInValid">
            <v-card-text>
              <v-container>
                <v-row>
                  <v-col cols="12">
                    <v-text-field
                      v-model="user.username"
                      :counter="18"
                      :rules="usernameRules"
                      label="Username*"
                      required
                    ></v-text-field>
                  </v-col>
                  <v-col cols="12">
                    <v-text-field
                      v-model="user.password"
                      :counter="18"
                      :rules="passwordRules"
                      label="Password*"
                      type="password"
                      required
                    ></v-text-field>
                  </v-col>
                </v-row>
              </v-container>
              <!-- <small>*indicates required field</small> -->
            </v-card-text>
            <v-divider></v-divider>
            <v-card-actions>
              <v-spacer></v-spacer>
              <v-btn color="green" text @click.native="$emit('input')">Close</v-btn>
              <v-btn color="primary" :disabled="!signInValid" @click="signIn">Sign In</v-btn>
            </v-card-actions>
          </v-form>
        </v-tab-item>
        <v-tab-item>
          <v-card-text>
            <v-container>
              <v-row>
                <v-col cols="12" sm="6" md="4">
                  <v-text-field label="Legal first name*" required></v-text-field>
                </v-col>
                <v-col cols="12" sm="6" md="4">
                  <v-text-field
                    label="Legal middle name"
                    hint="example of helper text only on focus"
                  ></v-text-field>
                </v-col>
                <v-col cols="12" sm="6" md="4">
                  <v-text-field
                    label="Legal last name*"
                    hint="example of persistent helper text"
                    persistent-hint
                    required
                  ></v-text-field>
                </v-col>
                <v-col cols="12">
                  <v-text-field label="Email*" required></v-text-field>
                </v-col>
                <v-col cols="12">
                  <v-text-field label="Password*" type="password" required></v-text-field>
                </v-col>
                <v-col cols="12" sm="6">
                  <v-select :items="['0-17', '18-29', '30-54', '54+']" label="Age*" required></v-select>
                </v-col>
                <v-col cols="12" sm="6">
                  <v-autocomplete
                    :items="['Skiing', 'Ice hockey', 'Soccer', 'Basketball', 'Hockey', 'Reading', 'Writing', 'Coding', 'Basejump']"
                    label="Interests"
                    multiple
                  ></v-autocomplete>
                </v-col>
              </v-row>
            </v-container>
            <small>*indicates required field</small>
          </v-card-text>
        </v-tab-item>
      </v-tabs-items>
    </v-card>
  </v-dialog>
</template>
<script>
import axios from "axios";
export default {
  name: "UserDialog",
  data() {
    return {
      user: {},
      signInValid: true,
      tabs: null,
      usernameRules: [
        v => !!v || "Username is required",
        v => (v && v.length <= 18) || "Username must be less than 18 characters"
      ],
      passwordRules: [
        v => !!v || "Password is required",
        v => (v && v.length <= 18) || "Password must be less than 18 characters"
      ]
    };
  },
  props: {
    value: {
      type: Boolean
    }
  },
  methods: {
    signIn() {
      axios
        .post("http://localhost:3001/users/authenticate", {
          username: this.user.username,
          password: this.user.password
        })
        .then(response => {
          if (response) {
            // store user details and basic auth credentials in local storage
            // to keep user logged in between page refreshes
            response.authdata = window.btoa(
              this.user.username + ":" + this.user.password
            );
            localStorage.setItem("user", JSON.stringify(response));
            window.location.href("http://localhost:8080/");
          }

          // this.$router.re({ path: "/home" });
        })
        .catch(e => {
          this.errors.push(e);
        });
    }
  }
};
</script>

express-lowdb

// const start = async function() {
// const adapter = new FileAsync(link);
// const db = await low(adapter);

// // Get all
// router.get("/products", function(req, res, next) {
// const products = db
// .get("products")
// .orderBy(["id"], ["desc"])
// .value();
// res.send(products);
// });

// // Create
// router.post("/products", function(req, res, next) {
// const newProductId = Object.keys(db.get("products").value()).length + 1;
// let object = req.body;
// let data = {
// userId: object.userId,
// id: newProductId,
// img: "https://cdn.vuetifyjs.com/images/cards/sunshine.jpg",
// title: object.title,
// description: object.description,
// content: object.content
// };
// db.get("products")
// .push(data)
// .write();
// });
// };

App.vue

    <v-img
      alt="Vuetify Name"
      class="shrink mt-1 hidden-sm-and-down"
      contain
      min-width="100"
      src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png"
      width="100"
    />
  </div>
  <v-spacer></v-spacer>
  <v-tabs background-color="primary" right hide-slider>
    <v-tab :to="{name:'HomePage'}">Home</v-tab>
    <v-tab :to="{name:'ProductTable'}" v-if="Object.keys(user).length !== 0">Product list</v-tab>
    <v-tab :to="{name:'ProductAddNew'}" v-if="Object.keys(user).length !== 0">Add Product</v-tab>
  </v-tabs>
  <v-btn
    color="success"
    dark
    @click="openDialog = true"
    v-if="Object.keys(user).length === 0"
  >Account</v-btn>
  <v-menu bottom left v-if="Object.keys(user).length !== 0">
    <template v-slot:activator="{ on }">
      <v-btn dark icon v-on="on">
        <v-icon>mdi-account-circle</v-icon>
      </v-btn>
    </template>
    <v-list>
      <v-list-item v-for="(item, i) in menu" :key="i" @click="selectItem(i)">
        <v-list-item-title>{{ item.title }}</v-list-item-title>
      </v-list-item>
    </v-list>
  </v-menu>
</v-app-bar>
<user-dialog v-model="openDialog" />

<v-content>
  <router-view></router-view>
</v-content>
<script> import UserDialog from "./components/User/UserDialog"; export default { name: "App", components: { UserDialog }, data() { return { user: {}, menu: [{ title: "About" }, { title: "Setting" }, { title: "Sign Out" }], openDialog: false }; }, created() { this.user = JSON.parse(localStorage.getItem("user")) || {}; }, methods: { selectItem(item) { if (item == 2) { localStorage.removeItem("user"); this.$router.go({ path: "/", force: true }); } } } }; </script>

route.js
import Vue from 'vue'
import Router from 'vue-router'
import HomePage from '@/components/HomePage'
import ProductDetail from '@/components/Product/ProductDetail'
import ProductTable from '@/components/Product/ProductTable'
import ProductAddNew from '@/components/Product/ProductAddNew'
import ProductEdit from '@/components/Product/ProductEdit'

Vue.use(Router)

const router = new Router({
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'HomePage',
component: HomePage
},
{
path: '/product-detail/:id',
name: 'ProductDetail',
component: ProductDetail
},
{
path: '/product',
name: 'ProductTable',
component: ProductTable
},
{
path: '/add-product',
name: 'ProductAddNew',
component: ProductAddNew
},
{
path: '/edit-product/:id',
name: 'ProductEdit',
component: ProductEdit
}
]
})
router.beforeEach((to, from, next) => {
// redirect to login page if not logged in and trying to access a restricted page
const publicPages = ['/home', '/product-detail']
const path = to.path.split('/')[1]
const authRequired = !publicPages.includes('/' + path)
const loggedIn = localStorage.getItem('user')

if (authRequired && !loggedIn) {
return next({
path: '/home',
query: { returnUrl: to.path }
})
}

next()
})
export default router

use modal dialog

<template>
  <v-row dense>
    <v-col cols="3" v-for="product in products" :key="product.id">
      <v-card class="mx-auto" outlined>
        <v-list-item three-line>
          <v-list-item-content>
            <v-list-item-title class="headline mb-1">{{product.name}}</v-list-item-title>
            <v-list-item-subtitle>{{product.title}}</v-list-item-subtitle>
          </v-list-item-content>
        </v-list-item>
        <v-card-actions>
          <v-btn dark color="cyan" @click="openDialog = true, productSelectedFromChild = product">
            <v-icon dark>mdi-television</v-icon>
          </v-btn>
          <v-btn :to="{ name: 'ProductDetail', params: { id: product.id }}" color="primary">Detail</v-btn>
        </v-card-actions>
      </v-card>
    </v-col>
    <product-dialog v-model="openDialog" :productDetailInfo="productSelectedFromChild" />
  </v-row>
</template>

<script>
import axios from "axios";
import ProductDialog from "./ProductDialog.vue";

export default {
  name: "ProductList",
  components: {
    ProductDialog
  },
  data: function() {
    return {
      productSelectedFromChild: {},
      openDialog: false,
      products: [],
      errors: []
    };
  },
  created() {
    axios
      .get("http://localhost:3001/posts")
      .then(response => {
        this.products = response.data;
      })
      .catch(e => {
        this.errors.push(e);
      });
  },
  methods: {
    // This line below
    selectProduct(product) {
      this.$emit("productSelected", product);
    }
  }
};
</script>

<template>
  <v-dialog
    :value="value"
    @input="$emit('input')"
    max-width="500"
    v-if="Object.keys(productDetailInfo).length !== 0"
  >
    <v-card>
      <v-card-title class="headline grey lighten-2" primary-title>{{ productDetailInfo.name }}</v-card-title>
      <v-card-text>{{ productDetailInfo.title }}</v-card-text>
      <v-divider></v-divider>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn color="green" text @click.native="$emit('input')">Close</v-btn>
        <v-btn color="primary">Detail</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>
<script>
export default {
  name: "ProductDialog",

  props: {
    value: {
      type: Boolean
    },
    productDetailInfo: {
      type: Object
    }
  }
};
</script>

init editor

import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import { TiptapVuetifyPlugin } from 'tiptap-vuetify'
// don't forget to import styles
import 'tiptap-vuetify/dist/main.css'
const vuetify = new Vuetify()
Vue.use(TiptapVuetifyPlugin, {
// the next line is important! You need to provide the Vuetify Object to this place.
vuetify, // same as "vuetify: vuetify"
// optional, default to 'md' (default vuetify icons before v2.0.0)
iconsGroup: 'md'
})

export default new Vuetify({})

import Vue from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import router from './router'
import 'material-design-icons-iconfont/dist/material-design-icons.css'
import axios from 'axios'
import tiptapVuetifyPlugin from './plugins/tiptap'
Vue.config.productionTip = false
const baseURL = 'http://localhost:3001'
Vue.prototype.$axios = axios.create({ baseURL })
new Vue({
vuetify,
tiptapVuetifyPlugin,
router,
render: h => h(App)
}).$mount('#app')

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.