Compare commits

...

20 Commits

Author SHA1 Message Date
2927fb1597 11.0.0-beta.9 2019-04-13 17:27:17 +09:00
8c72e011d2 Fix bug 2019-04-13 17:26:38 +09:00
69662e24c3 Fix bug 2019-04-13 17:24:56 +09:00
96099ffe98 11.0.0-beta.8 2019-04-13 16:55:13 +09:00
ae16b45c11 Fix bug 2019-04-13 16:54:21 +09:00
cfee87d3ef 11.0.0-beta.7 2019-04-13 15:18:27 +09:00
5fcf5bc635 Fix bug 2019-04-13 15:18:12 +09:00
14bcb813cc Update migrate.ts 2019-04-13 15:09:16 +09:00
6af19794b6 11.0.0-beta.6 2019-04-13 15:03:56 +09:00
8316186695 Clean packed responses 2019-04-13 15:02:15 +09:00
85d3023cd5 Clean packed responses 2019-04-13 14:55:59 +09:00
78414dee29 Add note 2019-04-13 14:45:51 +09:00
084135141f typo 2019-04-13 14:37:45 +09:00
467a21f028 Update CONTRIBUTING.md 2019-04-13 14:36:35 +09:00
6e284c44d6 Update CONTRIBUTING.md 2019-04-13 14:34:34 +09:00
daf9a449e8 Update CONTRIBUTING.md 2019-04-13 14:31:05 +09:00
960268fd33 typo 2019-04-13 14:17:50 +09:00
8c331da315 Fix bug 2019-04-13 14:11:15 +09:00
b0d626d862 Update CONTRIBUTING.md 2019-04-13 14:04:29 +09:00
a51fbd7316 Suppress errors 2019-04-13 04:00:02 +09:00
16 changed files with 95 additions and 36 deletions

View File

