Merge branch 'develop' into mk.absturztau.be

This commit is contained in:
Puniko 2022-05-24 17:46:11 +02:00
commit 64c3e40d2c
24 changed files with 234 additions and 228 deletions

3
.github/labeler.yml vendored
View file

@ -3,3 +3,6 @@
'🖥Client':
- packages/client/**/*
'‼️ wrong locales':
- any: ['locales/*.yml', '!locales/ja-JP.yml']

View file

@ -1,10 +1,11 @@
# Contribution guide
We're glad you're interested in contributing Misskey! In this document you will find the information you need to contribute to the project.
** Important:** This project uses Japanese as its major language, **but you do not need to translate and write the Issues/PRs in Japanese.**
Also, you might receive comments on your Issue/PR in Japanese, but you do not need to reply to them in Japanese as well.\
The accuracy of machine translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language.
It will also allow the reader to use the translation tool of their preference if necessary.
> **Note**
> This project uses Japanese as its major language, **but you do not need to translate and write the Issues/PRs in Japanese.**
> Also, you might receive comments on your Issue/PR in Japanese, but you do not need to reply to them in Japanese as well.\
> The accuracy of machine translation into Japanese is not high, so it will be easier for us to understand if you write it in the original language.
> It will also allow the reader to use the translation tool of their preference if necessary.
## Roadmap
See [ROADMAP.md](./ROADMAP.md)
@ -15,7 +16,9 @@ Before creating an issue, please check the following:
- Do not use Issues to ask questions or troubleshooting.
- Issues should only be used to feature requests, suggestions, and bug tracking.
- Please ask questions or troubleshooting in the [Misskey Forum](https://forum.misskey.io/) or [Discord](https://discord.gg/Wp8gVStHW3).
- Do not close issues that are about to be resolved. It should remain open until a commit that actually resolves it is merged.
> **Warning**
> Do not close issues that are about to be resolved. It should remain open until a commit that actually resolves it is merged.
## Before implementation
When you want to add a feature or fix a bug, **first have the design and policy reviewed in an Issue** (if it is not there, please make one). Without this step, there is a high possibility that the PR will not be merged even if it is implemented.

View file

@ -6,24 +6,21 @@
**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀**
---
<a href="https://misskey-hub.net/instances.html">
<img src="https://custom-icon-badges.herokuapp.com/badge/find_an-instance-acea31?logoColor=acea31&style=for-the-badge&logo=misskey&labelColor=363B40" alt="find an instance"/></a>
<img src="https://custom-icon-badges.herokuapp.com/badge/find_an-instance-acea31?logoColor=acea31&style=for-the-badge&logo=misskey&labelColor=363B40" alt="find an instance"/></a>
<a href="https://misskey-hub.net/docs/install.html">
<img src="https://custom-icon-badges.herokuapp.com/badge/create_an-instance-FBD53C?logoColor=FBD53C&style=for-the-badge&logo=server&labelColor=363B40" alt="create an instance"/></a>
<img src="https://custom-icon-badges.herokuapp.com/badge/create_an-instance-FBD53C?logoColor=FBD53C&style=for-the-badge&logo=server&labelColor=363B40" alt="create an instance"/></a>
<a href="./CONTRIBUTING.md">
<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-contributor-A371F7?logoColor=A371F7&style=for-the-badge&logo=git-merge&labelColor=363B40" alt="become a contributor"/>
</a>
<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-contributor-A371F7?logoColor=A371F7&style=for-the-badge&logo=git-merge&labelColor=363B40" alt="become a contributor"/></a>
<a href="https://discord.gg/Wp8gVStHW3">
<img src="https://custom-icon-badges.herokuapp.com/badge/join_the-community-5865F2?logoColor=5865F2&style=for-the-badge&logo=discord&labelColor=363B40" alt="join the community"/>
</a>
<img src="https://custom-icon-badges.herokuapp.com/badge/join_the-community-5865F2?logoColor=5865F2&style=for-the-badge&logo=discord&labelColor=363B40" alt="join the community"/></a>
<a href="https://www.patreon.com/syuilo">
<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-patron-F96854?logoColor=F96854&style=for-the-badge&logo=patreon&labelColor=363B40" alt="become a patron"/>
</a>
<img src="https://custom-icon-badges.herokuapp.com/badge/become_a-patron-F96854?logoColor=F96854&style=for-the-badge&logo=patreon&labelColor=363B40" alt="become a patron"/></a>
---

View file

@ -5,6 +5,6 @@
"loader=./test/loader.js"
],
"slow": 1000,
"timeout": 35000,
"timeout": 3000,
"exit": true
}

View file

@ -5,9 +5,6 @@ pg.types.setTypeParser(20, Number);
import { Logger, DataSource } from 'typeorm';
import * as highlight from 'cli-highlight';
import config from '@/config/index.js';
import { envOption } from '../env.js';
import { dbLogger } from './logger.js';
import { User } from '@/models/entities/user.js';
import { DriveFile } from '@/models/entities/drive-file.js';
@ -74,6 +71,8 @@ import { UserPending } from '@/models/entities/user-pending.js';
import { entities as charts } from '@/services/chart/entities.js';
import { Webhook } from '@/models/entities/webhook.js';
import { envOption } from '../env.js';
import { dbLogger } from './logger.js';
const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);
@ -212,7 +211,7 @@ export async function initDb() {
if (db.isInitialized) {
// nop
} else {
await db.connect();
await db.initialize();
}
}

