From dbd58fc39d73ff9bc36cda92a141cfe05d6e4854 Mon Sep 17 00:00:00 2001 From: Xeltica Date: Fri, 24 Jul 2020 01:53:00 +0900 Subject: [PATCH] wip --- src/app.ts | 5 +- src/die.ts | 6 ++ src/index.ts | 100 ---------------------------- src/render.ts | 34 ++++++++++ src/router.ts | 146 +++++++++++++++++++++++++++++++++++++++++ src/views/_base.pug | 5 +- src/views/settings.pug | 7 ++ src/views/timeline.pug | 4 +- 8 files changed, 201 insertions(+), 106 deletions(-) create mode 100644 src/die.ts delete mode 100644 src/index.ts create mode 100644 src/render.ts create mode 100644 src/router.ts create mode 100644 src/views/settings.pug diff --git a/src/app.ts b/src/app.ts index 8ee1c6d..781cb11 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,8 +1,8 @@ import Koa from 'koa'; -import { router, render } from '.'; +import { router } from './router'; import config from './config'; -import session from 'koa-session'; import bodyParser from 'koa-bodyparser'; +import { render } from './render'; const app = new Koa(); @@ -12,7 +12,6 @@ console.log('Simpkey v' + config.version); app.use(bodyParser()); app.use(render); app.use(router.routes()); -app.use(router.allowedMethods()); console.log('App launched!'); diff --git a/src/die.ts b/src/die.ts new file mode 100644 index 0000000..0dccad0 --- /dev/null +++ b/src/die.ts @@ -0,0 +1,6 @@ +import { Context } from 'koa'; + +export const die = (ctx: Context, error: string): Promise => { + ctx.status = 400; + return ctx.render('error', { error }); +}; diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 4199bf8..0000000 --- a/src/index.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Context, DefaultState } from 'koa'; -import views from 'koa-views'; -import Router from 'koa-router'; -import config from './config'; -import { signIn, api, i } from './misskey'; -import { Note } from './models/Note'; -import { User } from './models/User'; - -export const die = (ctx: Context, error: string): Promise => { - ctx.status = 400; - return ctx.render('error', { error }); -}; - -export const render = views(__dirname + '/views', { - extension: 'pug', options: { - ...config, - getAcct: (user: User) => user.host ? `@${user.username}@${user.host}` : `@${user.username}`, - getUserName: (user: User) => user.name || user.username, - } -}); - -export const router = new Router(); - -const staticRouting = [ - [ 'about', 'Simpkey について' ], - [ 'terms', '利用規約' ], - [ 'privacy-policy', 'プライバシーポリシー' ], -]; - -for (const [ name, title ] of staticRouting) { - router.get('/' + name, async (ctx, next) => { - await ctx.render(name, { title }); - await next(); - }); -} - -async function timeline(ctx: Context, host: string, endpoint: string, timelineName: string, token: string) { - const user = await i(host, token); - - const timeline = await api(host, endpoint, { i: token }); - await ctx.render('timeline', { - title: timelineName + ' - Simpkey', - user, timeline, timelineName - }); -} - -router.get('/ltl', async (ctx, next) => { - const token = ctx.cookies.get('i'); - const host = ctx.cookies.get('host'); - if (!token || !host) { - await die(ctx, 'ログインしてください'); - } else { - const meta = await api(host, 'meta', { i: token }); - if (meta.disableLocalTimeline) { - await die(ctx, 'ローカルタイムラインは無効化されています'); - } else { - await timeline(ctx, host, 'notes/local-timeline', 'ローカルタイムライン', token); - } - } - await next(); -}); - -router.get('/', async (ctx, next) => { - const token = ctx.cookies.get('i'); - const host = ctx.cookies.get('host'); - if (!token || !host) { - console.log('no session so show top page'); - await ctx.render('index', { - title: 'Simpkey' - }); - } else { - console.log('show timeline with the session'); - await timeline(ctx, host, 'notes/timeline', 'ホームタイムライン', token); - } - await next(); -}); - -router.post('/', async (ctx) => { - const { - host, - username, - password, - token - } = ctx.request.body; - if (!host || !username || !password) { - await die(ctx, 'パラメータが足りません'); - return; - } - try { - const { id, i } = await signIn(host, username, password, token); - ctx.cookies.set('id', id); - ctx.cookies.set('host', host); - ctx.cookies.set('i', i); - console.log('login as ' + username); - ctx.redirect('/'); - } catch (err) { - await die(ctx, err.message); - console.error(err); - } -}); \ No newline at end of file diff --git a/src/render.ts b/src/render.ts new file mode 100644 index 0000000..8387032 --- /dev/null +++ b/src/render.ts @@ -0,0 +1,34 @@ +import config from './config'; +import views from 'koa-views'; +import { User } from './models/User'; +import { Note } from './models/Note'; + +export const render = views(__dirname + '/views', { + extension: 'pug', options: { + ...config, + getAcct: (user: User) => user.host ? `@${user.username}@${user.host}` : `@${user.username}`, + getUserName: (user: User) => user.name || user.username, + getVisibility: (note: Note) => { + let icon: string; + switch (note.visibility) { + case 'public': + icon = '🌐'; + break; + case 'home': + icon = '🏠'; + break; + case 'followers': + icon = '🔒'; + break; + case 'specified': + icon = '✉️'; + break; + default: + icon = '❓'; + break; + } + if (note.localOnly) icon += '☣'; + return icon; + }, + } +}); \ No newline at end of file diff --git a/src/router.ts b/src/router.ts new file mode 100644 index 0000000..c24385b --- /dev/null +++ b/src/router.ts @@ -0,0 +1,146 @@ +import { Context, DefaultState } from 'koa'; +import Router from 'koa-router'; +import { signIn, api, i } from './misskey'; +import { Note } from './models/Note'; +import { die } from './die'; + +export const router = new Router(); + +const staticRouting = [ + [ 'about', 'Simpkey について' ], + [ 'terms', '利用規約' ], + [ 'privacy-policy', 'プライバシーポリシー' ], + [ 'settings', '設定' ], +]; + +for (const [ name, title ] of staticRouting) { + router.get('/' + name, async ctx => { + await ctx.render(name, { title }); + }); +} + +async function timeline(ctx: Context, host: string, endpoint: string, timelineName: string, token: string) { + const user = await i(host, token); + const timeline = await api(host, endpoint, { i: token }); + + await ctx.render('timeline', { + title: timelineName + ' - Simpkey', + user, timeline, timelineName + }); +} + +router.get('/', async ctx => { + const token = ctx.cookies.get('i'); + const host = ctx.cookies.get('host'); + if (!token || !host) { + console.log('no session so show top page'); + await ctx.render('index', { + title: 'Simpkey' + }); + return; + } + + await timeline(ctx, host, 'notes/timeline', 'ホームタイムライン', token); +}); + +router.get('/ltl', async ctx => { + const token = ctx.cookies.get('i'); + const host = ctx.cookies.get('host'); + if (!token || !host) { + await die(ctx, 'ログインしてください'); + return; + } + const meta = await api(host, 'meta', { i: token }); + if (meta.disableLocalTimeline) { + await die(ctx, 'ローカルタイムラインは無効化されています'); + } else { + await timeline(ctx, host, 'notes/local-timeline', 'ローカルタイムライン', token); + } +}); + +router.get('/stl', async ctx => { + const token = ctx.cookies.get('i'); + const host = ctx.cookies.get('host'); + if (!token || !host) { + await die(ctx, 'ログインしてください'); + return; + } + const meta = await api(host, 'meta', { i: token }); + if (meta.disableLocalTimeline) { + await die(ctx, 'ソーシャルタイムラインは無効化されています'); + } else { + await timeline(ctx, host, 'notes/hybrid-timeline', 'ソーシャルタイムライン', token); + } +}); +router.get('/gtl', async ctx => { + const token = ctx.cookies.get('i'); + const host = ctx.cookies.get('host'); + if (!token || !host) { + await die(ctx, 'ログインしてください'); + return; + } + + const meta = await api(host, 'meta', { i: token }); + if (meta.disableGlobalTimeline) { + await die(ctx, 'グローバルタイムラインは無効化されています'); + } else { + await timeline(ctx, host, 'notes/global-timeline', 'グローバルタイムライン', token); + } +}); + +router.post('/', async ctx => { + const { + host, + username, + password, + token + } = ctx.request.body; + if (!host || !username || !password) { + await die(ctx, 'パラメータが足りません'); + return; + } + try { + const { id, i } = await signIn(host, username, password, token); + ctx.cookies.set('id', id); + ctx.cookies.set('host', host); + ctx.cookies.set('i', i); + console.log('login as ' + username); + ctx.redirect('/'); + } catch (err) { + await die(ctx, err.message); + console.error(err); + } +}); + +router.post('/action/:action', async ctx => { + const i = ctx.cookies.get('i'); + const host = ctx.cookies.get('host'); + if (!i || !host) { + await die(ctx, 'ログインしてください'); + return; + } + + const action = ctx.params.action as string; + switch (action) { + case 'create-note': { + const { text } = ctx.request.body; + if (!text) await die(ctx, 'テキストがありません'); + await api(host, 'notes/create', { text, i }); + break; + } + } + ctx.redirect('back', '/'); +}); + +router.post('/logout', ctx => { + ctx.cookies.set('id'); + ctx.cookies.set('host'); + ctx.cookies.set('i'); + ctx.redirect('/'); +}); + +// Return 404 for other pages +router.all('(.*)', async ctx => { + ctx.status = 404; + await die(ctx, 'ページが見つかりませんでした'); +}); \ No newline at end of file diff --git a/src/views/_base.pug b/src/views/_base.pug index bfdd882..cb1d545 100644 --- a/src/views/_base.pug +++ b/src/views/_base.pug @@ -8,8 +8,9 @@ mixin note(note) |   span(style="color: gray")= getAcct(note.user) p= note.text - aside= new Date(note.createdAt).toLocaleString() - aside= note.visibility + aside + !=getVisibility(note) + !=new Date(note.createdAt).toLocaleString() html head diff --git a/src/views/settings.pug b/src/views/settings.pug new file mode 100644 index 0000000..62a48e8 --- /dev/null +++ b/src/views/settings.pug @@ -0,0 +1,7 @@ +extends _base + +block content + h2 設定 + h3 ユーザー + form(action="/logout", method="post") + button(type="submit") ログアウト diff --git a/src/views/timeline.pug b/src/views/timeline.pug index 5c9e92d..a3cf113 100644 --- a/src/views/timeline.pug +++ b/src/views/timeline.pug @@ -5,7 +5,7 @@ block content p: b=getUserName(user) |   span(style="color: gray")= getAcct(user) - form(action="/note", method="post") + form(action="/action/create-note", method="post") textarea(name="text", placeholder="今何してる?" style="max-width: 100%; min-width: 100%; height: 6em; margin-bottom: 8px") button(type="submit") ノート hr @@ -17,6 +17,8 @@ block content a(href="/stl") ソーシャル | ・ a(href="/gtl") グローバル + | ・ + a(href="/settings") 設定 h2= timelineName each note in timeline if (note.renote)