DEV Community

Sokhavuth TIN
Sokhavuth TIN

Posted on • Edited on

2 1

Blog Engine with Fresh: Query Post Item


GitHub: https://github.com/Sokhavuth/deno-fresh
Deno Deploy: https://khmerweb-fresh.deno.dev/login


// routes/admin/post.jsx

/** @jsx h */
import { h } from "preact";
import VPost from '../../components/admin/post.jsx';
import CPost from "../../controllers/admin/post.js";


export const handler = {
  async GET(req, ctx){
      return await CPost.getPage(req, ctx);
  },  

  async POST(req, ctx){
      return await CPost.createPost(req, ctx);
  },
}


export default function Template(props){
    return (
        <VPost data={ props.data } />
    )
}
Enter fullscreen mode Exit fullscreen mode
// controllers/admin/post.js

import { getCookies, deleteCookie } from "cookies";
import { setting, secret_key, myredis } from 'setting';
import { verify } from "jwt";
import postdb from "../../models/post.ts";


class Post{
    async getPage(req, ctx){
        const cookies = getCookies(req.headers);

        if((cookies)&&(cookies.session_id)){
            const jwt = await myredis.get(cookies.session_id);
            try{
                const payload = await verify(jwt, secret_key, "HS512");
                if(payload.user){
                    const config = setting();
                    config.page_title = "Post page";
                    config.username = payload.user.title;
                    config.count = await postdb.count();
                    config.items = await postdb.getPosts(config.post_amount);

                    return await ctx.render({"setting": config});
                }
            }catch(error){
                console.log(error);
                const config = setting();
                config.page_title = "Login page";
                const resp = new Response();
                deleteCookie(resp.headers, "session_id");
                return new Response(undefined, { headers: {location: `/login`}, status: 302 });
            }
        }   

        return new Response(undefined, { headers: {location: `/login`}, status: 302 });
    }

    async createPost(req, ctx){
        const cookies = getCookies(req.headers);
        if((cookies)&&(cookies.session_id)){
            const jwt = await myredis.get(cookies.session_id);
            try{
                const payload = await verify(jwt, secret_key, "HS512");
                if(payload.user.role in {'Admin':1,'Editor':1,'Author':1}){
                    await postdb.insertPost(req, payload.user.id);
                }
                return new Response(undefined, { headers: {location: `/admin/post`}, status: 302 });
            }catch(error){
                console.log(error);
                const resp = new Response(undefined, { headers: {location: `/login`}, status: 302 });
                deleteCookie(resp.headers, "session_id");
                return resp;
            }
        }

        return new Response(undefined, { headers: {location: `/login`}, status: 302 });
    }
}

export default new Post();
Enter fullscreen mode Exit fullscreen mode
// components/admin/index.jsx

/** @jsx h */
import { h } from "preact";
import Base from "../base.jsx"


function IndexJsx(props){
    const Page = props.data.pageInner;
    const items = props.data.setting.items;

    const listItems = items.map((item) =>
    <li>
      <a class="thumb" href={`/post/${item.id}`}>
        <img src={item.thumb} />
        {((item.videos !== "" )&&(item.videos !== "[]")) &&
          <img class="play-icon" src={`/images/play.png`} />
        }
      </a>
      <div class="title">
        <a href={`/post/${item.id}`}>{item.title}</a>
        <div>{(new Date(item.date)).toLocaleDateString('it-IT')}</div>
      </div>
      <div class="edit">
        <a href={`/admin/post/edit/${item.id}`}><img src={`/images/edit.png`} /></a>
        <a href={`/admin/post/delete/${item.id}`}><img src={`/images/delete.png`} /></a>
      </div>
    </li>
    )
    return(
        <section class="Index" >
            <link rel="stylesheet" href="/styles/admin/index.css" />
        <header>
          <div class="inner region">
              <div class="title">{props.data.setting.page_title}</div>
              <form action="/admin/search" method="post">
                <select name="admin_search">
                  <option>posts</option>
                  <option>books</option>
                </select>
                <input type="text" name="admin_q" required placeholder="Search" />
                <input type="submit" value="Search" />
              </form>
              <div class="logout"><span>{props.data.setting.username}</span> | <a href="/">Home</a> | <a href="/logout">Logout</a></div>
          </div>
        </header>

        <div class="main region">
          <div class="sidebar">
            <div class="inner">
              <a href="/admin/post"><img src="/images/movie.png" /></a>
              <a href="/admin/post">Post</a>

              <a href="/admin/book"><img src="/images/books.png" /></a>
              <a href="/admin/book">Book</a>

              <a href="/admin/category"><img src="/images/category.png" /></a>
              <a href="/admin/category">Category</a>

              <a href="/admin/upload"><img src="/images/upload.png" /></a>
              <a href="/admin/upload">Upload</a>

              <a href="/admin/user"><img src="/images/users.png" /></a>
              <a href="/admin/user">User</a>

              <a href="/admin/setting"><img src="/images/setting.png" /></a>
              <a href="/admin/setting">Setting</a>
            </div>
          </div>
          <div class="content">
            <Page data={props.data} />
          </div>
        </div>

        <div class="footer region">
          <div class="info">Total number of items: {props.data.setting.count}</div>
          <ul class="list">
              { listItems }
          </ul>
          <div class="pagination"><img src="/images/load-more.png" /></div>
          <div class="credit">&copy; <a href="https://khmerweb.vercel.app/">Khmer Web 2022</a></div>
        </div>
        </section>
    )
}

