Pages

Sunday, 23 July 2023

LC 01.2

 const { comperePassword, hashPassword} = require('../helpers/bcrypt');

const {Article, Category, User, History} = require('../models')
const {createToken} = require('../helpers/jwt')


const {OAuth2Client} = require('google-auth-library');
const { STRING } = require('sequelize');
const client = new OAuth2Client();

class Controller {
    static async createHistory(req, res, next){
      try {
        const histories = await History.findAll({
          order: [['id', 'DESC']]
        });
        res.json(histories);
      } catch (error) {
        next()
      }
    }

    static async getArticle(req, res, next) {
        try {
          const article = await Article.findAll();
          res.status(200).json(article);
        } catch (err) {
          next(err)
        }
      }

      static async getUser(req, res, next){
        try {
            const user = await User.findAll();
            res.status(200).json(user);
          } catch (err) {
            next(err)
          }
      }

      static async getCategory(req, res, next){
        try {
            const category = await Category.findAll();
            res.status(200).json(category);
          } catch (err) {
            next(err)
          }
      }

      static async postCategory(req, res, next){
        try {
          const data = req.body
          data.authorId = req.user.id
          const createCategory = await Category.create(data)
          if(createCategory){
            await History.create({
              title: 'POST',
              description: `New category with id ${createCategory.id} created`,
              updatedBy: `${req.user.username}`
            })
          }
          res.status(201).json(createCategory)
      } catch (err) {
          next(err)
      }
      }

      static async loginGoogle(req, res){
        try {
            // console.log(req.headers);
            const {google_token} = req.headers
            const ticket = await client.verifyIdToken({
                idToken: google_token,
                audience: '731493170239-2fc94ip6i8tjag20vec2fas5mq3iu4n4.apps.googleusercontent.com',  // Specify the CLIENT_ID of the app that accesses the backend
                // Or, if multiple clients access the backend:
                //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
            });
            const payload = ticket.getPayload();
            // console.log(payload);
            const {email, name } = payload
            const [user, created] = await User.findOrCreate({
                where: { email : email },
                defaults: {
                  username: name,
                  email:email,
                  password: hashPassword(String(Math.random())),
                  role: 'Staff'
                },
                hooks: false
              });
              const access_token = createToken({id: user.id})
              res.status(200).json(access_token)
        } catch (error) {
            console.log(error);
        }
      }

      static async updatePatch(req, res, next){
        try {
          const id = +req.params.id

          const article = await Article.findByPk(id)

          if(!article){
            res.status(400).json({msg: `Article ${id} not found`})
          }
          const {status} = req.body
          await Article.update({status}, {where: {id}})
          await History.create({
            title: 'PATCH',
            description: `Article with status id ${id} has been updated from ${article.status} to ${status}`,
            updatedBy: `${req.user.username}`
          })
         
          res.status(201).json({msg: `Article ${id} updated from ${article.status} to ${status}`})

        } catch (error) {
          next(error)
        }
      }

      static async updateData(req, res, next){
        try {
          const id = +req.params.id

          const article = await Article.findByPk(id)

          if(!article){
            res.status(400).json({msg: `Article ${id} not found`})
          }

         
          const [isUpdated] = await Article.update(req.body, {where: {id}})
          await History.create({
            title: 'PUT',
            description: `Article id ${id} has updated`,
            updatedBy: `${req.user.username}`
          })
          res.status(201).json({msg: `Article ${id} updated`})

        } catch (error) {
          next(error)
        }
      }

      static async getAllData(req, res, next){
            try {
                const article = await Article.findAll(
                    {include : [Category, User]}
                );
               
                res.status(200).json(article);
            } catch (err) {
                next(err)
            }
      }

      static async createArticle(req, res, next) {
        try {
            const data = req.body
            data.authorId = req.user.id
           
            const createArticle = await Article.create(data)
            if(createArticle){
              await History.create({
                title: 'POST',
                description: `New article with id ${createArticle.id} created`,
                updatedBy: `${req.user.username}`
              })
            }
           
            res.status(201).json(createArticle)
        } catch (err) {
            next(err)
        }
      }

      static async findArticleById (req, res, next){
        try {
            const id = req.params.id
            const article = await Article.findByPk(id);
            if(!article){
                res.status(404).json({message: `Article with id ${id} not found`})
            }else{
                res.status(200).json(article)
            }
        } catch (error) {
            next(error)
        }
      }