View file

@ -53,7 +53,7 @@ export default async function(resolver: Resolver, actor: CacheableRemoteUser, ac
throw e;
}
if (!await Notes.isVisibleForMe(renote, actor)) return 'skip: invalid actor for this activity';
if (!await Notes.isVisibleForMe(renote, actor.id)) return 'skip: invalid actor for this activity';
logger.info(`Creating the (Re)Note: ${uri}`);

View file

@ -28,7 +28,7 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note,
}
// check visibility
if (!await Notes.isVisibleForMe(note, user)) {
if (!await Notes.isVisibleForMe(note, user.id)) {
throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.');
}

View file

@ -1,7 +1,7 @@
process.env.NODE_ENV = 'test';
import rndstr from 'rndstr';
import * as assert from 'assert';
import rndstr from 'rndstr';
import { initTestDb } from './utils.js';
describe('ActivityPub', () => {
@ -57,8 +57,8 @@ describe('ActivityPub', () => {
const note = await createNote(post.id, resolver, true);
assert.deepStrictEqual(note?.uri, post.id);
assert.deepStrictEqual(note?.visibility, 'public');
assert.deepStrictEqual(note?.text, post.content);
assert.deepStrictEqual(note.visibility, 'public');
assert.deepStrictEqual(note.text, post.content);
});
});

View file

@ -1,7 +1,7 @@
import * as assert from 'assert';
import httpSignature from 'http-signature';
import { genRsaKeyPair } from '../src/misc/gen-key-pair.js';
import { createSignedPost, createSignedGet } from '../src/remote/activitypub/ap-request.js';
import httpSignature from 'http-signature';
export const buildParsedSignature = (signingString: string, signature: string, algorithm: string) => {
return {
@ -13,7 +13,7 @@ export const buildParsedSignature = (signingString: string, signature: string, a
signature: signature,
},
signingString: signingString,
algorithm: algorithm?.toUpperCase(),
algorithm: algorithm.toUpperCase(),
keyId: 'KeyID', // dummy, not used for verify
};
};
@ -26,7 +26,7 @@ describe('ap-request', () => {
const activity = { a: 1 };
const body = JSON.stringify(activity);
const headers = {
'User-Agent': 'UA'
'User-Agent': 'UA',
};
const req = createSignedPost({ key, url, body, additionalHeaders: headers });
@ -42,7 +42,7 @@ describe('ap-request', () => {
const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey };
const url = 'https://example.com/outbox';
const headers = {
'User-Agent': 'UA'
'User-Agent': 'UA',
};
const req = createSignedGet({ key, url, additionalHeaders: headers });

View file

@ -61,40 +61,40 @@ describe('API visibility', () => {
const show = async (noteId: any, by: any) => {
return await request('/notes/show', {
noteId
noteId,
}, by);
};
before(async () => {
//#region prepare
// signup
alice = await signup({ username: 'alice' });
alice = await signup({ username: 'alice' });
follower = await signup({ username: 'follower' });
other = await signup({ username: 'other' });
target = await signup({ username: 'target' });
target2 = await signup({ username: 'target2' });
other = await signup({ username: 'other' });
target = await signup({ username: 'target' });
target2 = await signup({ username: 'target2' });
// follow alice <= follower
await request('/following/create', { userId: alice.id }, follower);
// normal posts
pub = await post(alice, { text: 'x', visibility: 'public' });
pub = await post(alice, { text: 'x', visibility: 'public' });
home = await post(alice, { text: 'x', visibility: 'home' });
fol = await post(alice, { text: 'x', visibility: 'followers' });
spe = await post(alice, { text: 'x', visibility: 'specified', visibleUserIds: [target.id] });
fol = await post(alice, { text: 'x', visibility: 'followers' });
spe = await post(alice, { text: 'x', visibility: 'specified', visibleUserIds: [target.id] });
// replies
tgt = await post(target, { text: 'y', visibility: 'public' });
pubR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'public' });
pubR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'public' });
homeR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'home' });
folR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'followers' });
speR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'specified' });
folR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'followers' });
speR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'specified' });
// mentions
pubM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'public' });
pubM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'public' });
homeM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'home' });
folM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'followers' });
speM = await post(alice, { text: '@target2 x', replyId: tgt.id, visibility: 'specified' });
folM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'followers' });
speM = await post(alice, { text: '@target2 x', replyId: tgt.id, visibility: 'specified' });
//#endregion
});

View file