export default function Index(props){
    props.data.page = IndexJsx
    return(
        <Base data={props.data} />
    )
}
Enter fullscreen mode Exit fullscreen mode
/* static/styles/admin/index.css */

.Index header{
    background: var(--background-dark);
    border-bottom: 7px solid var(--background-light);
    margin-bottom: 20px;
}

.Index header .inner{
    padding: 5px 0;
}

.Index header .inner .title{
    font: 30px/1.5 StardosStencil, Limonf3;
    color: orange;
}

.Index header .inner{
    display: grid;
    grid-template-columns: 25% auto 25%;
    align-items: center;
}

.Index header .inner form{
    display: grid;
    grid-template-columns: 20% auto 20%;
}

.Index header .inner form input,
.Index header .inner form select{
    font: var(--body-font);
    padding: 2px 5px;
}

.Index header .inner .logout{
    text-align: right;
    color: white;
}

.Index header .inner .logout a{
    color: white;
}

.Index .main{
    display: grid;
    grid-template-columns: calc(25% - 10px) 75%;
    grid-gap: 10px;
}

.Index .main .sidebar{
    background: #17a372;
    padding: 20px;
}

.Index .main .sidebar .inner{
    display: grid;
    grid-template-columns: 25% auto;
    grid-gap: 20px 10px;
    align-items: center;
}

.Index .main .sidebar .inner img{
    width: 100%;
    float: left;
}

.Index .main .sidebar .inner a{
    color: white;
    font: 18px/1.5 Oswald, Bayon;
}

.Index .footer .info{
    margin-top: 10px;
    background: #17a372;
    text-align: center;
    padding: 10px;
    color: white;
}

.Index .footer ul{
    list-style-type: none;
    display: grid;
    grid-template-columns: calc(50% - 5px) calc(50% - 5px);
    grid-gap: 10px;
    padding: 10px 0;
}

.Index .footer ul li{
    display: grid;
    grid-template-columns: 25% 60% 15%;
    background: #17a372;
    align-items: center;
}

.Index .footer ul li .thumb{
    display: block;
    position: relative;
    padding-top: 56.25%;
}

.Index .footer ul li .thumb img{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    float: left;
}

.Index .footer ul li .thumb .play-icon{
    position: absolute;
    width: 25%;
    height: auto;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
}

.Index .footer ul li .title{
    padding: 5px 10px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.Index .footer ul li .title a{
    color: white;
    font: 17px/1.5 StardosStencil, Limonf3;
}   

.Index .footer ul li .edit img{
    width: 35px;
    margin-right: 5px;
    float: left;
    visibility: hidden;
}

.Index .footer ul li:hover .edit img{
    visibility: visible;
}

.Index .footer .pagination{
    text-align: center;
    background: #17a372;
    padding: 5px 0 0;
}

.Index .footer .pagination img:hover{
    cursor: pointer;
    opacity: .7;
}

.Index .footer .credit{
    text-align: center;
    padding: 30px 0;
}
Enter fullscreen mode Exit fullscreen mode

SurveyJS custom survey software

Simplify data collection in your JS app with a fully integrated form management platform. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more. Integrates with any backend system, giving you full control over your data and no user limits.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more