      static async deleteById(req, res, next){
        try {
            const id = +req.params.id
            const deleteArticle = await Article.findByPk(id)
            if(!deleteArticle) throw {name: 'NotFound'}
            await Article.destroy({where : {id}})

            res.json({message: `id ${deleteArticle.id} deleted`})
        } catch (err) {
            next(err)
        }

      }

      static async register(req, res, next){
        try {
            const {username, email, password, phoneNumber, address} = req.body
            // console.log(username, email, password, phoneNumber, address);
            const user = await User.create({username, email, password, phoneNumber, address})

            res.status(201).json({
                massage: `User with id ${user.id} has been created`
            })
        } catch (err) {
            next(err)
        }
      }

      static async login(req, res, next){
        try {
            const {email, password} = req.body
            if(!email || !password) throw {name: 'InvalidCredential'}
             
            const user = await User.findOne({where: {email}})
            if(!user) throw {name: 'InvalidCredential'}

            const isPassword = comperePassword(password, user.password)

            if(!isPassword) throw {name: 'InvalidCredential'}

            const access_token = createToken({id: user.id})
            res.json({access_token})

        } catch (err) {
            next(err)
        }
      }

     

}
module.exports = Controller

LC 01.1

 <script>

    export default {
      data (){
      },
      props: ['currentPage', 'categories', 'users'],
     
      methods:{
        toggleDashboard() {
          this.$emit('dashboard')
        }
      }
    }
</script>

<template>
    <ul>
        <li class="nav-item">
        <a class="nav-link" href="#" @click.prevent="toggleDashboard">
          <i class="fas fa-fw fa-database"></i>
          <span>Dashboard</span></a
        >
      </li>
  </ul>
</template>

<style>

</style>

<script>
export default {
  methods: {
    toggleAddNew() {
      this.$emit("formInputArticle");
    },
    toggleEdit() {
      this.$emit("formInputArticle");
    },
    updateArticleStatus(){
      this.$emit('updateStatus')
    }
   
  },
  props: ["articles"],
};
</script>

<template>
  <div class="container" id="showArticles">
    <div class="row">
      <div class="col-6">
        <button class="btn btn-primary mb-2" @click.prevent="toggleAddNew">
          Add New
        </button>
        <h4>Table List Article</h4>
      </div>
    </div>
    <table class="table">
      <thead>
        <tr>
          <th scope="col">No</th>
          <th scope="col">Title</th>
          <th scope="col">Content</th>
          <th scope="col">Image</th>
          <th scope="col">Category</th>
          <th scope="col">Author</th>
          <th scope="col">Status</th>
          <th scope="col">Action</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(article, index) in articles" :key="index">
          <th scope="row">{{ index + 1 }}</th>
          <td>{{ article.title }}</td>
          <td>{{ article.content }}</td>
          <td>
            <img :src="article.imgUrl" class="img-fluid" style="width: 75px" />
          </td>
          <td>{{ article.Category.name }}</td>
          <td>{{ article.User.username }}</td>
          <td>
            <select
              v-model="article.status"
              class="form-control"
              @change.prevent="updateArticleStatus(article.id)"
            >
              <option value="{{ article.status }}">{{ article.status }}</option>
              <option value="Active">Active</option>
              <option value="Archived">Archived</option>
            </select>
          </td>
          <td>
            <a href="#" @click.prevent="toggleEdit(article)"> EDIT </a>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<style></style>

<script>
  export default {
    data (){
      return {
        formInput: {
            title: '',
            content: '',
            imgUrl: '',
            categoryId: ''
      }
      }
    },
    methods: {
      doSubmitArticle(){
        this.$emit('handleAddNew', this.formInput)
      }
    },
    props : ['handleAddNew', 'categories']
     
    }
</script>