@ -25,7 +25,7 @@ describe('Block', () => {
it('Block作成', async(async () => {
const res = await request('/blocking/create', {
userId: bob.id
userId: bob.id,
}, alice);
assert.strictEqual(res.status, 200);

View file

@ -2,7 +2,6 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import * as lolex from '@sinonjs/fake-timers';
import { async, initTestDb } from './utils.js';
import TestChart from '../src/services/chart/charts/test.js';
import TestGroupedChart from '../src/services/chart/charts/test-grouped.js';
import TestUniqueChart from '../src/services/chart/charts/test-unique.js';
@ -11,6 +10,7 @@ import * as _TestChart from '../src/services/chart/charts/entities/test.js';
import * as _TestGroupedChart from '../src/services/chart/charts/entities/test-grouped.js';
import * as _TestUniqueChart from '../src/services/chart/charts/entities/test-unique.js';
import * as _TestIntersectionChart from '../src/services/chart/charts/entities/test-intersection.js';
import { async, initTestDb } from './utils.js';
describe('Chart', () => {
let testChart: TestChart;
@ -33,7 +33,7 @@ describe('Chart', () => {
testIntersectionChart = new TestIntersectionChart();
clock = lolex.install({
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0))
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
});
}));
@ -52,7 +52,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
@ -60,7 +60,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
}));
@ -76,7 +76,7 @@ describe('Chart', () => {
foo: {
dec: [1, 0, 0],
inc: [0, 0, 0],
total: [-1, 0, 0]
total: [-1, 0, 0],
},
});
@ -84,7 +84,7 @@ describe('Chart', () => {
foo: {
dec: [1, 0, 0],
inc: [0, 0, 0],
total: [-1, 0, 0]
total: [-1, 0, 0],
},
});
}));
@ -97,7 +97,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [0, 0, 0]
total: [0, 0, 0],
},
});
@ -105,7 +105,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [0, 0, 0]
total: [0, 0, 0],
},
});
}));
@ -123,7 +123,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [3, 0, 0],
total: [3, 0, 0]
total: [3, 0, 0],
},
});
@ -131,7 +131,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [3, 0, 0],
total: [3, 0, 0]
total: [3, 0, 0],
},
});
}));
@ -149,7 +149,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
@ -157,7 +157,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
}));
@ -178,7 +178,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 1, 0],
total: [2, 1, 0]
total: [2, 1, 0],
},
});
@ -186,7 +186,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [2, 0, 0],
total: [2, 0, 0]
total: [2, 0, 0],
},
});
}));
@ -238,7 +238,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 1],
total: [2, 1, 1]
total: [2, 1, 1],
},
});
@ -246,7 +246,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [2, 0, 0],
total: [2, 0, 0]
total: [2, 0, 0],
},
});
}));
@ -265,7 +265,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [1, 1, 1]
total: [1, 1, 1],
},
});
@ -273,7 +273,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
}));
@ -296,7 +296,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [2, 1, 1]
total: [2, 1, 1],
},
});
@ -304,7 +304,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [2, 0, 0],
total: [2, 0, 0]
total: [2, 0, 0],
},
});
}));
@ -325,7 +325,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
@ -333,7 +333,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [2, 0, 0],
total: [2, 0, 0]
total: [2, 0, 0],
},
});
}));
@ -356,7 +356,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
@ -364,7 +364,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [2, 0, 0],
total: [2, 0, 0]
total: [2, 0, 0],
},
});
}));
@ -383,7 +383,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
@ -391,7 +391,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
@ -399,7 +399,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [0, 0, 0]
total: [0, 0, 0],
},
});
@ -407,7 +407,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [0, 0, 0]
total: [0, 0, 0],
},
});
}));
@ -493,7 +493,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
@ -501,7 +501,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [1, 0, 0]
total: [1, 0, 0],
},
});
}));
@ -523,7 +523,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [0, 1, 0],
total: [100, 1, 0]
total: [100, 1, 0],
},
});
@ -531,7 +531,7 @@ describe('Chart', () => {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [100, 0, 0]
total: [100, 0, 0],
},
});
}));

View file

