From dcd87dd3e7f815f8321c6f06355e2b3aa881ccc8 Mon Sep 17 00:00:00 2001 From: ShokiYokota Date: Fri, 27 Oct 2023 22:44:20 +0900 Subject: [PATCH] =?UTF-8?q?dayjs=E3=81=A7=E6=99=82=E9=96=93=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=AE=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/posts-handler.js | 147 ++++++++++++++++++++++++------------------- package.json | 1 + public/nn-chat.js | 32 ++++++---- views/posts.pug | 3 +- 4 files changed, 106 insertions(+), 77 deletions(-) diff --git a/lib/posts-handler.js b/lib/posts-handler.js index f03e3c4..2401ad0 100644 --- a/lib/posts-handler.js +++ b/lib/posts-handler.js @@ -1,92 +1,111 @@ -'use strict'; -const pug = require('pug'); -const { PrismaClient } = require('@prisma/client'); -const prisma = new PrismaClient(); -const util = require('./handler-util'); +'use strict' +const pug = require('pug') +const { PrismaClient } = require('@prisma/client') +const prisma = new PrismaClient() +const util = require('./handler-util') + +const dayjs = require('dayjs') +const utc = require('dayjs/plugin/utc') +const timezone = require('dayjs/plugin/timezone') +const relativeTime = require('dayjs/plugin/relativeTime') +require('dayjs/locale/ja') +dayjs.locale('ja') +dayjs.extend(utc) +dayjs.extend(timezone) +dayjs.extend(relativeTime) +dayjs.tz.setDefault('Asia/Tokyo') async function handle(req, res) { switch (req.method) { case 'GET': res.writeHead(200, { - 'Content-Type': 'text/html; charset=utf-8' - }); + 'Content-Type': 'text/html; charset=utf-8', + }) const posts = await prisma.post.findMany({ orderBy: { - id: 'asc' - } - }); + id: 'asc', + }, + }) posts.forEach((post) => { - post.content = post.content.replace(/\n/g, '
'); - }); - res.end(pug.renderFile('./views/posts.pug', { posts, user: req.user })); + post.content = post.content.replace(/\n/g, '
') + post.relativeCreatedAt = dayjs(post.createdAt).tz().fromNow() + post.formattedCreatedAt = dayjs(post.createdAt) + .tz() + .format('YYYY年MM月DD日 HH時mm分ss秒') + }) + res.end(pug.renderFile('./views/posts.pug', { posts, user: req.user })) console.info( `閲覧されました: user: ${req.user}, ` + - `remoteAddress: ${req.socket.remoteAddress}, ` + - `userAgent: ${req.headers['user-agent']} ` - ); - break; + `remoteAddress: ${req.socket.remoteAddress}, ` + + `userAgent: ${req.headers['user-agent']} ` + ) + break case 'POST': - let body = ''; - req.on('data', (chunk) => { - body += chunk; - }).on('end', async () => { - const params = new URLSearchParams(body); - const content = params.get('content'); - console.info(`送信されました: ${content}`); - await prisma.post.create({ - data: { - content, - postedBy: req.user - } - }); - handleRedirectPosts(req, res); - }); - break; + let body = '' + req + .on('data', (chunk) => { + body += chunk + }) + .on('end', async () => { + const params = new URLSearchParams(body) + const content = params.get('content') + console.info(`送信されました: ${content}`) + await prisma.post.create({ + data: { + content, + postedBy: req.user, + }, + }) + handleRedirectPosts(req, res) + }) + break default: - util.handleBadRequest(req, res); - break; + util.handleBadRequest(req, res) + break } } function handleRedirectPosts(req, res) { res.writeHead(303, { - 'Location': '/posts' - }); - res.end(); + Location: '/posts', + }) + res.end() } function handleDelete(req, res) { switch (req.method) { case 'POST': - let body = ''; - req.on('data', (chunk) => { - body += chunk; - }).on('end', async () => { - const params = new URLSearchParams(body); - const id = parseInt(params.get('id')); - const post = await prisma.post.findUnique({ - where: { id } - }); - if (req.user === post.postedBy || req.user === 'admin') { - await prisma.post.delete({ - where: { id } - }); - console.info( - `削除されました: user: ${req.user}, ` + - `remoteAddress: ${req.socket.remoteAddress}, ` + - `userAgent: ${req.headers['user-agent']} ` - ); - handleRedirectPosts(req, res); - } - }); - break; + let body = '' + req + .on('data', (chunk) => { + body += chunk + }) + .on('end', async () => { + const params = new URLSearchParams(body) + const id = parseInt(params.get('id')) + const post = await prisma.post.findUnique({ + where: { id }, + }) + if (req.user === post.postedBy || req.user === 'admin') { + await prisma.post.delete({ + where: { id }, + }) + console.info( + `削除されました: user: ${req.user}, ` + + `remoteAddress: ${req.socket.remoteAddress}, ` + + `userAgent: ${req.headers['user-agent']} ` + ) + handleRedirectPosts(req, res) + } + }) + break default: - util.handleBadRequest(req, res); - break; + util.handleBadRequest(req, res) + break } } module.exports = { handle, - handleDelete -}; \ No newline at end of file + handleDelete, +} diff --git a/package.json b/package.json index 9afc3ee..0ad6a7d 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "license": "MIT", "dependencies": { "@prisma/client": "4.11.0", + "dayjs": "1.11.7", "http-auth": "4.2.0", "prisma": "4.11.0", "pug": "3.0.2" diff --git a/public/nn-chat.js b/public/nn-chat.js index 08b7cee..3834113 100644 --- a/public/nn-chat.js +++ b/public/nn-chat.js @@ -1,31 +1,39 @@ -'use strict'; +'use strict' // 一番下を表示 -window.onload = function() { - window.scrollTo(0,document.body.scrollHeight); +window.onload = function () { + window.scrollTo(0, document.body.scrollHeight) } // エンターキー と Ctrlキー(Macの場合はCommandキー)を押していたら送信 -const formElement = document.forms['message-form']; -const textareaElement = formElement.elements['content']; +const formElement = document.forms['message-form'] +const textareaElement = formElement.elements['content'] textareaElement.addEventListener('keydown', (event) => { // 送信キーを押したら if (isPressedSubmitKey(event)) { // キーボード入力をキャンセルして送信 - event.preventDefault(); - formElement.submit(); + event.preventDefault() + formElement.submit() } -}); +}) // 送信キーを押しているか判定 function isPressedSubmitKey(event) { if (event.key !== 'Enter') { - return false; + return false } if (event.ctrlKey) { - return true; + return true } // MacのCommandキーはmetaKeyという名前 if (event.metaKey) { - return true; + return true } -} \ No newline at end of file +} + +// ツールチップの有効化 +const tooltipTriggerElements = document.querySelectorAll( + '[data-bs-toggle="tooltip"]' +) +tooltipTriggerElements.forEach((tooltipTriggerElement) => { + new bootstrap.Tooltip(tooltipTriggerElement) +}) diff --git a/views/posts.pug b/views/posts.pug index d9f2b14..386ac77 100644 --- a/views/posts.pug +++ b/views/posts.pug @@ -29,7 +29,8 @@ html(lang="ja") h5.card-title #{post.postedBy} if post.postedBy === 'admin' i.bi-patch-check-fill.ms-1 - small.card-text.text-muted.float-end #{post.createdAt} + - const tooltipTitle = `${post.formattedCreatedAt}` + small.card-text.text-muted.float-end(data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true" title=tooltipTitle) #{post.relativeCreatedAt} p.card-text.lead!= post.content - const isDeletable = (user === post.postedBy || user === 'admin') if isDeletable