<template>
    <div class="container" id="showAddNew">
        <div class="row justify-content-center">
          <div class="col-xl-10 col-lg-12 col-md-9">
            <div class="card o-hidden border-0 shadow-lg my-5">
              <div class="card-body p-0">
                <div class="row">
                  <div class="col-lg-12">
                    <div class="p-5">
                      <div class="text-center">
                        <h1 class="h4 text-gray-900 mb-4">
                          Create a New Article!
                        </h1>
                      </div>
                      <form class="user" @submit.prevent="doSubmitArticle">
                        <div class="form-group row">
                          <div class="col-sm-6 mb-3 mb-sm-0">
                            <input
                              type="text"
                              class="form-control"
                              id="title"
                              name="title"
                              placeholder="Title"
                              v-model="formInput.title"
                            />
                          </div>
                          <div class="col-sm-6">
                            <input
                              type="text"
                              class="form-control"
                              id="content"
                              placeholder="Content"
                              v-model="formInput.content"
                            />
                          </div>
                        </div>
                        <div class="form-group">
                          <input
                            type="text"
                            class="form-control"
                            id="imgUrl"
                            placeholder="Image URL"
                            v-model="formInput.imgUrl"
                          />
                        </div>
                        <div class="form-group">
                          <select class="form-control" v-model="formInput.categoryId" id="categoryId">
                            <option v-for="(category, index) in categories" :key="index" :value="category.id">
                          {{ category.name }}
                        </option>
                          </select>
                        </div>
                        <button type="submit" class="btn btn-primary btn-user btn-block">
                          Submit Article
                        </button>
                      </form>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
</template>

<style>
</style>

LC 01

 <script>

import axios from "axios";
import Login from "./components/Login.vue";
import Navbar from "./components/Navbar.vue";

