// routes/admin/post/[name]/[id].tsx
/** @jsx h */
import { h } from "preact";
import { Handlers, PageProps } from "$fresh/server.ts";
import VPost from '../../../../components/admin/post.tsx';
import CPost from "../../../../controllers/admin/post_edit_delete.ts";
export const handler: Handlers = {
async GET(req, ctx){
return await CPost.editDeletePost(req, ctx);
},
async POST(req, ctx) {
return await CPost.updatePost(req, ctx);
},
}
export default function Template(props: PageProps) {
return (
<VPost data={props.data} />
)
}
// controllers/admin/post_edit_delete.ts
import { getCookies, deleteCookie } from "cookies";
import { setting, secret_key, myredis } from 'setting';
import { verify } from "jwt";
import postdb from "../../models/post.ts";
class PostEditDelete{
async editDeletePost(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 = "កែប្រែការផ្សាយ";
config.username = payload.user.title;
config.count = await postdb.count();
if(ctx.params.name === 'edit'){
config.item = await postdb.getPost(ctx.params.id);
}else if(ctx.params.name === 'delete'){
const post = await postdb.getPost(ctx.params.id);
if((payload.user.role in {'Admin':1})||(payload.user.id === post.userid)){
await postdb.deletePost(ctx.params.id);
}
return new Response(undefined, { headers: {location: `/admin/post`}, status: 302 });
}else{
console.log('');
}
config.items = await postdb.getPosts(config.post_amount);
return await ctx.render({"setting": config});
}
}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 });
}
async updatePost(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");
const post = await postdb.getPost(ctx.params.id);
if((post.userid === payload.user.id)||(payload.user.role in {'Admin':1,'Editor':1})){
if(ctx.params.name === 'edit'){
await postdb.updatePost(req, ctx.params.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 PostEditDelete();
// models/post.ts
import { mydb } from "setting"
interface PostSchema {
_id: ObjectId;
id: string;
title: string;
content: string;
categories: string[];
thumb: string;
date: string;
videos: string;
userid: string;
}
class Post{
async count(query={}){
const posts = mydb.collection<PostSchema>("posts")
return await posts.countDocuments(query)
}
async insertPost(req, user_id: string){
const id = crypto.randomUUID()
const formData = await req.formData()
let categories: string[]
if(formData.get("categories").includes(',')){
categories = formData.get("categories").split(',')
}else{
categories = [formData.get("categories")]
}
const new_post = {
id: id,
title: formData.get("title"),
content: formData.get("content"),
categories: categories,
thumb: formData.get("thumb"),
date: formData.get("datetime"),
videos: formData.get("videos"),
userid: user_id,
}
const posts = mydb.collection<PostSchema>("posts")
await posts.insertOne(new_post)
}
async getPosts(amount: number, query={}){
const posts = mydb.collection<PostSchema>("posts")
return await posts.find(query).sort({date:-1,_id:-1}).limit(amount).toArray()
}
async getPost(post_id: string){
const posts = mydb.collection<PostSchema>("posts")
return await posts.findOne({id: post_id})
}
async updatePost(req, post_id: string){
const formData = await req.formData()
let categories: string[]
if(formData.get("categories").includes(',')){
categories = formData.get("categories").split(',')
}else{
categories = [formData.get("categories")]
}
const edited_post = {$set:{
title: formData.get("title"),
content: formData.get("content"),
categories: categories,
thumb: formData.get("thumb"),
date: formData.get("datetime"),
videos: formData.get("videos"),
}}
const posts = mydb.collection<PostSchema>("posts")
await posts.updateOne({id: post_id}, edited_post)
}
async deletePost(post_id: string){
const posts = mydb.collection<PostSchema>("posts")
await posts.deleteOne({id: post_id})
}
}
export default new Post()
// components/admin/post.tsx
/** @jsx h */
import { h } from "preact"
import { PageProps } from "$fresh/server.ts";
import Index from "./index.tsx";
function PostTsx(props: PageProps){
const item = props.data.setting.item;
let editor = ``
let videos = ``
if(item){
editor = `
<form action="/admin/post/edit/${item.id}" name="form" method="post"
onSubmit="submitForm(event)">
<input type="text" name="title" value="${item.title}" required
placeholder="ចំណងជើង" />
<textarea id="editor" name="content" >${item.content}</textarea>
<input type="text" name="categories" value="${item.categories.toString()}" required
placeholder="បណ្តាជំពូក" />
<div class="wrapper">
<select id="category" onChange="getCategory()">
<option>ជ្រើសរើសជំពូក</option>
<option>News</option>
<option>Movie</option>
<option>Entertainment</option>
<option>Sport</option>
</select>
<input type="text" name="thumb" value="${item.thumb}" required
placeholder="តំណរភ្ជាប់រូបតំណាង" />
<input type="datetime-local" value="${item.date}" name="datetime" required />
<input type="submit" value="បញ្ជូន" />
<input type="hidden" name="videos" value='${item.videos}' />
</div>
</form>
`
videos = `
let is_video = null
is_video = JSON.parse('${item.videos}')
if((is_video !== '') && (is_video !== '[]')){
let html = ''
let episode = is_video.length
for(let video of is_video){
html += "<div>"
html += '<input value="'+video.type+'" required />'
html += '<input value="'+video.id+'" required />'
html += '<input value="'+video.status+'" required />'
html += '<p title="Delete" onClick="deleteRow(event)" class="episode">'+(episode--)+'</p>'
html += "</div>"
}
if($('.viddata div').html() === ''){
$('.viddata div').append('<b>ប្រភេទ</b>')
$('.viddata div').append('<b>អត្តសញ្ញាណ</b>')
$('.viddata div').append('<b>ស្ថានភាព</b>')
$('.viddata div').append('<b>ភាគ/លុប</b>')
}
$('.viddata div:eq(0)' ).after(html)
}
`
}else{
editor = `
<form action="/admin/post" name="form" method="post" onSubmit="submitForm(event)">
<input type="text" name="title" required placeholder="ចំណងជើង" />
<textarea id="editor" name="content"></textarea>
<input type="text" name="categories" required placeholder="បណ្តាជំពូក" />
<div class="wrapper">
<select id="category" onChange="getCategory()">
<option>ជ្រើសរើសជំពូក</option>
<option>News</option>
<option>Movie</option>
<option>Entertainment</option>
<option>Sport</option>
</select>
<input type="text" name="thumb" required placeholder="តំណរភ្ជាប់រូបតំណាង" />
<input type="datetime-local" name="datetime" required />
<input type="submit" value="បញ្ជូន" />
<input type="hidden" name="videos" value="" />
</div>
</form>
`
videos = ``
}
return(
<section class="Post">
<script src="/scripts/ckeditor/ckeditor.js"></script>
<script src="/scripts/addCategory.js"></script>
<script src="/scripts/video.js"></script>
<link rel="stylesheet" href="/styles/admin/post.css" />
<div dangerouslySetInnerHTML={{__html: `
${editor}
`}}/>
<script src="/scripts/ckeditor/config.js"></script>
<div class="wrapper" >
<select name="type">
<option>YouTube</option>
<option>YouTubePL</option>
<option>Facebook</option>
<option>OK</option>
</select>
<input type="text" name="videoid" required placeholder="អត្តសញ្ញាណវីដេអូ" />
<select name="status">
<option>ចប់</option>
<option>នៅមានត</option>
<option>~ ចប់</option>
</select>
<div dangerouslySetInnerHTML={{__html: `
<input onclick="genJson()" type="submit" value="បញ្ចូលវីដេអូ" />
`}} />
</div>
<div class='viddata'>
<div></div>
</div>
<script dangerouslySetInnerHTML={{__html: `${videos}`}}/>
</section>
)
}
export default function Post(props: PageProps){
props.data.pageInner = PostTsx
return(
<Index data={props.data} />
)
}
GitHub: https://github.com/Sokhavuth/khmerweb-fresh
Deno Deploy: https://khmerweb.deno.dev/login