✌️
This commit is contained in:
parent
f89c3af982
commit
6a5c6280ff
19 changed files with 150 additions and 11 deletions
88
src/api/bot/core.ts
Normal file
88
src/api/bot/core.ts
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import * as EventEmitter from 'events';
|
||||||
|
import * as bcrypt from 'bcryptjs';
|
||||||
|
|
||||||
|
import User, { IUser } from '../models/user';
|
||||||
|
|
||||||
|
export default class BotCore extends EventEmitter {
|
||||||
|
public user: IUser;
|
||||||
|
|
||||||
|
private context: Context = null;
|
||||||
|
|
||||||
|
constructor(user: IUser) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async q(query: string): Promise<string> {
|
||||||
|
if (this.context != null) {
|
||||||
|
return await this.context.q(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (query) {
|
||||||
|
case 'ping':
|
||||||
|
return 'PONG';
|
||||||
|
case 'ログイン':
|
||||||
|
case 'サインイン':
|
||||||
|
this.context = new SigninContext(this);
|
||||||
|
return await this.context.greet();
|
||||||
|
default:
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setUser(user: IUser) {
|
||||||
|
this.user = user;
|
||||||
|
this.emit('set-user', user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Context {
|
||||||
|
protected core: BotCore;
|
||||||
|
|
||||||
|
public abstract async greet(): Promise<string>;
|
||||||
|
public abstract async q(query: string): Promise<string>;
|
||||||
|
|
||||||
|
constructor(core: BotCore) {
|
||||||
|
this.core = core;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SigninContext extends Context {
|
||||||
|
private temporaryUser: IUser;
|
||||||
|
|
||||||
|
public async greet(): Promise<string> {
|
||||||
|
return 'まずユーザー名を教えてください:';
|
||||||
|
}
|
||||||
|
|
||||||
|
public async q(query: string): Promise<string> {
|
||||||
|
if (this.temporaryUser == null) {
|
||||||
|
// Fetch user
|
||||||
|
const user: IUser = await User.findOne({
|
||||||
|
username_lower: query.toLowerCase()
|
||||||
|
}, {
|
||||||
|
fields: {
|
||||||
|
data: false,
|
||||||
|
profile: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (user === null) {
|
||||||
|
return `${query}というユーザーは存在しませんでした... もう一度教えてください:`;
|
||||||
|
} else {
|
||||||
|
this.temporaryUser = user;
|
||||||
|
return `パスワードを教えてください:`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Compare password
|
||||||
|
const same = bcrypt.compareSync(query, this.temporaryUser.password);
|
||||||
|
|
||||||
|
if (same) {
|
||||||
|
this.core.setUser(this.temporaryUser);
|
||||||
|
return `${this.temporaryUser.name}さん、おかえりなさい!`;
|
||||||
|
} else {
|
||||||
|
return `パスワードが違います... もう一度教えてください:`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
src/api/bot/interfaces/line.ts
Normal file
37
src/api/bot/interfaces/line.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import * as EventEmitter from 'events';
|
||||||
|
import * as express from 'express';
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
//import User from '../../models/user';
|
||||||
|
import config from '../../../conf';
|
||||||
|
/*import BotCore from '../core';
|
||||||
|
|
||||||
|
const sessions: {
|
||||||
|
userId: string;
|
||||||
|
session: BotCore;
|
||||||
|
}[] = [];
|
||||||
|
*/
|
||||||
|
module.exports = async (app: express.Application) => {
|
||||||
|
if (config.line_bot == null) return;
|
||||||
|
|
||||||
|
const handler = new EventEmitter();
|
||||||
|
|
||||||
|
app.post('/hooks/line', (req, res, next) => {
|
||||||
|
// req.headers['X-Line-Signature'] は常に string ですが、型定義の都合上
|
||||||
|
// string | string[] になっているので string を明示しています
|
||||||
|
const sig1 = req.headers['X-Line-Signature'] as string;
|
||||||
|
|
||||||
|
const hash = crypto.createHmac('sha256', config.line_bot.channel_secret)
|
||||||
|
.update(JSON.stringify(req.body));
|
||||||
|
|
||||||
|
const sig2 = hash.digest('base64');
|
||||||
|
|
||||||
|
// シグネチャ比較
|
||||||
|
if (sig1 === sig2) {
|
||||||
|
console.log(req.body);
|
||||||
|
handler.emit(req.body.type);
|
||||||
|
res.sendStatus(200);
|
||||||
|
} else {
|
||||||
|
res.sendStatus(400);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -21,7 +21,7 @@ module.exports = (params, user, app, isSecure) => new Promise(async (res, rej) =
|
||||||
const [data, dataError] = $(params.data).optional.object()
|
const [data, dataError] = $(params.data).optional.object()
|
||||||
.pipe(obj => {
|
.pipe(obj => {
|
||||||
const hasInvalidData = Object.entries(obj).some(([k, v]) =>
|
const hasInvalidData = Object.entries(obj).some(([k, v]) =>
|
||||||
$(k).string().match(/^[a-z_]+$/).isNg() && $(v).string().isNg());
|
$(k).string().match(/^[a-z_]+$/).nok() && $(v).string().nok());
|
||||||
return !hasInvalidData;
|
return !hasInvalidData;
|
||||||
}).$;
|
}).$;
|
||||||
if (dataError) return rej('invalid data param');
|
if (dataError) return rej('invalid data param');
|
||||||
|
|
|
@ -57,6 +57,9 @@ export type IUser = {
|
||||||
user_id: string;
|
user_id: string;
|
||||||
screen_name: string;
|
screen_name: string;
|
||||||
};
|
};
|
||||||
|
line: {
|
||||||
|
user_id: string;
|
||||||
|
};
|
||||||
description: string;
|
description: string;
|
||||||
profile: {
|
profile: {
|
||||||
location: string;
|
location: string;
|
||||||
|
|
|
@ -79,6 +79,7 @@ export default (
|
||||||
delete _user.twitter.access_token;
|
delete _user.twitter.access_token;
|
||||||
delete _user.twitter.access_token_secret;
|
delete _user.twitter.access_token_secret;
|
||||||
}
|
}
|
||||||
|
delete _user.line;
|
||||||
|
|
||||||
// Visible via only the official client
|
// Visible via only the official client
|
||||||
if (!opts.includeSecrets) {
|
if (!opts.includeSecrets) {
|
||||||
|
|
|
@ -54,4 +54,6 @@ app.use((req, res, next) => {
|
||||||
require('./service/github')(app);
|
require('./service/github')(app);
|
||||||
require('./service/twitter')(app);
|
require('./service/twitter')(app);
|
||||||
|
|
||||||
|
require('./bot/interfaces/line')(app);
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
/**
|
||||||
|
* 投稿を表す文字列を取得します。
|
||||||
|
* @param {*} post 投稿
|
||||||
|
*/
|
||||||
const summarize = post => {
|
const summarize = post => {
|
||||||
let summary = post.text ? post.text : '';
|
let summary = post.text ? post.text : '';
|
||||||
|
|
|
@ -68,6 +68,9 @@ type Source = {
|
||||||
hook_secret: string;
|
hook_secret: string;
|
||||||
username: string;
|
username: string;
|
||||||
};
|
};
|
||||||
|
line_bot?: {
|
||||||
|
channel_secret: string;
|
||||||
|
};
|
||||||
analysis?: {
|
analysis?: {
|
||||||
mecab_command?: string;
|
mecab_command?: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ import * as riot from 'riot';
|
||||||
import init from '../init';
|
import init from '../init';
|
||||||
import route from './router';
|
import route from './router';
|
||||||
import fuckAdBlock from './scripts/fuck-ad-block';
|
import fuckAdBlock from './scripts/fuck-ad-block';
|
||||||
import getPostSummary from '../common/scripts/get-post-summary';
|
import getPostSummary from '../../../common/get-post-summary';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init
|
* init
|
||||||
|
|
|
@ -207,7 +207,7 @@
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import getPostSummary from '../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../common/get-post-summary';
|
||||||
this.getPostSummary = getPostSummary;
|
this.getPostSummary = getPostSummary;
|
||||||
|
|
||||||
this.mixin('i');
|
this.mixin('i');
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import Progress from '../../../common/scripts/loading';
|
import Progress from '../../../common/scripts/loading';
|
||||||
import getPostSummary from '../../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../../common/get-post-summary';
|
||||||
|
|
||||||
this.mixin('i');
|
this.mixin('i');
|
||||||
this.mixin('api');
|
this.mixin('api');
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import getPostSummary from '../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../common/get-post-summary';
|
||||||
this.getPostSummary = getPostSummary;
|
this.getPostSummary = getPostSummary;
|
||||||
this.notification = this.opts.notification;
|
this.notification = this.opts.notification;
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -163,7 +163,7 @@
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import getPostSummary from '../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../common/get-post-summary';
|
||||||
this.getPostSummary = getPostSummary;
|
this.getPostSummary = getPostSummary;
|
||||||
this.notification = this.opts.notification;
|
this.notification = this.opts.notification;
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import getPostSummary from '../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../common/get-post-summary';
|
||||||
this.getPostSummary = getPostSummary;
|
this.getPostSummary = getPostSummary;
|
||||||
|
|
||||||
this.mixin('api');
|
this.mixin('api');
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<script>
|
<script>
|
||||||
import ui from '../../scripts/ui-event';
|
import ui from '../../scripts/ui-event';
|
||||||
import Progress from '../../../common/scripts/loading';
|
import Progress from '../../../common/scripts/loading';
|
||||||
import getPostSummary from '../../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../../common/get-post-summary';
|
||||||
import openPostForm from '../../scripts/open-post-form';
|
import openPostForm from '../../scripts/open-post-form';
|
||||||
|
|
||||||
this.mixin('i');
|
this.mixin('i');
|
||||||
|
|
|
@ -264,7 +264,7 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import compile from '../../common/scripts/text-compiler';
|
import compile from '../../common/scripts/text-compiler';
|
||||||
import getPostSummary from '../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../common/get-post-summary';
|
||||||
import openPostForm from '../scripts/open-post-form';
|
import openPostForm from '../scripts/open-post-form';
|
||||||
|
|
||||||
this.mixin('api');
|
this.mixin('api');
|
||||||
|
|
|
@ -464,7 +464,7 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import compile from '../../common/scripts/text-compiler';
|
import compile from '../../common/scripts/text-compiler';
|
||||||
import getPostSummary from '../../common/scripts/get-post-summary';
|
import getPostSummary from '../../../../common/get-post-summary';
|
||||||
import openPostForm from '../scripts/open-post-form';
|
import openPostForm from '../scripts/open-post-form';
|
||||||
|
|
||||||
this.mixin('api');
|
this.mixin('api');
|
||||||
|
|
|
@ -428,7 +428,7 @@
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import summary from '../../common/scripts/get-post-summary';
|
import summary from '../../../../common/get-post-summary';
|
||||||
|
|
||||||
this.post = this.opts.post;
|
this.post = this.opts.post;
|
||||||
this.text = summary(this.post);
|
this.text = summary(this.post);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
"comment-format": [false],
|
"comment-format": [false],
|
||||||
"interface-over-type-literal": false,
|
"interface-over-type-literal": false,
|
||||||
"max-line-length": [false],
|
"max-line-length": [false],
|
||||||
|
"max-classes-per-file": false,
|
||||||
"member-ordering": [false],
|
"member-ordering": [false],
|
||||||
"ban-types": [
|
"ban-types": [
|
||||||
"Object"
|
"Object"
|
||||||
|
|
Loading…
Reference in a new issue