export default {
  data() {
    return {
      currentPage: "",
      articles: [],
      usersFetch: [],
      categories: [],
      logs: [],
      articlesData: [],
      categoriesData: [],
      message: "Hallo Vue",
    };
  },
  methods: {
    async handleLogin(login) {
      try {
        const { data } = await axios({
          method: "post",
          url: `http://localhost:3000/login`,
          data: login,
        });
        const accessToken = data.access_token;
        localStorage.setItem("access_token", accessToken);

        if (data) {
          const userName = data.name; // Assuming the user's name is available in the response
          Swal.fire("Good job!", `You are logged in as ${login.email}`, "success");

          this.currentPage = "navbar";
          this.currentPage = "dashboard";
          // this.currentPage = "navbar";
         
          this.fetchArticle();
          this.fetchCategory();
        }
      } catch (error) {
        Swal.fire("Error", "Login failed. Please try again.", "error");
        console.log(error);
      }
    },
    async updateArticleStatus(article) {
   
    async fetchArticle() {
      try {
        const response = await axios({
          method: "GET",
          url: "http://localhost:3000/categories/user",
          headers: {
            access_token: localStorage.access_token,
          },
        });
        this.articles = response.data;
       
       
      } catch (error) {
        console.log(error);
       
      }
    },
    async handleRegister(formRegister) {
      try {
        const { data } = await axios({
        method: "POST",
        url: `http://localhost:3000/register`,
        data: formRegister,
      });

      Swal.fire(
          'Success',
          `User is has created`,
          'success'
        );

      formRegister.username = "";
      formRegister.email = "";
      formRegister.password = "";
      formRegister.address = "";
      formRegister.phoneNumber = "";
      } catch (error) {
        console.log(error);
        Swal.fire(
          'Error',
          'Failed to create user status',
          'error'
        );
      }
    },
    async handleAddNew(dataInput) {
      try {
        await axios({
          method: "post",
          url: `http://localhost:3000/news`,
          data: dataInput,
          headers: {
            access_token: localStorage.getItem("access_token"),
          },
        });
        Swal.fire(
          'Success',
          `Article has created`,
          'success'
        );
        this.currentPage = "article";
       
        this.fetchArticle();
      } catch (error) {
        console.log(error);
        Swal.fire(
          'Error',
          'Failed to create article',
          'error'
        );
      }
    },
   
    moveToDashboard() {
      this.currentPage = "dashboard";
    },
    moveToArticles() {
      this.currentPage = "article";
      this.fetchArticle();
    },
    toggleLogout() {
      localStorage.removeItem("access_token");
      this.currentPage = "login";
      this.formLogin.email = "";
      this.formLogin.password = "";
    },
  },
  created() {
    if (localStorage.access_token) {
      this.currentPage = "navbar";
    } else {
      this.currentPage = "login";
    }
  },
  components: {
    Login
  },
};
</script>

<template>
  <div class="containerr">
    <Navbar
      @dashboard="moveToDashboard"
      @article="moveToArticles"
      @category="moveToCategory"
      @log="moveToLog"
      @logout="toggleLogout"
      :users="user"
    />
    <div class="page">
      <Login
        @handleLogin="handleLogin"
        @handleRegister="handleRegister"
        v-if="currentPage === `login`"
      />
      <Article
        :articles="articles"
        @updateStatus="updateArticleStatus"
        v-if="currentPage === `article`"
        @formInputArticle="formArticle"
      />
      <Category :categories="categories" v-if="currentPage === `categorie`" />
      <Logs :logs="logs" v-if="currentPage === `log`" />
      <FormArticle
        v-if="currentPage === `formInput`"
        @handleAddNew="handleAddNew"
        :categories="categories"
      />
      <Dashboard
        v-if="currentPage === `dashboard`"
        :articles="articles"
        :categories="categories"
      />
      <!-- <Footer /> -->
    </div>
  </div>
</template>

<style scoped>
.containerr {
  display: flex;
}
</style>

Tuesday, 4 July 2023

input tambahan

app.set('view engine', 'ejs')
app.use(express.urlencoded({ extended: false }))

 Asosiasi

static associate(models) {
      // define association here
      Employee.belongsTo(models.Store, { foreignKey: "StoreId" })
    }

untuk model Store dan employee

static associate(models) {
      // define association here
      Store.hasMany(models.Employee, {foreignKey: "StoreId"})
    }

Untuk validasi

Store.init({
    name: {
      type: DataTypes.STRING,
      allowNull: false,
      validate: {
        notNull: {
          msg: 'Name is required',
        },
        notEmpty: {
          msg: 'Name is required',
        }
      }
    },
    position: {
      type : DataTypes.STRING,
      allowNull : false,
      validate: {
        notNull : {
          msg: "Position is require"
        },
        notEmpty: {
          msg: "Position is require"
        },
        validPosition(value){
          if((this.position === 'S2' || this.position === 'S3') &&
          (value !== 'manager' && value !== 'CEO')){
            throw new Error('S2 & S3 only can be Manager or CEO')
          }
        }
      }
    },
    //untuk hooks
    sequelize,
    modelName: 'Store',
    hooks : {
      beforeCreate : function (store, opt){
        if(store.category === 'Mart'){
          store.code = `001-${new Date().getTime()}`
        }
        if(store.category === 'Midi'){
          store.code = `002-${new Date().getTime()}`
        }
        if(store.category === 'Express'){
          store.code = `003-${new Date().getTime()}`
        }
      },
      afterCreate : function(after, opt){
      }
    }
})

untuk errors
.catch((err) => {
            if (err.name === 'SequelizeValidationError'){
                const errors = err.errors.map(error => {
                    return error.message
                })
                res.send(errors)
                // console.log(errors);
               
            }else{
                res.send(err)
            }
        })
atau

.catch((err) => {
            if (err.name === 'SequelizeValidationError') {
                let errors = err.errors.map(el => el.message)
                res.redirect(`/stores/${storeId}/employees/${employeeId}/edit?errors=${errors}`)
            } else {
                res.send(err);
            }
          });

untuk update
Employee.update(
          { firstName, lastName, dateOfBirth, education, position, salary },
          { where: { id: employeeId } }
        )

utnuk delete
Art.destroy({
            where: {
                id: id
            }
        })

untuk tambah data

const {name, artist, date, photo, placeOfOrigin, description} = req.body
        Art.create({name, artist, date, photo, placeOfOrigin, description})

untuk search
static showArts(req, res){
        let {title, artist} = req.query
        let dataArt
        let option = {
        }

        if(title){
            option.where = {
                name:{
                    [Op.iLike] : `%${title}%`
                }
            }
        }

        if(artist){
            option.where = {
                artist:{
                    [Op.like] : `%${artist}%`
                }
            }
        }

        option.order = [['date', 'asc']]
        Art.findAll(option)
        .then((data) => {
            dataArt = data
            return Art.alert()
        })
        .then((alert) => {
            const { sumArt, oldYear, latestYear } = alert[0].dataValues;
            res.render('home',{data : dataArt, alert :{ sumArt, oldYear, latestYear }, title: 'List Of Art'})
        })
        .catch((err) => {
            res.send(err)
        })
    }