@ -1,7 +1,7 @@
import * as assert from 'assert';
import { extractMentions } from '../src/misc/extract-mentions.js';
import { parse } from 'mfm-js';
import { extractMentions } from '../src/misc/extract-mentions.js';
describe('Extract mentions', () => {
it('simple', () => {
@ -10,15 +10,15 @@ describe('Extract mentions', () => {
assert.deepStrictEqual(mentions, [{
username: 'foo',
acct: '@foo',
host: null
host: null,
}, {
username: 'bar',
acct: '@bar',
host: null
host: null,
}, {
username: 'baz',
acct: '@baz',
host: null
host: null,
}]);
});
@ -28,15 +28,15 @@ describe('Extract mentions', () => {
assert.deepStrictEqual(mentions, [{
username: 'foo',
acct: '@foo',
host: null
host: null,
}, {
username: 'bar',
acct: '@bar',
host: null
host: null,
}, {
username: 'baz',
acct: '@baz',
host: null
host: null,
}]);
});
});

View file

@ -2,8 +2,8 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, startServer, signup, post, request, simpleGet, port, shutdownServer } from './utils.js';
import * as openapi from '@redocly/openapi-core';
import { async, startServer, signup, post, request, simpleGet, port, shutdownServer } from './utils.js';
// Request Accept
const ONLY_AP = 'application/activity+json';
@ -26,7 +26,7 @@ describe('Fetch resource', () => {
p = await startServer();
alice = await signup({ username: 'alice' });
alicesPost = await post(alice, {
text: 'test'
text: 'test',
});
});
@ -70,7 +70,7 @@ describe('Fetch resource', () => {
const config = await openapi.loadConfig();
const result = await openapi.bundle({
config,
ref: `http://localhost:${port}/api.json`
ref: `http://localhost:${port}/api.json`,
});
for (const problem of result.problems) {

View file

@ -18,7 +18,7 @@ describe('Get file info', () => {
md5: 'd41d8cd98f00b204e9800998ecf8427e',
type: {
mime: 'application/octet-stream',
ext: null
ext: null,
},
width: undefined,
height: undefined,
@ -36,7 +36,7 @@ describe('Get file info', () => {
md5: '091b3f259662aa31e2ffef4519951168',
type: {
mime: 'image/jpeg',
ext: 'jpg'
ext: 'jpg',
},
width: 512,
height: 512,
@ -54,7 +54,7 @@ describe('Get file info', () => {
md5: '08189c607bea3b952704676bb3c979e0',
type: {
mime: 'image/apng',
ext: 'apng'
ext: 'apng',
},
width: 256,
height: 256,
@ -72,7 +72,7 @@ describe('Get file info', () => {
md5: '32c47a11555675d9267aee1a86571e7e',
type: {
mime: 'image/gif',
ext: 'gif'
ext: 'gif',
},
width: 256,
height: 256,
@ -90,7 +90,7 @@ describe('Get file info', () => {
md5: 'f73535c3e1e27508885b69b10cf6e991',
type: {
mime: 'image/png',
ext: 'png'
ext: 'png',
},
width: 256,
height: 256,
@ -108,7 +108,7 @@ describe('Get file info', () => {
md5: 'b6f52b4b021e7b92cdd04509c7267965',
type: {
mime: 'image/svg+xml',
ext: 'svg'
ext: 'svg',
},
width: 256,
height: 256,
@ -127,7 +127,7 @@ describe('Get file info', () => {
md5: '4b7a346cde9ccbeb267e812567e33397',
type: {
mime: 'image/svg+xml',
ext: 'svg'
ext: 'svg',
},
width: 256,
height: 256,
@ -145,7 +145,7 @@ describe('Get file info', () => {
md5: '268c5dde99e17cf8fe09f1ab3f97df56',
type: {
mime: 'application/octet-stream', // do not treat as image
ext: null
ext: null,
},
width: 25000,
height: 25000,
@ -163,7 +163,7 @@ describe('Get file info', () => {
md5: '68d5b2d8d1d1acbbce99203e3ec3857e',
type: {
mime: 'image/jpeg',
ext: 'jpg'
ext: 'jpg',
},
width: 512,
height: 256,

View file

@ -11,7 +11,7 @@ export class MockResolver extends Resolver {
public async _register(uri: string, content: string | Record<string, any>, type = 'application/activity+json') {
this._rs.set(uri, {
type,
content: typeof content === 'string' ? content : JSON.stringify(content)
content: typeof content === 'string' ? content : JSON.stringify(content),
});
}
@ -22,9 +22,9 @@ export class MockResolver extends Resolver {
if (!r) {
throw {
name: `StatusError`,
name: 'StatusError',
statusCode: 404,
message: `Not registed for mock`
message: 'Not registed for mock',
};
}

View file

@ -25,7 +25,7 @@ describe('Mute', () => {
it('ミュート作成', async(async () => {
const res = await request('/mute/create', {
userId: carol.id
userId: carol.id,
}, alice);
assert.strictEqual(res.status, 204);
@ -117,7 +117,7 @@ describe('Mute', () => {
const aliceNote = await post(alice);
const carolNote = await post(carol);
const bobNote = await post(bob, {
renoteId: carolNote.id
renoteId: carolNote.id,
});
const res = await request('/notes/local-timeline', {}, alice);

View file

@ -2,8 +2,8 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, uploadFile, startServer, shutdownServer, initTestDb } from './utils.js';
import { Note } from '../src/models/entities/note.js';
import { async, signup, request, post, uploadFile, startServer, shutdownServer, initTestDb } from './utils.js';
describe('Note', () => {
let p: childProcess.ChildProcess;
@ -26,7 +26,7 @@ describe('Note', () => {
it('投稿できる', async(async () => {
const post = {
text: 'test'
text: 'test',
};
const res = await request('/notes/create', post, alice);
@ -40,7 +40,7 @@ describe('Note', () => {
const file = await uploadFile(alice);
const res = await request('/notes/create', {
fileIds: [file.id]
fileIds: [file.id],
}, alice);
assert.strictEqual(res.status, 200);
@ -53,7 +53,7 @@ describe('Note', () => {
const res = await request('/notes/create', {
text: 'test',
fileIds: [file.id]
fileIds: [file.id],
}, alice);
assert.strictEqual(res.status, 200);
@ -64,7 +64,7 @@ describe('Note', () => {
it('存在しないファイルは無視', async(async () => {
const res = await request('/notes/create', {
text: 'test',
fileIds: ['000000000000000000000000']
fileIds: ['000000000000000000000000'],
}, alice);
assert.strictEqual(res.status, 200);
@ -74,19 +74,19 @@ describe('Note', () => {
it('不正なファイルIDで怒られる', async(async () => {
const res = await request('/notes/create', {
fileIds: ['kyoppie']
fileIds: ['kyoppie'],
}, alice);
assert.strictEqual(res.status, 400);
}));
it('返信できる', async(async () => {
const bobPost = await post(bob, {
text: 'foo'
text: 'foo',
});
const alicePost = {
text: 'bar',
replyId: bobPost.id
replyId: bobPost.id,
};
const res = await request('/notes/create', alicePost, alice);
@ -100,11 +100,11 @@ describe('Note', () => {
it('renoteできる', async(async () => {
const bobPost = await post(bob, {
text: 'test'
text: 'test',
});
const alicePost = {
renoteId: bobPost.id
renoteId: bobPost.id,
};
const res = await request('/notes/create', alicePost, alice);
@ -117,12 +117,12 @@ describe('Note', () => {
it('引用renoteできる', async(async () => {
const bobPost = await post(bob, {
text: 'test'
text: 'test',
});
const alicePost = {
text: 'test',
renoteId: bobPost.id
renoteId: bobPost.id,
};
const res = await request('/notes/create', alicePost, alice);
@ -136,7 +136,7 @@ describe('Note', () => {
it('文字数ぎりぎりで怒られない', async(async () => {
const post = {
text: '!'.repeat(500)
text: '!'.repeat(500),
};
const res = await request('/notes/create', post, alice);
assert.strictEqual(res.status, 200);
@ -144,7 +144,7 @@ describe('Note', () => {
it('文字数オーバーで怒られる', async(async () => {
const post = {
text: '!'.repeat(501)
text: '!'.repeat(501),
};
const res = await request('/notes/create', post, alice);
assert.strictEqual(res.status, 400);
@ -153,7 +153,7 @@ describe('Note', () => {
it('存在しないリプライ先で怒られる', async(async () => {
const post = {
text: 'test',
replyId: '000000000000000000000000'
replyId: '000000000000000000000000',
};
const res = await request('/notes/create', post, alice);
assert.strictEqual(res.status, 400);
@ -161,7 +161,7 @@ describe('Note', () => {
it('存在しないrenote対象で怒られる', async(async () => {
const post = {
renoteId: '000000000000000000000000'
renoteId: '000000000000000000000000',
};
const res = await request('/notes/create', post, alice);
assert.strictEqual(res.status, 400);
@ -170,7 +170,7 @@ describe('Note', () => {
it('不正なリプライ先IDで怒られる', async(async () => {
const post = {
text: 'test',
replyId: 'foo'
replyId: 'foo',
};
const res = await request('/notes/create', post, alice);
assert.strictEqual(res.status, 400);
@ -178,7 +178,7 @@ describe('Note', () => {
it('不正なrenote対象IDで怒られる', async(async () => {
const post = {
renoteId: 'foo'
renoteId: 'foo',
};
const res = await request('/notes/create', post, alice);
assert.strictEqual(res.status, 400);
@ -186,7 +186,7 @@ describe('Note', () => {
it('存在しないユーザーにメンションできる', async(async () => {
const post = {
text: '@ghost yo'
text: '@ghost yo',
};
const res = await request('/notes/create', post, alice);
@ -198,7 +198,7 @@ describe('Note', () => {
it('同じユーザーに複数メンションしても内部的にまとめられる', async(async () => {
const post = {
text: '@bob @bob @bob yo'
text: '@bob @bob @bob yo',
};
const res = await request('/notes/create', post, alice);
@ -216,8 +216,8 @@ describe('Note', () => {
const res = await request('/notes/create', {
text: 'test',
poll: {
choices: ['foo', 'bar']
}
choices: ['foo', 'bar'],
},
}, alice);
assert.strictEqual(res.status, 200);
@ -227,7 +227,7 @@ describe('Note', () => {
it('投票の選択肢が無くて怒られる', async(async () => {
const res = await request('/notes/create', {
poll: {}
poll: {},
}, alice);
assert.strictEqual(res.status, 400);
}));
@ -235,8 +235,8 @@ describe('Note', () => {
it('投票の選択肢が無くて怒られる (空の配列)', async(async () => {
const res = await request('/notes/create', {
poll: {
choices: []
}
choices: [],
},
}, alice);
assert.strictEqual(res.status, 400);
}));
@ -244,8 +244,8 @@ describe('Note', () => {
it('投票の選択肢が1つで怒られる', async(async () => {
const res = await request('/notes/create', {
poll: {
choices: ['Strawberry Pasta']
}
choices: ['Strawberry Pasta'],
},
}, alice);
assert.strictEqual(res.status, 400);
}));
@ -254,13 +254,13 @@ describe('Note', () => {
const { body } = await request('/notes/create', {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako']
}
choices: ['sakura', 'izumi', 'ako'],
},
}, alice);
const res = await request('/notes/polls/vote', {
noteId: body.createdNote.id,
choice: 1
choice: 1,
}, alice);
assert.strictEqual(res.status, 204);
@ -270,18 +270,18 @@ describe('Note', () => {
const { body } = await request('/notes/create', {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako']
}
choices: ['sakura', 'izumi', 'ako'],
},
}, alice);
await request('/notes/polls/vote', {
noteId: body.createdNote.id,
choice: 0
choice: 0,
}, alice);
const res = await request('/notes/polls/vote', {
noteId: body.createdNote.id,
choice: 2
choice: 2,
}, alice);
assert.strictEqual(res.status, 400);
@ -292,23 +292,23 @@ describe('Note', () => {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako'],
multiple: true
}
multiple: true,
},
}, alice);
await request('/notes/polls/vote', {
noteId: body.createdNote.id,
choice: 0
choice: 0,
}, alice);
await request('/notes/polls/vote', {
noteId: body.createdNote.id,
choice: 1
choice: 1,
}, alice);
const res = await request('/notes/polls/vote', {
noteId: body.createdNote.id,
choice: 2
choice: 2,
}, alice);
assert.strictEqual(res.status, 204);
@ -319,15 +319,15 @@ describe('Note', () => {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako'],
expiredAfter: 1
}
expiredAfter: 1,
},
}, alice);
await new Promise(x => setTimeout(x, 2));
const res = await request('/notes/polls/vote', {
noteId: body.createdNote.id,
choice: 1
choice: 1,
}, alice);
assert.strictEqual(res.status, 400);
@ -341,11 +341,11 @@ describe('Note', () => {
}, alice);
const replyOneRes = await request('/notes/create', {
text: 'reply one',
replyId: mainNoteRes.body.createdNote.id
replyId: mainNoteRes.body.createdNote.id,
}, alice);
const replyTwoRes = await request('/notes/create', {
text: 'reply two',
replyId: mainNoteRes.body.createdNote.id
replyId: mainNoteRes.body.createdNote.id,
}, alice);
const deleteOneRes = await request('/notes/delete', {
@ -353,7 +353,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(deleteOneRes.status, 204);
let mainNote = await Notes.findOne({id: mainNoteRes.body.createdNote.id});
let mainNote = await Notes.findOne({ id: mainNoteRes.body.createdNote.id });
assert.strictEqual(mainNote.repliesCount, 1);
const deleteTwoRes = await request('/notes/delete', {
@ -361,7 +361,7 @@ describe('Note', () => {
}, alice);
assert.strictEqual(deleteTwoRes.status, 204);
mainNote = await Notes.findOne({id: mainNoteRes.body.createdNote.id});
mainNote = await Notes.findOne({ id: mainNoteRes.body.createdNote.id });
assert.strictEqual(mainNote.repliesCount, 0);
}));
});

View file

@ -6,7 +6,7 @@ describe('url', () => {
const s = query({
foo: 'ふぅ',
bar: 'b a r',
baz: undefined
baz: undefined,
});
assert.deepStrictEqual(s, 'foo=%E3%81%B5%E3%81%85&bar=b%20a%20r');
});

View file

@ -2,8 +2,8 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import * as childProcess from 'child_process';
import { connectStream, signup, request, post, startServer, shutdownServer, initTestDb } from './utils.js';
import { Following } from '../src/models/entities/following.js';
import { connectStream, signup, request, post, startServer, shutdownServer, initTestDb } from './utils.js';
describe('Streaming', () => {
let p: childProcess.ChildProcess;
@ -30,7 +30,7 @@ describe('Streaming', () => {
followerSharedInbox: null,
followeeHost: followee.host,
followeeInbox: null,
followeeSharedInbox: null
followeeSharedInbox: null,
});
};
@ -47,7 +47,7 @@ describe('Streaming', () => {
});
post(alice, {
text: 'foo @bob bar'
text: 'foo @bob bar',
});
}));
@ -55,7 +55,7 @@ describe('Streaming', () => {
const alice = await signup({ username: 'alice' });
const bob = await signup({ username: 'bob' });
const bobNote = await post(bob, {
text: 'foo'
text: 'foo',
});
const ws = await connectStream(bob, 'main', ({ type, body }) => {
@ -67,14 +67,14 @@ describe('Streaming', () => {
});
post(alice, {
renoteId: bobNote.id
renoteId: bobNote.id,
});
}));
describe('Home Timeline', () => {
it('自分の投稿が流れる', () => new Promise(async done => {
const post = {
text: 'foo'
text: 'foo',
};
const me = await signup();
@ -96,7 +96,7 @@ describe('Streaming', () => {
// Alice が Bob をフォロー
await request('/following/create', {
userId: bob.id
userId: bob.id,
}, alice);
const ws = await connectStream(alice, 'homeTimeline', ({ type, body }) => {
@ -108,7 +108,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
}));
@ -125,7 +125,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
setTimeout(() => {
@ -141,7 +141,7 @@ describe('Streaming', () => {
// Alice が Bob をフォロー
await request('/following/create', {
userId: bob.id
userId: bob.id,
}, alice);
const ws = await connectStream(alice, 'homeTimeline', ({ type, body }) => {
@ -157,7 +157,7 @@ describe('Streaming', () => {
post(bob, {
text: 'foo',
visibility: 'specified',
visibleUserIds: [alice.id]
visibleUserIds: [alice.id],
});
}));
@ -168,7 +168,7 @@ describe('Streaming', () => {
// Alice が Bob をフォロー
await request('/following/create', {
userId: bob.id
userId: bob.id,
}, alice);
let fired = false;
@ -183,7 +183,7 @@ describe('Streaming', () => {
post(bob, {
text: 'foo',
visibility: 'specified',
visibleUserIds: [carol.id]
visibleUserIds: [carol.id],
});
setTimeout(() => {
@ -207,7 +207,7 @@ describe('Streaming', () => {
});
post(me, {
text: 'foo'
text: 'foo',
});
}));
@ -224,7 +224,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
}));
@ -241,7 +241,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
setTimeout(() => {
@ -257,7 +257,7 @@ describe('Streaming', () => {
// Alice が Bob をフォロー
await request('/following/create', {
userId: bob.id
userId: bob.id,
}, alice);
let fired = false;
@ -269,7 +269,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
setTimeout(() => {
@ -294,7 +294,7 @@ describe('Streaming', () => {
// ホーム指定
post(bob, {
text: 'foo',
visibility: 'home'
visibility: 'home',
});
setTimeout(() => {
@ -310,7 +310,7 @@ describe('Streaming', () => {
// Alice が Bob をフォロー
await request('/following/create', {
userId: bob.id
userId: bob.id,
}, alice);
let fired = false;
@ -325,7 +325,7 @@ describe('Streaming', () => {
post(bob, {
text: 'foo',
visibility: 'specified',
visibleUserIds: [alice.id]
visibleUserIds: [alice.id],
});
setTimeout(() => {
@ -350,7 +350,7 @@ describe('Streaming', () => {
// フォロワー宛て投稿
post(bob, {
text: 'foo',
visibility: 'followers'
visibility: 'followers',
});
setTimeout(() => {
@ -374,7 +374,7 @@ describe('Streaming', () => {
});
post(me, {
text: 'foo'
text: 'foo',
});
}));
@ -391,7 +391,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
}));
@ -411,7 +411,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
}));
@ -428,7 +428,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
setTimeout(() => {
@ -444,7 +444,7 @@ describe('Streaming', () => {
// Alice が Bob をフォロー
await request('/following/create', {
userId: bob.id
userId: bob.id,
}, alice);
const ws = await connectStream(alice, 'hybridTimeline', ({ type, body }) => {
@ -460,7 +460,7 @@ describe('Streaming', () => {
post(bob, {
text: 'foo',
visibility: 'specified',
visibleUserIds: [alice.id]
visibleUserIds: [alice.id],
});
}));
@ -470,7 +470,7 @@ describe('Streaming', () => {
// Alice が Bob をフォロー
await request('/following/create', {
userId: bob.id
userId: bob.id,
}, alice);
const ws = await connectStream(alice, 'hybridTimeline', ({ type, body }) => {
@ -485,7 +485,7 @@ describe('Streaming', () => {
// ホーム投稿
post(bob, {
text: 'foo',
visibility: 'home'
visibility: 'home',
});
}));
@ -504,7 +504,7 @@ describe('Streaming', () => {
// ホーム投稿
post(bob, {
text: 'foo',
visibility: 'home'
visibility: 'home',
});
setTimeout(() => {
@ -529,7 +529,7 @@ describe('Streaming', () => {
// フォロワー宛て投稿
post(bob, {
text: 'foo',
visibility: 'followers'
visibility: 'followers',
});
setTimeout(() => {
@ -554,7 +554,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
}));
@ -571,7 +571,7 @@ describe('Streaming', () => {
});
post(bob, {
text: 'foo'
text: 'foo',
});
}));
@ -590,7 +590,7 @@ describe('Streaming', () => {
// ホーム投稿
post(bob, {
text: 'foo',
visibility: 'home'
visibility: 'home',
});
setTimeout(() => {
@ -608,13 +608,13 @@ describe('Streaming', () => {
// リスト作成
const list = await request('/users/lists/create', {
name: 'my list'
name: 'my list',
}, alice).then(x => x.body);
// Alice が Bob をリスイン
await request('/users/lists/push', {
listId: list.id,
userId: bob.id
userId: bob.id,
}, alice);
const ws = await connectStream(alice, 'userList', ({ type, body }) => {
@ -624,11 +624,11 @@ describe('Streaming', () => {
done();
}
}, {
listId: list.id
listId: list.id,
});
post(bob, {
text: 'foo'
text: 'foo',
});
}));
@ -638,7 +638,7 @@ describe('Streaming', () => {
// リスト作成
const list = await request('/users/lists/create', {
name: 'my list'
name: 'my list',
}, alice).then(x => x.body);
let fired = false;
@ -648,11 +648,11 @@ describe('Streaming', () => {
fired = true;
}
}, {
listId: list.id
listId: list.id,
});
post(bob, {
text: 'foo'
text: 'foo',
});
setTimeout(() => {
@ -669,13 +669,13 @@ describe('Streaming', () => {
// リスト作成
const list = await request('/users/lists/create', {
name: 'my list'
name: 'my list',
}, alice).then(x => x.body);
// Alice が Bob をリスイン
await request('/users/lists/push', {
listId: list.id,
userId: bob.id
userId: bob.id,
}, alice);
const ws = await connectStream(alice, 'userList', ({ type, body }) => {
@ -686,14 +686,14 @@ describe('Streaming', () => {
done();
}
}, {
listId: list.id
listId: list.id,
});
// Bob が Alice 宛てのダイレクト投稿
post(bob, {
text: 'foo',
visibility: 'specified',
visibleUserIds: [alice.id]
visibleUserIds: [alice.id],
});
}));
@ -704,13 +704,13 @@ describe('Streaming', () => {
// リスト作成
const list = await request('/users/lists/create', {
name: 'my list'
name: 'my list',
}, alice).then(x => x.body);
// Alice が Bob をリスイン
await request('/users/lists/push', {
listId: list.id,
userId: bob.id
userId: bob.id,
}, alice);
let fired = false;
@ -720,13 +720,13 @@ describe('Streaming', () => {
fired = true;
}
}, {
listId: list.id
listId: list.id,
});
// フォロワー宛て投稿
post(bob, {
text: 'foo',
visibility: 'followers'
visibility: 'followers',
});
setTimeout(() => {
@ -749,12 +749,12 @@ describe('Streaming', () => {
}
}, {
q: [
['foo']
]
['foo'],
],
});
post(me, {
text: '#foo'
text: '#foo',
});
}));
@ -773,20 +773,20 @@ describe('Streaming', () => {
}
}, {
q: [
['foo', 'bar']
]
['foo', 'bar'],
],
});
post(me, {
text: '#foo'
text: '#foo',
});
post(me, {
text: '#bar'
text: '#bar',
});
post(me, {
text: '#foo #bar'
text: '#foo #bar',
});
setTimeout(() => {
@ -816,24 +816,24 @@ describe('Streaming', () => {
}, {
q: [
['foo'],
['bar']
]
['bar'],
],
});
post(me, {
text: '#foo'
text: '#foo',
});
post(me, {
text: '#bar'
text: '#bar',
});
post(me, {
text: '#foo #bar'
text: '#foo #bar',
});
post(me, {
text: '#piyo'
text: '#piyo',
});
setTimeout(() => {
@ -866,28 +866,28 @@ describe('Streaming', () => {
}, {
q: [
['foo', 'bar'],
['piyo']
]
['piyo'],
],
});
post(me, {
text: '#foo'
text: '#foo',
});
post(me, {
text: '#bar'
text: '#bar',
});
post(me, {
text: '#foo #bar'
text: '#foo #bar',
});
post(me, {
text: '#piyo'
text: '#piyo',
});
post(me, {
text: '#waaa'
text: '#waaa',
});
setTimeout(() => {

View file

@ -23,13 +23,13 @@ describe('users/notes', () => {
const jpg = await uploadFile(alice, _dirname + '/resources/Lenna.jpg');
const png = await uploadFile(alice, _dirname + '/resources/Lenna.png');
jpgNote = await post(alice, {
fileIds: [jpg.id]
fileIds: [jpg.id],
});
pngNote = await post(alice, {
fileIds: [png.id]
fileIds: [png.id],
});
jpgPngNote = await post(alice, {
fileIds: [jpg.id, png.id]
fileIds: [jpg.id, png.id],
});
});
@ -40,7 +40,7 @@ describe('users/notes', () => {
it('ファイルタイプ指定 (jpg)', async(async () => {
const res = await request('/users/notes', {
userId: alice.id,
fileType: ['image/jpeg']
fileType: ['image/jpeg'],
}, alice);
assert.strictEqual(res.status, 200);
@ -53,7 +53,7 @@ describe('users/notes', () => {
it('ファイルタイプ指定 (jpg or png)', async(async () => {
const res = await request('/users/notes', {
userId: alice.id,
fileType: ['image/jpeg', 'image/png']
fileType: ['image/jpeg', 'image/png'],
}, alice);
assert.strictEqual(res.status, 200);

View file

@ -159,7 +159,7 @@ export function launchServer(callbackSpawnedProcess: (p: childProcess.ChildProce
export async function initTestDb(justBorrow = false, initEntities?: any[]) {
if (process.env.NODE_ENV !== 'test') throw 'NODE_ENV is not a test';
return new DataSource({
const db = new DataSource({
type: 'postgres',
host: config.db.host,
port: config.db.port,
@ -170,6 +170,10 @@ export async function initTestDb(justBorrow = false, initEntities?: any[]) {
dropSchema: true && !justBorrow,
entities: initEntities || entities,
});
await db.initialize();
return db;
}
export function startServer(timeout = 30 * 1000): Promise<childProcess.ChildProcess> {

View file

@ -106,8 +106,8 @@ const props = defineProps({
function onUsernameChange() {
os.api('users/show', {
username: username
}).then(user => {
user = user;
}).then(userResponse => {
user = userResponse;
}, () => {
user = null;
});

View file

@ -52,7 +52,7 @@
</template>
</I18n>
</li>
<li>{{ i18n.ts._2fa.step2 }}<br><img :src="twoFactorData.qr"><p>{{ $ts._2fa.step2Url }}<br>{{ data.url }}</p></li>
<li>{{ i18n.ts._2fa.step2 }}<br><img :src="twoFactorData.qr"><p>{{ $ts._2fa.step2Url }}<br>{{ twoFactorData.url }}</p></li>
<li>
{{ i18n.ts._2fa.step3 }}<br>
<MkInput v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false"><template #label>{{ i18n.ts.token }}</template></MkInput>