@ -130,6 +130,40 @@ const users = userIds.length > 0 ? await Users.find({
}) : [];
```
### 配列のインデックス in SQL
SQLでは配列のインデックスは**1始まり**。
`[a, b, c]`の `a`にアクセスしたいなら`[0]`ではなく`[1]`と書く
### `undefined`にご用心
MongoDBの時とは違い、findOneでレコードを取得する時に対象レコードが存在しない場合 **`undefined`** が返ってくるので注意。
MongoDBは`null`で返してきてたので、その感覚で`if (x === null)`とか書くとバグる。代わりに`if (x == null)`と書いてください
### 簡素な`undefined`チェック
データベースからレコードを取得するときに、プログラムの流れ的に(ほぼ)絶対`undefined`にはならない場合でも、`undefined`チェックしないとTypeScriptに怒られます。
でもいちいち複数行を費やして、発生するはずのない`undefined`をチェックするのも面倒なので、`ensure`というユーティリティ関数を用意しています。
例えば、
``` ts
const user = await Users.findOne(userId);
// この時点で user の型は User | undefined
if (user == null) {
throw 'missing user';
}
// この時点で user の型は User
```
という処理を`ensure`を使うと
``` ts
const user = await Users.findOne(userId).then(ensure);
// この時点で user の型は User
```
という風に書けます。
もちろん`ensure`内部でエラーを握りつぶすようなことはしておらず、万が一`undefined`だった場合はPromiseがRejectされ後続の処理は実行されません。
``` ts
const user = await Users.findOne(userId).then(ensure);
// 万が一 Users.findOne の結果が undefined だったら、ensure でエラーが発生するので
// この行に到達することは無い
// なので、.then(ensure) は
// if (user == null) {
// throw 'missing user';
// }
// の糖衣構文のような扱いです
```

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "11.0.0-beta.5",
"version": "11.0.0-beta.9",
"codename": "daybreak",
"repository": {
"type": "git",

View File

@ -24,9 +24,14 @@ import { UserPublickey } from './models/entities/user-publickey';
import { UserKeypair } from './models/entities/user-keypair';
import { extractPublic } from './crypto_key';
import { Emoji } from './models/entities/emoji';
import { toPuny } from './misc/convert-host';
import { toPuny as _toPuny } from './misc/convert-host';
import { UserProfile } from './models/entities/user-profile';
function toPuny(x: string | null): string | null {
if (x == null) return null;
return _toPuny(x);
}
const u = (config as any).mongodb.user ? encodeURIComponent((config as any).mongodb.user) : null;
const p = (config as any).mongodb.pass ? encodeURIComponent((config as any).mongodb.pass) : null;

View File

@ -19,3 +19,8 @@ export function extractDbHost(uri: string) {
export function toPuny(host: string) {
return toASCII(host.toLowerCase());
}
export function toPunyNullable(host: string | null | undefined): string | null {
if (host == null) return null;
return toASCII(host.toLowerCase());
}

View File

@ -148,7 +148,7 @@ export class NoteRepository extends Repository<Note> {
return reaction.reaction;
}
return null;
return undefined;
}
let text = note.text;
@ -162,15 +162,15 @@ export class NoteRepository extends Repository<Note> {
const packed = await rap({
id: note.id,
createdAt: note.createdAt,
app: note.appId ? Apps.pack(note.appId) : null,
app: note.appId ? Apps.pack(note.appId) : undefined,
userId: note.userId,
user: Users.pack(note.user || note.userId, meId),
text: text,
cw: note.cw,
visibility: note.visibility,
localOnly: note.localOnly,
visibleUserIds: note.visibleUserIds,
viaMobile: note.viaMobile,
localOnly: note.localOnly || undefined,
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
viaMobile: note.viaMobile || undefined,
renoteCount: note.renoteCount,
repliesCount: note.repliesCount,
reactions: note.reactions,
@ -188,13 +188,13 @@ export class NoteRepository extends Repository<Note> {
...(opts.detail ? {
reply: note.replyId ? this.pack(note.replyId, meId, {
detail: false
}) : null,
}) : undefined,
renote: note.renoteId ? this.pack(note.renoteId, meId, {
detail: true
}) : null,
}) : undefined,
poll: note.hasPoll ? populatePoll() : null,
poll: note.hasPoll ? populatePoll() : undefined,
...(meId ? {
myReaction: populateMyReaction()

View File

@ -1,6 +1,7 @@
import { EntityRepository, Repository } from 'typeorm';
import { UserList } from '../entities/user-list';
import { ensure } from '../../prelude/ensure';
import { UserListJoinings } from '..';
@EntityRepository(UserList)
export class UserListRepository extends Repository<UserList> {
@ -9,9 +10,14 @@ export class UserListRepository extends Repository<UserList> {
) {
const userList = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
const users = await UserListJoinings.find({
userListId: userList.id
});
return {
id: userList.id,
name: userList.name
name: userList.name,
userIds: users.map(x => x.userId)
};
}
}

View File

@ -89,13 +89,11 @@ export class UserRepository extends Repository<User> {
username: user.username,
host: user.host,
avatarUrl: user.avatarUrl,
bannerUrl: user.bannerUrl,
avatarColor: user.avatarColor,
bannerColor: user.bannerColor,
isAdmin: user.isAdmin,
isBot: user.isBot,
isCat: user.isCat,
isVerified: user.isVerified,
isAdmin: user.isAdmin || undefined,
isBot: user.isBot || undefined,
isCat: user.isCat || undefined,
isVerified: user.isVerified || undefined,
// カスタム絵文字添付
emojis: user.emojis.length > 0 ? Emojis.find({
@ -121,6 +119,8 @@ export class UserRepository extends Repository<User> {
url: profile!.url,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
bannerUrl: user.bannerUrl,
bannerColor: user.bannerColor,
description: profile!.description,
location: profile!.location,
birthday: profile!.birthday,

View File

@ -1,3 +1,6 @@
/**
* 値が null または undefined の場合はエラーを発生させ、そうでない場合は値をそのまま返します
*/
export function ensure<T>(x: T): NonNullable<T> {
if (x == null) {
throw 'ぬるぽ';

View File

@ -12,7 +12,7 @@ import { Instances, Users, UserPublickeys } from '../../models';
import { instanceChart } from '../../services/chart';
import { UserPublickey } from '../../models/entities/user-publickey';
import fetchMeta from '../../misc/fetch-meta';
import { toPuny } from '../../misc/convert-host';
import { toPuny, toPunyNullable } from '../../misc/convert-host';
import { validActor } from '../../remote/activitypub/type';
import { ensure } from '../../prelude/ensure';
@ -36,7 +36,7 @@ export default async (job: Bull.Job): Promise<void> => {
if (keyIdLower.startsWith('acct:')) {
const acct = parseAcct(keyIdLower.slice('acct:'.length));
const host = acct.host ? toPuny(acct.host) : null;
const host = toPunyNullable(acct.host);
const username = toPuny(acct.username);
if (host === null) {

View File

@ -1,7 +1,7 @@
import $ from 'cafy';
import define from '../../../define';
import { Emojis } from '../../../../../models';
import { toPuny } from '../../../../../misc/convert-host';
import { toPunyNullable } from '../../../../../misc/convert-host';
export const meta = {
desc: {
@ -23,7 +23,7 @@ export const meta = {
export default define(meta, async (ps) => {
const emojis = await Emojis.find({
host: ps.host ? toPuny(ps.host) : null
host: toPunyNullable(ps.host)
});
return emojis.map(e => ({

View File

@ -34,7 +34,7 @@ export default define(meta, async (ps) => {
if (ps.domain) {
const whiteDomains = ps.domain.split(' ').filter(x => !x.startsWith('-'));
const blackDomains = ps.domain.split(' ').filter(x => x.startsWith('-'));
const blackDomains = ps.domain.split(' ').filter(x => x.startsWith('-')).map(x => x.substr(1));
if (whiteDomains.length > 0) {
query.andWhere(new Brackets(qb => {
@ -53,11 +53,17 @@ export default define(meta, async (ps) => {
if (blackDomains.length > 0) {
query.andWhere(new Brackets(qb => {
for (const blackDomain of blackDomains) {
const subDomains = blackDomain.split('.');
let i = 0;
for (const subDomain of blackDomain.split('.')) {
for (const subDomain of subDomains) {
const p = `blackSubDomain_${subDomain}_${i}`;
// SQL is 1 based, so we need '+ 1'
qb.andWhere(`log.domain[${i + 1}] != :${p}`, { [p]: subDomain });
if (i === subDomains.length - 1) {
// SQL is 1 based, so we need '+ 1'
qb.andWhere(`log.domain[${i + 1}] != :${p}`, { [p]: subDomain });
} else {
// SQL is 1 based, so we need '+ 1'
qb.andWhere(`log.domain[${i + 1}] = :${p}`, { [p]: subDomain });
}
i++;
}
}

View File

@ -76,12 +76,12 @@ export default define(meta, async (ps, user) => {
user: meta.smtpUser,
pass: meta.smtpPass
} : undefined
});
} as any);
const link = `${config.url}/verify-email/${code}`;
transporter.sendMail({
from: meta.email,
from: meta.email!,
to: ps.email,
subject: meta.name || 'Misskey',
text: `To verify email, please click this link: ${link}`

View File

@ -124,7 +124,7 @@ export default define(meta, async (ps, user) => {
// Increment votes count
const index = ps.choice + 1; // In SQL, array index is 1 based
await Polls.query(`UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE noteId = '${poll.noteId}'`);
await Polls.query(`UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE "noteId" = '${poll.noteId}'`);
publishNoteStream(note.id, 'pollVoted', {
choice: ps.choice,

View File

@ -4,7 +4,7 @@ import define from '../../define';
import { ApiError } from '../../error';
import { Users, Followings } from '../../../../models';
import { makePaginationQuery } from '../../common/make-pagination-query';
import { toPuny } from '../../../../misc/convert-host';
import { toPunyNullable } from '../../../../misc/convert-host';
export const meta = {
desc: {
@ -66,7 +66,7 @@ export const meta = {
export default define(meta, async (ps, me) => {
const user = await Users.findOne(ps.userId != null
? { id: ps.userId }
: { usernameLower: ps.username!.toLowerCase(), host: toPuny(ps.host!) });
: { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) });
if (user == null) {
throw new ApiError(meta.errors.noSuchUser);

View File

@ -4,7 +4,7 @@ import define from '../../define';
import { ApiError } from '../../error';
import { Users, Followings } from '../../../../models';
import { makePaginationQuery } from '../../common/make-pagination-query';
import { toPuny } from '../../../../misc/convert-host';
import { toPunyNullable } from '../../../../misc/convert-host';
export const meta = {
desc: {
@ -66,7 +66,7 @@ export const meta = {
export default define(meta, async (ps, me) => {
const user = await Users.findOne(ps.userId != null
? { id: ps.userId }
: { usernameLower: ps.username!.toLowerCase(), host: toPuny(ps.host!) });
: { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) });
if (user == null) {
throw new ApiError(meta.errors.noSuchUser);

View File

@ -10,7 +10,7 @@ import { genId } from '../../../misc/gen-id';
import { usersChart } from '../../../services/chart';
import { User } from '../../../models/entities/user';
import { UserKeypair } from '../../../models/entities/user-keypair';
import { toPuny } from '../../../misc/convert-host';
import { toPunyNullable } from '../../../misc/convert-host';
import { UserProfile } from '../../../models/entities/user-profile';
import { getConnection } from 'typeorm';
@ -36,7 +36,7 @@ export default async (ctx: Koa.BaseContext) => {
const username = body['username'];
const password = body['password'];
const host = process.env.NODE_ENV === 'test' ? (body['host'] || null) : null;
const host: string | null = process.env.NODE_ENV === 'test' ? (body['host'] || null) : null;
const invitationCode = body['invitationCode'];
if (instance && instance.disableRegistration) {
@ -96,7 +96,7 @@ export default async (ctx: Koa.BaseContext) => {
cipher: undefined,
passphrase: undefined
}
}, (e, publicKey, privateKey) =>
} as any, (e, publicKey, privateKey) =>
e ? j(e) : s([publicKey, privateKey])
));
@ -109,7 +109,7 @@ export default async (ctx: Koa.BaseContext) => {
createdAt: new Date(),
username: username,
usernameLower: username.toLowerCase(),
host: toPuny(host),
host: toPunyNullable(host),
token: secret,
isAdmin: config.autoAdmin && usersCount === 0,
}));