mirror of
https://github.com/andrigamerita/simpkey
synced 2025-02-17 20:30:49 +01:00
wip
This commit is contained in:
parent
b958350d0f
commit
dbd58fc39d
@ -1,8 +1,8 @@
|
|||||||
import Koa from 'koa';
|
import Koa from 'koa';
|
||||||
import { router, render } from '.';
|
import { router } from './router';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import session from 'koa-session';
|
|
||||||
import bodyParser from 'koa-bodyparser';
|
import bodyParser from 'koa-bodyparser';
|
||||||
|
import { render } from './render';
|
||||||
|
|
||||||
|
|
||||||
const app = new Koa();
|
const app = new Koa();
|
||||||
@ -12,7 +12,6 @@ console.log('Simpkey v' + config.version);
|
|||||||
app.use(bodyParser());
|
app.use(bodyParser());
|
||||||
app.use(render);
|
app.use(render);
|
||||||
app.use(router.routes());
|
app.use(router.routes());
|
||||||
app.use(router.allowedMethods());
|
|
||||||
|
|
||||||
console.log('App launched!');
|
console.log('App launched!');
|
||||||
|
|
||||||
|
6
src/die.ts
Normal file
6
src/die.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { Context } from 'koa';
|
||||||
|
|
||||||
|
export const die = (ctx: Context, error: string): Promise<void> => {
|
||||||
|
ctx.status = 400;
|
||||||
|
return ctx.render('error', { error });
|
||||||
|
};
|
100
src/index.ts
100
src/index.ts
@ -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<void> => {
|
|
||||||
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<DefaultState, Context>();
|
|
||||||
|
|
||||||
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<Note[]>(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<any>(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);
|
|
||||||
}
|
|
||||||
});
|
|
34
src/render.ts
Normal file
34
src/render.ts
Normal file
@ -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;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
146
src/router.ts
Normal file
146
src/router.ts
Normal file
@ -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<DefaultState, Context>();
|
||||||
|
|
||||||
|
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<Note[]>(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<any>(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<any>(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<any>(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, 'ページが見つかりませんでした');
|
||||||
|
});
|
@ -8,8 +8,9 @@ mixin note(note)
|
|||||||
|
|
|
|
||||||
span(style="color: gray")= getAcct(note.user)
|
span(style="color: gray")= getAcct(note.user)
|
||||||
p= note.text
|
p= note.text
|
||||||
aside= new Date(note.createdAt).toLocaleString()
|
aside
|
||||||
aside= note.visibility
|
!=getVisibility(note)
|
||||||
|
!=new Date(note.createdAt).toLocaleString()
|
||||||
|
|
||||||
html
|
html
|
||||||
head
|
head
|
||||||
|
7
src/views/settings.pug
Normal file
7
src/views/settings.pug
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
extends _base
|
||||||
|
|
||||||
|
block content
|
||||||
|
h2 設定
|
||||||
|
h3 ユーザー
|
||||||
|
form(action="/logout", method="post")
|
||||||
|
button(type="submit") ログアウト
|
@ -5,7 +5,7 @@ block content
|
|||||||
p: b=getUserName(user)
|
p: b=getUserName(user)
|
||||||
|
|
|
|
||||||
span(style="color: gray")= getAcct(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")
|
textarea(name="text", placeholder="今何してる?" style="max-width: 100%; min-width: 100%; height: 6em; margin-bottom: 8px")
|
||||||
button(type="submit") ノート
|
button(type="submit") ノート
|
||||||
hr
|
hr
|
||||||
@ -17,6 +17,8 @@ block content
|
|||||||
a(href="/stl") ソーシャル
|
a(href="/stl") ソーシャル
|
||||||
| ・
|
| ・
|
||||||
a(href="/gtl") グローバル
|
a(href="/gtl") グローバル
|
||||||
|
| ・
|
||||||
|
a(href="/settings") 設定
|
||||||
h2= timelineName
|
h2= timelineName
|
||||||
each note in timeline
|
each note in timeline
|
||||||
if (note.renote)
|
if (note.renote)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user