Merge branch 'develop' into fix-stl-note-fetch
This commit is contained in:
commit
d3228d5570
|
@ -0,0 +1,40 @@
|
||||||
|
name: "Release Manager: sync changelog with PR"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- release/**
|
||||||
|
paths:
|
||||||
|
- 'CHANGELOG.md'
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
edit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# headがrelease/かつopenのPRを1つ取得
|
||||||
|
- name: Get PR
|
||||||
|
run: |
|
||||||
|
echo "pr_number=$(gh pr list --limit 1 --head "${{ github.ref_name }}" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
|
||||||
|
id: get_pr
|
||||||
|
- name: Get target version
|
||||||
|
uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1
|
||||||
|
id: v
|
||||||
|
# CHANGELOG.mdの内容を取得
|
||||||
|
- name: Get changelog
|
||||||
|
uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v1
|
||||||
|
with:
|
||||||
|
version: ${{ steps.v.outputs.target_version }}
|
||||||
|
id: changelog
|
||||||
|
# PRのnotesを更新
|
||||||
|
- name: Update PR
|
||||||
|
run: |
|
||||||
|
gh pr edit ${{ steps.get_pr.outputs.pr_number }} --body "${{ steps.changelog.outputs.changelog }}"
|
|
@ -0,0 +1,122 @@
|
||||||
|
name: "Release Manager [Dispatch]"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
## Specify the type of the next release.
|
||||||
|
#version_increment_type:
|
||||||
|
# type: choice
|
||||||
|
# description: 'VERSION INCREMENT TYPE'
|
||||||
|
# default: 'patch'
|
||||||
|
# required: false
|
||||||
|
# options:
|
||||||
|
# - 'major'
|
||||||
|
# - 'minor'
|
||||||
|
# - 'patch'
|
||||||
|
merge:
|
||||||
|
type: boolean
|
||||||
|
description: 'MERGE RELEASE BRANCH TO MAIN'
|
||||||
|
default: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
get-pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
pr_number: ${{ steps.get_pr.outputs.pr_number }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# headがrelease/かつopenのPRを1つ取得
|
||||||
|
- name: Get PRs
|
||||||
|
run: |
|
||||||
|
echo "pr_number=$(gh pr list --limit 1 --search "head:release/ is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
|
||||||
|
id: get_pr
|
||||||
|
|
||||||
|
merge:
|
||||||
|
uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v1
|
||||||
|
needs: get-pr
|
||||||
|
if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge == true }}
|
||||||
|
with:
|
||||||
|
pr_number: ${{ needs.get-pr.outputs.pr_number }}
|
||||||
|
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
|
||||||
|
# Text to prepend to the changelog
|
||||||
|
# The first line must be `## Unreleased`
|
||||||
|
changes_template: |
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### General
|
||||||
|
-
|
||||||
|
|
||||||
|
### Client
|
||||||
|
-
|
||||||
|
|
||||||
|
### Server
|
||||||
|
-
|
||||||
|
|
||||||
|
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
|
||||||
|
secrets:
|
||||||
|
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
|
||||||
|
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
||||||
|
RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
|
||||||
|
RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
create-prerelease:
|
||||||
|
uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
|
||||||
|
needs: get-pr
|
||||||
|
if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge != true }}
|
||||||
|
with:
|
||||||
|
pr_number: ${{ needs.get-pr.outputs.pr_number }}
|
||||||
|
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
|
||||||
|
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
|
||||||
|
secrets:
|
||||||
|
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
|
||||||
|
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
create-target:
|
||||||
|
uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v1
|
||||||
|
needs: get-pr
|
||||||
|
if: ${{ needs.get-pr.outputs.pr_number == '' }}
|
||||||
|
with:
|
||||||
|
# The script for version increment.
|
||||||
|
# process.env.CURRENT_VERSION: The current version.
|
||||||
|
#
|
||||||
|
# Misskey calender versioning (yyyy.MM.patch) example
|
||||||
|
version_increment_script: |
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.toLocaleDateString('en-US', { year: 'numeric', timeZone: 'Asia/Tokyo' });
|
||||||
|
const month = now.toLocaleDateString('en-US', { month: 'numeric', timeZone: 'Asia/Tokyo' });
|
||||||
|
const [major, minor, _patch] = process.env.CURRENT_VERSION.split('.');
|
||||||
|
const patch = Number(_patch.split('-')[0]);
|
||||||
|
if (Number.isNaN(patch)) {
|
||||||
|
console.error('Invalid patch version', year, month, process.env.CURRENT_VERSION, major, minor, _patch);
|
||||||
|
throw new Error('Invalid patch version');
|
||||||
|
}
|
||||||
|
if (year !== major || month !== minor) {
|
||||||
|
return `${year}.${month}.0`;
|
||||||
|
} else {
|
||||||
|
return `${major}.${minor}.${patch + 1}`;
|
||||||
|
}
|
||||||
|
##Semver example
|
||||||
|
#version_increment_script: |
|
||||||
|
# const [major, minor, patch] = process.env.CURRENT_VERSION.split('.');
|
||||||
|
# if ("${{ inputs.version_increment_type }}" === "major") {
|
||||||
|
# return `${Number(major) + 1}.0.0`;
|
||||||
|
# } else if ("${{ inputs.version_increment_type }}" === "minor") {
|
||||||
|
# return `${major}.${Number(minor) + 1}.0`;
|
||||||
|
# } else {
|
||||||
|
# return `${major}.${minor}.${Number(patch) + 1}`;
|
||||||
|
# }
|
||||||
|
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
|
||||||
|
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
|
||||||
|
secrets:
|
||||||
|
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
|
||||||
|
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
||||||
|
RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
|
||||||
|
RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
|
|
@ -0,0 +1,38 @@
|
||||||
|
name: "Release Manager: release RC when ready for review"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [ready_for_review]
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
ref: ${{ steps.get_pr.outputs.ref }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# PR情報を取得
|
||||||
|
- name: Get PR
|
||||||
|
run: |
|
||||||
|
pr_json=$(gh pr view ${{ github.event.pull_request.number }} --json isDraft,headRefName)
|
||||||
|
echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
|
||||||
|
id: get_pr
|
||||||
|
release:
|
||||||
|
uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
|
||||||
|
needs: check
|
||||||
|
if: startsWith(needs.check.outputs.ref, 'release/')
|
||||||
|
with:
|
||||||
|
pr_number: ${{ github.event.pull_request.number }}
|
||||||
|
package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
|
||||||
|
use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
|
||||||
|
secrets:
|
||||||
|
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
|
||||||
|
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,18 +1,18 @@
|
||||||
<!--
|
## Unreleased
|
||||||
## 202x.x.x (unreleased)
|
|
||||||
|
|
||||||
### General
|
### General
|
||||||
-
|
-
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
-
|
- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
|
||||||
|
- Enhance: リアクション・いいねの総数を表示するように
|
||||||
|
- Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
|
||||||
|
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
-
|
-
|
||||||
|
|
||||||
-->
|
## 2024.3.1
|
||||||
|
|
||||||
## 2024.3.1 (unreleased)
|
|
||||||
|
|
||||||
### General
|
### General
|
||||||
-
|
-
|
||||||
|
|
|
@ -316,6 +316,98 @@ export const handlers = [
|
||||||
|
|
||||||
Don't forget to re-run the `.storybook/generate.js` script after adding, editing, or removing the above files.
|
Don't forget to re-run the `.storybook/generate.js` script after adding, editing, or removing the above files.
|
||||||
|
|
||||||
|
## Nest
|
||||||
|
|
||||||
|
### Nest Service Circular dependency / Nestでサービスの循環参照でエラーが起きた場合
|
||||||
|
|
||||||
|
#### forwardRef
|
||||||
|
まずは簡単に`forwardRef`を試してみる
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export class FooService {
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => BarService))
|
||||||
|
private barService: BarService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### OnModuleInit
|
||||||
|
できなければ`OnModuleInit`を使う
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { ModuleRef } from '@nestjs/core';
|
||||||
|
import { BarService } from '@/core/BarService';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FooService implements OnModuleInit {
|
||||||
|
private barService: BarService // constructorから移動してくる
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private moduleRef: ModuleRef,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
async onModuleInit() {
|
||||||
|
this.barService = this.moduleRef.get(BarService.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async niceMethod() {
|
||||||
|
return await this.barService.incredibleMethod({ hoge: 'fuga' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Service Unit Test
|
||||||
|
テストで`onModuleInit`を呼び出す必要がある
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// import ...
|
||||||
|
|
||||||
|
describe('test', () => {
|
||||||
|
let app: TestingModule;
|
||||||
|
let fooService: FooService; // for test case
|
||||||
|
let barService: BarService; // for test case
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = await Test.createTestingModule({
|
||||||
|
imports: ...,
|
||||||
|
providers: [
|
||||||
|
FooService,
|
||||||
|
{ // mockする (mockは必須ではないかもしれない)
|
||||||
|
provide: BarService,
|
||||||
|
useFactory: () => ({
|
||||||
|
incredibleMethod: jest.fn(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{ // Provideにする
|
||||||
|
provide: BarService.name,
|
||||||
|
useExisting: BarService,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.useMocker(...
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
fooService = app.get<FooService>(FooService);
|
||||||
|
barService = app.get<BarService>(BarService) as jest.Mocked<BarService>;
|
||||||
|
|
||||||
|
// onModuleInitを実行する
|
||||||
|
await fooService.onModuleInit();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('nice', () => {
|
||||||
|
await fooService.niceMethod();
|
||||||
|
|
||||||
|
expect(barService.incredibleMethod).toHaveBeenCalled();
|
||||||
|
expect(barService.incredibleMethod.mock.lastCall![0])
|
||||||
|
.toEqual({ hoge: 'fuga' });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
### Misskeyのドメイン固有の概念は`Mi`をprefixする
|
### Misskeyのドメイン固有の概念は`Mi`をprefixする
|
||||||
|
|
41
README.md
41
README.md
|
@ -1,9 +1,11 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://misskey-hub.net">
|
<a href="https://misskey-hub.net">
|
||||||
<img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="400"/>
|
<img src="./assets/title_float.svg" alt="Misskey logo" style="border-radius:50%" width="300"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀**
|
**🌎 **Misskey** is an open source, federated social media platform that's free forever! 🚀**
|
||||||
|
|
||||||
|
[Learn more](https://misskey-hub.net/)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -22,41 +24,6 @@
|
||||||
<a href="https://www.patreon.com/syuilo">
|
<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>
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[![codecov](https://codecov.io/gh/misskey-dev/misskey/branch/develop/graph/badge.svg?token=R6IQZ3QJOL)](https://codecov.io/gh/misskey-dev/misskey)
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<a href="https://xn--931a.moe/"><img src="https://github.com/misskey-dev/misskey/blob/develop/assets/ai.png?raw=true" align="right" height="320px"/></a>
|
|
||||||
|
|
||||||
## ✨ Features
|
|
||||||
- **ActivityPub support**\
|
|
||||||
Not on Misskey? No problem! Not only can Misskey instances talk to each other, but you can make friends with people on other networks like Mastodon and Pixelfed!
|
|
||||||
- **Reactions**\
|
|
||||||
You can add emoji reactions to any post! No longer are you bound by a like button, show everyone exactly how you feel with the tap of a button.
|
|
||||||
- **Drive**\
|
|
||||||
With Misskey's built in drive, you get cloud storage right in your social media, where you can upload any files, make folders, and find media from posts you've made!
|
|
||||||
- **Rich Web UI**\
|
|
||||||
Misskey has a rich and easy to use Web UI!
|
|
||||||
It is highly customizable, from changing the layout and adding widgets to making custom themes.
|
|
||||||
Furthermore, plugins can be created using AiScript, an original programming language.
|
|
||||||
- And much more...
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="clear: both;"></div>
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Misskey Documentation can be found at [Misskey Hub](https://misskey-hub.net/docs/), some of the links and graphics above also lead to specific portions of it.
|
|
||||||
|
|
||||||
## Sponsors
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<a class="rss3" title="RSS3" href="https://rss3.io/" target="_blank"><img src="https://rss3.mypinata.cloud/ipfs/QmUG6H3Z7D5P511shn7sB4CPmpjH5uZWu4m5mWX7U3Gqbu" alt="RSS3" height="60"></a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
|
@ -8909,6 +8909,10 @@ export interface Locale extends ILocale {
|
||||||
* {n}人がリアクションしました
|
* {n}人がリアクションしました
|
||||||
*/
|
*/
|
||||||
"reactedBySomeUsers": ParameterizedString<"n">;
|
"reactedBySomeUsers": ParameterizedString<"n">;
|
||||||
|
/**
|
||||||
|
* {n}人がいいねしました
|
||||||
|
*/
|
||||||
|
"likedBySomeUsers": ParameterizedString<"n">;
|
||||||
/**
|
/**
|
||||||
* {n}人がリノートしました
|
* {n}人がリノートしました
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2355,6 +2355,7 @@ _notification:
|
||||||
sendTestNotification: "テスト通知を送信する"
|
sendTestNotification: "テスト通知を送信する"
|
||||||
notificationWillBeDisplayedLikeThis: "通知はこのように表示されます"
|
notificationWillBeDisplayedLikeThis: "通知はこのように表示されます"
|
||||||
reactedBySomeUsers: "{n}人がリアクションしました"
|
reactedBySomeUsers: "{n}人がリアクションしました"
|
||||||
|
likedBySomeUsers: "{n}人がいいねしました"
|
||||||
renotedBySomeUsers: "{n}人がリノートしました"
|
renotedBySomeUsers: "{n}人がリノートしました"
|
||||||
followedBySomeUsers: "{n}人にフォローされました"
|
followedBySomeUsers: "{n}人にフォローされました"
|
||||||
flushNotification: "通知の履歴をリセットする"
|
flushNotification: "通知の履歴をリセットする"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2024.3.0",
|
"version": "2024.3.1",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -51,21 +51,35 @@ export class FetchInstanceMetadataService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async tryLock(host: string): Promise<boolean> {
|
// public for test
|
||||||
const mutex = await this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '1', 'GET');
|
public async tryLock(host: string): Promise<string | null> {
|
||||||
return mutex !== '1';
|
// TODO: マイグレーションなのであとで消す (2024.3.1)
|
||||||
|
this.redisClient.del(`fetchInstanceMetadata:mutex:${host}`);
|
||||||
|
|
||||||
|
return await this.redisClient.set(
|
||||||
|
`fetchInstanceMetadata:mutex:v2:${host}`, '1',
|
||||||
|
'EX', 30, // 30秒したら自動でロック解除 https://github.com/misskey-dev/misskey/issues/13506#issuecomment-1975375395
|
||||||
|
'GET' // 古い値を返す(なかったらnull)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public unlock(host: string): Promise<'OK'> {
|
// public for test
|
||||||
return this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '0');
|
public unlock(host: string): Promise<number> {
|
||||||
|
return this.redisClient.del(`fetchInstanceMetadata:mutex:v2:${host}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise<void> {
|
public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise<void> {
|
||||||
const host = instance.host;
|
const host = instance.host;
|
||||||
// Acquire mutex to ensure no parallel runs
|
|
||||||
if (!await this.tryLock(host)) return;
|
// finallyでunlockされてしまうのでtry内でロックチェックをしない
|
||||||
|
// (returnであってもfinallyは実行される)
|
||||||
|
if (!force && await this.tryLock(host) === '1') {
|
||||||
|
// 1が返ってきていたらロックされているという意味なので、何もしない
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
const _instance = await this.federatedInstanceService.fetch(host);
|
const _instance = await this.federatedInstanceService.fetch(host);
|
||||||
|
|
|
@ -248,7 +248,7 @@ export class DriveFileEntityService {
|
||||||
folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
|
folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
|
||||||
detail: true,
|
detail: true,
|
||||||
}) : null,
|
}) : null,
|
||||||
userId: opts.withUser ? file.userId : null,
|
userId: file.userId,
|
||||||
user: (opts.withUser && file.userId) ? this.userEntityService.pack(file.userId) : null,
|
user: (opts.withUser && file.userId) ? this.userEntityService.pack(file.userId) : null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -333,6 +333,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
|
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
|
||||||
renoteCount: note.renoteCount,
|
renoteCount: note.renoteCount,
|
||||||
repliesCount: note.repliesCount,
|
repliesCount: note.repliesCount,
|
||||||
|
reactionCount: Object.values(note.reactions).reduce((a, b) => a + b, 0),
|
||||||
reactions: this.reactionService.convertLegacyReactions(note.reactions),
|
reactions: this.reactionService.convertLegacyReactions(note.reactions),
|
||||||
reactionEmojis: this.customEmojiService.populateEmojis(reactionEmojiNames, host),
|
reactionEmojis: this.customEmojiService.populateEmojis(reactionEmojiNames, host),
|
||||||
reactionAndUserPairCache: opts.withReactionAndUserPairCache ? note.reactionAndUserPairCache : undefined,
|
reactionAndUserPairCache: opts.withReactionAndUserPairCache ? note.reactionAndUserPairCache : undefined,
|
||||||
|
|
|
@ -223,6 +223,10 @@ export const packedNoteSchema = {
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
reactionCount: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
renoteCount: {
|
renoteCount: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -86,8 +86,8 @@
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Script
|
//#region Script
|
||||||
function importAppScript() {
|
async function importAppScript() {
|
||||||
import(`/vite/${CLIENT_ENTRY}`)
|
await import(`/vite/${CLIENT_ENTRY}`)
|
||||||
.catch(async e => {
|
.catch(async e => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
renderError('APP_IMPORT', e);
|
renderError('APP_IMPORT', e);
|
||||||
|
|
|
@ -187,7 +187,7 @@ describe('2要素認証', () => {
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
test('が設定でき、OTPでログインできる。', async () => {
|
test('が設定でき、OTPでログインできる。', async () => {
|
||||||
const registerResponse = await api('/i/2fa/register', {
|
const registerResponse = await api('i/2fa/register', {
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(registerResponse.status, 200);
|
assert.strictEqual(registerResponse.status, 200);
|
||||||
|
@ -197,18 +197,18 @@ describe('2要素認証', () => {
|
||||||
assert.strictEqual(registerResponse.body.label, username);
|
assert.strictEqual(registerResponse.body.label, username);
|
||||||
assert.strictEqual(registerResponse.body.issuer, config.host);
|
assert.strictEqual(registerResponse.body.issuer, config.host);
|
||||||
|
|
||||||
const doneResponse = await api('/i/2fa/done', {
|
const doneResponse = await api('i/2fa/done', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(doneResponse.status, 200);
|
assert.strictEqual(doneResponse.status, 200);
|
||||||
|
|
||||||
const usersShowResponse = await api('/users/show', {
|
const usersShowResponse = await api('users/show', {
|
||||||
username,
|
username,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(usersShowResponse.status, 200);
|
assert.strictEqual(usersShowResponse.status, 200);
|
||||||
assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
|
assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
|
||||||
|
|
||||||
const signinResponse = await api('/signin', {
|
const signinResponse = await api('signin', {
|
||||||
...signinParam(),
|
...signinParam(),
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
});
|
});
|
||||||
|
@ -216,24 +216,24 @@ describe('2要素認証', () => {
|
||||||
assert.notEqual(signinResponse.body.i, undefined);
|
assert.notEqual(signinResponse.body.i, undefined);
|
||||||
|
|
||||||
// 後片付け
|
// 後片付け
|
||||||
await api('/i/2fa/unregister', {
|
await api('i/2fa/unregister', {
|
||||||
password,
|
password,
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('が設定でき、セキュリティキーでログインできる。', async () => {
|
test('が設定でき、セキュリティキーでログインできる。', async () => {
|
||||||
const registerResponse = await api('/i/2fa/register', {
|
const registerResponse = await api('i/2fa/register', {
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(registerResponse.status, 200);
|
assert.strictEqual(registerResponse.status, 200);
|
||||||
|
|
||||||
const doneResponse = await api('/i/2fa/done', {
|
const doneResponse = await api('i/2fa/done', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(doneResponse.status, 200);
|
assert.strictEqual(doneResponse.status, 200);
|
||||||
|
|
||||||
const registerKeyResponse = await api('/i/2fa/register-key', {
|
const registerKeyResponse = await api('i/2fa/register-key', {
|
||||||
password,
|
password,
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -243,23 +243,23 @@ describe('2要素認証', () => {
|
||||||
|
|
||||||
const keyName = 'example-key';
|
const keyName = 'example-key';
|
||||||
const credentialId = crypto.randomBytes(0x41);
|
const credentialId = crypto.randomBytes(0x41);
|
||||||
const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
|
const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
keyName,
|
keyName,
|
||||||
credentialId,
|
credentialId,
|
||||||
creationOptions: registerKeyResponse.body,
|
creationOptions: registerKeyResponse.body,
|
||||||
}), alice);
|
}) as any, alice);
|
||||||
assert.strictEqual(keyDoneResponse.status, 200);
|
assert.strictEqual(keyDoneResponse.status, 200);
|
||||||
assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url'));
|
assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url'));
|
||||||
assert.strictEqual(keyDoneResponse.body.name, keyName);
|
assert.strictEqual(keyDoneResponse.body.name, keyName);
|
||||||
|
|
||||||
const usersShowResponse = await api('/users/show', {
|
const usersShowResponse = await api('users/show', {
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
assert.strictEqual(usersShowResponse.status, 200);
|
assert.strictEqual(usersShowResponse.status, 200);
|
||||||
assert.strictEqual(usersShowResponse.body.securityKeys, true);
|
assert.strictEqual(usersShowResponse.body.securityKeys, true);
|
||||||
|
|
||||||
const signinResponse = await api('/signin', {
|
const signinResponse = await api('signin', {
|
||||||
...signinParam(),
|
...signinParam(),
|
||||||
});
|
});
|
||||||
assert.strictEqual(signinResponse.status, 200);
|
assert.strictEqual(signinResponse.status, 200);
|
||||||
|
@ -268,7 +268,7 @@ describe('2要素認証', () => {
|
||||||
assert.notEqual(signinResponse.body.allowCredentials, undefined);
|
assert.notEqual(signinResponse.body.allowCredentials, undefined);
|
||||||
assert.strictEqual(signinResponse.body.allowCredentials[0].id, credentialId.toString('base64url'));
|
assert.strictEqual(signinResponse.body.allowCredentials[0].id, credentialId.toString('base64url'));
|
||||||
|
|
||||||
const signinResponse2 = await api('/signin', signinWithSecurityKeyParam({
|
const signinResponse2 = await api('signin', signinWithSecurityKeyParam({
|
||||||
keyName,
|
keyName,
|
||||||
credentialId,
|
credentialId,
|
||||||
requestOptions: signinResponse.body,
|
requestOptions: signinResponse.body,
|
||||||
|
@ -277,24 +277,24 @@ describe('2要素認証', () => {
|
||||||
assert.notEqual(signinResponse2.body.i, undefined);
|
assert.notEqual(signinResponse2.body.i, undefined);
|
||||||
|
|
||||||
// 後片付け
|
// 後片付け
|
||||||
await api('/i/2fa/unregister', {
|
await api('i/2fa/unregister', {
|
||||||
password,
|
password,
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('が設定でき、セキュリティキーでパスワードレスログインできる。', async () => {
|
test('が設定でき、セキュリティキーでパスワードレスログインできる。', async () => {
|
||||||
const registerResponse = await api('/i/2fa/register', {
|
const registerResponse = await api('i/2fa/register', {
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(registerResponse.status, 200);
|
assert.strictEqual(registerResponse.status, 200);
|
||||||
|
|
||||||
const doneResponse = await api('/i/2fa/done', {
|
const doneResponse = await api('i/2fa/done', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(doneResponse.status, 200);
|
assert.strictEqual(doneResponse.status, 200);
|
||||||
|
|
||||||
const registerKeyResponse = await api('/i/2fa/register-key', {
|
const registerKeyResponse = await api('i/2fa/register-key', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -302,33 +302,33 @@ describe('2要素認証', () => {
|
||||||
|
|
||||||
const keyName = 'example-key';
|
const keyName = 'example-key';
|
||||||
const credentialId = crypto.randomBytes(0x41);
|
const credentialId = crypto.randomBytes(0x41);
|
||||||
const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
|
const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
keyName,
|
keyName,
|
||||||
credentialId,
|
credentialId,
|
||||||
creationOptions: registerKeyResponse.body,
|
creationOptions: registerKeyResponse.body,
|
||||||
}), alice);
|
}) as any, alice);
|
||||||
assert.strictEqual(keyDoneResponse.status, 200);
|
assert.strictEqual(keyDoneResponse.status, 200);
|
||||||
|
|
||||||
const passwordLessResponse = await api('/i/2fa/password-less', {
|
const passwordLessResponse = await api('i/2fa/password-less', {
|
||||||
value: true,
|
value: true,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(passwordLessResponse.status, 204);
|
assert.strictEqual(passwordLessResponse.status, 204);
|
||||||
|
|
||||||
const usersShowResponse = await api('/users/show', {
|
const usersShowResponse = await api('users/show', {
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
assert.strictEqual(usersShowResponse.status, 200);
|
assert.strictEqual(usersShowResponse.status, 200);
|
||||||
assert.strictEqual(usersShowResponse.body.usePasswordLessLogin, true);
|
assert.strictEqual(usersShowResponse.body.usePasswordLessLogin, true);
|
||||||
|
|
||||||
const signinResponse = await api('/signin', {
|
const signinResponse = await api('signin', {
|
||||||
...signinParam(),
|
...signinParam(),
|
||||||
password: '',
|
password: '',
|
||||||
});
|
});
|
||||||
assert.strictEqual(signinResponse.status, 200);
|
assert.strictEqual(signinResponse.status, 200);
|
||||||
assert.strictEqual(signinResponse.body.i, undefined);
|
assert.strictEqual(signinResponse.body.i, undefined);
|
||||||
|
|
||||||
const signinResponse2 = await api('/signin', {
|
const signinResponse2 = await api('signin', {
|
||||||
...signinWithSecurityKeyParam({
|
...signinWithSecurityKeyParam({
|
||||||
keyName,
|
keyName,
|
||||||
credentialId,
|
credentialId,
|
||||||
|
@ -340,24 +340,24 @@ describe('2要素認証', () => {
|
||||||
assert.notEqual(signinResponse2.body.i, undefined);
|
assert.notEqual(signinResponse2.body.i, undefined);
|
||||||
|
|
||||||
// 後片付け
|
// 後片付け
|
||||||
await api('/i/2fa/unregister', {
|
await api('i/2fa/unregister', {
|
||||||
password,
|
password,
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('が設定でき、設定したセキュリティキーの名前を変更できる。', async () => {
|
test('が設定でき、設定したセキュリティキーの名前を変更できる。', async () => {
|
||||||
const registerResponse = await api('/i/2fa/register', {
|
const registerResponse = await api('i/2fa/register', {
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(registerResponse.status, 200);
|
assert.strictEqual(registerResponse.status, 200);
|
||||||
|
|
||||||
const doneResponse = await api('/i/2fa/done', {
|
const doneResponse = await api('i/2fa/done', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(doneResponse.status, 200);
|
assert.strictEqual(doneResponse.status, 200);
|
||||||
|
|
||||||
const registerKeyResponse = await api('/i/2fa/register-key', {
|
const registerKeyResponse = await api('i/2fa/register-key', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -365,22 +365,22 @@ describe('2要素認証', () => {
|
||||||
|
|
||||||
const keyName = 'example-key';
|
const keyName = 'example-key';
|
||||||
const credentialId = crypto.randomBytes(0x41);
|
const credentialId = crypto.randomBytes(0x41);
|
||||||
const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
|
const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
keyName,
|
keyName,
|
||||||
credentialId,
|
credentialId,
|
||||||
creationOptions: registerKeyResponse.body,
|
creationOptions: registerKeyResponse.body,
|
||||||
}), alice);
|
}) as any, alice);
|
||||||
assert.strictEqual(keyDoneResponse.status, 200);
|
assert.strictEqual(keyDoneResponse.status, 200);
|
||||||
|
|
||||||
const renamedKey = 'other-key';
|
const renamedKey = 'other-key';
|
||||||
const updateKeyResponse = await api('/i/2fa/update-key', {
|
const updateKeyResponse = await api('i/2fa/update-key', {
|
||||||
name: renamedKey,
|
name: renamedKey,
|
||||||
credentialId: credentialId.toString('base64url'),
|
credentialId: credentialId.toString('base64url'),
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(updateKeyResponse.status, 200);
|
assert.strictEqual(updateKeyResponse.status, 200);
|
||||||
|
|
||||||
const iResponse = await api('/i', {
|
const iResponse = await api('i', {
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(iResponse.status, 200);
|
assert.strictEqual(iResponse.status, 200);
|
||||||
const securityKeys = iResponse.body.securityKeysList.filter((s: { id: string; }) => s.id === credentialId.toString('base64url'));
|
const securityKeys = iResponse.body.securityKeysList.filter((s: { id: string; }) => s.id === credentialId.toString('base64url'));
|
||||||
|
@ -389,24 +389,24 @@ describe('2要素認証', () => {
|
||||||
assert.notEqual(securityKeys[0].lastUsed, undefined);
|
assert.notEqual(securityKeys[0].lastUsed, undefined);
|
||||||
|
|
||||||
// 後片付け
|
// 後片付け
|
||||||
await api('/i/2fa/unregister', {
|
await api('i/2fa/unregister', {
|
||||||
password,
|
password,
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('が設定でき、設定したセキュリティキーを削除できる。', async () => {
|
test('が設定でき、設定したセキュリティキーを削除できる。', async () => {
|
||||||
const registerResponse = await api('/i/2fa/register', {
|
const registerResponse = await api('i/2fa/register', {
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(registerResponse.status, 200);
|
assert.strictEqual(registerResponse.status, 200);
|
||||||
|
|
||||||
const doneResponse = await api('/i/2fa/done', {
|
const doneResponse = await api('i/2fa/done', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(doneResponse.status, 200);
|
assert.strictEqual(doneResponse.status, 200);
|
||||||
|
|
||||||
const registerKeyResponse = await api('/i/2fa/register-key', {
|
const registerKeyResponse = await api('i/2fa/register-key', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -414,20 +414,20 @@ describe('2要素認証', () => {
|
||||||
|
|
||||||
const keyName = 'example-key';
|
const keyName = 'example-key';
|
||||||
const credentialId = crypto.randomBytes(0x41);
|
const credentialId = crypto.randomBytes(0x41);
|
||||||
const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
|
const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
keyName,
|
keyName,
|
||||||
credentialId,
|
credentialId,
|
||||||
creationOptions: registerKeyResponse.body,
|
creationOptions: registerKeyResponse.body,
|
||||||
}), alice);
|
}) as any, alice);
|
||||||
assert.strictEqual(keyDoneResponse.status, 200);
|
assert.strictEqual(keyDoneResponse.status, 200);
|
||||||
|
|
||||||
// テストの実行順によっては複数残ってるので全部消す
|
// テストの実行順によっては複数残ってるので全部消す
|
||||||
const iResponse = await api('/i', {
|
const iResponse = await api('i', {
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(iResponse.status, 200);
|
assert.strictEqual(iResponse.status, 200);
|
||||||
for (const key of iResponse.body.securityKeysList) {
|
for (const key of iResponse.body.securityKeysList) {
|
||||||
const removeKeyResponse = await api('/i/2fa/remove-key', {
|
const removeKeyResponse = await api('i/2fa/remove-key', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
password,
|
password,
|
||||||
credentialId: key.id,
|
credentialId: key.id,
|
||||||
|
@ -435,13 +435,13 @@ describe('2要素認証', () => {
|
||||||
assert.strictEqual(removeKeyResponse.status, 200);
|
assert.strictEqual(removeKeyResponse.status, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
const usersShowResponse = await api('/users/show', {
|
const usersShowResponse = await api('users/show', {
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
assert.strictEqual(usersShowResponse.status, 200);
|
assert.strictEqual(usersShowResponse.status, 200);
|
||||||
assert.strictEqual(usersShowResponse.body.securityKeys, false);
|
assert.strictEqual(usersShowResponse.body.securityKeys, false);
|
||||||
|
|
||||||
const signinResponse = await api('/signin', {
|
const signinResponse = await api('signin', {
|
||||||
...signinParam(),
|
...signinParam(),
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
});
|
});
|
||||||
|
@ -449,43 +449,43 @@ describe('2要素認証', () => {
|
||||||
assert.notEqual(signinResponse.body.i, undefined);
|
assert.notEqual(signinResponse.body.i, undefined);
|
||||||
|
|
||||||
// 後片付け
|
// 後片付け
|
||||||
await api('/i/2fa/unregister', {
|
await api('i/2fa/unregister', {
|
||||||
password,
|
password,
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('が設定でき、設定解除できる。(パスワードのみでログインできる。)', async () => {
|
test('が設定でき、設定解除できる。(パスワードのみでログインできる。)', async () => {
|
||||||
const registerResponse = await api('/i/2fa/register', {
|
const registerResponse = await api('i/2fa/register', {
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(registerResponse.status, 200);
|
assert.strictEqual(registerResponse.status, 200);
|
||||||
|
|
||||||
const doneResponse = await api('/i/2fa/done', {
|
const doneResponse = await api('i/2fa/done', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(doneResponse.status, 200);
|
assert.strictEqual(doneResponse.status, 200);
|
||||||
|
|
||||||
const usersShowResponse = await api('/users/show', {
|
const usersShowResponse = await api('users/show', {
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
assert.strictEqual(usersShowResponse.status, 200);
|
assert.strictEqual(usersShowResponse.status, 200);
|
||||||
assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
|
assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
|
||||||
|
|
||||||
const unregisterResponse = await api('/i/2fa/unregister', {
|
const unregisterResponse = await api('i/2fa/unregister', {
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
password,
|
password,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(unregisterResponse.status, 204);
|
assert.strictEqual(unregisterResponse.status, 204);
|
||||||
|
|
||||||
const signinResponse = await api('/signin', {
|
const signinResponse = await api('signin', {
|
||||||
...signinParam(),
|
...signinParam(),
|
||||||
});
|
});
|
||||||
assert.strictEqual(signinResponse.status, 200);
|
assert.strictEqual(signinResponse.status, 200);
|
||||||
assert.notEqual(signinResponse.body.i, undefined);
|
assert.notEqual(signinResponse.body.i, undefined);
|
||||||
|
|
||||||
// 後片付け
|
// 後片付け
|
||||||
await api('/i/2fa/unregister', {
|
await api('i/2fa/unregister', {
|
||||||
password,
|
password,
|
||||||
token: otpToken(registerResponse.body.secret),
|
token: otpToken(registerResponse.body.secret),
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
|
@ -7,7 +7,6 @@ process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
|
||||||
import {
|
import {
|
||||||
api,
|
api,
|
||||||
failedApiCall,
|
failedApiCall,
|
||||||
|
@ -29,10 +28,7 @@ describe('アンテナ', () => {
|
||||||
// エンティティとしてのアンテナを主眼においたテストを記述する
|
// エンティティとしてのアンテナを主眼においたテストを記述する
|
||||||
// (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからノートを取得するエンドポイントをテストする)
|
// (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからノートを取得するエンドポイントをテストする)
|
||||||
|
|
||||||
// BUG misskey-jsとjson-schemaが一致していない。
|
type Antenna = misskey.entities.Antenna;
|
||||||
// - srcのenumにgroupが残っている
|
|
||||||
// - userGroupIdが残っている, isActiveがない
|
|
||||||
type Antenna = misskey.entities.Antenna | Packed<'Antenna'>;
|
|
||||||
type User = misskey.entities.SignupResponse;
|
type User = misskey.entities.SignupResponse;
|
||||||
type Note = misskey.entities.Note;
|
type Note = misskey.entities.Note;
|
||||||
|
|
||||||
|
@ -80,7 +76,7 @@ describe('アンテナ', () => {
|
||||||
aliceList = await userList(alice, {});
|
aliceList = await userList(alice, {});
|
||||||
bob = await signup({ username: 'bob' });
|
bob = await signup({ username: 'bob' });
|
||||||
aliceList = await userList(alice, {});
|
aliceList = await userList(alice, {});
|
||||||
bobFile = (await uploadFile(bob)).body;
|
bobFile = (await uploadFile(bob)).body!;
|
||||||
bobList = await userList(bob);
|
bobList = await userList(bob);
|
||||||
carol = await signup({ username: 'carol' });
|
carol = await signup({ username: 'carol' });
|
||||||
await api('users/lists/push', { listId: aliceList.id, userId: bob.id }, alice);
|
await api('users/lists/push', { listId: aliceList.id, userId: bob.id }, alice);
|
||||||
|
@ -129,9 +125,9 @@ describe('アンテナ', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
// テスト間で影響し合わないように毎回全部消す。
|
// テスト間で影響し合わないように毎回全部消す。
|
||||||
for (const user of [alice, bob]) {
|
for (const user of [alice, bob]) {
|
||||||
const list = await api('/antennas/list', {}, user);
|
const list = await api('antennas/list', {}, user);
|
||||||
for (const antenna of list.body) {
|
for (const antenna of list.body) {
|
||||||
await api('/antennas/delete', { antennaId: antenna.id }, user);
|
await api('antennas/delete', { antennaId: antenna.id }, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -141,11 +137,11 @@ describe('アンテナ', () => {
|
||||||
test('が作成できること、キーが過不足なく入っていること。', async () => {
|
test('が作成できること、キーが過不足なく入っていること。', async () => {
|
||||||
const response = await successfulApiCall({
|
const response = await successfulApiCall({
|
||||||
endpoint: 'antennas/create',
|
endpoint: 'antennas/create',
|
||||||
parameters: { ...defaultParam },
|
parameters: defaultParam,
|
||||||
user: alice,
|
user: alice,
|
||||||
});
|
});
|
||||||
assert.match(response.id, /[0-9a-z]{10}/);
|
assert.match(response.id, /[0-9a-z]{10}/);
|
||||||
const expected = {
|
const expected: Antenna = {
|
||||||
id: response.id,
|
id: response.id,
|
||||||
caseSensitive: false,
|
caseSensitive: false,
|
||||||
createdAt: new Date(response.createdAt).toISOString(),
|
createdAt: new Date(response.createdAt).toISOString(),
|
||||||
|
@ -161,7 +157,7 @@ describe('アンテナ', () => {
|
||||||
withFile: false,
|
withFile: false,
|
||||||
withReplies: false,
|
withReplies: false,
|
||||||
localOnly: false,
|
localOnly: false,
|
||||||
} as Antenna;
|
};
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -202,27 +198,27 @@ describe('アンテナ', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const antennaParamPattern = [
|
const antennaParamPattern = [
|
||||||
{ parameters: (): object => ({ name: 'x'.repeat(100) }) },
|
{ parameters: () => ({ name: 'x'.repeat(100) }) },
|
||||||
{ parameters: (): object => ({ name: 'x' }) },
|
{ parameters: () => ({ name: 'x' }) },
|
||||||
{ parameters: (): object => ({ src: 'home' }) },
|
{ parameters: () => ({ src: 'home' as const }) },
|
||||||
{ parameters: (): object => ({ src: 'all' }) },
|
{ parameters: () => ({ src: 'all' as const }) },
|
||||||
{ parameters: (): object => ({ src: 'users' }) },
|
{ parameters: () => ({ src: 'users' as const }) },
|
||||||
{ parameters: (): object => ({ src: 'list' }) },
|
{ parameters: () => ({ src: 'list' as const }) },
|
||||||
{ parameters: (): object => ({ userListId: null }) },
|
{ parameters: () => ({ userListId: null }) },
|
||||||
{ parameters: (): object => ({ src: 'list', userListId: aliceList.id }) },
|
{ parameters: () => ({ src: 'list' as const, userListId: aliceList.id }) },
|
||||||
{ parameters: (): object => ({ keywords: [['x']] }) },
|
{ parameters: () => ({ keywords: [['x']] }) },
|
||||||
{ parameters: (): object => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
|
{ parameters: () => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
|
||||||
{ parameters: (): object => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
|
{ parameters: () => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
|
||||||
{ parameters: (): object => ({ users: [alice.username] }) },
|
{ parameters: () => ({ users: [alice.username] }) },
|
||||||
{ parameters: (): object => ({ users: [alice.username, bob.username, carol.username] }) },
|
{ parameters: () => ({ users: [alice.username, bob.username, carol.username] }) },
|
||||||
{ parameters: (): object => ({ caseSensitive: false }) },
|
{ parameters: () => ({ caseSensitive: false }) },
|
||||||
{ parameters: (): object => ({ caseSensitive: true }) },
|
{ parameters: () => ({ caseSensitive: true }) },
|
||||||
{ parameters: (): object => ({ withReplies: false }) },
|
{ parameters: () => ({ withReplies: false }) },
|
||||||
{ parameters: (): object => ({ withReplies: true }) },
|
{ parameters: () => ({ withReplies: true }) },
|
||||||
{ parameters: (): object => ({ withFile: false }) },
|
{ parameters: () => ({ withFile: false }) },
|
||||||
{ parameters: (): object => ({ withFile: true }) },
|
{ parameters: () => ({ withFile: true }) },
|
||||||
{ parameters: (): object => ({ notify: false }) },
|
{ parameters: () => ({ notify: false }) },
|
||||||
{ parameters: (): object => ({ notify: true }) },
|
{ parameters: () => ({ notify: true }) },
|
||||||
];
|
];
|
||||||
test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
|
test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
|
||||||
const response = await successfulApiCall({
|
const response = await successfulApiCall({
|
||||||
|
@ -335,7 +331,7 @@ describe('アンテナ', () => {
|
||||||
test.each([
|
test.each([
|
||||||
{
|
{
|
||||||
label: '全体から',
|
label: '全体から',
|
||||||
parameters: (): object => ({ src: 'all' }),
|
parameters: () => ({ src: 'all' }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true },
|
||||||
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
|
||||||
|
@ -346,7 +342,7 @@ describe('アンテナ', () => {
|
||||||
{
|
{
|
||||||
// BUG e4144a1 以降home指定は壊れている(allと同じ)
|
// BUG e4144a1 以降home指定は壊れている(allと同じ)
|
||||||
label: 'ホーム指定はallと同じ',
|
label: 'ホーム指定はallと同じ',
|
||||||
parameters: (): object => ({ src: 'home' }),
|
parameters: () => ({ src: 'home' }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true },
|
||||||
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
|
||||||
|
@ -357,7 +353,7 @@ describe('アンテナ', () => {
|
||||||
{
|
{
|
||||||
// https://github.com/misskey-dev/misskey/issues/9025
|
// https://github.com/misskey-dev/misskey/issues/9025
|
||||||
label: 'ただし、フォロワー限定投稿とDM投稿を含まない。フォロワーであっても。',
|
label: 'ただし、フォロワー限定投稿とDM投稿を含まない。フォロワーであっても。',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'public' }), included: true },
|
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'public' }), included: true },
|
||||||
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'home' }), included: true },
|
{ note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'home' }), included: true },
|
||||||
|
@ -367,56 +363,56 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'ブロックしているユーザーのノートは含む',
|
label: 'ブロックしているユーザーのノートは含む',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userBlockedByAlice, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userBlockedByAlice, { text: `${keyword}` }), included: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'ブロックされているユーザーのノートは含まない',
|
label: 'ブロックされているユーザーのノートは含まない',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userBlockingAlice, { text: `${keyword}` }) },
|
{ note: (): Promise<Note> => post(userBlockingAlice, { text: `${keyword}` }) },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'ミュートしているユーザーのノートは含まない',
|
label: 'ミュートしているユーザーのノートは含まない',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userMutedByAlice, { text: `${keyword}` }) },
|
{ note: (): Promise<Note> => post(userMutedByAlice, { text: `${keyword}` }) },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'ミュートされているユーザーのノートは含む',
|
label: 'ミュートされているユーザーのノートは含む',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userMutingAlice, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userMutingAlice, { text: `${keyword}` }), included: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '「見つけやすくする」がOFFのユーザーのノートも含まれる',
|
label: '「見つけやすくする」がOFFのユーザーのノートも含まれる',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userNotExplorable, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userNotExplorable, { text: `${keyword}` }), included: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '鍵付きユーザーのノートも含まれる',
|
label: '鍵付きユーザーのノートも含まれる',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userLocking, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userLocking, { text: `${keyword}` }), included: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'サイレンスのノートも含まれる',
|
label: 'サイレンスのノートも含まれる',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userSilenced, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userSilenced, { text: `${keyword}` }), included: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '削除ユーザーのノートも含まれる',
|
label: '削除ユーザーのノートも含まれる',
|
||||||
parameters: (): object => ({}),
|
parameters: () => ({}),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(userDeletedBySelf, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userDeletedBySelf, { text: `${keyword}` }), included: true },
|
||||||
{ note: (): Promise<Note> => post(userDeletedByAdmin, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(userDeletedByAdmin, { text: `${keyword}` }), included: true },
|
||||||
|
@ -424,7 +420,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'ユーザー指定で',
|
label: 'ユーザー指定で',
|
||||||
parameters: (): object => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }),
|
parameters: () => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) },
|
{ note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
||||||
|
@ -433,7 +429,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'リスト指定で',
|
label: 'リスト指定で',
|
||||||
parameters: (): object => ({ src: 'list', userListId: aliceList.id }),
|
parameters: () => ({ src: 'list', userListId: aliceList.id }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) },
|
{ note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
||||||
|
@ -442,14 +438,14 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'CWにもマッチする',
|
label: 'CWにもマッチする',
|
||||||
parameters: (): object => ({ keywords: [[keyword]] }),
|
parameters: () => ({ keywords: [[keyword]] }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'test', cw: `cw ${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: 'test', cw: `cw ${keyword}` }), included: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'キーワード1つ',
|
label: 'キーワード1つ',
|
||||||
parameters: (): object => ({ keywords: [[keyword]] }),
|
parameters: () => ({ keywords: [[keyword]] }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(alice, { text: 'test' }) },
|
{ note: (): Promise<Note> => post(alice, { text: 'test' }) },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
||||||
|
@ -458,7 +454,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'キーワード3つ(AND)',
|
label: 'キーワード3つ(AND)',
|
||||||
parameters: (): object => ({ keywords: [['A', 'B', 'C']] }),
|
parameters: () => ({ keywords: [['A', 'B', 'C']] }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'test A' }) },
|
{ note: (): Promise<Note> => post(bob, { text: 'test A' }) },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'test A B' }) },
|
{ note: (): Promise<Note> => post(bob, { text: 'test A B' }) },
|
||||||
|
@ -469,7 +465,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'キーワード3つ(OR)',
|
label: 'キーワード3つ(OR)',
|
||||||
parameters: (): object => ({ keywords: [['A'], ['B'], ['C']] }),
|
parameters: () => ({ keywords: [['A'], ['B'], ['C']] }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'test' }) },
|
{ note: (): Promise<Note> => post(bob, { text: 'test' }) },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'test A' }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: 'test A' }), included: true },
|
||||||
|
@ -482,7 +478,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '除外ワード3つ(AND)',
|
label: '除外ワード3つ(AND)',
|
||||||
parameters: (): object => ({ excludeKeywords: [['A', 'B', 'C']] }),
|
parameters: () => ({ excludeKeywords: [['A', 'B', 'C']] }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }), included: true },
|
||||||
|
@ -495,7 +491,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '除外ワード3つ(OR)',
|
label: '除外ワード3つ(OR)',
|
||||||
parameters: (): object => ({ excludeKeywords: [['A'], ['B'], ['C']] }),
|
parameters: () => ({ excludeKeywords: [['A'], ['B'], ['C']] }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }) },
|
{ note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }) },
|
||||||
|
@ -508,7 +504,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'キーワード1つ(大文字小文字区別する)',
|
label: 'キーワード1つ(大文字小文字区別する)',
|
||||||
parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: true }),
|
parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: true }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'keyword' }) },
|
{ note: (): Promise<Note> => post(bob, { text: 'keyword' }) },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }) },
|
{ note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }) },
|
||||||
|
@ -517,7 +513,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'キーワード1つ(大文字小文字区別しない)',
|
label: 'キーワード1つ(大文字小文字区別しない)',
|
||||||
parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: false }),
|
parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: false }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'keyword' }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: 'keyword' }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }), included: true },
|
||||||
|
@ -526,7 +522,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '除外ワード1つ(大文字小文字区別する)',
|
label: '除外ワード1つ(大文字小文字区別する)',
|
||||||
parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }),
|
parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }), included: true },
|
||||||
|
@ -536,7 +532,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '除外ワード1つ(大文字小文字区別しない)',
|
label: '除外ワード1つ(大文字小文字区別しない)',
|
||||||
parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }),
|
parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }) },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }) },
|
||||||
|
@ -546,7 +542,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '添付ファイルを問わない',
|
label: '添付ファイルを問わない',
|
||||||
parameters: (): object => ({ withFile: false }),
|
parameters: () => ({ withFile: false }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
||||||
|
@ -554,7 +550,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '添付ファイル付きのみ',
|
label: '添付ファイル付きのみ',
|
||||||
parameters: (): object => ({ withFile: true }),
|
parameters: () => ({ withFile: true }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }) },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }) },
|
||||||
|
@ -562,7 +558,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'リプライ以外',
|
label: 'リプライ以外',
|
||||||
parameters: (): object => ({ withReplies: false }),
|
parameters: () => ({ withReplies: false }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }) },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }) },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
||||||
|
@ -570,7 +566,7 @@ describe('アンテナ', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'リプライも含む',
|
label: 'リプライも含む',
|
||||||
parameters: (): object => ({ withReplies: true }),
|
parameters: () => ({ withReplies: true }),
|
||||||
posts: [
|
posts: [
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }), included: true },
|
||||||
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
{ note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true },
|
||||||
|
@ -633,7 +629,7 @@ describe('アンテナ', () => {
|
||||||
endpoint: 'antennas/notes',
|
endpoint: 'antennas/notes',
|
||||||
parameters: { antennaId: antenna.id, ...paginationParam },
|
parameters: { antennaId: antenna.id, ...paginationParam },
|
||||||
user: alice,
|
user: alice,
|
||||||
}) as any as Note[];
|
});
|
||||||
}, offsetBy, 'desc');
|
}, offsetBy, 'desc');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { api, post, signup } from '../utils.js';
|
import { UserToken, api, post, signup } from '../utils.js';
|
||||||
import type * as misskey from 'misskey-js';
|
import type * as misskey from 'misskey-js';
|
||||||
|
|
||||||
describe('API visibility', () => {
|
describe('API visibility', () => {
|
||||||
|
@ -24,38 +24,38 @@ describe('API visibility', () => {
|
||||||
let target2: misskey.entities.SignupResponse;
|
let target2: misskey.entities.SignupResponse;
|
||||||
|
|
||||||
/** public-post */
|
/** public-post */
|
||||||
let pub: any;
|
let pub: misskey.entities.Note;
|
||||||
/** home-post */
|
/** home-post */
|
||||||
let home: any;
|
let home: misskey.entities.Note;
|
||||||
/** followers-post */
|
/** followers-post */
|
||||||
let fol: any;
|
let fol: misskey.entities.Note;
|
||||||
/** specified-post */
|
/** specified-post */
|
||||||
let spe: any;
|
let spe: misskey.entities.Note;
|
||||||
|
|
||||||
/** public-reply to target's post */
|
/** public-reply to target's post */
|
||||||
let pubR: any;
|
let pubR: misskey.entities.Note;
|
||||||
/** home-reply to target's post */
|
/** home-reply to target's post */
|
||||||
let homeR: any;
|
let homeR: misskey.entities.Note;
|
||||||
/** followers-reply to target's post */
|
/** followers-reply to target's post */
|
||||||
let folR: any;
|
let folR: misskey.entities.Note;
|
||||||
/** specified-reply to target's post */
|
/** specified-reply to target's post */
|
||||||
let speR: any;
|
let speR: misskey.entities.Note;
|
||||||
|
|
||||||
/** public-mention to target */
|
/** public-mention to target */
|
||||||
let pubM: any;
|
let pubM: misskey.entities.Note;
|
||||||
/** home-mention to target */
|
/** home-mention to target */
|
||||||
let homeM: any;
|
let homeM: misskey.entities.Note;
|
||||||
/** followers-mention to target */
|
/** followers-mention to target */
|
||||||
let folM: any;
|
let folM: misskey.entities.Note;
|
||||||
/** specified-mention to target */
|
/** specified-mention to target */
|
||||||
let speM: any;
|
let speM: misskey.entities.Note;
|
||||||
|
|
||||||
/** reply target post */
|
/** reply target post */
|
||||||
let tgt: any;
|
let tgt: misskey.entities.Note;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
const show = async (noteId: any, by: any) => {
|
const show = async (noteId: misskey.entities.Note['id'], by?: UserToken) => {
|
||||||
return await api('/notes/show', {
|
return await api('notes/show', {
|
||||||
noteId,
|
noteId,
|
||||||
}, by);
|
}, by);
|
||||||
};
|
};
|
||||||
|
@ -70,7 +70,7 @@ describe('API visibility', () => {
|
||||||
target2 = await signup({ username: 'target2' });
|
target2 = await signup({ username: 'target2' });
|
||||||
|
|
||||||
// follow alice <= follower
|
// follow alice <= follower
|
||||||
await api('/following/create', { userId: alice.id }, follower);
|
await api('following/create', { userId: alice.id }, follower);
|
||||||
|
|
||||||
// normal posts
|
// normal posts
|
||||||
pub = await post(alice, { text: 'x', visibility: 'public' });
|
pub = await post(alice, { text: 'x', visibility: 'public' });
|
||||||
|
@ -111,7 +111,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] public-postを未認証が見れる', async () => {
|
test('[show] public-postを未認証が見れる', async () => {
|
||||||
const res = await show(pub.id, null);
|
const res = await show(pub.id);
|
||||||
assert.strictEqual(res.body.text, 'x');
|
assert.strictEqual(res.body.text, 'x');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] home-postを未認証が見れる', async () => {
|
test('[show] home-postを未認証が見れる', async () => {
|
||||||
const res = await show(home.id, null);
|
const res = await show(home.id);
|
||||||
assert.strictEqual(res.body.text, 'x');
|
assert.strictEqual(res.body.text, 'x');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] followers-postを未認証が見れない', async () => {
|
test('[show] followers-postを未認証が見れない', async () => {
|
||||||
const res = await show(fol.id, null);
|
const res = await show(fol.id);
|
||||||
assert.strictEqual(res.body.isHidden, true);
|
assert.strictEqual(res.body.isHidden, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] specified-postを未認証が見れない', async () => {
|
test('[show] specified-postを未認証が見れない', async () => {
|
||||||
const res = await show(spe.id, null);
|
const res = await show(spe.id);
|
||||||
assert.strictEqual(res.body.isHidden, true);
|
assert.strictEqual(res.body.isHidden, true);
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@ -207,7 +207,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] public-replyを未認証が見れる', async () => {
|
test('[show] public-replyを未認証が見れる', async () => {
|
||||||
const res = await show(pubR.id, null);
|
const res = await show(pubR.id);
|
||||||
assert.strictEqual(res.body.text, 'x');
|
assert.strictEqual(res.body.text, 'x');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] home-replyを未認証が見れる', async () => {
|
test('[show] home-replyを未認証が見れる', async () => {
|
||||||
const res = await show(homeR.id, null);
|
const res = await show(homeR.id);
|
||||||
assert.strictEqual(res.body.text, 'x');
|
assert.strictEqual(res.body.text, 'x');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] followers-replyを未認証が見れない', async () => {
|
test('[show] followers-replyを未認証が見れない', async () => {
|
||||||
const res = await show(folR.id, null);
|
const res = await show(folR.id);
|
||||||
assert.strictEqual(res.body.isHidden, true);
|
assert.strictEqual(res.body.isHidden, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] specified-replyを未認証が見れない', async () => {
|
test('[show] specified-replyを未認証が見れない', async () => {
|
||||||
const res = await show(speR.id, null);
|
const res = await show(speR.id);
|
||||||
assert.strictEqual(res.body.isHidden, true);
|
assert.strictEqual(res.body.isHidden, true);
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@ -318,7 +318,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] public-mentionを未認証が見れる', async () => {
|
test('[show] public-mentionを未認証が見れる', async () => {
|
||||||
const res = await show(pubM.id, null);
|
const res = await show(pubM.id);
|
||||||
assert.strictEqual(res.body.text, '@target x');
|
assert.strictEqual(res.body.text, '@target x');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] home-mentionを未認証が見れる', async () => {
|
test('[show] home-mentionを未認証が見れる', async () => {
|
||||||
const res = await show(homeM.id, null);
|
const res = await show(homeM.id);
|
||||||
assert.strictEqual(res.body.text, '@target x');
|
assert.strictEqual(res.body.text, '@target x');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] followers-mentionを未認証が見れない', async () => {
|
test('[show] followers-mentionを未認証が見れない', async () => {
|
||||||
const res = await show(folM.id, null);
|
const res = await show(folM.id);
|
||||||
assert.strictEqual(res.body.isHidden, true);
|
assert.strictEqual(res.body.isHidden, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -401,28 +401,28 @@ describe('API visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[show] specified-mentionを未認証が見れない', async () => {
|
test('[show] specified-mentionを未認証が見れない', async () => {
|
||||||
const res = await show(speM.id, null);
|
const res = await show(speM.id);
|
||||||
assert.strictEqual(res.body.isHidden, true);
|
assert.strictEqual(res.body.isHidden, true);
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region HTL
|
//#region HTL
|
||||||
test('[HTL] public-post が 自分が見れる', async () => {
|
test('[HTL] public-post が 自分が見れる', async () => {
|
||||||
const res = await api('/notes/timeline', { limit: 100 }, alice);
|
const res = await api('notes/timeline', { limit: 100 }, alice);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === pub.id);
|
const notes = res.body.filter((n: any) => n.id === pub.id);
|
||||||
assert.strictEqual(notes[0].text, 'x');
|
assert.strictEqual(notes[0].text, 'x');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[HTL] public-post が 非フォロワーから見れない', async () => {
|
test('[HTL] public-post が 非フォロワーから見れない', async () => {
|
||||||
const res = await api('/notes/timeline', { limit: 100 }, other);
|
const res = await api('notes/timeline', { limit: 100 }, other);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === pub.id);
|
const notes = res.body.filter((n: any) => n.id === pub.id);
|
||||||
assert.strictEqual(notes.length, 0);
|
assert.strictEqual(notes.length, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[HTL] followers-post が フォロワーから見れる', async () => {
|
test('[HTL] followers-post が フォロワーから見れる', async () => {
|
||||||
const res = await api('/notes/timeline', { limit: 100 }, follower);
|
const res = await api('notes/timeline', { limit: 100 }, follower);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === fol.id);
|
const notes = res.body.filter((n: any) => n.id === fol.id);
|
||||||
assert.strictEqual(notes[0].text, 'x');
|
assert.strictEqual(notes[0].text, 'x');
|
||||||
|
@ -431,21 +431,21 @@ describe('API visibility', () => {
|
||||||
|
|
||||||
//#region RTL
|
//#region RTL
|
||||||
test('[replies] followers-reply が フォロワーから見れる', async () => {
|
test('[replies] followers-reply が フォロワーから見れる', async () => {
|
||||||
const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, follower);
|
const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, follower);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === folR.id);
|
const notes = res.body.filter((n: any) => n.id === folR.id);
|
||||||
assert.strictEqual(notes[0].text, 'x');
|
assert.strictEqual(notes[0].text, 'x');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[replies] followers-reply が 非フォロワー (リプライ先ではない) から見れない', async () => {
|
test('[replies] followers-reply が 非フォロワー (リプライ先ではない) から見れない', async () => {
|
||||||
const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, other);
|
const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, other);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === folR.id);
|
const notes = res.body.filter((n: any) => n.id === folR.id);
|
||||||
assert.strictEqual(notes.length, 0);
|
assert.strictEqual(notes.length, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[replies] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
|
test('[replies] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
|
||||||
const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, target);
|
const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, target);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === folR.id);
|
const notes = res.body.filter((n: any) => n.id === folR.id);
|
||||||
assert.strictEqual(notes[0].text, 'x');
|
assert.strictEqual(notes[0].text, 'x');
|
||||||
|
@ -454,14 +454,14 @@ describe('API visibility', () => {
|
||||||
|
|
||||||
//#region MTL
|
//#region MTL
|
||||||
test('[mentions] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
|
test('[mentions] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
|
||||||
const res = await api('/notes/mentions', { limit: 100 }, target);
|
const res = await api('notes/mentions', { limit: 100 }, target);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === folR.id);
|
const notes = res.body.filter((n: any) => n.id === folR.id);
|
||||||
assert.strictEqual(notes[0].text, 'x');
|
assert.strictEqual(notes[0].text, 'x');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[mentions] followers-mention が 非フォロワー (メンション先である) から見れる', async () => {
|
test('[mentions] followers-mention が 非フォロワー (メンション先である) から見れる', async () => {
|
||||||
const res = await api('/notes/mentions', { limit: 100 }, target);
|
const res = await api('notes/mentions', { limit: 100 }, target);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const notes = res.body.filter((n: any) => n.id === folM.id);
|
const notes = res.body.filter((n: any) => n.id === folM.id);
|
||||||
assert.strictEqual(notes[0].text, '@target x');
|
assert.strictEqual(notes[0].text, '@target x');
|
||||||
|
|
|
@ -23,32 +23,32 @@ import type * as misskey from 'misskey-js';
|
||||||
describe('API', () => {
|
describe('API', () => {
|
||||||
let alice: misskey.entities.SignupResponse;
|
let alice: misskey.entities.SignupResponse;
|
||||||
let bob: misskey.entities.SignupResponse;
|
let bob: misskey.entities.SignupResponse;
|
||||||
let carol: misskey.entities.SignupResponse;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
alice = await signup({ username: 'alice' });
|
alice = await signup({ username: 'alice' });
|
||||||
bob = await signup({ username: 'bob' });
|
bob = await signup({ username: 'bob' });
|
||||||
carol = await signup({ username: 'carol' });
|
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
describe('General validation', () => {
|
describe('General validation', () => {
|
||||||
test('wrong type', async () => {
|
test('wrong type', async () => {
|
||||||
const res = await api('/test', {
|
const res = await api('test', {
|
||||||
required: true,
|
required: true,
|
||||||
|
// @ts-expect-error string must be string
|
||||||
string: 42,
|
string: 42,
|
||||||
});
|
});
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('missing require param', async () => {
|
test('missing require param', async () => {
|
||||||
const res = await api('/test', {
|
// @ts-expect-error required is required
|
||||||
|
const res = await api('test', {
|
||||||
string: 'a',
|
string: 'a',
|
||||||
});
|
});
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invalid misskey:id (empty string)', async () => {
|
test('invalid misskey:id (empty string)', async () => {
|
||||||
const res = await api('/test', {
|
const res = await api('test', {
|
||||||
required: true,
|
required: true,
|
||||||
id: '',
|
id: '',
|
||||||
});
|
});
|
||||||
|
@ -56,7 +56,7 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('valid misskey:id', async () => {
|
test('valid misskey:id', async () => {
|
||||||
const res = await api('/test', {
|
const res = await api('test', {
|
||||||
required: true,
|
required: true,
|
||||||
id: '8wvhjghbxu',
|
id: '8wvhjghbxu',
|
||||||
});
|
});
|
||||||
|
@ -64,7 +64,7 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('default value', async () => {
|
test('default value', async () => {
|
||||||
const res = await api('/test', {
|
const res = await api('test', {
|
||||||
required: true,
|
required: true,
|
||||||
string: 'a',
|
string: 'a',
|
||||||
});
|
});
|
||||||
|
@ -73,7 +73,7 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can set null even if it has default value', async () => {
|
test('can set null even if it has default value', async () => {
|
||||||
const res = await api('/test', {
|
const res = await api('test', {
|
||||||
required: true,
|
required: true,
|
||||||
nullableDefault: null,
|
nullableDefault: null,
|
||||||
});
|
});
|
||||||
|
@ -82,7 +82,7 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cannot set undefined if it has default value', async () => {
|
test('cannot set undefined if it has default value', async () => {
|
||||||
const res = await api('/test', {
|
const res = await api('test', {
|
||||||
required: true,
|
required: true,
|
||||||
nullableDefault: undefined,
|
nullableDefault: undefined,
|
||||||
});
|
});
|
||||||
|
@ -99,14 +99,14 @@ describe('API', () => {
|
||||||
|
|
||||||
// aliceは管理者、APIを使える
|
// aliceは管理者、APIを使える
|
||||||
await successfulApiCall({
|
await successfulApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: alice,
|
user: alice,
|
||||||
});
|
});
|
||||||
|
|
||||||
// bobは一般ユーザーだからダメ
|
// bobは一般ユーザーだからダメ
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: bob,
|
user: bob,
|
||||||
}, {
|
}, {
|
||||||
|
@ -117,7 +117,7 @@ describe('API', () => {
|
||||||
|
|
||||||
// publicアクセスももちろんダメ
|
// publicアクセスももちろんダメ
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: undefined,
|
user: undefined,
|
||||||
}, {
|
}, {
|
||||||
|
@ -128,7 +128,7 @@ describe('API', () => {
|
||||||
|
|
||||||
// ごまがしもダメ
|
// ごまがしもダメ
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: { token: 'tsukawasete' },
|
user: { token: 'tsukawasete' },
|
||||||
}, {
|
}, {
|
||||||
|
@ -138,13 +138,13 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await successfulApiCall({
|
await successfulApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: { token: application2 },
|
user: { token: application2 },
|
||||||
});
|
});
|
||||||
|
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: { token: application },
|
user: { token: application },
|
||||||
}, {
|
}, {
|
||||||
|
@ -154,7 +154,7 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: { token: application3 },
|
user: { token: application3 },
|
||||||
}, {
|
}, {
|
||||||
|
@ -164,7 +164,7 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: { token: application4 },
|
user: { token: application4 },
|
||||||
}, {
|
}, {
|
||||||
|
@ -177,7 +177,7 @@ describe('API', () => {
|
||||||
describe('Authentication header', () => {
|
describe('Authentication header', () => {
|
||||||
test('一般リクエスト', async () => {
|
test('一般リクエスト', async () => {
|
||||||
await successfulApiCall({
|
await successfulApiCall({
|
||||||
endpoint: '/admin/get-index-stats',
|
endpoint: 'admin/get-index-stats',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: {
|
user: {
|
||||||
token: alice.token,
|
token: alice.token,
|
||||||
|
@ -211,7 +211,7 @@ describe('API', () => {
|
||||||
describe('tokenエラー応答でWWW-Authenticate headerを送る', () => {
|
describe('tokenエラー応答でWWW-Authenticate headerを送る', () => {
|
||||||
describe('invalid_token', () => {
|
describe('invalid_token', () => {
|
||||||
test('一般リクエスト', async () => {
|
test('一般リクエスト', async () => {
|
||||||
const result = await api('/admin/get-index-stats', {}, {
|
const result = await api('admin/get-index-stats', {}, {
|
||||||
token: 'syuilo',
|
token: 'syuilo',
|
||||||
bearer: true,
|
bearer: true,
|
||||||
});
|
});
|
||||||
|
@ -246,7 +246,7 @@ describe('API', () => {
|
||||||
|
|
||||||
describe('tokenがないとrealmだけおくる', () => {
|
describe('tokenがないとrealmだけおくる', () => {
|
||||||
test('一般リクエスト', async () => {
|
test('一般リクエスト', async () => {
|
||||||
const result = await api('/admin/get-index-stats', {});
|
const result = await api('admin/get-index-stats', {});
|
||||||
assert.strictEqual(result.status, 401);
|
assert.strictEqual(result.status, 401);
|
||||||
assert.strictEqual(result.headers.get('WWW-Authenticate'), 'Bearer realm="Misskey"');
|
assert.strictEqual(result.headers.get('WWW-Authenticate'), 'Bearer realm="Misskey"');
|
||||||
});
|
});
|
||||||
|
@ -259,7 +259,8 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invalid_request', async () => {
|
test('invalid_request', async () => {
|
||||||
const result = await api('/notes/create', { text: true }, {
|
// @ts-expect-error text must be string
|
||||||
|
const result = await api('notes/create', { text: true }, {
|
||||||
token: alice.token,
|
token: alice.token,
|
||||||
bearer: true,
|
bearer: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,7 +22,7 @@ describe('Block', () => {
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
test('Block作成', async () => {
|
test('Block作成', async () => {
|
||||||
const res = await api('/blocking/create', {
|
const res = await api('blocking/create', {
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ describe('Block', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ブロックされているユーザーをフォローできない', async () => {
|
test('ブロックされているユーザーをフォローできない', async () => {
|
||||||
const res = await api('/following/create', { userId: alice.id }, bob);
|
const res = await api('following/create', { userId: alice.id }, bob);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
assert.strictEqual(res.body.error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0');
|
assert.strictEqual(res.body.error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0');
|
||||||
|
@ -39,7 +39,7 @@ describe('Block', () => {
|
||||||
test('ブロックされているユーザーにリアクションできない', async () => {
|
test('ブロックされているユーザーにリアクションできない', async () => {
|
||||||
const note = await post(alice, { text: 'hello' });
|
const note = await post(alice, { text: 'hello' });
|
||||||
|
|
||||||
const res = await api('/notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob);
|
const res = await api('notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
assert.strictEqual(res.body.error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec');
|
assert.strictEqual(res.body.error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec');
|
||||||
|
@ -48,7 +48,7 @@ describe('Block', () => {
|
||||||
test('ブロックされているユーザーに返信できない', async () => {
|
test('ブロックされているユーザーに返信できない', async () => {
|
||||||
const note = await post(alice, { text: 'hello' });
|
const note = await post(alice, { text: 'hello' });
|
||||||
|
|
||||||
const res = await api('/notes/create', { replyId: note.id, text: 'yo' }, bob);
|
const res = await api('notes/create', { replyId: note.id, text: 'yo' }, bob);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
|
assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
|
||||||
|
@ -57,7 +57,7 @@ describe('Block', () => {
|
||||||
test('ブロックされているユーザーのノートをRenoteできない', async () => {
|
test('ブロックされているユーザーのノートをRenoteできない', async () => {
|
||||||
const note = await post(alice, { text: 'hello' });
|
const note = await post(alice, { text: 'hello' });
|
||||||
|
|
||||||
const res = await api('/notes/create', { renoteId: note.id, text: 'yo' }, bob);
|
const res = await api('notes/create', { renoteId: note.id, text: 'yo' }, bob);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
|
assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
|
||||||
|
@ -72,12 +72,13 @@ describe('Block', () => {
|
||||||
const bobNote = await post(bob, { text: 'hi' });
|
const bobNote = await post(bob, { text: 'hi' });
|
||||||
const carolNote = await post(carol, { text: 'hi' });
|
const carolNote = await post(carol, { text: 'hi' });
|
||||||
|
|
||||||
const res = await api('/notes/local-timeline', {}, bob);
|
const res = await api('notes/local-timeline', {}, bob);
|
||||||
|
const body = res.body as misskey.entities.Note[];
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), false);
|
assert.strictEqual(body.some(note => note.id === aliceNote.id), false);
|
||||||
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
|
assert.strictEqual(body.some(note => note.id === bobNote.id), true);
|
||||||
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
|
assert.strictEqual(body.some(note => note.id === carolNote.id), true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,47 +6,34 @@
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { JTDDataType } from 'ajv/dist/jtd';
|
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
|
||||||
import { paramDef as CreateParamDef } from '@/server/api/endpoints/clips/create.js';
|
|
||||||
import { paramDef as UpdateParamDef } from '@/server/api/endpoints/clips/update.js';
|
|
||||||
import { paramDef as DeleteParamDef } from '@/server/api/endpoints/clips/delete.js';
|
|
||||||
import { paramDef as ShowParamDef } from '@/server/api/endpoints/clips/show.js';
|
|
||||||
import { paramDef as FavoriteParamDef } from '@/server/api/endpoints/clips/favorite.js';
|
|
||||||
import { paramDef as UnfavoriteParamDef } from '@/server/api/endpoints/clips/unfavorite.js';
|
|
||||||
import { paramDef as AddNoteParamDef } from '@/server/api/endpoints/clips/add-note.js';
|
|
||||||
import { paramDef as RemoveNoteParamDef } from '@/server/api/endpoints/clips/remove-note.js';
|
|
||||||
import { paramDef as NotesParamDef } from '@/server/api/endpoints/clips/notes.js';
|
|
||||||
import { api, ApiRequest, failedApiCall, hiddenNote, post, signup, successfulApiCall } from '../utils.js';
|
import { api, ApiRequest, failedApiCall, hiddenNote, post, signup, successfulApiCall } from '../utils.js';
|
||||||
|
import type * as Misskey from 'misskey-js';
|
||||||
|
|
||||||
|
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
||||||
|
|
||||||
describe('クリップ', () => {
|
describe('クリップ', () => {
|
||||||
type User = Packed<'User'>;
|
let alice: Misskey.entities.SignupResponse;
|
||||||
type Note = Packed<'Note'>;
|
let bob: Misskey.entities.SignupResponse;
|
||||||
type Clip = Packed<'Clip'>;
|
let aliceNote: Misskey.entities.Note;
|
||||||
|
let aliceHomeNote: Misskey.entities.Note;
|
||||||
let alice: User;
|
let aliceFollowersNote: Misskey.entities.Note;
|
||||||
let bob: User;
|
let aliceSpecifiedNote: Misskey.entities.Note;
|
||||||
let aliceNote: Note;
|
let bobNote: Misskey.entities.Note;
|
||||||
let aliceHomeNote: Note;
|
let bobHomeNote: Misskey.entities.Note;
|
||||||
let aliceFollowersNote: Note;
|
let bobFollowersNote: Misskey.entities.Note;
|
||||||
let aliceSpecifiedNote: Note;
|
let bobSpecifiedNote: Misskey.entities.Note;
|
||||||
let bobNote: Note;
|
|
||||||
let bobHomeNote: Note;
|
|
||||||
let bobFollowersNote: Note;
|
|
||||||
let bobSpecifiedNote: Note;
|
|
||||||
|
|
||||||
const compareBy = <T extends { id: string }, >(selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => {
|
const compareBy = <T extends { id: string }, >(selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => {
|
||||||
return selector(a).localeCompare(selector(b));
|
return selector(a).localeCompare(selector(b));
|
||||||
};
|
};
|
||||||
|
|
||||||
type CreateParam = JTDDataType<typeof CreateParamDef>;
|
const defaultCreate = (): Pick<Misskey.entities.ClipsCreateRequest, 'name'> => ({
|
||||||
const defaultCreate = (): Partial<CreateParam> => ({
|
|
||||||
name: 'test',
|
name: 'test',
|
||||||
});
|
});
|
||||||
const create = async (parameters: Partial<CreateParam> = {}, request: Partial<ApiRequest> = {}): Promise<Clip> => {
|
const create = async (parameters: Partial<Misskey.entities.ClipsCreateRequest> = {}, request: Partial<ApiRequest<'clips/create'>> = {}): Promise<Misskey.entities.Clip> => {
|
||||||
const clip = await successfulApiCall<Clip>({
|
const clip = await successfulApiCall({
|
||||||
endpoint: '/clips/create',
|
endpoint: 'clips/create',
|
||||||
parameters: {
|
parameters: {
|
||||||
...defaultCreate(),
|
...defaultCreate(),
|
||||||
...parameters,
|
...parameters,
|
||||||
|
@ -64,17 +51,16 @@ describe('クリップ', () => {
|
||||||
return clip;
|
return clip;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createMany = async (parameters: Partial<CreateParam>, count = 10, user = alice): Promise<Clip[]> => {
|
const createMany = async (parameters: Partial<Misskey.entities.ClipsCreateRequest>, count = 10, user = alice): Promise<Misskey.entities.Clip[]> => {
|
||||||
return await Promise.all([...Array(count)].map((_, i) => create({
|
return await Promise.all([...Array(count)].map((_, i) => create({
|
||||||
name: `test${i}`,
|
name: `test${i}`,
|
||||||
...parameters,
|
...parameters,
|
||||||
}, { user })));
|
}, { user })));
|
||||||
};
|
};
|
||||||
|
|
||||||
type UpdateParam = JTDDataType<typeof UpdateParamDef>;
|
const update = async (parameters: Optional<Misskey.entities.ClipsUpdateRequest, 'name'>, request: Partial<ApiRequest<'clips/update'>> = {}): Promise<Misskey.entities.Clip> => {
|
||||||
const update = async (parameters: Partial<UpdateParam>, request: Partial<ApiRequest> = {}): Promise<Clip> => {
|
const clip = await successfulApiCall({
|
||||||
const clip = await successfulApiCall<Clip>({
|
endpoint: 'clips/update',
|
||||||
endpoint: '/clips/update',
|
|
||||||
parameters: {
|
parameters: {
|
||||||
name: 'updated',
|
name: 'updated',
|
||||||
...parameters,
|
...parameters,
|
||||||
|
@ -92,41 +78,39 @@ describe('クリップ', () => {
|
||||||
return clip;
|
return clip;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DeleteParam = JTDDataType<typeof DeleteParamDef>;
|
const deleteClip = async (parameters: Misskey.entities.ClipsDeleteRequest, request: Partial<ApiRequest<'clips/delete'>> = {}): Promise<void> => {
|
||||||
const deleteClip = async (parameters: DeleteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
|
return await successfulApiCall({
|
||||||
return await successfulApiCall<void>({
|
endpoint: 'clips/delete',
|
||||||
endpoint: '/clips/delete',
|
|
||||||
parameters,
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
}, {
|
}, {
|
||||||
status: 204,
|
status: 204,
|
||||||
});
|
}) as any as void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ShowParam = JTDDataType<typeof ShowParamDef>;
|
const show = async (parameters: Misskey.entities.ClipsShowRequest, request: Partial<ApiRequest<'clips/show'>> = {}): Promise<Misskey.entities.Clip> => {
|
||||||
const show = async (parameters: ShowParam, request: Partial<ApiRequest> = {}): Promise<Clip> => {
|
return await successfulApiCall({
|
||||||
return await successfulApiCall<Clip>({
|
endpoint: 'clips/show',
|
||||||
endpoint: '/clips/show',
|
|
||||||
parameters,
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const list = async (request: Partial<ApiRequest>): Promise<Clip[]> => {
|
const list = async (request: Partial<ApiRequest<'clips/list'>>): Promise<Misskey.entities.Clip[]> => {
|
||||||
return successfulApiCall<Clip[]>({
|
return successfulApiCall({
|
||||||
endpoint: '/clips/list',
|
endpoint: 'clips/list',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const usersClips = async (request: Partial<ApiRequest>): Promise<Clip[]> => {
|
const usersClips = async (parameters: Misskey.entities.UsersClipsRequest, request: Partial<ApiRequest<'users/clips'>> = {}): Promise<Misskey.entities.Clip[]> => {
|
||||||
return await successfulApiCall<Clip[]>({
|
return await successfulApiCall({
|
||||||
endpoint: '/users/clips',
|
endpoint: 'users/clips',
|
||||||
parameters: {},
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
});
|
});
|
||||||
|
@ -136,23 +120,22 @@ describe('クリップ', () => {
|
||||||
alice = await signup({ username: 'alice' });
|
alice = await signup({ username: 'alice' });
|
||||||
bob = await signup({ username: 'bob' });
|
bob = await signup({ username: 'bob' });
|
||||||
|
|
||||||
// FIXME: misskey-jsのNoteはoutdatedなので直接変換できない
|
aliceNote = await post(alice, { text: 'test' });
|
||||||
aliceNote = await post(alice, { text: 'test' }) as any;
|
aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' });
|
||||||
aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' }) as any;
|
aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' });
|
||||||
aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' }) as any;
|
aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' });
|
||||||
aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' }) as any;
|
bobNote = await post(bob, { text: 'test' });
|
||||||
bobNote = await post(bob, { text: 'test' }) as any;
|
bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' });
|
||||||
bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' }) as any;
|
bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' });
|
||||||
bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' }) as any;
|
bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' });
|
||||||
bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' }) as any;
|
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
// テスト間で影響し合わないように毎回全部消す。
|
// テスト間で影響し合わないように毎回全部消す。
|
||||||
for (const user of [alice, bob]) {
|
for (const user of [alice, bob]) {
|
||||||
const list = await api('/clips/list', { limit: 11 }, user);
|
const list = await api('clips/list', { limit: 11 }, user);
|
||||||
for (const clip of list.body) {
|
for (const clip of list.body) {
|
||||||
await api('/clips/delete', { clipId: clip.id }, user);
|
await api('clips/delete', { clipId: clip.id }, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -177,7 +160,7 @@ describe('クリップ', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/clips/create',
|
endpoint: 'clips/create',
|
||||||
parameters: defaultCreate(),
|
parameters: defaultCreate(),
|
||||||
user: alice,
|
user: alice,
|
||||||
}, {
|
}, {
|
||||||
|
@ -204,7 +187,8 @@ describe('クリップ', () => {
|
||||||
{ label: 'descriptionが最大長+1', parameters: { description: 'a'.repeat(2049) } },
|
{ label: 'descriptionが最大長+1', parameters: { description: 'a'.repeat(2049) } },
|
||||||
];
|
];
|
||||||
test.each(createClipDenyPattern)('の作成は$labelならできない', async ({ parameters }) => failedApiCall({
|
test.each(createClipDenyPattern)('の作成は$labelならできない', async ({ parameters }) => failedApiCall({
|
||||||
endpoint: '/clips/create',
|
endpoint: 'clips/create',
|
||||||
|
// @ts-expect-error invalid params
|
||||||
parameters: {
|
parameters: {
|
||||||
...defaultCreate(),
|
...defaultCreate(),
|
||||||
...parameters,
|
...parameters,
|
||||||
|
@ -246,15 +230,15 @@ describe('クリップ', () => {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
|
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
|
||||||
} },
|
} },
|
||||||
{ label: '他人のクリップ', user: (): User => bob, assertion: {
|
{ label: '他人のクリップ', user: () => bob, assertion: {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
|
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
|
||||||
} },
|
} },
|
||||||
...createClipDenyPattern as any,
|
...createClipDenyPattern as any,
|
||||||
])('の更新は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
])('の更新は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
||||||
endpoint: '/clips/update',
|
endpoint: 'clips/update',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
|
clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
|
||||||
name: 'updated',
|
name: 'updated',
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
|
@ -279,14 +263,15 @@ describe('クリップ', () => {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '70ca08ba-6865-4630-b6fb-8494759aa754',
|
id: '70ca08ba-6865-4630-b6fb-8494759aa754',
|
||||||
} },
|
} },
|
||||||
{ label: '他人のクリップ', user: (): User => bob, assertion: {
|
{ label: '他人のクリップ', user: () => bob, assertion: {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '70ca08ba-6865-4630-b6fb-8494759aa754',
|
id: '70ca08ba-6865-4630-b6fb-8494759aa754',
|
||||||
} },
|
} },
|
||||||
])('の削除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
])('の削除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
||||||
endpoint: '/clips/delete',
|
endpoint: 'clips/delete',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
|
// @ts-expect-error clipId must not be null
|
||||||
|
clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
user: alice,
|
user: alice,
|
||||||
|
@ -306,7 +291,7 @@ describe('クリップ', () => {
|
||||||
test('のID指定取得は他人のPrivateなクリップは取得できない', async () => {
|
test('のID指定取得は他人のPrivateなクリップは取得できない', async () => {
|
||||||
const clip = await create({ isPublic: false }, { user: bob } );
|
const clip = await create({ isPublic: false }, { user: bob } );
|
||||||
failedApiCall({
|
failedApiCall({
|
||||||
endpoint: '/clips/show',
|
endpoint: 'clips/show',
|
||||||
parameters: { clipId: clip.id },
|
parameters: { clipId: clip.id },
|
||||||
user: alice,
|
user: alice,
|
||||||
}, {
|
}, {
|
||||||
|
@ -323,7 +308,8 @@ describe('クリップ', () => {
|
||||||
id: 'c3c5fe33-d62c-44d2-9ea5-d997703f5c20',
|
id: 'c3c5fe33-d62c-44d2-9ea5-d997703f5c20',
|
||||||
} },
|
} },
|
||||||
])('のID指定取得は$labelならできない', async ({ parameters, assetion }) => failedApiCall({
|
])('のID指定取得は$labelならできない', async ({ parameters, assetion }) => failedApiCall({
|
||||||
endpoint: '/clips/show',
|
endpoint: 'clips/show',
|
||||||
|
// @ts-expect-error clipId must not be undefined
|
||||||
parameters: {
|
parameters: {
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
|
@ -356,27 +342,23 @@ describe('クリップ', () => {
|
||||||
|
|
||||||
test('の一覧が取得できる(空)', async () => {
|
test('の一覧が取得できる(空)', async () => {
|
||||||
const res = await usersClips({
|
const res = await usersClips({
|
||||||
parameters: {
|
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
assert.deepStrictEqual(res, []);
|
assert.deepStrictEqual(res, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '' },
|
{ label: '' },
|
||||||
{ label: '他人アカウントから', user: (): User => bob },
|
{ label: '他人アカウントから', user: () => bob },
|
||||||
])('の一覧が$label取得できる', async () => {
|
])('の一覧が$label取得できる', async () => {
|
||||||
const clips = await createMany({ isPublic: true });
|
const clips = await createMany({ isPublic: true });
|
||||||
const res = await usersClips({
|
const res = await usersClips({
|
||||||
parameters: {
|
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 返ってくる配列には順序保障がないのでidでソートして厳密比較
|
// 返ってくる配列には順序保障がないのでidでソートして厳密比較
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
res.sort(compareBy<Clip>(s => s.id)),
|
res.sort(compareBy<Misskey.entities.Clip>(s => s.id)),
|
||||||
clips.sort(compareBy(s => s.id)));
|
clips.sort(compareBy(s => s.id)));
|
||||||
|
|
||||||
// 認証状態で見たときだけisFavoritedが入っている
|
// 認証状態で見たときだけisFavoritedが入っている
|
||||||
|
@ -386,17 +368,16 @@ describe('クリップ', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '未認証', user: (): undefined => undefined },
|
{ label: '未認証', user: () => undefined },
|
||||||
{ label: '存在しないユーザーのもの', parameters: { userId: 'xxxxxxx' } },
|
{ label: '存在しないユーザーのもの', parameters: { userId: 'xxxxxxx' } },
|
||||||
])('の一覧は$labelでも取得できる', async ({ parameters, user }) => {
|
])('の一覧は$labelでも取得できる', async ({ parameters, user }) => {
|
||||||
const clips = await createMany({ isPublic: true });
|
const clips = await createMany({ isPublic: true });
|
||||||
const res = await usersClips({
|
const res = await usersClips({
|
||||||
parameters: {
|
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
limit: clips.length,
|
limit: clips.length,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
}, {
|
||||||
user: (user ?? ((): User => alice))(),
|
user: (user ?? (() => alice))(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// 未認証で見たときはisFavoritedは入らない
|
// 未認証で見たときはisFavoritedは入らない
|
||||||
|
@ -409,10 +390,8 @@ describe('クリップ', () => {
|
||||||
await create({ isPublic: false });
|
await create({ isPublic: false });
|
||||||
const aliceClip = await create({ isPublic: true });
|
const aliceClip = await create({ isPublic: true });
|
||||||
const res = await usersClips({
|
const res = await usersClips({
|
||||||
parameters: {
|
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
limit: 2,
|
limit: 2,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
assert.deepStrictEqual(res, [aliceClip]);
|
assert.deepStrictEqual(res, [aliceClip]);
|
||||||
});
|
});
|
||||||
|
@ -421,17 +400,15 @@ describe('クリップ', () => {
|
||||||
const clips = await createMany({ isPublic: true }, 7);
|
const clips = await createMany({ isPublic: true }, 7);
|
||||||
clips.sort(compareBy(s => s.id));
|
clips.sort(compareBy(s => s.id));
|
||||||
const res = await usersClips({
|
const res = await usersClips({
|
||||||
parameters: {
|
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
sinceId: clips[1].id,
|
sinceId: clips[1].id,
|
||||||
untilId: clips[5].id,
|
untilId: clips[5].id,
|
||||||
limit: 4,
|
limit: 4,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Promise.allで返ってくる配列には順序保障がないのでidでソートして厳密比較
|
// Promise.allで返ってくる配列には順序保障がないのでidでソートして厳密比較
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
res.sort(compareBy<Clip>(s => s.id)),
|
res.sort(compareBy<Misskey.entities.Clip>(s => s.id)),
|
||||||
[clips[2], clips[3], clips[4]], // sinceIdとuntilId自体は結果に含まれない
|
[clips[2], clips[3], clips[4]], // sinceIdとuntilId自体は結果に含まれない
|
||||||
clips[1].id + ' ... ' + clips[3].id + ' with ' + clips.map(s => s.id) + ' vs. ' + res.map(s => s.id));
|
clips[1].id + ' ... ' + clips[3].id + ' with ' + clips.map(s => s.id) + ' vs. ' + res.map(s => s.id));
|
||||||
});
|
});
|
||||||
|
@ -441,8 +418,9 @@ describe('クリップ', () => {
|
||||||
{ label: 'limitゼロ', parameters: { limit: 0 } },
|
{ label: 'limitゼロ', parameters: { limit: 0 } },
|
||||||
{ label: 'limit最大+1', parameters: { limit: 101 } },
|
{ label: 'limit最大+1', parameters: { limit: 101 } },
|
||||||
])('の一覧は$labelだと取得できない', async ({ parameters }) => failedApiCall({
|
])('の一覧は$labelだと取得できない', async ({ parameters }) => failedApiCall({
|
||||||
endpoint: '/users/clips',
|
endpoint: 'users/clips',
|
||||||
parameters: {
|
parameters: {
|
||||||
|
// @ts-expect-error userId must not be undefined
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
|
@ -454,15 +432,15 @@ describe('クリップ', () => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '作成', endpoint: '/clips/create' },
|
{ label: '作成', endpoint: 'clips/create' as const },
|
||||||
{ label: '更新', endpoint: '/clips/update' },
|
{ label: '更新', endpoint: 'clips/update' as const },
|
||||||
{ label: '削除', endpoint: '/clips/delete' },
|
{ label: '削除', endpoint: 'clips/delete' as const },
|
||||||
{ label: '取得', endpoint: '/clips/list' },
|
{ label: '取得', endpoint: 'clips/list' as const },
|
||||||
{ label: 'お気に入り設定', endpoint: '/clips/favorite' },
|
{ label: 'お気に入り設定', endpoint: 'clips/favorite' as const },
|
||||||
{ label: 'お気に入り解除', endpoint: '/clips/unfavorite' },
|
{ label: 'お気に入り解除', endpoint: 'clips/unfavorite' as const },
|
||||||
{ label: 'お気に入り取得', endpoint: '/clips/my-favorites' },
|
{ label: 'お気に入り取得', endpoint: 'clips/my-favorites' as const },
|
||||||
{ label: 'ノート追加', endpoint: '/clips/add-note' },
|
{ label: 'ノート追加', endpoint: 'clips/add-note' as const },
|
||||||
{ label: 'ノート削除', endpoint: '/clips/remove-note' },
|
{ label: 'ノート削除', endpoint: 'clips/remove-note' as const },
|
||||||
])('の$labelは未認証ではできない', async ({ endpoint }) => await failedApiCall({
|
])('の$labelは未認証ではできない', async ({ endpoint }) => await failedApiCall({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
parameters: {},
|
parameters: {},
|
||||||
|
@ -474,35 +452,33 @@ describe('クリップ', () => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('のお気に入り', () => {
|
describe('のお気に入り', () => {
|
||||||
let aliceClip: Clip;
|
let aliceClip: Misskey.entities.Clip;
|
||||||
|
|
||||||
type FavoriteParam = JTDDataType<typeof FavoriteParamDef>;
|
const favorite = async (parameters: Misskey.entities.ClipsFavoriteRequest, request: Partial<ApiRequest<'clips/favorite'>> = {}): Promise<void> => {
|
||||||
const favorite = async (parameters: FavoriteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
|
return successfulApiCall({
|
||||||
return successfulApiCall<void>({
|
endpoint: 'clips/favorite',
|
||||||
endpoint: '/clips/favorite',
|
|
||||||
parameters,
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
}, {
|
}, {
|
||||||
status: 204,
|
status: 204,
|
||||||
});
|
}) as any as void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type UnfavoriteParam = JTDDataType<typeof UnfavoriteParamDef>;
|
const unfavorite = async (parameters: Misskey.entities.ClipsUnfavoriteRequest, request: Partial<ApiRequest<'clips/unfavorite'>> = {}): Promise<void> => {
|
||||||
const unfavorite = async (parameters: UnfavoriteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
|
return successfulApiCall({
|
||||||
return successfulApiCall<void>({
|
endpoint: 'clips/unfavorite',
|
||||||
endpoint: '/clips/unfavorite',
|
|
||||||
parameters,
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
}, {
|
}, {
|
||||||
status: 204,
|
status: 204,
|
||||||
});
|
}) as any as void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const myFavorites = async (request: Partial<ApiRequest> = {}): Promise<Clip[]> => {
|
const myFavorites = async (request: Partial<ApiRequest<'clips/my-favorites'>> = {}): Promise<Misskey.entities.Clip[]> => {
|
||||||
return successfulApiCall<Clip[]>({
|
return successfulApiCall({
|
||||||
endpoint: '/clips/my-favorites',
|
endpoint: 'clips/my-favorites',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
|
@ -568,7 +544,7 @@ describe('クリップ', () => {
|
||||||
test('は同じクリップに対して二回設定できない。', async () => {
|
test('は同じクリップに対して二回設定できない。', async () => {
|
||||||
await favorite({ clipId: aliceClip.id });
|
await favorite({ clipId: aliceClip.id });
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/clips/favorite',
|
endpoint: 'clips/favorite',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: aliceClip.id,
|
clipId: aliceClip.id,
|
||||||
},
|
},
|
||||||
|
@ -586,14 +562,15 @@ describe('クリップ', () => {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
|
id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
|
||||||
} },
|
} },
|
||||||
{ label: '他人のクリップ', user: (): User => bob, assertion: {
|
{ label: '他人のクリップ', user: () => bob, assertion: {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
|
id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
|
||||||
} },
|
} },
|
||||||
])('の設定は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
])('の設定は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
||||||
endpoint: '/clips/favorite',
|
endpoint: 'clips/favorite',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
|
// @ts-expect-error clipId must not be null
|
||||||
|
clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
user: alice,
|
user: alice,
|
||||||
|
@ -619,7 +596,7 @@ describe('クリップ', () => {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '2603966e-b865-426c-94a7-af4a01241dc1',
|
id: '2603966e-b865-426c-94a7-af4a01241dc1',
|
||||||
} },
|
} },
|
||||||
{ label: '他人のクリップ', user: (): User => bob, assertion: {
|
{ label: '他人のクリップ', user: () => bob, assertion: {
|
||||||
code: 'NOT_FAVORITED',
|
code: 'NOT_FAVORITED',
|
||||||
id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
|
id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
|
||||||
} },
|
} },
|
||||||
|
@ -628,9 +605,10 @@ describe('クリップ', () => {
|
||||||
id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
|
id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
|
||||||
} },
|
} },
|
||||||
])('の設定解除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
])('の設定解除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
|
||||||
endpoint: '/clips/unfavorite',
|
endpoint: 'clips/unfavorite',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
|
// @ts-expect-error clipId must not be null
|
||||||
|
clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
user: alice,
|
user: alice,
|
||||||
|
@ -655,41 +633,38 @@ describe('クリップ', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('に紐づくノート', () => {
|
describe('に紐づくノート', () => {
|
||||||
let aliceClip: Clip;
|
let aliceClip: Misskey.entities.Clip;
|
||||||
|
|
||||||
const sampleNotes = (): Note[] => [
|
const sampleNotes = (): Misskey.entities.Note[] => [
|
||||||
aliceNote, aliceHomeNote, aliceFollowersNote, aliceSpecifiedNote,
|
aliceNote, aliceHomeNote, aliceFollowersNote, aliceSpecifiedNote,
|
||||||
bobNote, bobHomeNote, bobFollowersNote, bobSpecifiedNote,
|
bobNote, bobHomeNote, bobFollowersNote, bobSpecifiedNote,
|
||||||
];
|
];
|
||||||
|
|
||||||
type AddNoteParam = JTDDataType<typeof AddNoteParamDef>;
|
const addNote = async (parameters: Misskey.entities.ClipsAddNoteRequest, request: Partial<ApiRequest<'clips/add-note'>> = {}): Promise<void> => {
|
||||||
const addNote = async (parameters: AddNoteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
|
return successfulApiCall({
|
||||||
return successfulApiCall<void>({
|
endpoint: 'clips/add-note',
|
||||||
endpoint: '/clips/add-note',
|
|
||||||
parameters,
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
}, {
|
}, {
|
||||||
status: 204,
|
status: 204,
|
||||||
});
|
}) as any as void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RemoveNoteParam = JTDDataType<typeof RemoveNoteParamDef>;
|
const removeNote = async (parameters: Misskey.entities.ClipsRemoveNoteRequest, request: Partial<ApiRequest<'clips/remove-note'>> = {}): Promise<void> => {
|
||||||
const removeNote = async (parameters: RemoveNoteParam, request: Partial<ApiRequest> = {}): Promise<void> => {
|
return successfulApiCall({
|
||||||
return successfulApiCall<void>({
|
endpoint: 'clips/remove-note',
|
||||||
endpoint: '/clips/remove-note',
|
|
||||||
parameters,
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
}, {
|
}, {
|
||||||
status: 204,
|
status: 204,
|
||||||
});
|
}) as any as void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NotesParam = JTDDataType<typeof NotesParamDef>;
|
const notes = async (parameters: Misskey.entities.ClipsNotesRequest, request: Partial<ApiRequest<'clips/notes'>> = {}): Promise<Misskey.entities.Note[]> => {
|
||||||
const notes = async (parameters: Partial<NotesParam>, request: Partial<ApiRequest> = {}): Promise<Note[]> => {
|
return successfulApiCall({
|
||||||
return successfulApiCall<Note[]>({
|
endpoint: 'clips/notes',
|
||||||
endpoint: '/clips/notes',
|
|
||||||
parameters,
|
parameters,
|
||||||
user: alice,
|
user: alice,
|
||||||
...request,
|
...request,
|
||||||
|
@ -715,7 +690,7 @@ describe('クリップ', () => {
|
||||||
test('として同じノートを二回紐づけることはできない', async () => {
|
test('として同じノートを二回紐づけることはできない', async () => {
|
||||||
await addNote({ clipId: aliceClip.id, noteId: aliceNote.id });
|
await addNote({ clipId: aliceClip.id, noteId: aliceNote.id });
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/clips/add-note',
|
endpoint: 'clips/add-note',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: aliceClip.id,
|
clipId: aliceClip.id,
|
||||||
noteId: aliceNote.id,
|
noteId: aliceNote.id,
|
||||||
|
@ -733,11 +708,11 @@ describe('クリップ', () => {
|
||||||
const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1;
|
const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1;
|
||||||
const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, {
|
const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, {
|
||||||
text: `test ${i}`,
|
text: `test ${i}`,
|
||||||
}) as unknown)) as Note[];
|
}) as unknown)) as Misskey.entities.Note[];
|
||||||
await Promise.all(noteList.map(s => addNote({ clipId: aliceClip.id, noteId: s.id })));
|
await Promise.all(noteList.map(s => addNote({ clipId: aliceClip.id, noteId: s.id })));
|
||||||
|
|
||||||
await failedApiCall({
|
await failedApiCall({
|
||||||
endpoint: '/clips/add-note',
|
endpoint: 'clips/add-note',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: aliceClip.id,
|
clipId: aliceClip.id,
|
||||||
noteId: aliceNote.id,
|
noteId: aliceNote.id,
|
||||||
|
@ -751,7 +726,7 @@ describe('クリップ', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('は他人のクリップへ追加できない。', async () => await failedApiCall({
|
test('は他人のクリップへ追加できない。', async () => await failedApiCall({
|
||||||
endpoint: '/clips/add-note',
|
endpoint: 'clips/add-note',
|
||||||
parameters: {
|
parameters: {
|
||||||
clipId: aliceClip.id,
|
clipId: aliceClip.id,
|
||||||
noteId: aliceNote.id,
|
noteId: aliceNote.id,
|
||||||
|
@ -774,18 +749,20 @@ describe('クリップ', () => {
|
||||||
code: 'NO_SUCH_NOTE',
|
code: 'NO_SUCH_NOTE',
|
||||||
id: 'fc8c0b49-c7a3-4664-a0a6-b418d386bb8b',
|
id: 'fc8c0b49-c7a3-4664-a0a6-b418d386bb8b',
|
||||||
} },
|
} },
|
||||||
{ label: '他人のクリップ', user: (): object => bob, assetion: {
|
{ label: '他人のクリップ', user: () => bob, assetion: {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: 'd6e76cc0-a1b5-4c7c-a287-73fa9c716dcf',
|
id: 'd6e76cc0-a1b5-4c7c-a287-73fa9c716dcf',
|
||||||
} },
|
} },
|
||||||
])('の追加は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
|
])('の追加は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
|
||||||
endpoint: '/clips/add-note',
|
endpoint: 'clips/add-note',
|
||||||
parameters: {
|
parameters: {
|
||||||
|
// @ts-expect-error clipId must not be undefined
|
||||||
clipId: aliceClip.id,
|
clipId: aliceClip.id,
|
||||||
|
// @ts-expect-error noteId must not be undefined
|
||||||
noteId: aliceNote.id,
|
noteId: aliceNote.id,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
user: (user ?? ((): User => alice))(),
|
user: (user ?? (() => alice))(),
|
||||||
}, {
|
}, {
|
||||||
status: 400,
|
status: 400,
|
||||||
code: 'INVALID_PARAM',
|
code: 'INVALID_PARAM',
|
||||||
|
@ -810,18 +787,20 @@ describe('クリップ', () => {
|
||||||
code: 'NO_SUCH_NOTE',
|
code: 'NO_SUCH_NOTE',
|
||||||
id: 'aff017de-190e-434b-893e-33a9ff5049d8', // add-noteと異なる
|
id: 'aff017de-190e-434b-893e-33a9ff5049d8', // add-noteと異なる
|
||||||
} },
|
} },
|
||||||
{ label: '他人のクリップ', user: (): object => bob, assetion: {
|
{ label: '他人のクリップ', user: () => bob, assetion: {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', // add-noteと異なる
|
id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', // add-noteと異なる
|
||||||
} },
|
} },
|
||||||
])('の削除は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
|
])('の削除は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
|
||||||
endpoint: '/clips/remove-note',
|
endpoint: 'clips/remove-note',
|
||||||
parameters: {
|
parameters: {
|
||||||
|
// @ts-expect-error clipId must not be undefined
|
||||||
clipId: aliceClip.id,
|
clipId: aliceClip.id,
|
||||||
|
// @ts-expect-error noteId must not be undefined
|
||||||
noteId: aliceNote.id,
|
noteId: aliceNote.id,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
user: (user ?? ((): User => alice))(),
|
user: (user ?? (() => alice))(),
|
||||||
}, {
|
}, {
|
||||||
status: 400,
|
status: 400,
|
||||||
code: 'INVALID_PARAM',
|
code: 'INVALID_PARAM',
|
||||||
|
@ -925,21 +904,22 @@ describe('クリップ', () => {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
|
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
|
||||||
} },
|
} },
|
||||||
{ label: '他人のPrivateなクリップから', user: (): object => bob, assertion: {
|
{ label: '他人のPrivateなクリップから', user: () => bob, assertion: {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
|
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
|
||||||
} },
|
} },
|
||||||
{ label: '未認証でPrivateなクリップから', user: (): undefined => undefined, assertion: {
|
{ label: '未認証でPrivateなクリップから', user: () => undefined, assertion: {
|
||||||
code: 'NO_SUCH_CLIP',
|
code: 'NO_SUCH_CLIP',
|
||||||
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
|
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
|
||||||
} },
|
} },
|
||||||
])('は$labelだと取得できない', async ({ parameters, user, assertion }) => failedApiCall({
|
])('は$labelだと取得できない', async ({ parameters, user, assertion }) => failedApiCall({
|
||||||
endpoint: '/clips/notes',
|
endpoint: 'clips/notes',
|
||||||
parameters: {
|
parameters: {
|
||||||
|
// @ts-expect-error clipId must not be undefined
|
||||||
clipId: aliceClip.id,
|
clipId: aliceClip.id,
|
||||||
...parameters,
|
...parameters,
|
||||||
},
|
},
|
||||||
user: (user ?? ((): User => alice))(),
|
user: (user ?? (() => alice))(),
|
||||||
}, {
|
}, {
|
||||||
status: 400,
|
status: 400,
|
||||||
code: 'INVALID_PARAM',
|
code: 'INVALID_PARAM',
|
||||||
|
|
|
@ -6,22 +6,14 @@
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { MiNote } from '@/models/Note.js';
|
import { api, makeStreamCatcher, post, signup, uploadFile } from '../utils.js';
|
||||||
import { api, initTestDb, makeStreamCatcher, post, signup, uploadFile } from '../utils.js';
|
|
||||||
import type * as misskey from 'misskey-js';
|
import type * as misskey from 'misskey-js';
|
||||||
import type{ Repository } from 'typeorm'
|
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
|
||||||
|
|
||||||
|
|
||||||
describe('Drive', () => {
|
describe('Drive', () => {
|
||||||
let Notes: Repository<MiNote>;
|
|
||||||
|
|
||||||
let alice: misskey.entities.SignupResponse;
|
let alice: misskey.entities.SignupResponse;
|
||||||
let bob: misskey.entities.SignupResponse;
|
let bob: misskey.entities.SignupResponse;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const connection = await initTestDb(true);
|
|
||||||
Notes = connection.getRepository(MiNote);
|
|
||||||
alice = await signup({ username: 'alice' });
|
alice = await signup({ username: 'alice' });
|
||||||
bob = await signup({ username: 'bob' });
|
bob = await signup({ username: 'bob' });
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
@ -31,13 +23,13 @@ describe('Drive', () => {
|
||||||
|
|
||||||
const marker = Math.random().toString();
|
const marker = Math.random().toString();
|
||||||
|
|
||||||
const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'
|
const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg';
|
||||||
|
|
||||||
const catcher = makeStreamCatcher(
|
const catcher = makeStreamCatcher(
|
||||||
alice,
|
alice,
|
||||||
'main',
|
'main',
|
||||||
(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
|
(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
|
||||||
(msg) => msg.body.file as Packed<'DriveFile'>,
|
(msg) => msg.body.file,
|
||||||
10 * 1000);
|
10 * 1000);
|
||||||
|
|
||||||
const res = await api('drive/files/upload-from-url', {
|
const res = await api('drive/files/upload-from-url', {
|
||||||
|
@ -51,7 +43,7 @@ describe('Drive', () => {
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
assert.strictEqual(file.name, 'Lenna.jpg');
|
assert.strictEqual(file.name, 'Lenna.jpg');
|
||||||
assert.strictEqual(file.type, 'image/jpeg');
|
assert.strictEqual(file.type, 'image/jpeg');
|
||||||
})
|
});
|
||||||
|
|
||||||
test('ローカルからアップロードできる', async () => {
|
test('ローカルからアップロードできる', async () => {
|
||||||
// APIレスポンスを直接使用するので utils.js uploadFile が通過することで成功とする
|
// APIレスポンスを直接使用するので utils.js uploadFile が通過することで成功とする
|
||||||
|
@ -59,27 +51,27 @@ describe('Drive', () => {
|
||||||
const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画像' });
|
const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画像' });
|
||||||
|
|
||||||
assert.strictEqual(res.body?.name, 'テスト画像.jpg');
|
assert.strictEqual(res.body?.name, 'テスト画像.jpg');
|
||||||
assert.strictEqual(res.body?.type, 'image/jpeg');
|
assert.strictEqual(res.body.type, 'image/jpeg');
|
||||||
})
|
});
|
||||||
|
|
||||||
test('添付ノート一覧を取得できる', async () => {
|
test('添付ノート一覧を取得できる', async () => {
|
||||||
const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id)
|
const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id);
|
||||||
|
|
||||||
const note0 = await post(alice, { fileIds: [ids[0]] });
|
const note0 = await post(alice, { fileIds: [ids[0]] });
|
||||||
const note1 = await post(alice, { fileIds: [ids[0], ids[1]] });
|
const note1 = await post(alice, { fileIds: [ids[0], ids[1]] });
|
||||||
|
|
||||||
const attached0 = await api('drive/files/attached-notes', { fileId: ids[0] }, alice);
|
const attached0 = await api('drive/files/attached-notes', { fileId: ids[0] }, alice);
|
||||||
assert.strictEqual(attached0.body.length, 2);
|
assert.strictEqual(attached0.body.length, 2);
|
||||||
assert.strictEqual(attached0.body[0].id, note1.id)
|
assert.strictEqual(attached0.body[0].id, note1.id);
|
||||||
assert.strictEqual(attached0.body[1].id, note0.id)
|
assert.strictEqual(attached0.body[1].id, note0.id);
|
||||||
|
|
||||||
const attached1 = await api('drive/files/attached-notes', { fileId: ids[1] }, alice);
|
const attached1 = await api('drive/files/attached-notes', { fileId: ids[1] }, alice);
|
||||||
assert.strictEqual(attached1.body.length, 1);
|
assert.strictEqual(attached1.body.length, 1);
|
||||||
assert.strictEqual(attached1.body[0].id, note1.id)
|
assert.strictEqual(attached1.body[0].id, note1.id);
|
||||||
|
|
||||||
const attached2 = await api('drive/files/attached-notes', { fileId: ids[2] }, alice);
|
const attached2 = await api('drive/files/attached-notes', { fileId: ids[2] }, alice);
|
||||||
assert.strictEqual(attached2.body.length, 0)
|
assert.strictEqual(attached2.body.length, 0);
|
||||||
})
|
});
|
||||||
|
|
||||||
test('添付ノート一覧は他の人から見えない', async () => {
|
test('添付ノート一覧は他の人から見えない', async () => {
|
||||||
const file = await uploadFile(alice);
|
const file = await uploadFile(alice);
|
||||||
|
@ -89,7 +81,5 @@ describe('Drive', () => {
|
||||||
const res = await api('drive/files/attached-notes', { fileId: file.body!.id }, bob);
|
const res = await api('drive/files/attached-notes', { fileId: file.body!.id }, bob);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
assert.strictEqual('error' in res.body, true);
|
assert.strictEqual('error' in res.body, true);
|
||||||
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -79,6 +79,7 @@ describe('Endpoints', () => {
|
||||||
test('クエリをインジェクションできない', async () => {
|
test('クエリをインジェクションできない', async () => {
|
||||||
const res = await api('signin', {
|
const res = await api('signin', {
|
||||||
username: 'test1',
|
username: 'test1',
|
||||||
|
// @ts-expect-error password must be string
|
||||||
password: {
|
password: {
|
||||||
$gt: '',
|
$gt: '',
|
||||||
},
|
},
|
||||||
|
@ -103,7 +104,7 @@ describe('Endpoints', () => {
|
||||||
const myLocation = '七森中';
|
const myLocation = '七森中';
|
||||||
const myBirthday = '2000-09-07';
|
const myBirthday = '2000-09-07';
|
||||||
|
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
name: myName,
|
name: myName,
|
||||||
location: myLocation,
|
location: myLocation,
|
||||||
birthday: myBirthday,
|
birthday: myBirthday,
|
||||||
|
@ -117,7 +118,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('名前を空白にできる', async () => {
|
test('名前を空白にできる', async () => {
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
name: ' ',
|
name: ' ',
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
|
@ -125,11 +126,11 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('誕生日の設定を削除できる', async () => {
|
test('誕生日の設定を削除できる', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
birthday: '2000-09-07',
|
birthday: '2000-09-07',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
birthday: null,
|
birthday: null,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -139,7 +140,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('不正な誕生日の形式で怒られる', async () => {
|
test('不正な誕生日の形式で怒られる', async () => {
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
birthday: '2000/09/07',
|
birthday: '2000/09/07',
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
|
@ -148,7 +149,7 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
describe('users/show', () => {
|
describe('users/show', () => {
|
||||||
test('ユーザーが取得できる', async () => {
|
test('ユーザーが取得できる', async () => {
|
||||||
const res = await api('/users/show', {
|
const res = await api('users/show', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -158,14 +159,14 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ユーザーが存在しなかったら怒る', async () => {
|
test('ユーザーが存在しなかったら怒る', async () => {
|
||||||
const res = await api('/users/show', {
|
const res = await api('users/show', {
|
||||||
userId: '000000000000000000000000',
|
userId: '000000000000000000000000',
|
||||||
});
|
});
|
||||||
assert.strictEqual(res.status, 404);
|
assert.strictEqual(res.status, 404);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('間違ったIDで怒られる', async () => {
|
test('間違ったIDで怒られる', async () => {
|
||||||
const res = await api('/users/show', {
|
const res = await api('users/show', {
|
||||||
userId: 'kyoppie',
|
userId: 'kyoppie',
|
||||||
});
|
});
|
||||||
assert.strictEqual(res.status, 404);
|
assert.strictEqual(res.status, 404);
|
||||||
|
@ -178,7 +179,7 @@ describe('Endpoints', () => {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await api('/notes/show', {
|
const res = await api('notes/show', {
|
||||||
noteId: myPost.id,
|
noteId: myPost.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -189,14 +190,14 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('投稿が存在しなかったら怒る', async () => {
|
test('投稿が存在しなかったら怒る', async () => {
|
||||||
const res = await api('/notes/show', {
|
const res = await api('notes/show', {
|
||||||
noteId: '000000000000000000000000',
|
noteId: '000000000000000000000000',
|
||||||
});
|
});
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('間違ったIDで怒られる', async () => {
|
test('間違ったIDで怒られる', async () => {
|
||||||
const res = await api('/notes/show', {
|
const res = await api('notes/show', {
|
||||||
noteId: 'kyoppie',
|
noteId: 'kyoppie',
|
||||||
});
|
});
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
|
@ -207,14 +208,14 @@ describe('Endpoints', () => {
|
||||||
test('リアクションできる', async () => {
|
test('リアクションできる', async () => {
|
||||||
const bobPost = await post(bob, { text: 'hi' });
|
const bobPost = await post(bob, { text: 'hi' });
|
||||||
|
|
||||||
const res = await api('/notes/reactions/create', {
|
const res = await api('notes/reactions/create', {
|
||||||
noteId: bobPost.id,
|
noteId: bobPost.id,
|
||||||
reaction: '🚀',
|
reaction: '🚀',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
const resNote = await api('/notes/show', {
|
const resNote = await api('notes/show', {
|
||||||
noteId: bobPost.id,
|
noteId: bobPost.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -225,7 +226,7 @@ describe('Endpoints', () => {
|
||||||
test('自分の投稿にもリアクションできる', async () => {
|
test('自分の投稿にもリアクションできる', async () => {
|
||||||
const myPost = await post(alice, { text: 'hi' });
|
const myPost = await post(alice, { text: 'hi' });
|
||||||
|
|
||||||
const res = await api('/notes/reactions/create', {
|
const res = await api('notes/reactions/create', {
|
||||||
noteId: myPost.id,
|
noteId: myPost.id,
|
||||||
reaction: '🚀',
|
reaction: '🚀',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -236,19 +237,19 @@ describe('Endpoints', () => {
|
||||||
test('二重にリアクションすると上書きされる', async () => {
|
test('二重にリアクションすると上書きされる', async () => {
|
||||||
const bobPost = await post(bob, { text: 'hi' });
|
const bobPost = await post(bob, { text: 'hi' });
|
||||||
|
|
||||||
await api('/notes/reactions/create', {
|
await api('notes/reactions/create', {
|
||||||
noteId: bobPost.id,
|
noteId: bobPost.id,
|
||||||
reaction: '🥰',
|
reaction: '🥰',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/notes/reactions/create', {
|
const res = await api('notes/reactions/create', {
|
||||||
noteId: bobPost.id,
|
noteId: bobPost.id,
|
||||||
reaction: '🚀',
|
reaction: '🚀',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
const resNote = await api('/notes/show', {
|
const resNote = await api('notes/show', {
|
||||||
noteId: bobPost.id,
|
noteId: bobPost.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -257,7 +258,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('存在しない投稿にはリアクションできない', async () => {
|
test('存在しない投稿にはリアクションできない', async () => {
|
||||||
const res = await api('/notes/reactions/create', {
|
const res = await api('notes/reactions/create', {
|
||||||
noteId: '000000000000000000000000',
|
noteId: '000000000000000000000000',
|
||||||
reaction: '🚀',
|
reaction: '🚀',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -266,13 +267,14 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('空のパラメータで怒られる', async () => {
|
test('空のパラメータで怒られる', async () => {
|
||||||
const res = await api('/notes/reactions/create', {}, alice);
|
// @ts-expect-error param must not be empty
|
||||||
|
const res = await api('notes/reactions/create', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('間違ったIDで怒られる', async () => {
|
test('間違ったIDで怒られる', async () => {
|
||||||
const res = await api('/notes/reactions/create', {
|
const res = await api('notes/reactions/create', {
|
||||||
noteId: 'kyoppie',
|
noteId: 'kyoppie',
|
||||||
reaction: '🚀',
|
reaction: '🚀',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -283,7 +285,7 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
describe('following/create', () => {
|
describe('following/create', () => {
|
||||||
test('フォローできる', async () => {
|
test('フォローできる', async () => {
|
||||||
const res = await api('/following/create', {
|
const res = await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -301,7 +303,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('既にフォローしている場合は怒る', async () => {
|
test('既にフォローしている場合は怒る', async () => {
|
||||||
const res = await api('/following/create', {
|
const res = await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -309,7 +311,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('存在しないユーザーはフォローできない', async () => {
|
test('存在しないユーザーはフォローできない', async () => {
|
||||||
const res = await api('/following/create', {
|
const res = await api('following/create', {
|
||||||
userId: '000000000000000000000000',
|
userId: '000000000000000000000000',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -317,7 +319,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('自分自身はフォローできない', async () => {
|
test('自分自身はフォローできない', async () => {
|
||||||
const res = await api('/following/create', {
|
const res = await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -325,13 +327,14 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('空のパラメータで怒られる', async () => {
|
test('空のパラメータで怒られる', async () => {
|
||||||
const res = await api('/following/create', {}, alice);
|
// @ts-expect-error params must not be empty
|
||||||
|
const res = await api('following/create', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('間違ったIDで怒られる', async () => {
|
test('間違ったIDで怒られる', async () => {
|
||||||
const res = await api('/following/create', {
|
const res = await api('following/create', {
|
||||||
userId: 'foo',
|
userId: 'foo',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -341,11 +344,11 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
describe('following/delete', () => {
|
describe('following/delete', () => {
|
||||||
test('フォロー解除できる', async () => {
|
test('フォロー解除できる', async () => {
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const res = await api('/following/delete', {
|
const res = await api('following/delete', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -363,7 +366,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('フォローしていない場合は怒る', async () => {
|
test('フォローしていない場合は怒る', async () => {
|
||||||
const res = await api('/following/delete', {
|
const res = await api('following/delete', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -371,7 +374,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('存在しないユーザーはフォロー解除できない', async () => {
|
test('存在しないユーザーはフォロー解除できない', async () => {
|
||||||
const res = await api('/following/delete', {
|
const res = await api('following/delete', {
|
||||||
userId: '000000000000000000000000',
|
userId: '000000000000000000000000',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -379,7 +382,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('自分自身はフォロー解除できない', async () => {
|
test('自分自身はフォロー解除できない', async () => {
|
||||||
const res = await api('/following/delete', {
|
const res = await api('following/delete', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -387,13 +390,14 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('空のパラメータで怒られる', async () => {
|
test('空のパラメータで怒られる', async () => {
|
||||||
const res = await api('/following/delete', {}, alice);
|
// @ts-expect-error params must not be empty
|
||||||
|
const res = await api('following/delete', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('間違ったIDで怒られる', async () => {
|
test('間違ったIDで怒られる', async () => {
|
||||||
const res = await api('/following/delete', {
|
const res = await api('following/delete', {
|
||||||
userId: 'kyoppie',
|
userId: 'kyoppie',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -403,20 +407,20 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
describe('channels/search', () => {
|
describe('channels/search', () => {
|
||||||
test('空白検索で一覧を取得できる', async () => {
|
test('空白検索で一覧を取得できる', async () => {
|
||||||
await api('/channels/create', {
|
await api('channels/create', {
|
||||||
name: 'aaa',
|
name: 'aaa',
|
||||||
description: 'bbb',
|
description: 'bbb',
|
||||||
}, bob);
|
}, bob);
|
||||||
await api('/channels/create', {
|
await api('channels/create', {
|
||||||
name: 'ccc1',
|
name: 'ccc1',
|
||||||
description: 'ddd1',
|
description: 'ddd1',
|
||||||
}, bob);
|
}, bob);
|
||||||
await api('/channels/create', {
|
await api('channels/create', {
|
||||||
name: 'ccc2',
|
name: 'ccc2',
|
||||||
description: 'ddd2',
|
description: 'ddd2',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: '',
|
query: '',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -425,7 +429,7 @@ describe('Endpoints', () => {
|
||||||
assert.strictEqual(res.body.length, 3);
|
assert.strictEqual(res.body.length, 3);
|
||||||
});
|
});
|
||||||
test('名前のみの検索で名前を検索できる', async () => {
|
test('名前のみの検索で名前を検索できる', async () => {
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: 'aaa',
|
query: 'aaa',
|
||||||
type: 'nameOnly',
|
type: 'nameOnly',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
@ -436,7 +440,7 @@ describe('Endpoints', () => {
|
||||||
assert.strictEqual(res.body[0].name, 'aaa');
|
assert.strictEqual(res.body[0].name, 'aaa');
|
||||||
});
|
});
|
||||||
test('名前のみの検索で名前を複数検索できる', async () => {
|
test('名前のみの検索で名前を複数検索できる', async () => {
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: 'ccc',
|
query: 'ccc',
|
||||||
type: 'nameOnly',
|
type: 'nameOnly',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
@ -446,7 +450,7 @@ describe('Endpoints', () => {
|
||||||
assert.strictEqual(res.body.length, 2);
|
assert.strictEqual(res.body.length, 2);
|
||||||
});
|
});
|
||||||
test('名前のみの検索で説明は検索できない', async () => {
|
test('名前のみの検索で説明は検索できない', async () => {
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: 'bbb',
|
query: 'bbb',
|
||||||
type: 'nameOnly',
|
type: 'nameOnly',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
@ -456,7 +460,7 @@ describe('Endpoints', () => {
|
||||||
assert.strictEqual(res.body.length, 0);
|
assert.strictEqual(res.body.length, 0);
|
||||||
});
|
});
|
||||||
test('名前と説明の検索で名前を検索できる', async () => {
|
test('名前と説明の検索で名前を検索できる', async () => {
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: 'ccc1',
|
query: 'ccc1',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -466,7 +470,7 @@ describe('Endpoints', () => {
|
||||||
assert.strictEqual(res.body[0].name, 'ccc1');
|
assert.strictEqual(res.body[0].name, 'ccc1');
|
||||||
});
|
});
|
||||||
test('名前と説明での検索で説明を検索できる', async () => {
|
test('名前と説明での検索で説明を検索できる', async () => {
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: 'ddd1',
|
query: 'ddd1',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -476,7 +480,7 @@ describe('Endpoints', () => {
|
||||||
assert.strictEqual(res.body[0].name, 'ccc1');
|
assert.strictEqual(res.body[0].name, 'ccc1');
|
||||||
});
|
});
|
||||||
test('名前と説明の検索で名前を複数検索できる', async () => {
|
test('名前と説明の検索で名前を複数検索できる', async () => {
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: 'ccc',
|
query: 'ccc',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -485,7 +489,7 @@ describe('Endpoints', () => {
|
||||||
assert.strictEqual(res.body.length, 2);
|
assert.strictEqual(res.body.length, 2);
|
||||||
});
|
});
|
||||||
test('名前と説明での検索で説明を複数検索できる', async () => {
|
test('名前と説明での検索で説明を複数検索できる', async () => {
|
||||||
const res = await api('/channels/search', {
|
const res = await api('channels/search', {
|
||||||
query: 'ddd',
|
query: 'ddd',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -506,7 +510,7 @@ describe('Endpoints', () => {
|
||||||
await uploadFile(alice, {
|
await uploadFile(alice, {
|
||||||
blob: new Blob([new Uint8Array(1024)]),
|
blob: new Blob([new Uint8Array(1024)]),
|
||||||
});
|
});
|
||||||
const res = await api('/drive', {}, alice);
|
const res = await api('drive', {}, alice);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
expect(res.body).toHaveProperty('usage', 1792);
|
expect(res.body).toHaveProperty('usage', 1792);
|
||||||
|
@ -519,7 +523,7 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
assert.strictEqual(res.body.name, 'Lenna.jpg');
|
assert.strictEqual(res.body!.name, 'Lenna.jpg');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイルに名前を付けられる', async () => {
|
test('ファイルに名前を付けられる', async () => {
|
||||||
|
@ -527,7 +531,7 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
assert.strictEqual(res.body.name, 'Belmond.jpg');
|
assert.strictEqual(res.body!.name, 'Belmond.jpg');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイルに名前を付けられるが、拡張子は正しいものになる', async () => {
|
test('ファイルに名前を付けられるが、拡張子は正しいものになる', async () => {
|
||||||
|
@ -535,11 +539,12 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
assert.strictEqual(res.body.name, 'Belmond.png.jpg');
|
assert.strictEqual(res.body!.name, 'Belmond.png.jpg');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイル無しで怒られる', async () => {
|
test('ファイル無しで怒られる', async () => {
|
||||||
const res = await api('/drive/files/create', {}, alice);
|
// @ts-expect-error params must not be empty
|
||||||
|
const res = await api('drive/files/create', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
@ -549,14 +554,14 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
assert.strictEqual(res.body.name, 'image.svg');
|
assert.strictEqual(res.body!.name, 'image.svg');
|
||||||
assert.strictEqual(res.body.type, 'image/svg+xml');
|
assert.strictEqual(res.body!.type, 'image/svg+xml');
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const type of ['webp', 'avif']) {
|
for (const type of ['webp', 'avif']) {
|
||||||
const mediaType = `image/${type}`;
|
const mediaType = `image/${type}`;
|
||||||
|
|
||||||
const getWebpublicType = async (user: any, fileId: string): Promise<string> => {
|
const getWebpublicType = async (user: misskey.entities.SignupResponse, fileId: string): Promise<string> => {
|
||||||
// drive/files/create does not expose webpublicType directly, so get it by posting it
|
// drive/files/create does not expose webpublicType directly, so get it by posting it
|
||||||
const res = await post(user, {
|
const res = await post(user, {
|
||||||
text: mediaType,
|
text: mediaType,
|
||||||
|
@ -573,10 +578,10 @@ describe('Endpoints', () => {
|
||||||
const res = await uploadFile(alice, { path });
|
const res = await uploadFile(alice, { path });
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(res.body.name, path);
|
assert.strictEqual(res.body!.name, path);
|
||||||
assert.strictEqual(res.body.type, mediaType);
|
assert.strictEqual(res.body!.type, mediaType);
|
||||||
|
|
||||||
const webpublicType = await getWebpublicType(alice, res.body.id);
|
const webpublicType = await getWebpublicType(alice, res.body!.id);
|
||||||
assert.strictEqual(webpublicType, 'image/webp');
|
assert.strictEqual(webpublicType, 'image/webp');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -584,10 +589,10 @@ describe('Endpoints', () => {
|
||||||
const path = `without-alpha.${type}`;
|
const path = `without-alpha.${type}`;
|
||||||
const res = await uploadFile(alice, { path });
|
const res = await uploadFile(alice, { path });
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(res.body.name, path);
|
assert.strictEqual(res.body!.name, path);
|
||||||
assert.strictEqual(res.body.type, mediaType);
|
assert.strictEqual(res.body!.type, mediaType);
|
||||||
|
|
||||||
const webpublicType = await getWebpublicType(alice, res.body.id);
|
const webpublicType = await getWebpublicType(alice, res.body!.id);
|
||||||
assert.strictEqual(webpublicType, 'image/webp');
|
assert.strictEqual(webpublicType, 'image/webp');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -598,8 +603,8 @@ describe('Endpoints', () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
const newName = 'いちごパスタ.png';
|
const newName = 'いちごパスタ.png';
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
name: newName,
|
name: newName,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -611,8 +616,8 @@ describe('Endpoints', () => {
|
||||||
test('他人のファイルは更新できない', async () => {
|
test('他人のファイルは更新できない', async () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
name: 'いちごパスタ.png',
|
name: 'いちごパスタ.png',
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -621,12 +626,12 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
test('親フォルダを更新できる', async () => {
|
test('親フォルダを更新できる', async () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -638,17 +643,17 @@ describe('Endpoints', () => {
|
||||||
test('親フォルダを無しにできる', async () => {
|
test('親フォルダを無しにできる', async () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
|
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
|
|
||||||
await api('/drive/files/update', {
|
await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -659,12 +664,12 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
test('他人のフォルダには入れられない', async () => {
|
test('他人のフォルダには入れられない', async () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, bob)).body;
|
}, bob)).body;
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -674,8 +679,8 @@ describe('Endpoints', () => {
|
||||||
test('存在しないフォルダで怒られる', async () => {
|
test('存在しないフォルダで怒られる', async () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
folderId: '000000000000000000000000',
|
folderId: '000000000000000000000000',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -685,8 +690,8 @@ describe('Endpoints', () => {
|
||||||
test('不正なフォルダIDで怒られる', async () => {
|
test('不正なフォルダIDで怒られる', async () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
folderId: 'foo',
|
folderId: 'foo',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -694,7 +699,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイルが存在しなかったら怒る', async () => {
|
test('ファイルが存在しなかったら怒る', async () => {
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: '000000000000000000000000',
|
fileId: '000000000000000000000000',
|
||||||
name: 'いちごパスタ.png',
|
name: 'いちごパスタ.png',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -706,8 +711,8 @@ describe('Endpoints', () => {
|
||||||
const file = (await uploadFile(alice)).body;
|
const file = (await uploadFile(alice)).body;
|
||||||
const newName = '';
|
const newName = '';
|
||||||
|
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file!.id,
|
||||||
name: newName,
|
name: newName,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -715,7 +720,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('間違ったIDで怒られる', async () => {
|
test('間違ったIDで怒られる', async () => {
|
||||||
const res = await api('/drive/files/update', {
|
const res = await api('drive/files/update', {
|
||||||
fileId: 'kyoppie',
|
fileId: 'kyoppie',
|
||||||
name: 'いちごパスタ.png',
|
name: 'いちごパスタ.png',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -726,7 +731,7 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
describe('drive/folders/create', () => {
|
describe('drive/folders/create', () => {
|
||||||
test('フォルダを作成できる', async () => {
|
test('フォルダを作成できる', async () => {
|
||||||
const res = await api('/drive/folders/create', {
|
const res = await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -738,11 +743,11 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
describe('drive/folders/update', () => {
|
describe('drive/folders/update', () => {
|
||||||
test('名前を更新できる', async () => {
|
test('名前を更新できる', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
name: 'new name',
|
name: 'new name',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -753,11 +758,11 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('他人のフォルダを更新できない', async () => {
|
test('他人のフォルダを更新できない', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, bob)).body;
|
}, bob)).body;
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
name: 'new name',
|
name: 'new name',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -766,14 +771,14 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('親フォルダを更新できる', async () => {
|
test('親フォルダを更新できる', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
const parentFolder = (await api('/drive/folders/create', {
|
const parentFolder = (await api('drive/folders/create', {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
parentId: parentFolder.id,
|
parentId: parentFolder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -784,18 +789,18 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('親フォルダを無しに更新できる', async () => {
|
test('親フォルダを無しに更新できる', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
const parentFolder = (await api('/drive/folders/create', {
|
const parentFolder = (await api('drive/folders/create', {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
await api('/drive/folders/update', {
|
await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
parentId: parentFolder.id,
|
parentId: parentFolder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
parentId: null,
|
parentId: null,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -806,14 +811,14 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('他人のフォルダを親フォルダに設定できない', async () => {
|
test('他人のフォルダを親フォルダに設定できない', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
const parentFolder = (await api('/drive/folders/create', {
|
const parentFolder = (await api('drive/folders/create', {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
}, bob)).body;
|
}, bob)).body;
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
parentId: parentFolder.id,
|
parentId: parentFolder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -822,18 +827,18 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('フォルダが循環するような構造にできない', async () => {
|
test('フォルダが循環するような構造にできない', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
const parentFolder = (await api('/drive/folders/create', {
|
const parentFolder = (await api('drive/folders/create', {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
await api('/drive/folders/update', {
|
await api('drive/folders/update', {
|
||||||
folderId: parentFolder.id,
|
folderId: parentFolder.id,
|
||||||
parentId: folder.id,
|
parentId: folder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
parentId: parentFolder.id,
|
parentId: parentFolder.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -842,25 +847,25 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('フォルダが循環するような構造にできない(再帰的)', async () => {
|
test('フォルダが循環するような構造にできない(再帰的)', async () => {
|
||||||
const folderA = (await api('/drive/folders/create', {
|
const folderA = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
const folderB = (await api('/drive/folders/create', {
|
const folderB = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
const folderC = (await api('/drive/folders/create', {
|
const folderC = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
await api('/drive/folders/update', {
|
await api('drive/folders/update', {
|
||||||
folderId: folderB.id,
|
folderId: folderB.id,
|
||||||
parentId: folderA.id,
|
parentId: folderA.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/drive/folders/update', {
|
await api('drive/folders/update', {
|
||||||
folderId: folderC.id,
|
folderId: folderC.id,
|
||||||
parentId: folderB.id,
|
parentId: folderB.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folderA.id,
|
folderId: folderA.id,
|
||||||
parentId: folderC.id,
|
parentId: folderC.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -869,11 +874,11 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('フォルダが循環するような構造にできない(自身)', async () => {
|
test('フォルダが循環するような構造にできない(自身)', async () => {
|
||||||
const folderA = (await api('/drive/folders/create', {
|
const folderA = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folderA.id,
|
folderId: folderA.id,
|
||||||
parentId: folderA.id,
|
parentId: folderA.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -882,11 +887,11 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('存在しない親フォルダを設定できない', async () => {
|
test('存在しない親フォルダを設定できない', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
parentId: '000000000000000000000000',
|
parentId: '000000000000000000000000',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -895,11 +900,11 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('不正な親フォルダIDで怒られる', async () => {
|
test('不正な親フォルダIDで怒られる', async () => {
|
||||||
const folder = (await api('/drive/folders/create', {
|
const folder = (await api('drive/folders/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
}, alice)).body;
|
}, alice)).body;
|
||||||
|
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
parentId: 'foo',
|
parentId: 'foo',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -908,7 +913,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('存在しないフォルダを更新できない', async () => {
|
test('存在しないフォルダを更新できない', async () => {
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: '000000000000000000000000',
|
folderId: '000000000000000000000000',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -916,7 +921,7 @@ describe('Endpoints', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('不正なフォルダIDで怒られる', async () => {
|
test('不正なフォルダIDで怒られる', async () => {
|
||||||
const res = await api('/drive/folders/update', {
|
const res = await api('drive/folders/update', {
|
||||||
folderId: 'foo',
|
folderId: 'foo',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -937,7 +942,7 @@ describe('Endpoints', () => {
|
||||||
visibleUserIds: [alice.id],
|
visibleUserIds: [alice.id],
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await api('/notes/replies', {
|
const res = await api('notes/replies', {
|
||||||
noteId: alicePost.id,
|
noteId: alicePost.id,
|
||||||
}, carol);
|
}, carol);
|
||||||
|
|
||||||
|
@ -949,7 +954,7 @@ describe('Endpoints', () => {
|
||||||
|
|
||||||
describe('notes/timeline', () => {
|
describe('notes/timeline', () => {
|
||||||
test('フォロワー限定投稿が含まれる', async () => {
|
test('フォロワー限定投稿が含まれる', async () => {
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: carol.id,
|
userId: carol.id,
|
||||||
}, dave);
|
}, dave);
|
||||||
|
|
||||||
|
@ -958,7 +963,7 @@ describe('Endpoints', () => {
|
||||||
visibility: 'followers',
|
visibility: 'followers',
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await api('/notes/timeline', {}, dave);
|
const res = await api('notes/timeline', {}, dave);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -979,12 +984,12 @@ describe('Endpoints', () => {
|
||||||
test('他者に関するメモを更新できる', async () => {
|
test('他者に関するメモを更新できる', async () => {
|
||||||
const memo = '10月まで低浮上とのこと。';
|
const memo = '10月まで低浮上とのこと。';
|
||||||
|
|
||||||
const res1 = await api('/users/update-memo', {
|
const res1 = await api('users/update-memo', {
|
||||||
memo,
|
memo,
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res2 = await api('/users/show', {
|
const res2 = await api('users/show', {
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res1.status, 204);
|
assert.strictEqual(res1.status, 204);
|
||||||
|
@ -994,12 +999,12 @@ describe('Endpoints', () => {
|
||||||
test('自分に関するメモを更新できる', async () => {
|
test('自分に関するメモを更新できる', async () => {
|
||||||
const memo = 'チケットを月末までに買う。';
|
const memo = 'チケットを月末までに買う。';
|
||||||
|
|
||||||
const res1 = await api('/users/update-memo', {
|
const res1 = await api('users/update-memo', {
|
||||||
memo,
|
memo,
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res2 = await api('/users/show', {
|
const res2 = await api('users/show', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res1.status, 204);
|
assert.strictEqual(res1.status, 204);
|
||||||
|
@ -1009,17 +1014,17 @@ describe('Endpoints', () => {
|
||||||
test('メモを削除できる', async () => {
|
test('メモを削除できる', async () => {
|
||||||
const memo = '10月まで低浮上とのこと。';
|
const memo = '10月まで低浮上とのこと。';
|
||||||
|
|
||||||
await api('/users/update-memo', {
|
await api('users/update-memo', {
|
||||||
memo,
|
memo,
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
await api('/users/update-memo', {
|
await api('users/update-memo', {
|
||||||
memo: '',
|
memo: '',
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/users/show', {
|
const res = await api('users/show', {
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -1032,21 +1037,21 @@ describe('Endpoints', () => {
|
||||||
const memoCarolToBob = '例の件について今度問いただす。';
|
const memoCarolToBob = '例の件について今度問いただす。';
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
api('/users/update-memo', {
|
api('users/update-memo', {
|
||||||
memo: memoAliceToBob,
|
memo: memoAliceToBob,
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice),
|
}, alice),
|
||||||
api('/users/update-memo', {
|
api('users/update-memo', {
|
||||||
memo: memoCarolToBob,
|
memo: memoCarolToBob,
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, carol),
|
}, carol),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const [resAlice, resCarol] = await Promise.all([
|
const [resAlice, resCarol] = await Promise.all([
|
||||||
api('/users/show', {
|
api('users/show', {
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, alice),
|
}, alice),
|
||||||
api('/users/show', {
|
api('users/show', {
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, carol),
|
}, carol),
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -18,7 +18,7 @@ describe('export-clips', () => {
|
||||||
// XXX: Any better way to get the result?
|
// XXX: Any better way to get the result?
|
||||||
async function pollFirstDriveFile() {
|
async function pollFirstDriveFile() {
|
||||||
while (true) {
|
while (true) {
|
||||||
const files = (await api('/drive/files', {}, alice)).body;
|
const files = (await api('drive/files', {}, alice)).body;
|
||||||
if (!files.length) {
|
if (!files.length) {
|
||||||
await new Promise(r => setTimeout(r, 100));
|
await new Promise(r => setTimeout(r, 100));
|
||||||
continue;
|
continue;
|
||||||
|
@ -26,7 +26,7 @@ describe('export-clips', () => {
|
||||||
if (files.length > 1) {
|
if (files.length > 1) {
|
||||||
throw new Error('Too many files?');
|
throw new Error('Too many files?');
|
||||||
}
|
}
|
||||||
const file = (await api('/drive/files/show', { fileId: files[0].id }, alice)).body;
|
const file = (await api('drive/files/show', { fileId: files[0].id }, alice)).body;
|
||||||
const res = await fetch(new URL(new URL(file.url).pathname, `http://127.0.0.1:${port}`));
|
const res = await fetch(new URL(new URL(file.url).pathname, `http://127.0.0.1:${port}`));
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
|
@ -44,16 +44,16 @@ describe('export-clips', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
// Clean all clips and files of alice
|
// Clean all clips and files of alice
|
||||||
const clips = (await api('/clips/list', {}, alice)).body;
|
const clips = (await api('clips/list', {}, alice)).body;
|
||||||
for (const clip of clips) {
|
for (const clip of clips) {
|
||||||
const res = await api('/clips/delete', { clipId: clip.id }, alice);
|
const res = await api('clips/delete', { clipId: clip.id }, alice);
|
||||||
if (res.status !== 204) {
|
if (res.status !== 204) {
|
||||||
throw new Error('Failed to delete clip');
|
throw new Error('Failed to delete clip');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const files = (await api('/drive/files', {}, alice)).body;
|
const files = (await api('drive/files', {}, alice)).body;
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const res = await api('/drive/files/delete', { fileId: file.id }, alice);
|
const res = await api('drive/files/delete', { fileId: file.id }, alice);
|
||||||
if (res.status !== 204) {
|
if (res.status !== 204) {
|
||||||
throw new Error('Failed to delete file');
|
throw new Error('Failed to delete file');
|
||||||
}
|
}
|
||||||
|
@ -61,13 +61,13 @@ describe('export-clips', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('basic export', async () => {
|
test('basic export', async () => {
|
||||||
let res = await api('/clips/create', {
|
let res = await api('clips/create', {
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
description: 'bar',
|
description: 'bar',
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
|
|
||||||
res = await api('/i/export-clips', {}, alice);
|
res = await api('i/export-clips', {}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
const exported = await pollFirstDriveFile();
|
const exported = await pollFirstDriveFile();
|
||||||
|
@ -77,7 +77,7 @@ describe('export-clips', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('export with notes', async () => {
|
test('export with notes', async () => {
|
||||||
let res = await api('/clips/create', {
|
let res = await api('clips/create', {
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
description: 'bar',
|
description: 'bar',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -96,14 +96,14 @@ describe('export-clips', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const note of [note1, note2]) {
|
for (const note of [note1, note2]) {
|
||||||
res = await api('/clips/add-note', {
|
res = await api('clips/add-note', {
|
||||||
clipId: clip.id,
|
clipId: clip.id,
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = await api('/i/export-clips', {}, alice);
|
res = await api('i/export-clips', {}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
const exported = await pollFirstDriveFile();
|
const exported = await pollFirstDriveFile();
|
||||||
|
@ -116,14 +116,14 @@ describe('export-clips', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('multiple clips', async () => {
|
test('multiple clips', async () => {
|
||||||
let res = await api('/clips/create', {
|
let res = await api('clips/create', {
|
||||||
name: 'kawaii',
|
name: 'kawaii',
|
||||||
description: 'kawaii',
|
description: 'kawaii',
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
const clip1 = res.body;
|
const clip1 = res.body;
|
||||||
|
|
||||||
res = await api('/clips/create', {
|
res = await api('clips/create', {
|
||||||
name: 'yuri',
|
name: 'yuri',
|
||||||
description: 'yuri',
|
description: 'yuri',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -138,19 +138,19 @@ describe('export-clips', () => {
|
||||||
text: 'baz2',
|
text: 'baz2',
|
||||||
});
|
});
|
||||||
|
|
||||||
res = await api('/clips/add-note', {
|
res = await api('clips/add-note', {
|
||||||
clipId: clip1.id,
|
clipId: clip1.id,
|
||||||
noteId: note1.id,
|
noteId: note1.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
res = await api('/clips/add-note', {
|
res = await api('clips/add-note', {
|
||||||
clipId: clip2.id,
|
clipId: clip2.id,
|
||||||
noteId: note2.id,
|
noteId: note2.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
res = await api('/i/export-clips', {}, alice);
|
res = await api('i/export-clips', {}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
const exported = await pollFirstDriveFile();
|
const exported = await pollFirstDriveFile();
|
||||||
|
@ -163,7 +163,7 @@ describe('export-clips', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Clipping other user\'s note', async () => {
|
test('Clipping other user\'s note', async () => {
|
||||||
let res = await api('/clips/create', {
|
let res = await api('clips/create', {
|
||||||
name: 'kawaii',
|
name: 'kawaii',
|
||||||
description: 'kawaii',
|
description: 'kawaii',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -175,13 +175,13 @@ describe('export-clips', () => {
|
||||||
visibility: 'followers',
|
visibility: 'followers',
|
||||||
});
|
});
|
||||||
|
|
||||||
res = await api('/clips/add-note', {
|
res = await api('clips/add-note', {
|
||||||
clipId: clip.id,
|
clipId: clip.id,
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
res = await api('/i/export-clips', {}, alice);
|
res = await api('i/export-clips', {}, alice);
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
const exported = await pollFirstDriveFile();
|
const exported = await pollFirstDriveFile();
|
||||||
|
|
|
@ -23,13 +23,13 @@ const JSON_UTF8 = 'application/json; charset=utf-8';
|
||||||
|
|
||||||
describe('Webリソース', () => {
|
describe('Webリソース', () => {
|
||||||
let alice: misskey.entities.SignupResponse;
|
let alice: misskey.entities.SignupResponse;
|
||||||
let aliceUploadedFile: any;
|
let aliceUploadedFile: misskey.entities.DriveFile | null;
|
||||||
let alicesPost: any;
|
let alicesPost: misskey.entities.Note;
|
||||||
let alicePage: any;
|
let alicePage: misskey.entities.Page;
|
||||||
let alicePlay: any;
|
let alicePlay: misskey.entities.Flash;
|
||||||
let aliceClip: any;
|
let aliceClip: misskey.entities.Clip;
|
||||||
let aliceGalleryPost: any;
|
let aliceGalleryPost: misskey.entities.GalleryPost;
|
||||||
let aliceChannel: any;
|
let aliceChannel: misskey.entities.Channel;
|
||||||
|
|
||||||
let bob: misskey.entities.SignupResponse;
|
let bob: misskey.entities.SignupResponse;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ describe('Webリソース', () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
alice = await signup({ username: 'alice' });
|
alice = await signup({ username: 'alice' });
|
||||||
aliceUploadedFile = await uploadFile(alice);
|
aliceUploadedFile = (await uploadFile(alice)).body;
|
||||||
alicesPost = await post(alice, {
|
alicesPost = await post(alice, {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
});
|
});
|
||||||
|
@ -85,7 +85,7 @@ describe('Webリソース', () => {
|
||||||
alicePlay = await play(alice, {});
|
alicePlay = await play(alice, {});
|
||||||
aliceClip = await clip(alice, {});
|
aliceClip = await clip(alice, {});
|
||||||
aliceGalleryPost = await galleryPost(alice, {
|
aliceGalleryPost = await galleryPost(alice, {
|
||||||
fileIds: [aliceUploadedFile.body.id],
|
fileIds: [aliceUploadedFile!.id],
|
||||||
});
|
});
|
||||||
aliceChannel = await channel(alice, {});
|
aliceChannel = await channel(alice, {});
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,15 @@ describe('FF visibility', () => {
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => {
|
test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -39,36 +39,36 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => {
|
test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
|
@ -78,36 +78,36 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => {
|
test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
|
@ -116,15 +116,15 @@ describe('FF visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => {
|
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -136,36 +136,36 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
|
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
|
@ -175,36 +175,36 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
|
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
|
@ -213,15 +213,15 @@ describe('FF visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => {
|
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -231,34 +231,34 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => {
|
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 400);
|
assert.strictEqual(followingRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 400);
|
assert.strictEqual(followingRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 400);
|
assert.strictEqual(followingRes.status, 400);
|
||||||
|
@ -267,34 +267,34 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => {
|
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 400);
|
assert.strictEqual(followersRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 400);
|
assert.strictEqual(followersRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 400);
|
assert.strictEqual(followersRes.status, 400);
|
||||||
|
@ -302,19 +302,19 @@ describe('FF visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => {
|
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -326,45 +326,45 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => {
|
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
|
@ -374,45 +374,45 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => {
|
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
|
@ -421,15 +421,15 @@ describe('FF visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => {
|
test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -441,36 +441,36 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
|
test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
|
@ -480,36 +480,36 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
|
test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
|
@ -518,15 +518,15 @@ describe('FF visibility', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => {
|
test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -536,34 +536,34 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => {
|
test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 400);
|
assert.strictEqual(followingRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 400);
|
assert.strictEqual(followingRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followingRes = await api('/users/following', {
|
const followingRes = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followingRes.status, 400);
|
assert.strictEqual(followingRes.status, 400);
|
||||||
|
@ -572,34 +572,34 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => {
|
test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 400);
|
assert.strictEqual(followersRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 400);
|
assert.strictEqual(followersRes.status, 400);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const followersRes = await api('/users/followers', {
|
const followersRes = await api('users/followers', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
assert.strictEqual(followersRes.status, 400);
|
assert.strictEqual(followersRes.status, 400);
|
||||||
|
@ -609,7 +609,7 @@ describe('FF visibility', () => {
|
||||||
describe('AP', () => {
|
describe('AP', () => {
|
||||||
test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => {
|
test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -617,7 +617,7 @@ describe('FF visibility', () => {
|
||||||
assert.strictEqual(followingRes.status, 200);
|
assert.strictEqual(followingRes.status, 200);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'followers',
|
followingVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -625,7 +625,7 @@ describe('FF visibility', () => {
|
||||||
assert.strictEqual(followingRes.status, 403);
|
assert.strictEqual(followingRes.status, 403);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followingVisibility: 'private',
|
followingVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -636,7 +636,7 @@ describe('FF visibility', () => {
|
||||||
|
|
||||||
test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => {
|
test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => {
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ describe('FF visibility', () => {
|
||||||
assert.strictEqual(followersRes.status, 200);
|
assert.strictEqual(followersRes.status, 200);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followersVisibility: 'followers',
|
followersVisibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -652,7 +652,7 @@ describe('FF visibility', () => {
|
||||||
assert.strictEqual(followersRes.status, 403);
|
assert.strictEqual(followersRes.status, 403);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
followersVisibility: 'private',
|
followersVisibility: 'private',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ describe('Account Move', () => {
|
||||||
}, 1000 * 10);
|
}, 1000 * 10);
|
||||||
|
|
||||||
test('Able to create an alias', async () => {
|
test('Able to create an alias', async () => {
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
alsoKnownAs: [`@alice@${url.hostname}`],
|
alsoKnownAs: [`@alice@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Able to create a local alias without hostname', async () => {
|
test('Able to create a local alias without hostname', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
alsoKnownAs: ['@alice'],
|
alsoKnownAs: ['@alice'],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Able to create a local alias without @', async () => {
|
test('Able to create a local alias without @', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
alsoKnownAs: ['alice'],
|
alsoKnownAs: ['alice'],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Able to set remote user (but may fail)', async () => {
|
test('Able to set remote user (but may fail)', async () => {
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
alsoKnownAs: ['@syuilo@example.com'],
|
alsoKnownAs: ['@syuilo@example.com'],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Unable to add duplicated aliases to alsoKnownAs', async () => {
|
test('Unable to add duplicated aliases to alsoKnownAs', async () => {
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
alsoKnownAs: [`@alice@${url.hostname}`, `@alice@${url.hostname}`],
|
alsoKnownAs: [`@alice@${url.hostname}`, `@alice@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Unable to add itself', async () => {
|
test('Unable to add itself', async () => {
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
alsoKnownAs: [`@bob@${url.hostname}`],
|
alsoKnownAs: [`@bob@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Unable to add a nonexisting local account to alsoKnownAs', async () => {
|
test('Unable to add a nonexisting local account to alsoKnownAs', async () => {
|
||||||
const res1 = await api('/i/update', {
|
const res1 = await api('i/update', {
|
||||||
alsoKnownAs: [`@nonexist@${url.hostname}`],
|
alsoKnownAs: [`@nonexist@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ describe('Account Move', () => {
|
||||||
assert.strictEqual(res1.body.error.code, 'NO_SUCH_USER');
|
assert.strictEqual(res1.body.error.code, 'NO_SUCH_USER');
|
||||||
assert.strictEqual(res1.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
|
assert.strictEqual(res1.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
|
||||||
|
|
||||||
const res2 = await api('/i/update', {
|
const res2 = await api('i/update', {
|
||||||
alsoKnownAs: ['@alice', 'nonexist'],
|
alsoKnownAs: ['@alice', 'nonexist'],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Able to add two existing local account to alsoKnownAs', async () => {
|
test('Able to add two existing local account to alsoKnownAs', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
alsoKnownAs: [`@alice@${url.hostname}`, `@carol@${url.hostname}`],
|
alsoKnownAs: [`@alice@${url.hostname}`, `@carol@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -146,10 +146,10 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Able to properly overwrite alsoKnownAs', async () => {
|
test('Able to properly overwrite alsoKnownAs', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
alsoKnownAs: [`@alice@${url.hostname}`],
|
alsoKnownAs: [`@alice@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
alsoKnownAs: [`@carol@${url.hostname}`, `@dave@${url.hostname}`],
|
alsoKnownAs: [`@carol@${url.hostname}`, `@dave@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -164,27 +164,27 @@ describe('Account Move', () => {
|
||||||
let antennaId = '';
|
let antennaId = '';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
alsoKnownAs: [`@alice@${url.hostname}`],
|
alsoKnownAs: [`@alice@${url.hostname}`],
|
||||||
}, root);
|
}, root);
|
||||||
const listRoot = await api('/users/lists/create', {
|
const listRoot = await api('users/lists/create', {
|
||||||
name: secureRndstr(8),
|
name: secureRndstr(8),
|
||||||
}, root);
|
}, root);
|
||||||
await api('/users/lists/push', {
|
await api('users/lists/push', {
|
||||||
listId: listRoot.body.id,
|
listId: listRoot.body.id,
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, root);
|
}, root);
|
||||||
|
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: root.id,
|
userId: root.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: eve.id,
|
userId: eve.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
const antenna = await api('/antennas/create', {
|
const antenna = await api('antennas/create', {
|
||||||
name: secureRndstr(8),
|
name: secureRndstr(8),
|
||||||
src: 'home',
|
src: 'home',
|
||||||
keywords: [secureRndstr(8)],
|
keywords: [[secureRndstr(8)]],
|
||||||
excludeKeywords: [],
|
excludeKeywords: [],
|
||||||
users: [],
|
users: [],
|
||||||
caseSensitive: false,
|
caseSensitive: false,
|
||||||
|
@ -195,48 +195,48 @@ describe('Account Move', () => {
|
||||||
}, alice);
|
}, alice);
|
||||||
antennaId = antenna.body.id;
|
antennaId = antenna.body.id;
|
||||||
|
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
alsoKnownAs: [`@alice@${url.hostname}`],
|
alsoKnownAs: [`@alice@${url.hostname}`],
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, carol);
|
}, carol);
|
||||||
|
|
||||||
await api('/mute/create', {
|
await api('mute/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, dave);
|
}, dave);
|
||||||
await api('/blocking/create', {
|
await api('blocking/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, dave);
|
}, dave);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: eve.id,
|
userId: eve.id,
|
||||||
}, dave);
|
}, dave);
|
||||||
|
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: dave.id,
|
userId: dave.id,
|
||||||
}, eve);
|
}, eve);
|
||||||
const listEve = await api('/users/lists/create', {
|
const listEve = await api('users/lists/create', {
|
||||||
name: secureRndstr(8),
|
name: secureRndstr(8),
|
||||||
}, eve);
|
}, eve);
|
||||||
await api('/users/lists/push', {
|
await api('users/lists/push', {
|
||||||
listId: listEve.body.id,
|
listId: listEve.body.id,
|
||||||
userId: bob.id,
|
userId: bob.id,
|
||||||
}, eve);
|
}, eve);
|
||||||
|
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
isLocked: true,
|
isLocked: true,
|
||||||
}, frank);
|
}, frank);
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: frank.id,
|
userId: frank.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
await api('/following/requests/accept', {
|
await api('following/requests/accept', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, frank);
|
}, frank);
|
||||||
}, 1000 * 10);
|
}, 1000 * 10);
|
||||||
|
|
||||||
test('Prohibit the root account from moving', async () => {
|
test('Prohibit the root account from moving', async () => {
|
||||||
const res = await api('/i/move', {
|
const res = await api('i/move', {
|
||||||
moveToAccount: `@bob@${url.hostname}`,
|
moveToAccount: `@bob@${url.hostname}`,
|
||||||
}, root);
|
}, root);
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Unable to move to a nonexisting local account', async () => {
|
test('Unable to move to a nonexisting local account', async () => {
|
||||||
const res = await api('/i/move', {
|
const res = await api('i/move', {
|
||||||
moveToAccount: `@nonexist@${url.hostname}`,
|
moveToAccount: `@nonexist@${url.hostname}`,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Unable to move if alsoKnownAs is invalid', async () => {
|
test('Unable to move if alsoKnownAs is invalid', async () => {
|
||||||
const res = await api('/i/move', {
|
const res = await api('i/move', {
|
||||||
moveToAccount: `@carol@${url.hostname}`,
|
moveToAccount: `@carol@${url.hostname}`,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Relationships have been properly migrated', async () => {
|
test('Relationships have been properly migrated', async () => {
|
||||||
const move = await api('/i/move', {
|
const move = await api('i/move', {
|
||||||
moveToAccount: `@bob@${url.hostname}`,
|
moveToAccount: `@bob@${url.hostname}`,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -275,13 +275,13 @@ describe('Account Move', () => {
|
||||||
await sleep(1000 * 3); // wait for jobs to finish
|
await sleep(1000 * 3); // wait for jobs to finish
|
||||||
|
|
||||||
// Unfollow delayed?
|
// Unfollow delayed?
|
||||||
const aliceFollowings = await api('/users/following', {
|
const aliceFollowings = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(aliceFollowings.status, 200);
|
assert.strictEqual(aliceFollowings.status, 200);
|
||||||
assert.strictEqual(aliceFollowings.body.length, 3);
|
assert.strictEqual(aliceFollowings.body.length, 3);
|
||||||
|
|
||||||
const carolFollowings = await api('/users/following', {
|
const carolFollowings = await api('users/following', {
|
||||||
userId: carol.id,
|
userId: carol.id,
|
||||||
}, carol);
|
}, carol);
|
||||||
assert.strictEqual(carolFollowings.status, 200);
|
assert.strictEqual(carolFollowings.status, 200);
|
||||||
|
@ -289,25 +289,25 @@ describe('Account Move', () => {
|
||||||
assert.strictEqual(carolFollowings.body[0].followeeId, bob.id);
|
assert.strictEqual(carolFollowings.body[0].followeeId, bob.id);
|
||||||
assert.strictEqual(carolFollowings.body[1].followeeId, alice.id);
|
assert.strictEqual(carolFollowings.body[1].followeeId, alice.id);
|
||||||
|
|
||||||
const blockings = await api('/blocking/list', {}, dave);
|
const blockings = await api('blocking/list', {}, dave);
|
||||||
assert.strictEqual(blockings.status, 200);
|
assert.strictEqual(blockings.status, 200);
|
||||||
assert.strictEqual(blockings.body.length, 2);
|
assert.strictEqual(blockings.body.length, 2);
|
||||||
assert.strictEqual(blockings.body[0].blockeeId, bob.id);
|
assert.strictEqual(blockings.body[0].blockeeId, bob.id);
|
||||||
assert.strictEqual(blockings.body[1].blockeeId, alice.id);
|
assert.strictEqual(blockings.body[1].blockeeId, alice.id);
|
||||||
|
|
||||||
const mutings = await api('/mute/list', {}, dave);
|
const mutings = await api('mute/list', {}, dave);
|
||||||
assert.strictEqual(mutings.status, 200);
|
assert.strictEqual(mutings.status, 200);
|
||||||
assert.strictEqual(mutings.body.length, 2);
|
assert.strictEqual(mutings.body.length, 2);
|
||||||
assert.strictEqual(mutings.body[0].muteeId, bob.id);
|
assert.strictEqual(mutings.body[0].muteeId, bob.id);
|
||||||
assert.strictEqual(mutings.body[1].muteeId, alice.id);
|
assert.strictEqual(mutings.body[1].muteeId, alice.id);
|
||||||
|
|
||||||
const rootLists = await api('/users/lists/list', {}, root);
|
const rootLists = await api('users/lists/list', {}, root);
|
||||||
assert.strictEqual(rootLists.status, 200);
|
assert.strictEqual(rootLists.status, 200);
|
||||||
assert.strictEqual(rootLists.body[0].userIds.length, 2);
|
assert.strictEqual(rootLists.body[0].userIds.length, 2);
|
||||||
assert.ok(rootLists.body[0].userIds.find((id: string) => id === bob.id));
|
assert.ok(rootLists.body[0].userIds.find((id: string) => id === bob.id));
|
||||||
assert.ok(rootLists.body[0].userIds.find((id: string) => id === alice.id));
|
assert.ok(rootLists.body[0].userIds.find((id: string) => id === alice.id));
|
||||||
|
|
||||||
const eveLists = await api('/users/lists/list', {}, eve);
|
const eveLists = await api('users/lists/list', {}, eve);
|
||||||
assert.strictEqual(eveLists.status, 200);
|
assert.strictEqual(eveLists.status, 200);
|
||||||
assert.strictEqual(eveLists.body[0].userIds.length, 1);
|
assert.strictEqual(eveLists.body[0].userIds.length, 1);
|
||||||
assert.ok(eveLists.body[0].userIds.find((id: string) => id === bob.id));
|
assert.ok(eveLists.body[0].userIds.find((id: string) => id === bob.id));
|
||||||
|
@ -315,13 +315,13 @@ describe('Account Move', () => {
|
||||||
|
|
||||||
test('A locked account automatically accept the follow request if it had already accepted the old account.', async () => {
|
test('A locked account automatically accept the follow request if it had already accepted the old account.', async () => {
|
||||||
await successfulApiCall({
|
await successfulApiCall({
|
||||||
endpoint: '/following/create',
|
endpoint: 'following/create',
|
||||||
parameters: {
|
parameters: {
|
||||||
userId: frank.id,
|
userId: frank.id,
|
||||||
},
|
},
|
||||||
user: bob,
|
user: bob,
|
||||||
});
|
});
|
||||||
const followers = await api('/users/followers', {
|
const followers = await api('users/followers', {
|
||||||
userId: frank.id,
|
userId: frank.id,
|
||||||
}, frank);
|
}, frank);
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ describe('Account Move', () => {
|
||||||
test('Unfollowed after 10 sec (24 hours in production).', async () => {
|
test('Unfollowed after 10 sec (24 hours in production).', async () => {
|
||||||
await sleep(1000 * 8);
|
await sleep(1000 * 8);
|
||||||
|
|
||||||
const following = await api('/users/following', {
|
const following = await api('users/following', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Unable to move if the destination account has already moved.', async () => {
|
test('Unable to move if the destination account has already moved.', async () => {
|
||||||
const res = await api('/i/move', {
|
const res = await api('i/move', {
|
||||||
moveToAccount: `@alice@${url.hostname}`,
|
moveToAccount: `@alice@${url.hostname}`,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Follow and follower counts are properly adjusted', async () => {
|
test('Follow and follower counts are properly adjusted', async () => {
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, eve);
|
}, eve);
|
||||||
const newAlice = await Users.findOneByOrFail({ id: alice.id });
|
const newAlice = await Users.findOneByOrFail({ id: alice.id });
|
||||||
|
@ -365,7 +365,7 @@ describe('Account Move', () => {
|
||||||
assert.strictEqual(newEve.followingCount, 1);
|
assert.strictEqual(newEve.followingCount, 1);
|
||||||
assert.strictEqual(newEve.followersCount, 1);
|
assert.strictEqual(newEve.followersCount, 1);
|
||||||
|
|
||||||
await api('/following/delete', {
|
await api('following/delete', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, eve);
|
}, eve);
|
||||||
newEve = await Users.findOneByOrFail({ id: eve.id });
|
newEve = await Users.findOneByOrFail({ id: eve.id });
|
||||||
|
@ -374,49 +374,49 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
'/antennas/create',
|
'antennas/create',
|
||||||
'/channels/create',
|
'channels/create',
|
||||||
'/channels/favorite',
|
'channels/favorite',
|
||||||
'/channels/follow',
|
'channels/follow',
|
||||||
'/channels/unfavorite',
|
'channels/unfavorite',
|
||||||
'/channels/unfollow',
|
'channels/unfollow',
|
||||||
'/clips/add-note',
|
'clips/add-note',
|
||||||
'/clips/create',
|
'clips/create',
|
||||||
'/clips/favorite',
|
'clips/favorite',
|
||||||
'/clips/remove-note',
|
'clips/remove-note',
|
||||||
'/clips/unfavorite',
|
'clips/unfavorite',
|
||||||
'/clips/update',
|
'clips/update',
|
||||||
'/drive/files/upload-from-url',
|
'drive/files/upload-from-url',
|
||||||
'/flash/create',
|
'flash/create',
|
||||||
'/flash/like',
|
'flash/like',
|
||||||
'/flash/unlike',
|
'flash/unlike',
|
||||||
'/flash/update',
|
'flash/update',
|
||||||
'/following/create',
|
'following/create',
|
||||||
'/gallery/posts/create',
|
'gallery/posts/create',
|
||||||
'/gallery/posts/like',
|
'gallery/posts/like',
|
||||||
'/gallery/posts/unlike',
|
'gallery/posts/unlike',
|
||||||
'/gallery/posts/update',
|
'gallery/posts/update',
|
||||||
'/i/claim-achievement',
|
'i/claim-achievement',
|
||||||
'/i/move',
|
'i/move',
|
||||||
'/i/import-blocking',
|
'i/import-blocking',
|
||||||
'/i/import-following',
|
'i/import-following',
|
||||||
'/i/import-muting',
|
'i/import-muting',
|
||||||
'/i/import-user-lists',
|
'i/import-user-lists',
|
||||||
'/i/pin',
|
'i/pin',
|
||||||
'/mute/create',
|
'mute/create',
|
||||||
'/notes/create',
|
'notes/create',
|
||||||
'/notes/favorites/create',
|
'notes/favorites/create',
|
||||||
'/notes/polls/vote',
|
'notes/polls/vote',
|
||||||
'/notes/reactions/create',
|
'notes/reactions/create',
|
||||||
'/pages/create',
|
'pages/create',
|
||||||
'/pages/like',
|
'pages/like',
|
||||||
'/pages/unlike',
|
'pages/unlike',
|
||||||
'/pages/update',
|
'pages/update',
|
||||||
'/renote-mute/create',
|
'renote-mute/create',
|
||||||
'/users/lists/create',
|
'users/lists/create',
|
||||||
'/users/lists/pull',
|
'users/lists/pull',
|
||||||
'/users/lists/push',
|
'users/lists/push',
|
||||||
])('Prohibit access after moving: %s', async (endpoint) => {
|
] as const)('Prohibit access after moving: %s', async (endpoint) => {
|
||||||
const res = await api(endpoint, {}, alice);
|
const res = await api(endpoint, {}, alice);
|
||||||
assert.strictEqual(res.status, 403);
|
assert.strictEqual(res.status, 403);
|
||||||
assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
|
assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
|
||||||
|
@ -424,11 +424,11 @@ describe('Account Move', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Prohibit access after moving: /antennas/update', async () => {
|
test('Prohibit access after moving: /antennas/update', async () => {
|
||||||
const res = await api('/antennas/update', {
|
const res = await api('antennas/update', {
|
||||||
antennaId,
|
antennaId,
|
||||||
name: secureRndstr(8),
|
name: secureRndstr(8),
|
||||||
src: 'users',
|
src: 'users',
|
||||||
keywords: [secureRndstr(8)],
|
keywords: [[secureRndstr(8)]],
|
||||||
excludeKeywords: [],
|
excludeKeywords: [],
|
||||||
users: [eve.id],
|
users: [eve.id],
|
||||||
caseSensitive: false,
|
caseSensitive: false,
|
||||||
|
@ -447,12 +447,12 @@ describe('Account Move', () => {
|
||||||
const res = await uploadFile(alice);
|
const res = await uploadFile(alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 403);
|
assert.strictEqual(res.status, 403);
|
||||||
assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
|
assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.code, 'YOUR_ACCOUNT_MOVED');
|
||||||
assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
|
assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Prohibit updating alsoKnownAs after moving', async () => {
|
test('Prohibit updating alsoKnownAs after moving', async () => {
|
||||||
const res = await api('/i/update', {
|
const res = await api('i/update', {
|
||||||
alsoKnownAs: [`@eve@${url.hostname}`],
|
alsoKnownAs: [`@eve@${url.hostname}`],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
|
|
@ -19,21 +19,31 @@ describe('Mute', () => {
|
||||||
alice = await signup({ username: 'alice' });
|
alice = await signup({ username: 'alice' });
|
||||||
bob = await signup({ username: 'bob' });
|
bob = await signup({ username: 'bob' });
|
||||||
carol = await signup({ username: 'carol' });
|
carol = await signup({ username: 'carol' });
|
||||||
|
|
||||||
|
// Mute: alice ==> carol
|
||||||
|
await api('mute/create', {
|
||||||
|
userId: carol.id,
|
||||||
|
}, alice);
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
test('ミュート作成', async () => {
|
test('ミュート作成', async () => {
|
||||||
const res = await api('/mute/create', {
|
const res = await api('mute/create', {
|
||||||
userId: carol.id,
|
userId: bob.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 204);
|
assert.strictEqual(res.status, 204);
|
||||||
|
|
||||||
|
// 単体でも走らせられるように副作用消す
|
||||||
|
await api('mute/delete', {
|
||||||
|
userId: bob.id,
|
||||||
|
}, alice);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('「自分宛ての投稿」にミュートしているユーザーの投稿が含まれない', async () => {
|
test('「自分宛ての投稿」にミュートしているユーザーの投稿が含まれない', async () => {
|
||||||
const bobNote = await post(bob, { text: '@alice hi' });
|
const bobNote = await post(bob, { text: '@alice hi' });
|
||||||
const carolNote = await post(carol, { text: '@alice hi' });
|
const carolNote = await post(carol, { text: '@alice hi' });
|
||||||
|
|
||||||
const res = await api('/notes/mentions', {}, alice);
|
const res = await api('notes/mentions', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -43,11 +53,11 @@ describe('Mute', () => {
|
||||||
|
|
||||||
test('ミュートしているユーザーからメンションされても、hasUnreadMentions が true にならない', async () => {
|
test('ミュートしているユーザーからメンションされても、hasUnreadMentions が true にならない', async () => {
|
||||||
// 状態リセット
|
// 状態リセット
|
||||||
await api('/i/read-all-unread-notes', {}, alice);
|
await api('i/read-all-unread-notes', {}, alice);
|
||||||
|
|
||||||
await post(carol, { text: '@alice hi' });
|
await post(carol, { text: '@alice hi' });
|
||||||
|
|
||||||
const res = await api('/i', {}, alice);
|
const res = await api('i', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(res.body.hasUnreadMentions, false);
|
assert.strictEqual(res.body.hasUnreadMentions, false);
|
||||||
|
@ -55,7 +65,7 @@ describe('Mute', () => {
|
||||||
|
|
||||||
test('ミュートしているユーザーからメンションされても、ストリームに unreadMention イベントが流れてこない', async () => {
|
test('ミュートしているユーザーからメンションされても、ストリームに unreadMention イベントが流れてこない', async () => {
|
||||||
// 状態リセット
|
// 状態リセット
|
||||||
await api('/i/read-all-unread-notes', {}, alice);
|
await api('i/read-all-unread-notes', {}, alice);
|
||||||
|
|
||||||
const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadMention');
|
const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadMention');
|
||||||
|
|
||||||
|
@ -64,8 +74,8 @@ describe('Mute', () => {
|
||||||
|
|
||||||
test('ミュートしているユーザーからメンションされても、ストリームに unreadNotification イベントが流れてこない', async () => {
|
test('ミュートしているユーザーからメンションされても、ストリームに unreadNotification イベントが流れてこない', async () => {
|
||||||
// 状態リセット
|
// 状態リセット
|
||||||
await api('/i/read-all-unread-notes', {}, alice);
|
await api('i/read-all-unread-notes', {}, alice);
|
||||||
await api('/notifications/mark-all-as-read', {}, alice);
|
await api('notifications/mark-all-as-read', {}, alice);
|
||||||
|
|
||||||
const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadNotification');
|
const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadNotification');
|
||||||
|
|
||||||
|
@ -78,7 +88,7 @@ describe('Mute', () => {
|
||||||
const bobNote = await post(bob, { text: 'hi' });
|
const bobNote = await post(bob, { text: 'hi' });
|
||||||
const carolNote = await post(carol, { text: 'hi' });
|
const carolNote = await post(carol, { text: 'hi' });
|
||||||
|
|
||||||
const res = await api('/notes/local-timeline', {}, alice);
|
const res = await api('notes/local-timeline', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -94,7 +104,7 @@ describe('Mute', () => {
|
||||||
renoteId: carolNote.id,
|
renoteId: carolNote.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await api('/notes/local-timeline', {}, alice);
|
const res = await api('notes/local-timeline', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -110,7 +120,7 @@ describe('Mute', () => {
|
||||||
await react(bob, aliceNote, 'like');
|
await react(bob, aliceNote, 'like');
|
||||||
await react(carol, aliceNote, 'like');
|
await react(carol, aliceNote, 'like');
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -123,7 +133,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { text: '@alice hi', replyId: aliceNote.id });
|
await post(bob, { text: '@alice hi', replyId: aliceNote.id });
|
||||||
await post(carol, { text: '@alice hi', replyId: aliceNote.id });
|
await post(carol, { text: '@alice hi', replyId: aliceNote.id });
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -137,7 +147,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { text: '@alice hi' });
|
await post(bob, { text: '@alice hi' });
|
||||||
await post(carol, { text: '@alice hi' });
|
await post(carol, { text: '@alice hi' });
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -151,7 +161,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { text: 'hi', renoteId: aliceNote.id });
|
await post(bob, { text: 'hi', renoteId: aliceNote.id });
|
||||||
await post(carol, { text: 'hi', renoteId: aliceNote.id });
|
await post(carol, { text: 'hi', renoteId: aliceNote.id });
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -165,7 +175,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { renoteId: aliceNote.id });
|
await post(bob, { renoteId: aliceNote.id });
|
||||||
await post(carol, { renoteId: aliceNote.id });
|
await post(carol, { renoteId: aliceNote.id });
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -175,30 +185,36 @@ describe('Mute', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
|
test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
|
||||||
await api('/i/follow', { userId: alice.id }, bob);
|
await api('following/create', { userId: alice.id }, bob);
|
||||||
await api('/i/follow', { userId: alice.id }, carol);
|
await api('following/create', { userId: alice.id }, carol);
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
|
||||||
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
|
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
|
||||||
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
|
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
|
||||||
|
|
||||||
|
await api('following/delete', { userId: alice.id }, bob);
|
||||||
|
await api('following/delete', { userId: alice.id }, carol);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
|
test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
|
||||||
await api('/i/update/', { isLocked: true }, alice);
|
await api('i/update', { isLocked: true }, alice);
|
||||||
await api('/following/create', { userId: alice.id }, bob);
|
await api('following/create', { userId: alice.id }, bob);
|
||||||
await api('/following/create', { userId: alice.id }, carol);
|
await api('following/create', { userId: alice.id }, carol);
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
|
||||||
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
|
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
|
||||||
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
|
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
|
||||||
|
|
||||||
|
await api('following/delete', { userId: alice.id }, bob);
|
||||||
|
await api('following/delete', { userId: alice.id }, carol);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -208,7 +224,7 @@ describe('Mute', () => {
|
||||||
await react(bob, aliceNote, 'like');
|
await react(bob, aliceNote, 'like');
|
||||||
await react(carol, aliceNote, 'like');
|
await react(carol, aliceNote, 'like');
|
||||||
|
|
||||||
const res = await api('/i/notifications-grouped', {}, alice);
|
const res = await api('i/notifications-grouped', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -220,7 +236,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { text: '@alice hi', replyId: aliceNote.id });
|
await post(bob, { text: '@alice hi', replyId: aliceNote.id });
|
||||||
await post(carol, { text: '@alice hi', replyId: aliceNote.id });
|
await post(carol, { text: '@alice hi', replyId: aliceNote.id });
|
||||||
|
|
||||||
const res = await api('/i/notifications-grouped', {}, alice);
|
const res = await api('i/notifications-grouped', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -234,7 +250,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { text: '@alice hi' });
|
await post(bob, { text: '@alice hi' });
|
||||||
await post(carol, { text: '@alice hi' });
|
await post(carol, { text: '@alice hi' });
|
||||||
|
|
||||||
const res = await api('/i/notifications-grouped', {}, alice);
|
const res = await api('i/notifications-grouped', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -248,7 +264,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { text: 'hi', renoteId: aliceNote.id });
|
await post(bob, { text: 'hi', renoteId: aliceNote.id });
|
||||||
await post(carol, { text: 'hi', renoteId: aliceNote.id });
|
await post(carol, { text: 'hi', renoteId: aliceNote.id });
|
||||||
|
|
||||||
const res = await api('/i/notifications-grouped', {}, alice);
|
const res = await api('i/notifications-grouped', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -262,7 +278,7 @@ describe('Mute', () => {
|
||||||
await post(bob, { renoteId: aliceNote.id });
|
await post(bob, { renoteId: aliceNote.id });
|
||||||
await post(carol, { renoteId: aliceNote.id });
|
await post(carol, { renoteId: aliceNote.id });
|
||||||
|
|
||||||
const res = await api('/i/notifications-grouped', {}, alice);
|
const res = await api('i/notifications-grouped', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -272,24 +288,27 @@ describe('Mute', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
|
test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
|
||||||
await api('/i/follow', { userId: alice.id }, bob);
|
await api('following/create', { userId: alice.id }, bob);
|
||||||
await api('/i/follow', { userId: alice.id }, carol);
|
await api('following/create', { userId: alice.id }, carol);
|
||||||
|
|
||||||
const res = await api('/i/notifications-grouped', {}, alice);
|
const res = await api('i/notifications-grouped', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
|
||||||
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
|
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
|
||||||
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
|
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
|
||||||
|
|
||||||
|
await api('following/delete', { userId: alice.id }, bob);
|
||||||
|
await api('following/delete', { userId: alice.id }, carol);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
|
test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
|
||||||
await api('/i/update/', { isLocked: true }, alice);
|
await api('i/update', { isLocked: true }, alice);
|
||||||
await api('/following/create', { userId: alice.id }, bob);
|
await api('following/create', { userId: alice.id }, bob);
|
||||||
await api('/following/create', { userId: alice.id }, carol);
|
await api('following/create', { userId: alice.id }, carol);
|
||||||
|
|
||||||
const res = await api('/i/notifications-grouped', {}, alice);
|
const res = await api('i/notifications-grouped', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
|
|
@ -31,7 +31,7 @@ describe('Note', () => {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
|
@ -41,7 +41,7 @@ describe('Note', () => {
|
||||||
test('ファイルを添付できる', async () => {
|
test('ファイルを添付できる', async () => {
|
||||||
const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
|
const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
|
||||||
|
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
fileIds: [file.id],
|
fileIds: [file.id],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ describe('Note', () => {
|
||||||
test('他人のファイルで怒られる', async () => {
|
test('他人のファイルで怒られる', async () => {
|
||||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
|
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
|
||||||
|
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
fileIds: [file.id],
|
fileIds: [file.id],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -64,7 +64,7 @@ describe('Note', () => {
|
||||||
}, 1000 * 10);
|
}, 1000 * 10);
|
||||||
|
|
||||||
test('存在しないファイルで怒られる', async () => {
|
test('存在しないファイルで怒られる', async () => {
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
fileIds: ['000000000000000000000000'],
|
fileIds: ['000000000000000000000000'],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -75,7 +75,7 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('不正なファイルIDで怒られる', async () => {
|
test('不正なファイルIDで怒られる', async () => {
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
fileIds: ['kyoppie'],
|
fileIds: ['kyoppie'],
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
|
@ -93,7 +93,7 @@ describe('Note', () => {
|
||||||
replyId: bobPost.id,
|
replyId: bobPost.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await api('/notes/create', alicePost, alice);
|
const res = await api('notes/create', alicePost, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
|
@ -111,7 +111,7 @@ describe('Note', () => {
|
||||||
renoteId: bobPost.id,
|
renoteId: bobPost.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await api('/notes/create', alicePost, alice);
|
const res = await api('notes/create', alicePost, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
|
@ -129,7 +129,7 @@ describe('Note', () => {
|
||||||
renoteId: bobPost.id,
|
renoteId: bobPost.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await api('/notes/create', alicePost, alice);
|
const res = await api('notes/create', alicePost, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
|
@ -142,7 +142,7 @@ describe('Note', () => {
|
||||||
const bobPost = await post(bob, {
|
const bobPost = await post(bob, {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
});
|
});
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
text: ' ',
|
text: ' ',
|
||||||
renoteId: bobPost.id,
|
renoteId: bobPost.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -152,7 +152,7 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('visibility: followersでrenoteできる', async () => {
|
test('visibility: followersでrenoteできる', async () => {
|
||||||
const createRes = await api('/notes/create', {
|
const createRes = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
visibility: 'followers',
|
visibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -160,7 +160,7 @@ describe('Note', () => {
|
||||||
assert.strictEqual(createRes.status, 200);
|
assert.strictEqual(createRes.status, 200);
|
||||||
|
|
||||||
const renoteId = createRes.body.createdNote.id;
|
const renoteId = createRes.body.createdNote.id;
|
||||||
const renoteRes = await api('/notes/create', {
|
const renoteRes = await api('notes/create', {
|
||||||
visibility: 'followers',
|
visibility: 'followers',
|
||||||
renoteId,
|
renoteId,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -169,7 +169,7 @@ describe('Note', () => {
|
||||||
assert.strictEqual(renoteRes.body.createdNote.renoteId, renoteId);
|
assert.strictEqual(renoteRes.body.createdNote.renoteId, renoteId);
|
||||||
assert.strictEqual(renoteRes.body.createdNote.visibility, 'followers');
|
assert.strictEqual(renoteRes.body.createdNote.visibility, 'followers');
|
||||||
|
|
||||||
const deleteRes = await api('/notes/delete', {
|
const deleteRes = await api('notes/delete', {
|
||||||
noteId: renoteRes.body.createdNote.id,
|
noteId: renoteRes.body.createdNote.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -177,11 +177,11 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('visibility: followersなノートに対してフォロワーはリプライできる', async () => {
|
test('visibility: followersなノートに対してフォロワーはリプライできる', async () => {
|
||||||
await api('/following/create', {
|
await api('following/create', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
|
||||||
const aliceNote = await api('/notes/create', {
|
const aliceNote = await api('notes/create', {
|
||||||
text: 'direct note to bob',
|
text: 'direct note to bob',
|
||||||
visibility: 'followers',
|
visibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -189,7 +189,7 @@ describe('Note', () => {
|
||||||
assert.strictEqual(aliceNote.status, 200);
|
assert.strictEqual(aliceNote.status, 200);
|
||||||
|
|
||||||
const replyId = aliceNote.body.createdNote.id;
|
const replyId = aliceNote.body.createdNote.id;
|
||||||
const bobReply = await api('/notes/create', {
|
const bobReply = await api('notes/create', {
|
||||||
text: 'reply to alice note',
|
text: 'reply to alice note',
|
||||||
replyId,
|
replyId,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
@ -197,20 +197,20 @@ describe('Note', () => {
|
||||||
assert.strictEqual(bobReply.status, 200);
|
assert.strictEqual(bobReply.status, 200);
|
||||||
assert.strictEqual(bobReply.body.createdNote.replyId, replyId);
|
assert.strictEqual(bobReply.body.createdNote.replyId, replyId);
|
||||||
|
|
||||||
await api('/following/delete', {
|
await api('following/delete', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('visibility: followersなノートに対してフォロワーでないユーザーがリプライしようとすると怒られる', async () => {
|
test('visibility: followersなノートに対してフォロワーでないユーザーがリプライしようとすると怒られる', async () => {
|
||||||
const aliceNote = await api('/notes/create', {
|
const aliceNote = await api('notes/create', {
|
||||||
text: 'direct note to bob',
|
text: 'direct note to bob',
|
||||||
visibility: 'followers',
|
visibility: 'followers',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(aliceNote.status, 200);
|
assert.strictEqual(aliceNote.status, 200);
|
||||||
|
|
||||||
const bobReply = await api('/notes/create', {
|
const bobReply = await api('notes/create', {
|
||||||
text: 'reply to alice note',
|
text: 'reply to alice note',
|
||||||
replyId: aliceNote.body.createdNote.id,
|
replyId: aliceNote.body.createdNote.id,
|
||||||
}, bob);
|
}, bob);
|
||||||
|
@ -220,7 +220,7 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('visibility: specifiedなノートに対してvisibility: specifiedで返信できる', async () => {
|
test('visibility: specifiedなノートに対してvisibility: specifiedで返信できる', async () => {
|
||||||
const aliceNote = await api('/notes/create', {
|
const aliceNote = await api('notes/create', {
|
||||||
text: 'direct note to bob',
|
text: 'direct note to bob',
|
||||||
visibility: 'specified',
|
visibility: 'specified',
|
||||||
visibleUserIds: [bob.id],
|
visibleUserIds: [bob.id],
|
||||||
|
@ -228,7 +228,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
assert.strictEqual(aliceNote.status, 200);
|
assert.strictEqual(aliceNote.status, 200);
|
||||||
|
|
||||||
const bobReply = await api('/notes/create', {
|
const bobReply = await api('notes/create', {
|
||||||
text: 'reply to alice note',
|
text: 'reply to alice note',
|
||||||
replyId: aliceNote.body.createdNote.id,
|
replyId: aliceNote.body.createdNote.id,
|
||||||
visibility: 'specified',
|
visibility: 'specified',
|
||||||
|
@ -239,7 +239,7 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('visibility: specifiedなノートに対してvisibility: follwersで返信しようとすると怒られる', async () => {
|
test('visibility: specifiedなノートに対してvisibility: follwersで返信しようとすると怒られる', async () => {
|
||||||
const aliceNote = await api('/notes/create', {
|
const aliceNote = await api('notes/create', {
|
||||||
text: 'direct note to bob',
|
text: 'direct note to bob',
|
||||||
visibility: 'specified',
|
visibility: 'specified',
|
||||||
visibleUserIds: [bob.id],
|
visibleUserIds: [bob.id],
|
||||||
|
@ -247,7 +247,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
assert.strictEqual(aliceNote.status, 200);
|
assert.strictEqual(aliceNote.status, 200);
|
||||||
|
|
||||||
const bobReply = await api('/notes/create', {
|
const bobReply = await api('notes/create', {
|
||||||
text: 'reply to alice note with visibility: followers',
|
text: 'reply to alice note with visibility: followers',
|
||||||
replyId: aliceNote.body.createdNote.id,
|
replyId: aliceNote.body.createdNote.id,
|
||||||
visibility: 'followers',
|
visibility: 'followers',
|
||||||
|
@ -261,7 +261,7 @@ describe('Note', () => {
|
||||||
const post = {
|
const post = {
|
||||||
text: '!'.repeat(MAX_NOTE_TEXT_LENGTH), // 3000文字
|
text: '!'.repeat(MAX_NOTE_TEXT_LENGTH), // 3000文字
|
||||||
};
|
};
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ describe('Note', () => {
|
||||||
const post = {
|
const post = {
|
||||||
text: '!'.repeat(MAX_NOTE_TEXT_LENGTH + 1), // 3001文字
|
text: '!'.repeat(MAX_NOTE_TEXT_LENGTH + 1), // 3001文字
|
||||||
};
|
};
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ describe('Note', () => {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
replyId: '000000000000000000000000',
|
replyId: '000000000000000000000000',
|
||||||
};
|
};
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ describe('Note', () => {
|
||||||
const post = {
|
const post = {
|
||||||
renoteId: '000000000000000000000000',
|
renoteId: '000000000000000000000000',
|
||||||
};
|
};
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ describe('Note', () => {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
replyId: 'foo',
|
replyId: 'foo',
|
||||||
};
|
};
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ describe('Note', () => {
|
||||||
const post = {
|
const post = {
|
||||||
renoteId: 'foo',
|
renoteId: 'foo',
|
||||||
};
|
};
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ describe('Note', () => {
|
||||||
text: '@ghost yo',
|
text: '@ghost yo',
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
|
@ -324,7 +324,7 @@ describe('Note', () => {
|
||||||
text: '@bob @bob @bob yo',
|
text: '@bob @bob @bob yo',
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await api('/notes/create', post, alice);
|
const res = await api('notes/create', post, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
|
@ -337,25 +337,25 @@ describe('Note', () => {
|
||||||
describe('添付ファイル情報', () => {
|
describe('添付ファイル情報', () => {
|
||||||
test('ファイルを添付した場合、投稿成功時にファイル情報入りのレスポンスが帰ってくる', async () => {
|
test('ファイルを添付した場合、投稿成功時にファイル情報入りのレスポンスが帰ってくる', async () => {
|
||||||
const file = await uploadFile(alice);
|
const file = await uploadFile(alice);
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
fileIds: [file.body.id],
|
fileIds: [file.body!.id],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||||
assert.strictEqual(res.body.createdNote.files.length, 1);
|
assert.strictEqual(res.body.createdNote.files.length, 1);
|
||||||
assert.strictEqual(res.body.createdNote.files[0].id, file.body.id);
|
assert.strictEqual(res.body.createdNote.files[0].id, file.body!.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイルを添付した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
test('ファイルを添付した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
||||||
const file = await uploadFile(alice);
|
const file = await uploadFile(alice);
|
||||||
const createdNote = await api('/notes/create', {
|
const createdNote = await api('notes/create', {
|
||||||
fileIds: [file.body.id],
|
fileIds: [file.body!.id],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(createdNote.status, 200);
|
assert.strictEqual(createdNote.status, 200);
|
||||||
|
|
||||||
const res = await api('/notes', {
|
const res = await api('notes', {
|
||||||
withFiles: true,
|
withFiles: true,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -364,23 +364,23 @@ describe('Note', () => {
|
||||||
const myNote = res.body.find((note: { id: string; files: { id: string }[] }) => note.id === createdNote.body.createdNote.id);
|
const myNote = res.body.find((note: { id: string; files: { id: string }[] }) => note.id === createdNote.body.createdNote.id);
|
||||||
assert.notEqual(myNote, null);
|
assert.notEqual(myNote, null);
|
||||||
assert.strictEqual(myNote.files.length, 1);
|
assert.strictEqual(myNote.files.length, 1);
|
||||||
assert.strictEqual(myNote.files[0].id, file.body.id);
|
assert.strictEqual(myNote.files[0].id, file.body!.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイルが添付されたノートをリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
test('ファイルが添付されたノートをリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
||||||
const file = await uploadFile(alice);
|
const file = await uploadFile(alice);
|
||||||
const createdNote = await api('/notes/create', {
|
const createdNote = await api('notes/create', {
|
||||||
fileIds: [file.body.id],
|
fileIds: [file.body!.id],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(createdNote.status, 200);
|
assert.strictEqual(createdNote.status, 200);
|
||||||
|
|
||||||
const renoted = await api('/notes/create', {
|
const renoted = await api('notes/create', {
|
||||||
renoteId: createdNote.body.createdNote.id,
|
renoteId: createdNote.body.createdNote.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(renoted.status, 200);
|
assert.strictEqual(renoted.status, 200);
|
||||||
|
|
||||||
const res = await api('/notes', {
|
const res = await api('notes', {
|
||||||
renote: true,
|
renote: true,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -389,24 +389,24 @@ describe('Note', () => {
|
||||||
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
|
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
|
||||||
assert.notEqual(myNote, null);
|
assert.notEqual(myNote, null);
|
||||||
assert.strictEqual(myNote.renote.files.length, 1);
|
assert.strictEqual(myNote.renote.files.length, 1);
|
||||||
assert.strictEqual(myNote.renote.files[0].id, file.body.id);
|
assert.strictEqual(myNote.renote.files[0].id, file.body!.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイルが添付されたノートに返信した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
test('ファイルが添付されたノートに返信した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
||||||
const file = await uploadFile(alice);
|
const file = await uploadFile(alice);
|
||||||
const createdNote = await api('/notes/create', {
|
const createdNote = await api('notes/create', {
|
||||||
fileIds: [file.body.id],
|
fileIds: [file.body!.id],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(createdNote.status, 200);
|
assert.strictEqual(createdNote.status, 200);
|
||||||
|
|
||||||
const reply = await api('/notes/create', {
|
const reply = await api('notes/create', {
|
||||||
replyId: createdNote.body.createdNote.id,
|
replyId: createdNote.body.createdNote.id,
|
||||||
text: 'this is reply',
|
text: 'this is reply',
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(reply.status, 200);
|
assert.strictEqual(reply.status, 200);
|
||||||
|
|
||||||
const res = await api('/notes', {
|
const res = await api('notes', {
|
||||||
reply: true,
|
reply: true,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -415,29 +415,29 @@ describe('Note', () => {
|
||||||
const myNote = res.body.find((note: { id: string }) => note.id === reply.body.createdNote.id);
|
const myNote = res.body.find((note: { id: string }) => note.id === reply.body.createdNote.id);
|
||||||
assert.notEqual(myNote, null);
|
assert.notEqual(myNote, null);
|
||||||
assert.strictEqual(myNote.reply.files.length, 1);
|
assert.strictEqual(myNote.reply.files.length, 1);
|
||||||
assert.strictEqual(myNote.reply.files[0].id, file.body.id);
|
assert.strictEqual(myNote.reply.files[0].id, file.body!.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ファイルが添付されたノートへの返信をリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
test('ファイルが添付されたノートへの返信をリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
|
||||||
const file = await uploadFile(alice);
|
const file = await uploadFile(alice);
|
||||||
const createdNote = await api('/notes/create', {
|
const createdNote = await api('notes/create', {
|
||||||
fileIds: [file.body.id],
|
fileIds: [file.body!.id],
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(createdNote.status, 200);
|
assert.strictEqual(createdNote.status, 200);
|
||||||
|
|
||||||
const reply = await api('/notes/create', {
|
const reply = await api('notes/create', {
|
||||||
replyId: createdNote.body.createdNote.id,
|
replyId: createdNote.body.createdNote.id,
|
||||||
text: 'this is reply',
|
text: 'this is reply',
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(reply.status, 200);
|
assert.strictEqual(reply.status, 200);
|
||||||
|
|
||||||
const renoted = await api('/notes/create', {
|
const renoted = await api('notes/create', {
|
||||||
renoteId: reply.body.createdNote.id,
|
renoteId: reply.body.createdNote.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(renoted.status, 200);
|
assert.strictEqual(renoted.status, 200);
|
||||||
|
|
||||||
const res = await api('/notes', {
|
const res = await api('notes', {
|
||||||
renote: true,
|
renote: true,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ describe('Note', () => {
|
||||||
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
|
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
|
||||||
assert.notEqual(myNote, null);
|
assert.notEqual(myNote, null);
|
||||||
assert.strictEqual(myNote.renote.reply.files.length, 1);
|
assert.strictEqual(myNote.renote.reply.files.length, 1);
|
||||||
assert.strictEqual(myNote.renote.reply.files[0].id, file.body.id);
|
assert.strictEqual(myNote.renote.reply.files[0].id, file.body!.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('NSFWが強制されている場合変更できない', async () => {
|
test('NSFWが強制されている場合変更できない', async () => {
|
||||||
|
@ -483,15 +483,15 @@ describe('Note', () => {
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(assign.status, 204);
|
assert.strictEqual(assign.status, 204);
|
||||||
assert.strictEqual(file.body.isSensitive, false);
|
assert.strictEqual(file.body!.isSensitive, false);
|
||||||
|
|
||||||
const nsfwfile = await uploadFile(alice);
|
const nsfwfile = await uploadFile(alice);
|
||||||
|
|
||||||
assert.strictEqual(nsfwfile.status, 200);
|
assert.strictEqual(nsfwfile.status, 200);
|
||||||
assert.strictEqual(nsfwfile.body.isSensitive, true);
|
assert.strictEqual(nsfwfile.body!.isSensitive, true);
|
||||||
|
|
||||||
const liftnsfw = await api('drive/files/update', {
|
const liftnsfw = await api('drive/files/update', {
|
||||||
fileId: nsfwfile.body.id,
|
fileId: nsfwfile.body!.id,
|
||||||
isSensitive: false,
|
isSensitive: false,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -499,7 +499,7 @@ describe('Note', () => {
|
||||||
assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE');
|
assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE');
|
||||||
|
|
||||||
const oldaddnsfw = await api('drive/files/update', {
|
const oldaddnsfw = await api('drive/files/update', {
|
||||||
fileId: file.body.id,
|
fileId: file.body!.id,
|
||||||
isSensitive: true,
|
isSensitive: true,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
describe('notes/create', () => {
|
describe('notes/create', () => {
|
||||||
test('投票を添付できる', async () => {
|
test('投票を添付できる', async () => {
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
poll: {
|
poll: {
|
||||||
choices: ['foo', 'bar'],
|
choices: ['foo', 'bar'],
|
||||||
|
@ -531,14 +531,15 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('投票の選択肢が無くて怒られる', async () => {
|
test('投票の選択肢が無くて怒られる', async () => {
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
|
// @ts-expect-error poll must not be empty
|
||||||
poll: {},
|
poll: {},
|
||||||
}, alice);
|
}, alice);
|
||||||
assert.strictEqual(res.status, 400);
|
assert.strictEqual(res.status, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('投票の選択肢が無くて怒られる (空の配列)', async () => {
|
test('投票の選択肢が無くて怒られる (空の配列)', async () => {
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
poll: {
|
poll: {
|
||||||
choices: [],
|
choices: [],
|
||||||
},
|
},
|
||||||
|
@ -547,7 +548,7 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('投票の選択肢が1つで怒られる', async () => {
|
test('投票の選択肢が1つで怒られる', async () => {
|
||||||
const res = await api('/notes/create', {
|
const res = await api('notes/create', {
|
||||||
poll: {
|
poll: {
|
||||||
choices: ['Strawberry Pasta'],
|
choices: ['Strawberry Pasta'],
|
||||||
},
|
},
|
||||||
|
@ -556,14 +557,14 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('投票できる', async () => {
|
test('投票できる', async () => {
|
||||||
const { body } = await api('/notes/create', {
|
const { body } = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
poll: {
|
poll: {
|
||||||
choices: ['sakura', 'izumi', 'ako'],
|
choices: ['sakura', 'izumi', 'ako'],
|
||||||
},
|
},
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/notes/polls/vote', {
|
const res = await api('notes/polls/vote', {
|
||||||
noteId: body.createdNote.id,
|
noteId: body.createdNote.id,
|
||||||
choice: 1,
|
choice: 1,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -572,19 +573,19 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('複数投票できない', async () => {
|
test('複数投票できない', async () => {
|
||||||
const { body } = await api('/notes/create', {
|
const { body } = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
poll: {
|
poll: {
|
||||||
choices: ['sakura', 'izumi', 'ako'],
|
choices: ['sakura', 'izumi', 'ako'],
|
||||||
},
|
},
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
await api('/notes/polls/vote', {
|
await api('notes/polls/vote', {
|
||||||
noteId: body.createdNote.id,
|
noteId: body.createdNote.id,
|
||||||
choice: 0,
|
choice: 0,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/notes/polls/vote', {
|
const res = await api('notes/polls/vote', {
|
||||||
noteId: body.createdNote.id,
|
noteId: body.createdNote.id,
|
||||||
choice: 2,
|
choice: 2,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -593,7 +594,7 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('許可されている場合は複数投票できる', async () => {
|
test('許可されている場合は複数投票できる', async () => {
|
||||||
const { body } = await api('/notes/create', {
|
const { body } = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
poll: {
|
poll: {
|
||||||
choices: ['sakura', 'izumi', 'ako'],
|
choices: ['sakura', 'izumi', 'ako'],
|
||||||
|
@ -601,17 +602,17 @@ describe('Note', () => {
|
||||||
},
|
},
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
await api('/notes/polls/vote', {
|
await api('notes/polls/vote', {
|
||||||
noteId: body.createdNote.id,
|
noteId: body.createdNote.id,
|
||||||
choice: 0,
|
choice: 0,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
await api('/notes/polls/vote', {
|
await api('notes/polls/vote', {
|
||||||
noteId: body.createdNote.id,
|
noteId: body.createdNote.id,
|
||||||
choice: 1,
|
choice: 1,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
const res = await api('/notes/polls/vote', {
|
const res = await api('notes/polls/vote', {
|
||||||
noteId: body.createdNote.id,
|
noteId: body.createdNote.id,
|
||||||
choice: 2,
|
choice: 2,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -620,7 +621,7 @@ describe('Note', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('締め切られている場合は投票できない', async () => {
|
test('締め切られている場合は投票できない', async () => {
|
||||||
const { body } = await api('/notes/create', {
|
const { body } = await api('notes/create', {
|
||||||
text: 'test',
|
text: 'test',
|
||||||
poll: {
|
poll: {
|
||||||
choices: ['sakura', 'izumi', 'ako'],
|
choices: ['sakura', 'izumi', 'ako'],
|
||||||
|
@ -630,7 +631,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
await new Promise(x => setTimeout(x, 2));
|
await new Promise(x => setTimeout(x, 2));
|
||||||
|
|
||||||
const res = await api('/notes/polls/vote', {
|
const res = await api('notes/polls/vote', {
|
||||||
noteId: body.createdNote.id,
|
noteId: body.createdNote.id,
|
||||||
choice: 1,
|
choice: 1,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
@ -649,7 +650,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
await new Promise(x => setTimeout(x, 2));
|
await new Promise(x => setTimeout(x, 2));
|
||||||
|
|
||||||
const note1 = await api('/notes/create', {
|
const note1 = await api('notes/create', {
|
||||||
text: 'hogetesthuge',
|
text: 'hogetesthuge',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -666,7 +667,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
assert.strictEqual(sensitive.status, 204);
|
assert.strictEqual(sensitive.status, 204);
|
||||||
|
|
||||||
const note2 = await api('/notes/create', {
|
const note2 = await api('notes/create', {
|
||||||
text: 'hogetesthuge',
|
text: 'hogetesthuge',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -683,7 +684,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
assert.strictEqual(sensitive.status, 204);
|
assert.strictEqual(sensitive.status, 204);
|
||||||
|
|
||||||
const note2 = await api('/notes/create', {
|
const note2 = await api('notes/create', {
|
||||||
text: 'hogeTesthuge',
|
text: 'hogeTesthuge',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -702,7 +703,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
await new Promise(x => setTimeout(x, 2));
|
await new Promise(x => setTimeout(x, 2));
|
||||||
|
|
||||||
const note1 = await api('/notes/create', {
|
const note1 = await api('notes/create', {
|
||||||
text: 'hogetesthuge',
|
text: 'hogetesthuge',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -719,7 +720,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
assert.strictEqual(prohibited.status, 204);
|
assert.strictEqual(prohibited.status, 204);
|
||||||
|
|
||||||
const note2 = await api('/notes/create', {
|
const note2 = await api('notes/create', {
|
||||||
text: 'hogetesthuge',
|
text: 'hogetesthuge',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -736,7 +737,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
assert.strictEqual(prohibited.status, 204);
|
assert.strictEqual(prohibited.status, 204);
|
||||||
|
|
||||||
const note2 = await api('/notes/create', {
|
const note2 = await api('notes/create', {
|
||||||
text: 'hogeTesthuge',
|
text: 'hogeTesthuge',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -755,7 +756,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
await new Promise(x => setTimeout(x, 2));
|
await new Promise(x => setTimeout(x, 2));
|
||||||
|
|
||||||
const note1 = await api('/notes/create', {
|
const note1 = await api('notes/create', {
|
||||||
text: 'hogetesthuge',
|
text: 'hogetesthuge',
|
||||||
}, tom);
|
}, tom);
|
||||||
|
|
||||||
|
@ -799,7 +800,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
await new Promise(x => setTimeout(x, 2));
|
await new Promise(x => setTimeout(x, 2));
|
||||||
|
|
||||||
const note = await api('/notes/create', {
|
const note = await api('notes/create', {
|
||||||
text: '@bob potentially annoying text',
|
text: '@bob potentially annoying text',
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -853,7 +854,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
await new Promise(x => setTimeout(x, 2));
|
await new Promise(x => setTimeout(x, 2));
|
||||||
|
|
||||||
const note = await api('/notes/create', {
|
const note = await api('notes/create', {
|
||||||
text: 'potentially annoying text',
|
text: 'potentially annoying text',
|
||||||
visibility: 'specified',
|
visibility: 'specified',
|
||||||
visibleUserIds: [bob.id],
|
visibleUserIds: [bob.id],
|
||||||
|
@ -909,7 +910,7 @@ describe('Note', () => {
|
||||||
|
|
||||||
await new Promise(x => setTimeout(x, 2));
|
await new Promise(x => setTimeout(x, 2));
|
||||||
|
|
||||||
const note = await api('/notes/create', {
|
const note = await api('notes/create', {
|
||||||
text: '@bob potentially annoying text',
|
text: '@bob potentially annoying text',
|
||||||
visibility: 'specified',
|
visibility: 'specified',
|
||||||
visibleUserIds: [bob.id],
|
visibleUserIds: [bob.id],
|
||||||
|
|
|
@ -22,7 +22,7 @@ describe('Renote Mute', () => {
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
test('ミュート作成', async () => {
|
test('ミュート作成', async () => {
|
||||||
const res = await api('/renote-mute/create', {
|
const res = await api('renote-mute/create', {
|
||||||
userId: carol.id,
|
userId: carol.id,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ describe('Renote Mute', () => {
|
||||||
// redisに追加されるのを待つ
|
// redisに追加されるのを待つ
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
|
|
||||||
const res = await api('/notes/local-timeline', {}, alice);
|
const res = await api('notes/local-timeline', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -54,7 +54,7 @@ describe('Renote Mute', () => {
|
||||||
// redisに追加されるのを待つ
|
// redisに追加されるのを待つ
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
|
|
||||||
const res = await api('/notes/local-timeline', {}, alice);
|
const res = await api('notes/local-timeline', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
|
|
@ -601,7 +601,7 @@ describe('Streaming', () => {
|
||||||
|
|
||||||
// #10443
|
// #10443
|
||||||
test('ミュートしているサーバのノートがリストTLに流れない', async () => {
|
test('ミュートしているサーバのノートがリストTLに流れない', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
mutedInstances: ['example.com'],
|
mutedInstances: ['example.com'],
|
||||||
}, chitose);
|
}, chitose);
|
||||||
|
|
||||||
|
@ -618,7 +618,7 @@ describe('Streaming', () => {
|
||||||
|
|
||||||
// #10443
|
// #10443
|
||||||
test('ミュートしているサーバのノートに対するリプライがリストTLに流れない', async () => {
|
test('ミュートしているサーバのノートに対するリプライがリストTLに流れない', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
mutedInstances: ['example.com'],
|
mutedInstances: ['example.com'],
|
||||||
}, chitose);
|
}, chitose);
|
||||||
|
|
||||||
|
@ -635,7 +635,7 @@ describe('Streaming', () => {
|
||||||
|
|
||||||
// #10443
|
// #10443
|
||||||
test('ミュートしているサーバのノートに対するリノートがリストTLに流れない', async () => {
|
test('ミュートしているサーバのノートに対するリノートがリストTLに流れない', async () => {
|
||||||
await api('/i/update', {
|
await api('i/update', {
|
||||||
mutedInstances: ['example.com'],
|
mutedInstances: ['example.com'],
|
||||||
}, chitose);
|
}, chitose);
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,12 @@ describe('Note thread mute', () => {
|
||||||
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
||||||
const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
|
const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
|
||||||
|
|
||||||
await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
||||||
|
|
||||||
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
||||||
const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
|
const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
|
||||||
|
|
||||||
const res = await api('/notes/mentions', {}, alice);
|
const res = await api('notes/mentions', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
@ -40,15 +40,15 @@ describe('Note thread mute', () => {
|
||||||
|
|
||||||
test('ミュートしているスレッドからメンションされても、hasUnreadMentions が true にならない', async () => {
|
test('ミュートしているスレッドからメンションされても、hasUnreadMentions が true にならない', async () => {
|
||||||
// 状態リセット
|
// 状態リセット
|
||||||
await api('/i/read-all-unread-notes', {}, alice);
|
await api('i/read-all-unread-notes', {}, alice);
|
||||||
|
|
||||||
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
||||||
|
|
||||||
await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
||||||
|
|
||||||
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
||||||
|
|
||||||
const res = await api('/i', {}, alice);
|
const res = await api('i', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(res.body.hasUnreadMentions, false);
|
assert.strictEqual(res.body.hasUnreadMentions, false);
|
||||||
|
@ -56,11 +56,11 @@ describe('Note thread mute', () => {
|
||||||
|
|
||||||
test('ミュートしているスレッドからメンションされても、ストリームに unreadMention イベントが流れてこない', () => new Promise<void>(async done => {
|
test('ミュートしているスレッドからメンションされても、ストリームに unreadMention イベントが流れてこない', () => new Promise<void>(async done => {
|
||||||
// 状態リセット
|
// 状態リセット
|
||||||
await api('/i/read-all-unread-notes', {}, alice);
|
await api('i/read-all-unread-notes', {}, alice);
|
||||||
|
|
||||||
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
||||||
|
|
||||||
await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
||||||
|
|
||||||
let fired = false;
|
let fired = false;
|
||||||
|
|
||||||
|
@ -84,12 +84,12 @@ describe('Note thread mute', () => {
|
||||||
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
const bobNote = await post(bob, { text: '@alice @carol root note' });
|
||||||
const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
|
const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
|
||||||
|
|
||||||
await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
|
||||||
|
|
||||||
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
||||||
const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
|
const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
|
||||||
|
|
||||||
const res = await api('/i/notifications', {}, alice);
|
const res = await api('i/notifications', {}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 200);
|
assert.strictEqual(res.status, 200);
|
||||||
assert.strictEqual(Array.isArray(res.body), true);
|
assert.strictEqual(Array.isArray(res.body), true);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,9 +11,9 @@ import type * as misskey from 'misskey-js';
|
||||||
|
|
||||||
describe('users/notes', () => {
|
describe('users/notes', () => {
|
||||||
let alice: misskey.entities.SignupResponse;
|
let alice: misskey.entities.SignupResponse;
|
||||||
let jpgNote: any;
|
let jpgNote: misskey.entities.Note;
|
||||||
let pngNote: any;
|
let pngNote: misskey.entities.Note;
|
||||||
let jpgPngNote: any;
|
let jpgPngNote: misskey.entities.Note;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
alice = await signup({ username: 'alice' });
|
alice = await signup({ username: 'alice' });
|
||||||
|
@ -31,7 +31,7 @@ describe('users/notes', () => {
|
||||||
}, 1000 * 60 * 2);
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
test('withFiles', async () => {
|
test('withFiles', async () => {
|
||||||
const res = await api('/users/notes', {
|
const res = await api('users/notes', {
|
||||||
userId: alice.id,
|
userId: alice.id,
|
||||||
withFiles: true,
|
withFiles: true,
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
|
@ -8,7 +8,7 @@ process.env.NODE_ENV = 'test';
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { inspect } from 'node:util';
|
import { inspect } from 'node:util';
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import { api, page, post, role, signup, successfulApiCall, uploadFile } from '../utils.js';
|
import { api, post, role, signup, successfulApiCall, uploadFile } from '../utils.js';
|
||||||
import type * as misskey from 'misskey-js';
|
import type * as misskey from 'misskey-js';
|
||||||
|
|
||||||
describe('ユーザー', () => {
|
describe('ユーザー', () => {
|
||||||
|
@ -24,31 +24,12 @@ describe('ユーザー', () => {
|
||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
// BUG misskey-jsとjson-schemaと実際に返ってくるデータが全部違う
|
const show = async (id: string, me = root): Promise<misskey.entities.UserDetailed> => {
|
||||||
type UserLite = misskey.entities.UserLite & {
|
return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me });
|
||||||
badgeRoles: any[],
|
|
||||||
};
|
|
||||||
|
|
||||||
type UserDetailedNotMe = UserLite &
|
|
||||||
misskey.entities.UserDetailed & {
|
|
||||||
roles: any[],
|
|
||||||
};
|
|
||||||
|
|
||||||
type MeDetailed = UserDetailedNotMe &
|
|
||||||
misskey.entities.MeDetailed & {
|
|
||||||
achievements: object[],
|
|
||||||
loggedInDays: number,
|
|
||||||
policies: object,
|
|
||||||
};
|
|
||||||
|
|
||||||
type User = MeDetailed & { token: string };
|
|
||||||
|
|
||||||
const show = async (id: string, me = root): Promise<MeDetailed | UserDetailedNotMe> => {
|
|
||||||
return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me }) as any;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// UserLiteのキーが過不足なく入っている?
|
// UserLiteのキーが過不足なく入っている?
|
||||||
const userLite = (user: User): Partial<UserLite> => {
|
const userLite = (user: misskey.entities.UserLite): Partial<misskey.entities.UserLite> => {
|
||||||
return stripUndefined({
|
return stripUndefined({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
|
@ -71,7 +52,7 @@ describe('ユーザー', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// UserDetailedNotMeのキーが過不足なく入っている?
|
// UserDetailedNotMeのキーが過不足なく入っている?
|
||||||
const userDetailedNotMe = (user: User): Partial<UserDetailedNotMe> => {
|
const userDetailedNotMe = (user: misskey.entities.SignupResponse): Partial<misskey.entities.UserDetailedNotMe> => {
|
||||||
return stripUndefined({
|
return stripUndefined({
|
||||||
...userLite(user),
|
...userLite(user),
|
||||||
url: user.url,
|
url: user.url,
|
||||||
|
@ -111,7 +92,7 @@ describe('ユーザー', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Relations関連のキーが過不足なく入っている?
|
// Relations関連のキーが過不足なく入っている?
|
||||||
const userDetailedNotMeWithRelations = (user: User): Partial<UserDetailedNotMe> => {
|
const userDetailedNotMeWithRelations = (user: misskey.entities.SignupResponse): Partial<misskey.entities.UserDetailedNotMe> => {
|
||||||
return stripUndefined({
|
return stripUndefined({
|
||||||
...userDetailedNotMe(user),
|
...userDetailedNotMe(user),
|
||||||
isFollowing: user.isFollowing ?? false,
|
isFollowing: user.isFollowing ?? false,
|
||||||
|
@ -128,7 +109,7 @@ describe('ユーザー', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// MeDetailedのキーが過不足なく入っている?
|
// MeDetailedのキーが過不足なく入っている?
|
||||||
const meDetailed = (user: User, security = false): Partial<MeDetailed> => {
|
const meDetailed = (user: misskey.entities.SignupResponse, security = false): Partial<misskey.entities.MeDetailed> => {
|
||||||
return stripUndefined({
|
return stripUndefined({
|
||||||
...userDetailedNotMe(user),
|
...userDetailedNotMe(user),
|
||||||
avatarId: user.avatarId,
|
avatarId: user.avatarId,
|
||||||
|
@ -159,6 +140,7 @@ describe('ユーザー', () => {
|
||||||
mutedWords: user.mutedWords,
|
mutedWords: user.mutedWords,
|
||||||
hardMutedWords: user.hardMutedWords,
|
hardMutedWords: user.hardMutedWords,
|
||||||
mutedInstances: user.mutedInstances,
|
mutedInstances: user.mutedInstances,
|
||||||
|
// @ts-expect-error 後方互換性
|
||||||
mutingNotificationTypes: user.mutingNotificationTypes,
|
mutingNotificationTypes: user.mutingNotificationTypes,
|
||||||
notificationRecieveConfig: user.notificationRecieveConfig,
|
notificationRecieveConfig: user.notificationRecieveConfig,
|
||||||
emailNotificationTypes: user.emailNotificationTypes,
|
emailNotificationTypes: user.emailNotificationTypes,
|
||||||
|
@ -173,61 +155,53 @@ describe('ユーザー', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let root: User;
|
let root: misskey.entities.SignupResponse;
|
||||||
let alice: User;
|
let alice: misskey.entities.SignupResponse;
|
||||||
let aliceNote: misskey.entities.Note;
|
let aliceNote: misskey.entities.Note;
|
||||||
let alicePage: misskey.entities.Page;
|
|
||||||
let aliceList: misskey.entities.UserList;
|
|
||||||
|
|
||||||
let bob: User;
|
let bob: misskey.entities.SignupResponse;
|
||||||
let bobNote: misskey.entities.Note;
|
|
||||||
|
|
||||||
let carol: User;
|
// NOTE: これがないと落ちる(bob の updatedAt が null になってしまうため?)
|
||||||
let dave: User;
|
let bobNote: misskey.entities.Note; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
let ellen: User;
|
|
||||||
let frank: User;
|
|
||||||
|
|
||||||
let usersReplying: User[];
|
let carol: misskey.entities.SignupResponse;
|
||||||
|
|
||||||
let userNoNote: User;
|
let usersReplying: misskey.entities.SignupResponse[];
|
||||||
let userNotExplorable: User;
|
|
||||||
let userLocking: User;
|
let userNoNote: misskey.entities.SignupResponse;
|
||||||
let userAdmin: User;
|
let userNotExplorable: misskey.entities.SignupResponse;
|
||||||
let roleAdmin: any;
|
let userLocking: misskey.entities.SignupResponse;
|
||||||
let userModerator: User;
|
let userAdmin: misskey.entities.SignupResponse;
|
||||||
let roleModerator: any;
|
let roleAdmin: misskey.entities.Role;
|
||||||
let userRolePublic: User;
|
let userModerator: misskey.entities.SignupResponse;
|
||||||
let rolePublic: any;
|
let roleModerator: misskey.entities.Role;
|
||||||
let userRoleBadge: User;
|
let userRolePublic: misskey.entities.SignupResponse;
|
||||||
let roleBadge: any;
|
let rolePublic: misskey.entities.Role;
|
||||||
let userSilenced: User;
|
let userRoleBadge: misskey.entities.SignupResponse;
|
||||||
let roleSilenced: any;
|
let roleBadge: misskey.entities.Role;
|
||||||
let userSuspended: User;
|
let userSilenced: misskey.entities.SignupResponse;
|
||||||
let userDeletedBySelf: User;
|
let roleSilenced: misskey.entities.Role;
|
||||||
let userDeletedByAdmin: User;
|
let userSuspended: misskey.entities.SignupResponse;
|
||||||
let userFollowingAlice: User;
|
let userDeletedBySelf: misskey.entities.SignupResponse;
|
||||||
let userFollowedByAlice: User;
|
let userDeletedByAdmin: misskey.entities.SignupResponse;
|
||||||
let userBlockingAlice: User;
|
let userFollowingAlice: misskey.entities.SignupResponse;
|
||||||
let userBlockedByAlice: User;
|
let userFollowedByAlice: misskey.entities.SignupResponse;
|
||||||
let userMutingAlice: User;
|
let userBlockingAlice: misskey.entities.SignupResponse;
|
||||||
let userMutedByAlice: User;
|
let userBlockedByAlice: misskey.entities.SignupResponse;
|
||||||
let userRnMutingAlice: User;
|
let userMutingAlice: misskey.entities.SignupResponse;
|
||||||
let userRnMutedByAlice: User;
|
let userMutedByAlice: misskey.entities.SignupResponse;
|
||||||
let userFollowRequesting: User;
|
let userRnMutingAlice: misskey.entities.SignupResponse;
|
||||||
let userFollowRequested: User;
|
let userRnMutedByAlice: misskey.entities.SignupResponse;
|
||||||
|
let userFollowRequesting: misskey.entities.SignupResponse;
|
||||||
|
let userFollowRequested: misskey.entities.SignupResponse;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
root = await signup({ username: 'root' });
|
root = await signup({ username: 'root' });
|
||||||
alice = await signup({ username: 'alice' });
|
alice = await signup({ username: 'alice' });
|
||||||
aliceNote = await post(alice, { text: 'test' }) as any;
|
aliceNote = await post(alice, { text: 'test' });
|
||||||
alicePage = await page(alice);
|
|
||||||
aliceList = (await api('users/list/create', { name: 'aliceList' }, alice)).body;
|
|
||||||
bob = await signup({ username: 'bob' });
|
bob = await signup({ username: 'bob' });
|
||||||
bobNote = await post(bob, { text: 'test' }) as any;
|
bobNote = await post(bob, { text: 'test' });
|
||||||
carol = await signup({ username: 'carol' });
|
carol = await signup({ username: 'carol' });
|
||||||
dave = await signup({ username: 'dave' });
|
|
||||||
ellen = await signup({ username: 'ellen' });
|
|
||||||
frank = await signup({ username: 'frank' });
|
|
||||||
|
|
||||||
// @alice -> @replyingへのリプライ。Promise.allで一気に作るとtimeoutしてしまうのでreduceで一つ一つawaitする
|
// @alice -> @replyingへのリプライ。Promise.allで一気に作るとtimeoutしてしまうのでreduceで一つ一つawaitする
|
||||||
usersReplying = await [...Array(10)].map((_, i) => i).reduce(async (acc, i) => {
|
usersReplying = await [...Array(10)].map((_, i) => i).reduce(async (acc, i) => {
|
||||||
|
@ -238,7 +212,7 @@ describe('ユーザー', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (await acc).concat(u);
|
return (await acc).concat(u);
|
||||||
}, Promise.resolve([] as User[]));
|
}, Promise.resolve([] as misskey.entities.SignupResponse[]));
|
||||||
|
|
||||||
userNoNote = await signup({ username: 'userNoNote' });
|
userNoNote = await signup({ username: 'userNoNote' });
|
||||||
userNotExplorable = await signup({ username: 'userNotExplorable' });
|
userNotExplorable = await signup({ username: 'userNotExplorable' });
|
||||||
|
@ -306,7 +280,7 @@ describe('ユーザー', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
alice = {
|
alice = {
|
||||||
...alice,
|
...alice,
|
||||||
...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }) as any,
|
...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }),
|
||||||
};
|
};
|
||||||
aliceNote = await successfulApiCall({ endpoint: 'notes/show', parameters: { noteId: aliceNote.id }, user: alice });
|
aliceNote = await successfulApiCall({ endpoint: 'notes/show', parameters: { noteId: aliceNote.id }, user: alice });
|
||||||
});
|
});
|
||||||
|
@ -319,7 +293,7 @@ describe('ユーザー', () => {
|
||||||
endpoint: 'signup',
|
endpoint: 'signup',
|
||||||
parameters: { username: 'zoe', password: 'password' },
|
parameters: { username: 'zoe', password: 'password' },
|
||||||
user: undefined,
|
user: undefined,
|
||||||
}) as unknown as User; // BUG MeDetailedに足りないキーがある
|
}) as unknown as misskey.entities.SignupResponse; // BUG MeDetailedに足りないキーがある
|
||||||
|
|
||||||
// signupの時はtokenが含まれる特別なMeDetailedが返ってくる
|
// signupの時はtokenが含まれる特別なMeDetailedが返ってくる
|
||||||
assert.match(response.token, /[a-zA-Z0-9]{16}/);
|
assert.match(response.token, /[a-zA-Z0-9]{16}/);
|
||||||
|
@ -329,7 +303,7 @@ describe('ユーザー', () => {
|
||||||
assert.strictEqual(response.name, null);
|
assert.strictEqual(response.name, null);
|
||||||
assert.strictEqual(response.username, 'zoe');
|
assert.strictEqual(response.username, 'zoe');
|
||||||
assert.strictEqual(response.host, null);
|
assert.strictEqual(response.host, null);
|
||||||
assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
response.avatarUrl && assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
||||||
assert.strictEqual(response.avatarBlurhash, null);
|
assert.strictEqual(response.avatarBlurhash, null);
|
||||||
assert.deepStrictEqual(response.avatarDecorations, []);
|
assert.deepStrictEqual(response.avatarDecorations, []);
|
||||||
assert.strictEqual(response.isBot, false);
|
assert.strictEqual(response.isBot, false);
|
||||||
|
@ -401,6 +375,7 @@ describe('ユーザー', () => {
|
||||||
assert.deepStrictEqual(response.unreadAnnouncements, []);
|
assert.deepStrictEqual(response.unreadAnnouncements, []);
|
||||||
assert.deepStrictEqual(response.mutedWords, []);
|
assert.deepStrictEqual(response.mutedWords, []);
|
||||||
assert.deepStrictEqual(response.mutedInstances, []);
|
assert.deepStrictEqual(response.mutedInstances, []);
|
||||||
|
// @ts-expect-error 後方互換のため
|
||||||
assert.deepStrictEqual(response.mutingNotificationTypes, []);
|
assert.deepStrictEqual(response.mutingNotificationTypes, []);
|
||||||
assert.deepStrictEqual(response.notificationRecieveConfig, {});
|
assert.deepStrictEqual(response.notificationRecieveConfig, {});
|
||||||
assert.deepStrictEqual(response.emailNotificationTypes, ['follow', 'receiveFollowRequest']);
|
assert.deepStrictEqual(response.emailNotificationTypes, ['follow', 'receiveFollowRequest']);
|
||||||
|
@ -430,66 +405,66 @@ describe('ユーザー', () => {
|
||||||
//#region 自分の情報の更新(i/update)
|
//#region 自分の情報の更新(i/update)
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ parameters: (): object => ({ name: null }) },
|
{ parameters: () => ({ name: null }) },
|
||||||
{ parameters: (): object => ({ name: 'x'.repeat(50) }) },
|
{ parameters: () => ({ name: 'x'.repeat(50) }) },
|
||||||
{ parameters: (): object => ({ name: 'x' }) },
|
{ parameters: () => ({ name: 'x' }) },
|
||||||
{ parameters: (): object => ({ name: 'My name' }) },
|
{ parameters: () => ({ name: 'My name' }) },
|
||||||
{ parameters: (): object => ({ description: null }) },
|
{ parameters: () => ({ description: null }) },
|
||||||
{ parameters: (): object => ({ description: 'x'.repeat(1500) }) },
|
{ parameters: () => ({ description: 'x'.repeat(1500) }) },
|
||||||
{ parameters: (): object => ({ description: 'x' }) },
|
{ parameters: () => ({ description: 'x' }) },
|
||||||
{ parameters: (): object => ({ description: 'My description' }) },
|
{ parameters: () => ({ description: 'My description' }) },
|
||||||
{ parameters: (): object => ({ location: null }) },
|
{ parameters: () => ({ location: null }) },
|
||||||
{ parameters: (): object => ({ location: 'x'.repeat(50) }) },
|
{ parameters: () => ({ location: 'x'.repeat(50) }) },
|
||||||
{ parameters: (): object => ({ location: 'x' }) },
|
{ parameters: () => ({ location: 'x' }) },
|
||||||
{ parameters: (): object => ({ location: 'My location' }) },
|
{ parameters: () => ({ location: 'My location' }) },
|
||||||
{ parameters: (): object => ({ birthday: '0000-00-00' }) },
|
{ parameters: () => ({ birthday: '0000-00-00' }) },
|
||||||
{ parameters: (): object => ({ birthday: '9999-99-99' }) },
|
{ parameters: () => ({ birthday: '9999-99-99' }) },
|
||||||
{ parameters: (): object => ({ lang: 'en-US' }) },
|
{ parameters: () => ({ lang: 'en-US' as const }) },
|
||||||
{ parameters: (): object => ({ fields: [] }) },
|
{ parameters: () => ({ fields: [] }) },
|
||||||
{ parameters: (): object => ({ fields: [{ name: 'x', value: 'x' }] }) },
|
{ parameters: () => ({ fields: [{ name: 'x', value: 'x' }] }) },
|
||||||
{ parameters: (): object => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない
|
{ parameters: () => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない
|
||||||
{ parameters: (): object => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) },
|
{ parameters: () => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) },
|
||||||
{ parameters: (): object => ({ isLocked: true }) },
|
{ parameters: () => ({ isLocked: true }) },
|
||||||
{ parameters: (): object => ({ isLocked: false }) },
|
{ parameters: () => ({ isLocked: false }) },
|
||||||
{ parameters: (): object => ({ isExplorable: false }) },
|
{ parameters: () => ({ isExplorable: false }) },
|
||||||
{ parameters: (): object => ({ isExplorable: true }) },
|
{ parameters: () => ({ isExplorable: true }) },
|
||||||
{ parameters: (): object => ({ hideOnlineStatus: true }) },
|
{ parameters: () => ({ hideOnlineStatus: true }) },
|
||||||
{ parameters: (): object => ({ hideOnlineStatus: false }) },
|
{ parameters: () => ({ hideOnlineStatus: false }) },
|
||||||
{ parameters: (): object => ({ publicReactions: false }) },
|
{ parameters: () => ({ publicReactions: false }) },
|
||||||
{ parameters: (): object => ({ publicReactions: true }) },
|
{ parameters: () => ({ publicReactions: true }) },
|
||||||
{ parameters: (): object => ({ autoAcceptFollowed: true }) },
|
{ parameters: () => ({ autoAcceptFollowed: true }) },
|
||||||
{ parameters: (): object => ({ autoAcceptFollowed: false }) },
|
{ parameters: () => ({ autoAcceptFollowed: false }) },
|
||||||
{ parameters: (): object => ({ noCrawle: true }) },
|
{ parameters: () => ({ noCrawle: true }) },
|
||||||
{ parameters: (): object => ({ noCrawle: false }) },
|
{ parameters: () => ({ noCrawle: false }) },
|
||||||
{ parameters: (): object => ({ preventAiLearning: false }) },
|
{ parameters: () => ({ preventAiLearning: false }) },
|
||||||
{ parameters: (): object => ({ preventAiLearning: true }) },
|
{ parameters: () => ({ preventAiLearning: true }) },
|
||||||
{ parameters: (): object => ({ isBot: true }) },
|
{ parameters: () => ({ isBot: true }) },
|
||||||
{ parameters: (): object => ({ isBot: false }) },
|
{ parameters: () => ({ isBot: false }) },
|
||||||
{ parameters: (): object => ({ isCat: true }) },
|
{ parameters: () => ({ isCat: true }) },
|
||||||
{ parameters: (): object => ({ isCat: false }) },
|
{ parameters: () => ({ isCat: false }) },
|
||||||
{ parameters: (): object => ({ injectFeaturedNote: true }) },
|
{ parameters: () => ({ injectFeaturedNote: true }) },
|
||||||
{ parameters: (): object => ({ injectFeaturedNote: false }) },
|
{ parameters: () => ({ injectFeaturedNote: false }) },
|
||||||
{ parameters: (): object => ({ receiveAnnouncementEmail: true }) },
|
{ parameters: () => ({ receiveAnnouncementEmail: true }) },
|
||||||
{ parameters: (): object => ({ receiveAnnouncementEmail: false }) },
|
{ parameters: () => ({ receiveAnnouncementEmail: false }) },
|
||||||
{ parameters: (): object => ({ alwaysMarkNsfw: true }) },
|
{ parameters: () => ({ alwaysMarkNsfw: true }) },
|
||||||
{ parameters: (): object => ({ alwaysMarkNsfw: false }) },
|
{ parameters: () => ({ alwaysMarkNsfw: false }) },
|
||||||
{ parameters: (): object => ({ autoSensitive: true }) },
|
{ parameters: () => ({ autoSensitive: true }) },
|
||||||
{ parameters: (): object => ({ autoSensitive: false }) },
|
{ parameters: () => ({ autoSensitive: false }) },
|
||||||
{ parameters: (): object => ({ followingVisibility: 'private' }) },
|
{ parameters: () => ({ followingVisibility: 'private' as const }) },
|
||||||
{ parameters: (): object => ({ followingVisibility: 'followers' }) },
|
{ parameters: () => ({ followingVisibility: 'followers' as const }) },
|
||||||
{ parameters: (): object => ({ followingVisibility: 'public' }) },
|
{ parameters: () => ({ followingVisibility: 'public' as const }) },
|
||||||
{ parameters: (): object => ({ followersVisibility: 'private' }) },
|
{ parameters: () => ({ followersVisibility: 'private' as const }) },
|
||||||
{ parameters: (): object => ({ followersVisibility: 'followers' }) },
|
{ parameters: () => ({ followersVisibility: 'followers' as const }) },
|
||||||
{ parameters: (): object => ({ followersVisibility: 'public' }) },
|
{ parameters: () => ({ followersVisibility: 'public' as const }) },
|
||||||
{ parameters: (): object => ({ mutedWords: Array(19).fill(['xxxxx']) }) },
|
{ parameters: () => ({ mutedWords: Array(19).fill(['xxxxx']) }) },
|
||||||
{ parameters: (): object => ({ mutedWords: [['x'.repeat(194)]] }) },
|
{ parameters: () => ({ mutedWords: [['x'.repeat(194)]] }) },
|
||||||
{ parameters: (): object => ({ mutedWords: [] }) },
|
{ parameters: () => ({ mutedWords: [] }) },
|
||||||
{ parameters: (): object => ({ mutedInstances: ['xxxx.xxxxx'] }) },
|
{ parameters: () => ({ mutedInstances: ['xxxx.xxxxx'] }) },
|
||||||
{ parameters: (): object => ({ mutedInstances: [] }) },
|
{ parameters: () => ({ mutedInstances: [] }) },
|
||||||
{ parameters: (): object => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) },
|
{ parameters: () => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) },
|
||||||
{ parameters: (): object => ({ notificationRecieveConfig: {} }) },
|
{ parameters: () => ({ notificationRecieveConfig: {} }) },
|
||||||
{ parameters: (): object => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) },
|
{ parameters: () => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) },
|
||||||
{ parameters: (): object => ({ emailNotificationTypes: [] }) },
|
{ parameters: () => ({ emailNotificationTypes: [] }) },
|
||||||
] as const)('を書き換えることができる($#)', async ({ parameters }) => {
|
] as const)('を書き換えることができる($#)', async ({ parameters }) => {
|
||||||
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters(), user: alice });
|
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters(), user: alice });
|
||||||
const expected = { ...meDetailed(alice, true), ...parameters() };
|
const expected = { ...meDetailed(alice, true), ...parameters() };
|
||||||
|
@ -498,13 +473,13 @@ describe('ユーザー', () => {
|
||||||
|
|
||||||
test('を書き換えることができる(Avatar)', async () => {
|
test('を書き換えることができる(Avatar)', async () => {
|
||||||
const aliceFile = (await uploadFile(alice)).body;
|
const aliceFile = (await uploadFile(alice)).body;
|
||||||
const parameters = { avatarId: aliceFile.id };
|
const parameters = { avatarId: aliceFile!.id };
|
||||||
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
|
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
|
||||||
assert.match(response.avatarUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
assert.match(response.avatarUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
||||||
assert.match(response.avatarBlurhash ?? '.', /[ -~]{54}/);
|
assert.match(response.avatarBlurhash ?? '.', /[ -~]{54}/);
|
||||||
const expected = {
|
const expected = {
|
||||||
...meDetailed(alice, true),
|
...meDetailed(alice, true),
|
||||||
avatarId: aliceFile.id,
|
avatarId: aliceFile!.id,
|
||||||
avatarBlurhash: response.avatarBlurhash,
|
avatarBlurhash: response.avatarBlurhash,
|
||||||
avatarUrl: response.avatarUrl,
|
avatarUrl: response.avatarUrl,
|
||||||
};
|
};
|
||||||
|
@ -523,13 +498,13 @@ describe('ユーザー', () => {
|
||||||
|
|
||||||
test('を書き換えることができる(Banner)', async () => {
|
test('を書き換えることができる(Banner)', async () => {
|
||||||
const aliceFile = (await uploadFile(alice)).body;
|
const aliceFile = (await uploadFile(alice)).body;
|
||||||
const parameters = { bannerId: aliceFile.id };
|
const parameters = { bannerId: aliceFile!.id };
|
||||||
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
|
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
|
||||||
assert.match(response.bannerUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
assert.match(response.bannerUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
||||||
assert.match(response.bannerBlurhash ?? '.', /[ -~]{54}/);
|
assert.match(response.bannerBlurhash ?? '.', /[ -~]{54}/);
|
||||||
const expected = {
|
const expected = {
|
||||||
...meDetailed(alice, true),
|
...meDetailed(alice, true),
|
||||||
bannerId: aliceFile.id,
|
bannerId: aliceFile!.id,
|
||||||
bannerBlurhash: response.bannerBlurhash,
|
bannerBlurhash: response.bannerBlurhash,
|
||||||
bannerUrl: response.bannerUrl,
|
bannerUrl: response.bannerUrl,
|
||||||
};
|
};
|
||||||
|
@ -579,13 +554,13 @@ describe('ユーザー', () => {
|
||||||
//#region ユーザー(users)
|
//#region ユーザー(users)
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ label: 'ID昇順', parameters: { limit: 5 }, selector: (u: UserLite): string => u.id },
|
{ label: 'ID昇順', parameters: { limit: 5 }, selector: (u: misskey.entities.UserLite): string => u.id },
|
||||||
{ label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
|
{ label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
|
||||||
{ label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
|
{ label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
|
||||||
{ label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
|
{ label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
|
||||||
{ label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
|
{ label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
|
||||||
{ label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
|
{ label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
|
||||||
{ label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
|
{ label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
|
||||||
] as const)('をリスト形式で取得することができる($label)', async ({ parameters, selector }) => {
|
] as const)('をリスト形式で取得することができる($label)', async ({ parameters, selector }) => {
|
||||||
const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
|
const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
|
||||||
|
|
||||||
|
@ -598,15 +573,15 @@ describe('ユーザー', () => {
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '「見つけやすくする」がOFFのユーザーが含まれない', user: (): User => userNotExplorable, excluded: true },
|
{ label: '「見つけやすくする」がOFFのユーザーが含まれない', user: () => userNotExplorable, excluded: true },
|
||||||
{ label: 'ミュートユーザーが含まれない', user: (): User => userMutedByAlice, excluded: true },
|
{ label: 'ミュートユーザーが含まれない', user: () => userMutedByAlice, excluded: true },
|
||||||
{ label: 'ブロックされているユーザーが含まれない', user: (): User => userBlockedByAlice, excluded: true },
|
{ label: 'ブロックされているユーザーが含まれない', user: () => userBlockedByAlice, excluded: true },
|
||||||
{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice, excluded: true },
|
{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice, excluded: true },
|
||||||
{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
|
{ label: '承認制ユーザーが含まれる', user: () => userLocking },
|
||||||
{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
|
{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
|
||||||
{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
|
{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
|
||||||
{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
|
{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
|
||||||
{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
|
{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
|
||||||
] as const)('をリスト形式で取得することができ、結果に$label', async ({ user, excluded }) => {
|
] as const)('をリスト形式で取得することができ、結果に$label', async ({ user, excluded }) => {
|
||||||
const parameters = { limit: 100 };
|
const parameters = { limit: 100 };
|
||||||
const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
|
const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
|
||||||
|
@ -620,39 +595,44 @@ describe('ユーザー', () => {
|
||||||
//#region ユーザー情報(users/show)
|
//#region ユーザー情報(users/show)
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ label: 'ID指定で自分自身を', parameters: (): object => ({ userId: alice.id }), user: (): User => alice, type: meDetailed },
|
{ label: 'ID指定で自分自身を', parameters: () => ({ userId: alice.id }), user: () => alice, type: meDetailed },
|
||||||
{ label: 'ID指定で他人を', parameters: (): object => ({ userId: alice.id }), user: (): User => bob, type: userDetailedNotMeWithRelations },
|
{ label: 'ID指定で他人を', parameters: () => ({ userId: alice.id }), user: () => bob, type: userDetailedNotMeWithRelations },
|
||||||
{ label: 'ID指定かつ未認証', parameters: (): object => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe },
|
{ label: 'ID指定かつ未認証', parameters: () => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe },
|
||||||
{ label: '@指定で自分自身を', parameters: (): object => ({ username: alice.username }), user: (): User => alice, type: meDetailed },
|
{ label: '@指定で自分自身を', parameters: () => ({ username: alice.username }), user: () => alice, type: meDetailed },
|
||||||
{ label: '@指定で他人を', parameters: (): object => ({ username: alice.username }), user: (): User => bob, type: userDetailedNotMeWithRelations },
|
{ label: '@指定で他人を', parameters: () => ({ username: alice.username }), user: () => bob, type: userDetailedNotMeWithRelations },
|
||||||
{ label: '@指定かつ未認証', parameters: (): object => ({ username: alice.username }), user: undefined, type: userDetailedNotMe },
|
{ label: '@指定かつ未認証', parameters: () => ({ username: alice.username }), user: undefined, type: userDetailedNotMe },
|
||||||
] as const)('を取得することができる($label)', async ({ parameters, user, type }) => {
|
] as const)('を取得することができる($label)', async ({ parameters, user, type }) => {
|
||||||
const response = await successfulApiCall({ endpoint: 'users/show', parameters: parameters(), user: user?.() });
|
const response = await successfulApiCall({ endpoint: 'users/show', parameters: parameters(), user: user?.() });
|
||||||
const expected = type(alice);
|
const expected = type(alice);
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
{ label: 'Administratorになっている', user: (): User => userAdmin, me: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin },
|
{ label: 'Administratorになっている', user: () => userAdmin, me: () => userAdmin, selector: (user: misskey.entities.MeDetailed) => user.isAdmin },
|
||||||
{ label: '自分以外から見たときはAdministratorか判定できない', user: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin, expected: (): undefined => undefined },
|
// @ts-expect-error UserDetailedNotMe doesn't include isAdmin
|
||||||
{ label: 'Moderatorになっている', user: (): User => userModerator, me: (): User => userModerator, selector: (user: User): unknown => user.isModerator },
|
{ label: '自分以外から見たときはAdministratorか判定できない', user: () => userAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isAdmin, expected: () => undefined },
|
||||||
{ label: '自分以外から見たときはModeratorか判定できない', user: (): User => userModerator, selector: (user: User): unknown => user.isModerator, expected: (): undefined => undefined },
|
{ label: 'Moderatorになっている', user: () => userModerator, me: () => userModerator, selector: (user: misskey.entities.MeDetailed) => user.isModerator },
|
||||||
{ label: 'サイレンスになっている', user: (): User => userSilenced, selector: (user: User): unknown => user.isSilenced },
|
// @ts-expect-error UserDetailedNotMe doesn't include isModerator
|
||||||
//{ label: 'サスペンドになっている', user: (): User => userSuspended, selector: (user: User): unknown => user.isSuspended },
|
{ label: '自分以外から見たときはModeratorか判定できない', user: () => userModerator, selector: (user: misskey.entities.UserDetailedNotMe) => user.isModerator, expected: () => undefined },
|
||||||
{ label: '削除済みになっている', user: (): User => userDeletedBySelf, me: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted },
|
{ label: 'サイレンスになっている', user: () => userSilenced, selector: (user: misskey.entities.UserDetailed) => user.isSilenced },
|
||||||
{ label: '自分以外から見たときは削除済みか判定できない', user: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined },
|
// FIXME: 落ちる
|
||||||
{ label: '削除済み(byAdmin)になっている', user: (): User => userDeletedByAdmin, me: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted },
|
//{ label: 'サスペンドになっている', user: () => userSuspended, selector: (user: misskey.entities.UserDetailed) => user.isSuspended },
|
||||||
{ label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined },
|
{ label: '削除済みになっている', user: () => userDeletedBySelf, me: () => userDeletedBySelf, selector: (user: misskey.entities.MeDetailed) => user.isDeleted },
|
||||||
{ label: 'フォロー中になっている', user: (): User => userFollowedByAlice, selector: (user: User): unknown => user.isFollowing },
|
// @ts-expect-error UserDetailedNotMe doesn't include isDeleted
|
||||||
{ label: 'フォローされている', user: (): User => userFollowingAlice, selector: (user: User): unknown => user.isFollowed },
|
{ label: '自分以外から見たときは削除済みか判定できない', user: () => userDeletedBySelf, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined },
|
||||||
{ label: 'ブロック中になっている', user: (): User => userBlockedByAlice, selector: (user: User): unknown => user.isBlocking },
|
{ label: '削除済み(byAdmin)になっている', user: () => userDeletedByAdmin, me: () => userDeletedByAdmin, selector: (user: misskey.entities.MeDetailed) => user.isDeleted },
|
||||||
{ label: 'ブロックされている', user: (): User => userBlockingAlice, selector: (user: User): unknown => user.isBlocked },
|
// @ts-expect-error UserDetailedNotMe doesn't include isDeleted
|
||||||
{ label: 'ミュート中になっている', user: (): User => userMutedByAlice, selector: (user: User): unknown => user.isMuted },
|
{ label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: () => userDeletedByAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined },
|
||||||
{ label: 'リノートミュート中になっている', user: (): User => userRnMutedByAlice, selector: (user: User): unknown => user.isRenoteMuted },
|
{ label: 'フォロー中になっている', user: () => userFollowedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowing },
|
||||||
{ label: 'フォローリクエスト中になっている', user: (): User => userFollowRequested, me: (): User => userFollowRequesting, selector: (user: User): unknown => user.hasPendingFollowRequestFromYou },
|
{ label: 'フォローされている', user: () => userFollowingAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowed },
|
||||||
{ label: 'フォローリクエストされている', user: (): User => userFollowRequesting, me: (): User => userFollowRequested, selector: (user: User): unknown => user.hasPendingFollowRequestToYou },
|
{ label: 'ブロック中になっている', user: () => userBlockedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocking },
|
||||||
|
{ label: 'ブロックされている', user: () => userBlockingAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocked },
|
||||||
|
{ label: 'ミュート中になっている', user: () => userMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isMuted },
|
||||||
|
{ label: 'リノートミュート中になっている', user: () => userRnMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isRenoteMuted },
|
||||||
|
{ label: 'フォローリクエスト中になっている', user: () => userFollowRequested, me: () => userFollowRequesting, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestFromYou },
|
||||||
|
{ label: 'フォローリクエストされている', user: () => userFollowRequesting, me: () => userFollowRequested, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestToYou },
|
||||||
] as const)('を取得することができ、$labelこと', async ({ user, me, selector, expected }) => {
|
] as const)('を取得することができ、$labelこと', async ({ user, me, selector, expected }) => {
|
||||||
const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: user().id }, user: me?.() ?? alice });
|
const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: user().id }, user: me?.() ?? alice });
|
||||||
assert.strictEqual(selector(response), (expected ?? ((): true => true))());
|
assert.strictEqual(selector(response as any), (expected ?? ((): true => true))());
|
||||||
});
|
});
|
||||||
test('を取得することができ、Publicなロールがセットされていること', async () => {
|
test('を取得することができ、Publicなロールがセットされていること', async () => {
|
||||||
const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: userRolePublic.id }, user: alice });
|
const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: userRolePublic.id }, user: alice });
|
||||||
|
@ -694,17 +674,18 @@ describe('ユーザー', () => {
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
|
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
|
||||||
{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
|
{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
|
||||||
{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
|
{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
|
||||||
{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
|
{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
|
||||||
{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
|
{ label: '承認制ユーザーが含まれる', user: () => userLocking },
|
||||||
{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
|
{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
|
||||||
{ label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: (): User => userSuspended, me: (): User => root },
|
{ label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: () => userSuspended, me: () => root },
|
||||||
// BUG サスペンドユーザーを一般ユーザーから見るとrootユーザーが返ってくる
|
// BUG サスペンドユーザーを一般ユーザーから見るとrootユーザーが返ってくる
|
||||||
//{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: (): User => userSuspended, me: (): User => bob, excluded: true },
|
//{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: () => userSuspended, me: () => bob, excluded: true },
|
||||||
{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
|
{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
|
||||||
{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
|
{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
|
||||||
|
// @ts-expect-error excluded は上でコメントアウトされているので
|
||||||
] as const)('をID指定のリスト形式で取得することができ、結果に$label', async ({ user, me, excluded }) => {
|
] as const)('をID指定のリスト形式で取得することができ、結果に$label', async ({ user, me, excluded }) => {
|
||||||
const parameters = { userIds: [user().id] };
|
const parameters = { userIds: [user().id] };
|
||||||
const response = await successfulApiCall({ endpoint: 'users/show', parameters, user: me?.() ?? alice });
|
const response = await successfulApiCall({ endpoint: 'users/show', parameters, user: me?.() ?? alice });
|
||||||
|
@ -729,15 +710,15 @@ describe('ユーザー', () => {
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
|
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
|
||||||
{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
|
{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
|
||||||
{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
|
{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
|
||||||
{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
|
{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
|
||||||
{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
|
{ label: '承認制ユーザーが含まれる', user: () => userLocking },
|
||||||
{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
|
{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
|
||||||
{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
|
{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
|
||||||
{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
|
{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
|
||||||
{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
|
{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
|
||||||
] as const)('を検索することができ、結果に$labelが含まれる', async ({ user, excluded }) => {
|
] as const)('を検索することができ、結果に$labelが含まれる', async ({ user, excluded }) => {
|
||||||
const parameters = { query: user().username, limit: 1 };
|
const parameters = { query: user().username, limit: 1 };
|
||||||
const response = await successfulApiCall({ endpoint: 'users/search', parameters, user: alice });
|
const response = await successfulApiCall({ endpoint: 'users/search', parameters, user: alice });
|
||||||
|
@ -751,30 +732,30 @@ describe('ユーザー', () => {
|
||||||
//#region ID指定検索(users/search-by-username-and-host)
|
//#region ID指定検索(users/search-by-username-and-host)
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '自分', parameters: { username: 'alice' }, user: (): User[] => [alice] },
|
{ label: '自分', parameters: { username: 'alice' }, user: () => [alice] },
|
||||||
{ label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: (): User[] => [alice] },
|
{ label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: () => [alice] },
|
||||||
{ label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: (): User[] => [userFollowedByAlice] },
|
{ label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: () => [userFollowedByAlice] },
|
||||||
{ label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: (): User[] => [] },
|
{ label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: () => [] },
|
||||||
{ label: 'ローカルの他人1', parameters: { username: 'bob' }, user: (): User[] => [bob] },
|
{ label: 'ローカルの他人1', parameters: { username: 'bob' }, user: () => [bob] },
|
||||||
{ label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: (): User[] => [bob] },
|
{ label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: () => [bob] },
|
||||||
{ label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: (): User[] => [bob] },
|
{ label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: () => [bob] },
|
||||||
{ label: 'ローカル', parameters: { host: null, limit: 1 }, user: (): User[] => [userFollowedByAlice] },
|
{ label: 'ローカル', parameters: { host: null, limit: 1 }, user: () => [userFollowedByAlice] },
|
||||||
{ label: 'ローカル', parameters: { host: '.', limit: 1 }, user: (): User[] => [userFollowedByAlice] },
|
{ label: 'ローカル', parameters: { host: '.', limit: 1 }, user: () => [userFollowedByAlice] },
|
||||||
])('をID&ホスト指定で検索できる($label)', async ({ parameters, user }) => {
|
])('をID&ホスト指定で検索できる($label)', async ({ parameters, user }) => {
|
||||||
const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
|
const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
|
||||||
const expected = await Promise.all(user().map(u => show(u.id, alice)));
|
const expected = await Promise.all(user().map(u => show(u.id, alice)));
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
|
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
|
||||||
{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
|
{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
|
||||||
{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
|
{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
|
||||||
{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
|
{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
|
||||||
{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
|
{ label: '承認制ユーザーが含まれる', user: () => userLocking },
|
||||||
{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
|
{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
|
||||||
{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
|
{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
|
||||||
{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
|
{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
|
||||||
{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
|
{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
|
||||||
] as const)('をID&ホスト指定で検索でき、結果に$label', async ({ user, excluded }) => {
|
] as const)('をID&ホスト指定で検索でき、結果に$label', async ({ user, excluded }) => {
|
||||||
const parameters = { username: user().username };
|
const parameters = { username: user().username };
|
||||||
const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
|
const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
|
||||||
|
@ -796,15 +777,15 @@ describe('ユーザー', () => {
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
|
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
|
||||||
{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
|
{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
|
||||||
{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
|
{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
|
||||||
{ label: 'ブロックしてきているユーザーが含まれない', user: (): User => userBlockingAlice, excluded: true },
|
{ label: 'ブロックしてきているユーザーが含まれない', user: () => userBlockingAlice, excluded: true },
|
||||||
{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
|
{ label: '承認制ユーザーが含まれる', user: () => userLocking },
|
||||||
{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
|
{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
|
||||||
//{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
|
//{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
|
||||||
{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
|
{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
|
||||||
{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
|
{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
|
||||||
] as const)('がよくリプライをするユーザーのリストを取得でき、結果に$label', async ({ user, excluded }) => {
|
] as const)('がよくリプライをするユーザーのリストを取得でき、結果に$label', async ({ user, excluded }) => {
|
||||||
const replyTo = (await successfulApiCall({ endpoint: 'users/notes', parameters: { userId: user().id }, user: undefined }))[0];
|
const replyTo = (await successfulApiCall({ endpoint: 'users/notes', parameters: { userId: user().id }, user: undefined }))[0];
|
||||||
await post(alice, { text: `@${user().username} test`, replyId: replyTo.id });
|
await post(alice, { text: `@${user().username} test`, replyId: replyTo.id });
|
||||||
|
@ -818,12 +799,12 @@ describe('ユーザー', () => {
|
||||||
//#region ハッシュタグ(hashtags/users)
|
//#region ハッシュタグ(hashtags/users)
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{ label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
|
{ label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
|
||||||
{ label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
|
{ label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
|
||||||
{ label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
|
{ label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
|
||||||
{ label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
|
{ label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
|
||||||
{ label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
|
{ label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
|
||||||
{ label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
|
{ label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
|
||||||
] as const)('をハッシュタグ指定で取得することができる($label)', async ({ sort, selector }) => {
|
] as const)('をハッシュタグ指定で取得することができる($label)', async ({ sort, selector }) => {
|
||||||
const hashtag = 'test_hashtag';
|
const hashtag = 'test_hashtag';
|
||||||
await successfulApiCall({ endpoint: 'i/update', parameters: { description: `#${hashtag}` }, user: alice });
|
await successfulApiCall({ endpoint: 'i/update', parameters: { description: `#${hashtag}` }, user: alice });
|
||||||
|
@ -837,15 +818,15 @@ describe('ユーザー', () => {
|
||||||
assert.deepStrictEqual(response, expected);
|
assert.deepStrictEqual(response, expected);
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
|
{ label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
|
||||||
{ label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
|
{ label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
|
||||||
{ label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
|
{ label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
|
||||||
{ label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
|
{ label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
|
||||||
{ label: '承認制ユーザーが含まれる', user: (): User => userLocking },
|
{ label: '承認制ユーザーが含まれる', user: () => userLocking },
|
||||||
{ label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
|
{ label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
|
||||||
{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
|
{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
|
||||||
{ label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
|
{ label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
|
||||||
{ label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
|
{ label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
|
||||||
] as const)('をハッシュタグ指定で取得することができ、結果に$label', async ({ user, excluded }) => {
|
] as const)('をハッシュタグ指定で取得することができ、結果に$label', async ({ user, excluded }) => {
|
||||||
const hashtag = `user_test${user().username}`;
|
const hashtag = `user_test${user().username}`;
|
||||||
if (user() !== userSuspended) {
|
if (user() !== userSuspended) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ describe('AnnouncementService', () => {
|
||||||
|
|
||||||
function createAnnouncement(data: Partial<MiAnnouncement & { createdAt: Date }> = {}) {
|
function createAnnouncement(data: Partial<MiAnnouncement & { createdAt: Date }> = {}) {
|
||||||
return announcementsRepository.insert({
|
return announcementsRepository.insert({
|
||||||
id: genAidx(data.createdAt ?? new Date()),
|
id: genAidx(data.createdAt?.getTime() ?? Date.now()),
|
||||||
updatedAt: null,
|
updatedAt: null,
|
||||||
title: 'Title',
|
title: 'Title',
|
||||||
text: 'Text',
|
text: 'Text',
|
||||||
|
|
|
@ -19,8 +19,8 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { TestingModule } from '@nestjs/testing';
|
import type { TestingModule } from '@nestjs/testing';
|
||||||
|
|
||||||
function mockRedis() {
|
function mockRedis() {
|
||||||
const hash = {};
|
const hash = {} as any;
|
||||||
const set = jest.fn((key, value) => {
|
const set = jest.fn((key: string, value) => {
|
||||||
const ret = hash[key];
|
const ret = hash[key];
|
||||||
hash[key] = value;
|
hash[key] = value;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -56,12 +56,13 @@ describe('FetchInstanceMetadataService', () => {
|
||||||
} else if (token === DI.redis) {
|
} else if (token === DI.redis) {
|
||||||
return mockRedis;
|
return mockRedis;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
})
|
})
|
||||||
.compile();
|
.compile();
|
||||||
|
|
||||||
app.enableShutdownHooks();
|
app.enableShutdownHooks();
|
||||||
|
|
||||||
fetchInstanceMetadataService = app.get<FetchInstanceMetadataService>(FetchInstanceMetadataService);
|
fetchInstanceMetadataService = app.get<FetchInstanceMetadataService>(FetchInstanceMetadataService) as jest.Mocked<FetchInstanceMetadataService>;
|
||||||
federatedInstanceService = app.get<FederatedInstanceService>(FederatedInstanceService) as jest.Mocked<FederatedInstanceService>;
|
federatedInstanceService = app.get<FederatedInstanceService>(FederatedInstanceService) as jest.Mocked<FederatedInstanceService>;
|
||||||
redisClient = app.get<Redis>(DI.redis) as jest.Mocked<Redis>;
|
redisClient = app.get<Redis>(DI.redis) as jest.Mocked<Redis>;
|
||||||
httpRequestService = app.get<HttpRequestService>(HttpRequestService) as jest.Mocked<HttpRequestService>;
|
httpRequestService = app.get<HttpRequestService>(HttpRequestService) as jest.Mocked<HttpRequestService>;
|
||||||
|
@ -74,11 +75,12 @@ describe('FetchInstanceMetadataService', () => {
|
||||||
test('Lock and update', async () => {
|
test('Lock and update', async () => {
|
||||||
redisClient.set = mockRedis();
|
redisClient.set = mockRedis();
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } });
|
federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } } as any);
|
||||||
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
|
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
|
||||||
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
|
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
|
||||||
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
|
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
|
||||||
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
|
|
||||||
|
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
|
||||||
expect(tryLockSpy).toHaveBeenCalledTimes(1);
|
expect(tryLockSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(unlockSpy).toHaveBeenCalledTimes(1);
|
expect(unlockSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
|
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
|
||||||
|
@ -88,11 +90,12 @@ describe('FetchInstanceMetadataService', () => {
|
||||||
test('Lock and don\'t update', async () => {
|
test('Lock and don\'t update', async () => {
|
||||||
redisClient.set = mockRedis();
|
redisClient.set = mockRedis();
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now } });
|
federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now } } as any);
|
||||||
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
|
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
|
||||||
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
|
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
|
||||||
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
|
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
|
||||||
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
|
|
||||||
|
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
|
||||||
expect(tryLockSpy).toHaveBeenCalledTimes(1);
|
expect(tryLockSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(unlockSpy).toHaveBeenCalledTimes(1);
|
expect(unlockSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
|
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
|
||||||
|
@ -101,15 +104,33 @@ describe('FetchInstanceMetadataService', () => {
|
||||||
|
|
||||||
test('Do nothing when lock not acquired', async () => {
|
test('Do nothing when lock not acquired', async () => {
|
||||||
redisClient.set = mockRedis();
|
redisClient.set = mockRedis();
|
||||||
federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } });
|
const now = Date.now();
|
||||||
|
federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
|
||||||
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
|
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
|
||||||
|
await fetchInstanceMetadataService.tryLock('example.com');
|
||||||
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
|
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
|
||||||
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
|
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
|
||||||
await fetchInstanceMetadataService.tryLock('example.com');
|
|
||||||
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
|
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
|
||||||
expect(tryLockSpy).toHaveBeenCalledTimes(2);
|
expect(tryLockSpy).toHaveBeenCalledTimes(1);
|
||||||
expect(unlockSpy).toHaveBeenCalledTimes(0);
|
expect(unlockSpy).toHaveBeenCalledTimes(0);
|
||||||
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
|
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
|
||||||
expect(httpRequestService.getJson).toHaveBeenCalledTimes(0);
|
expect(httpRequestService.getJson).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Do when lock not acquired but forced', async () => {
|
||||||
|
redisClient.set = mockRedis();
|
||||||
|
const now = Date.now();
|
||||||
|
federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
|
||||||
|
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
|
||||||
|
await fetchInstanceMetadataService.tryLock('example.com');
|
||||||
|
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
|
||||||
|
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
|
||||||
|
|
||||||
|
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any, true);
|
||||||
|
expect(tryLockSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(unlockSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
|
||||||
|
expect(httpRequestService.getJson).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -228,11 +228,14 @@ describe('RoleService', () => {
|
||||||
},
|
},
|
||||||
target: 'conditional',
|
target: 'conditional',
|
||||||
condFormula: {
|
condFormula: {
|
||||||
|
id: '232a4221-9816-49a6-a967-ae0fac52ec5e',
|
||||||
type: 'and',
|
type: 'and',
|
||||||
values: [{
|
values: [{
|
||||||
|
id: '2a37ef43-2d93-4c4d-87f6-f2fdb7d9b530',
|
||||||
type: 'followersMoreThanOrEq',
|
type: 'followersMoreThanOrEq',
|
||||||
value: 10,
|
value: 10,
|
||||||
}, {
|
}, {
|
||||||
|
id: '1bd67839-b126-4f92-bad0-4e285dab453b',
|
||||||
type: 'createdMoreThan',
|
type: 'createdMoreThan',
|
||||||
sec: 60 * 60 * 24 * 7,
|
sec: 60 * 60 * 24 * 7,
|
||||||
}],
|
}],
|
||||||
|
|
|
@ -9,11 +9,10 @@ import { basename, isAbsolute } from 'node:path';
|
||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
import { inspect } from 'node:util';
|
import { inspect } from 'node:util';
|
||||||
import WebSocket, { ClientOptions } from 'ws';
|
import WebSocket, { ClientOptions } from 'ws';
|
||||||
import fetch, { File, RequestInit } from 'node-fetch';
|
import fetch, { File, RequestInit, type Headers } from 'node-fetch';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
|
||||||
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
||||||
import { entities } from '../src/postgres.js';
|
import { entities } from '../src/postgres.js';
|
||||||
import { loadConfig } from '../src/config.js';
|
import { loadConfig } from '../src/config.js';
|
||||||
|
@ -21,7 +20,7 @@ import type * as misskey from 'misskey-js';
|
||||||
|
|
||||||
export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js';
|
export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js';
|
||||||
|
|
||||||
interface UserToken {
|
export interface UserToken {
|
||||||
token: string;
|
token: string;
|
||||||
bearer?: boolean;
|
bearer?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -35,20 +34,15 @@ export const cookie = (me: UserToken): string => {
|
||||||
return `token=${me.token};`;
|
return `token=${me.token};`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const api = async (endpoint: string, params: any, me?: UserToken) => {
|
export type ApiRequest<E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req'] = misskey.Endpoints[E]['req']> = {
|
||||||
const normalized = endpoint.replace(/^\//, '');
|
endpoint: E,
|
||||||
return await request(`api/${normalized}`, params, me);
|
parameters: P,
|
||||||
};
|
|
||||||
|
|
||||||
export type ApiRequest = {
|
|
||||||
endpoint: string,
|
|
||||||
parameters: object,
|
|
||||||
user: UserToken | undefined,
|
user: UserToken | undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const successfulApiCall = async <T, >(request: ApiRequest, assertion: {
|
export const successfulApiCall = async <E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req']>(request: ApiRequest<E, P>, assertion: {
|
||||||
status?: number,
|
status?: number,
|
||||||
} = {}): Promise<T> => {
|
} = {}): Promise<misskey.api.SwitchCaseResponseType<E, P>> => {
|
||||||
const { endpoint, parameters, user } = request;
|
const { endpoint, parameters, user } = request;
|
||||||
const res = await api(endpoint, parameters, user);
|
const res = await api(endpoint, parameters, user);
|
||||||
const status = assertion.status ?? (res.body == null ? 204 : 200);
|
const status = assertion.status ?? (res.body == null ? 204 : 200);
|
||||||
|
@ -56,7 +50,7 @@ export const successfulApiCall = async <T, >(request: ApiRequest, assertion: {
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const failedApiCall = async <T, >(request: ApiRequest, assertion: {
|
export const failedApiCall = async <T, E extends keyof misskey.Endpoints, P extends misskey.Endpoints[E]['req']>(request: ApiRequest<E, P>, assertion: {
|
||||||
status: number,
|
status: number,
|
||||||
code: string,
|
code: string,
|
||||||
id: string
|
id: string
|
||||||
|
@ -70,7 +64,7 @@ export const failedApiCall = async <T, >(request: ApiRequest, assertion: {
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
const request = async (path: string, params: any, me?: UserToken): Promise<{
|
export const api = async <E extends keyof misskey.Endpoints>(path: E, params: misskey.Endpoints[E]['req'], me?: UserToken): Promise<{
|
||||||
status: number,
|
status: number,
|
||||||
headers: Headers,
|
headers: Headers,
|
||||||
body: any
|
body: any
|
||||||
|
@ -86,7 +80,7 @@ const request = async (path: string, params: any, me?: UserToken): Promise<{
|
||||||
bodyAuth.i = me.token;
|
bodyAuth.i = me.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await relativeFetch(path, {
|
const res = await relativeFetch(`api/${path}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers,
|
headers,
|
||||||
body: JSON.stringify(Object.assign(bodyAuth, params)),
|
body: JSON.stringify(Object.assign(bodyAuth, params)),
|
||||||
|
@ -141,7 +135,7 @@ export const signup = async (params?: Partial<misskey.Endpoints['signup']['req']
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const post = async (user: UserToken, params?: misskey.Endpoints['notes/create']['req']): Promise<misskey.entities.Note> => {
|
export const post = async (user: UserToken, params: misskey.Endpoints['notes/create']['req']): Promise<misskey.entities.Note> => {
|
||||||
const q = params;
|
const q = params;
|
||||||
|
|
||||||
const res = await api('notes/create', q, user);
|
const res = await api('notes/create', q, user);
|
||||||
|
@ -159,8 +153,8 @@ export const createAppToken = async (user: UserToken, permissions: (typeof missk
|
||||||
};
|
};
|
||||||
|
|
||||||
// 非公開ノートをAPI越しに見たときのノート NoteEntityService.ts
|
// 非公開ノートをAPI越しに見たときのノート NoteEntityService.ts
|
||||||
export const hiddenNote = (note: any): any => {
|
export const hiddenNote = (note: misskey.entities.Note): misskey.entities.Note => {
|
||||||
const temp = {
|
const temp: misskey.entities.Note = {
|
||||||
...note,
|
...note,
|
||||||
fileIds: [],
|
fileIds: [],
|
||||||
files: [],
|
files: [],
|
||||||
|
@ -173,21 +167,22 @@ export const hiddenNote = (note: any): any => {
|
||||||
return temp;
|
return temp;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const react = async (user: UserToken, note: any, reaction: string): Promise<any> => {
|
export const react = async (user: UserToken, note: misskey.entities.Note, reaction: string): Promise<void> => {
|
||||||
await api('notes/reactions/create', {
|
await api('notes/reactions/create', {
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
reaction: reaction,
|
reaction: reaction,
|
||||||
}, user);
|
}, user);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userList = async (user: UserToken, userList: any = {}): Promise<any> => {
|
export const userList = async (user: UserToken, userList: Partial<misskey.entities.UserList> = {}): Promise<misskey.entities.UserList> => {
|
||||||
const res = await api('users/lists/create', {
|
const res = await api('users/lists/create', {
|
||||||
name: 'test',
|
name: 'test',
|
||||||
|
...userList,
|
||||||
}, user);
|
}, user);
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const page = async (user: UserToken, page: any = {}): Promise<any> => {
|
export const page = async (user: UserToken, page: Partial<misskey.entities.Page> = {}): Promise<misskey.entities.Page> => {
|
||||||
const res = await api('pages/create', {
|
const res = await api('pages/create', {
|
||||||
alignCenter: false,
|
alignCenter: false,
|
||||||
content: [
|
content: [
|
||||||
|
@ -198,7 +193,7 @@ export const page = async (user: UserToken, page: any = {}): Promise<any> => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
eyeCatchingImageId: null,
|
eyeCatchingImageId: null,
|
||||||
font: 'sans-serif',
|
font: 'sans-serif' as any,
|
||||||
hideTitleWhenPinned: false,
|
hideTitleWhenPinned: false,
|
||||||
name: '1678594845072',
|
name: '1678594845072',
|
||||||
script: '',
|
script: '',
|
||||||
|
@ -210,7 +205,7 @@ export const page = async (user: UserToken, page: any = {}): Promise<any> => {
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const play = async (user: UserToken, play: any = {}): Promise<any> => {
|
export const play = async (user: UserToken, play: Partial<misskey.entities.Flash> = {}): Promise<misskey.entities.Flash> => {
|
||||||
const res = await api('flash/create', {
|
const res = await api('flash/create', {
|
||||||
permissions: [],
|
permissions: [],
|
||||||
script: 'test',
|
script: 'test',
|
||||||
|
@ -221,7 +216,7 @@ export const play = async (user: UserToken, play: any = {}): Promise<any> => {
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clip = async (user: UserToken, clip: any = {}): Promise<any> => {
|
export const clip = async (user: UserToken, clip: Partial<misskey.entities.Clip> = {}): Promise<misskey.entities.Clip> => {
|
||||||
const res = await api('clips/create', {
|
const res = await api('clips/create', {
|
||||||
description: null,
|
description: null,
|
||||||
isPublic: true,
|
isPublic: true,
|
||||||
|
@ -231,18 +226,18 @@ export const clip = async (user: UserToken, clip: any = {}): Promise<any> => {
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const galleryPost = async (user: UserToken, channel: any = {}): Promise<any> => {
|
export const galleryPost = async (user: UserToken, galleryPost: Partial<misskey.entities.GalleryPost> = {}): Promise<misskey.entities.GalleryPost> => {
|
||||||
const res = await api('gallery/posts/create', {
|
const res = await api('gallery/posts/create', {
|
||||||
description: null,
|
description: null,
|
||||||
fileIds: [],
|
fileIds: [],
|
||||||
isSensitive: false,
|
isSensitive: false,
|
||||||
title: 'test',
|
title: 'test',
|
||||||
...channel,
|
...galleryPost,
|
||||||
}, user);
|
}, user);
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const channel = async (user: UserToken, channel: any = {}): Promise<any> => {
|
export const channel = async (user: UserToken, channel: Partial<misskey.entities.Channel> = {}): Promise<misskey.entities.Channel> => {
|
||||||
const res = await api('channels/create', {
|
const res = await api('channels/create', {
|
||||||
bannerId: null,
|
bannerId: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
@ -252,7 +247,7 @@ export const channel = async (user: UserToken, channel: any = {}): Promise<any>
|
||||||
return res.body;
|
return res.body;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const role = async (user: UserToken, role: any = {}, policies: any = {}): Promise<any> => {
|
export const role = async (user: UserToken, role: Partial<misskey.entities.Role> = {}, policies: any = {}): Promise<misskey.entities.Role> => {
|
||||||
const res = await api('admin/roles/create', {
|
const res = await api('admin/roles/create', {
|
||||||
asBadge: false,
|
asBadge: false,
|
||||||
canEditMembersByModerator: false,
|
canEditMembersByModerator: false,
|
||||||
|
@ -260,7 +255,7 @@ export const role = async (user: UserToken, role: any = {}, policies: any = {}):
|
||||||
condFormula: {
|
condFormula: {
|
||||||
id: 'ebef1684-672d-49b6-ad82-1b3ec3784f85',
|
id: 'ebef1684-672d-49b6-ad82-1b3ec3784f85',
|
||||||
type: 'isRemote',
|
type: 'isRemote',
|
||||||
},
|
} as any,
|
||||||
description: '',
|
description: '',
|
||||||
displayOrder: 0,
|
displayOrder: 0,
|
||||||
iconUrl: null,
|
iconUrl: null,
|
||||||
|
@ -298,7 +293,7 @@ interface UploadOptions {
|
||||||
export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{
|
export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{
|
||||||
status: number,
|
status: number,
|
||||||
headers: Headers,
|
headers: Headers,
|
||||||
body: misskey.Endpoints['drive/files/create']['res'] | null
|
body: misskey.entities.DriveFile | null
|
||||||
}> => {
|
}> => {
|
||||||
const absPath = path == null
|
const absPath = path == null
|
||||||
? new URL('resources/Lenna.jpg', import.meta.url)
|
? new URL('resources/Lenna.jpg', import.meta.url)
|
||||||
|
@ -335,14 +330,14 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const uploadUrl = async (user: UserToken, url: string): Promise<Packed<'DriveFile'>> => {
|
export const uploadUrl = async (user: UserToken, url: string): Promise<misskey.entities.DriveFile> => {
|
||||||
const marker = Math.random().toString();
|
const marker = Math.random().toString();
|
||||||
|
|
||||||
const catcher = makeStreamCatcher(
|
const catcher = makeStreamCatcher(
|
||||||
user,
|
user,
|
||||||
'main',
|
'main',
|
||||||
(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
|
(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
|
||||||
(msg) => msg.body.file as Packed<'DriveFile'>,
|
(msg) => msg.body.file,
|
||||||
60 * 1000,
|
60 * 1000,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</ol>
|
</ol>
|
||||||
<ol v-else-if="emojis.length > 0" ref="suggests" :class="$style.list">
|
<ol v-else-if="emojis.length > 0" ref="suggests" :class="$style.list">
|
||||||
<li v-for="emoji in emojis" :key="emoji.emoji" :class="$style.item" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown">
|
<li v-for="emoji in emojis" :key="emoji.emoji" :class="$style.item" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown">
|
||||||
<MkCustomEmoji v-if="'isCustomEmoji' in emoji && emoji.isCustomEmoji" :name="emoji.emoji" :class="$style.emoji"/>
|
<MkCustomEmoji v-if="'isCustomEmoji' in emoji && emoji.isCustomEmoji" :name="emoji.emoji" :class="$style.emoji" :fallbackToImage="true"/>
|
||||||
<MkEmoji v-else :emoji="emoji.emoji" :class="$style.emoji"/>
|
<MkEmoji v-else :emoji="emoji.emoji" :class="$style.emoji"/>
|
||||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<span v-if="q" :class="$style.emojiName" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span>
|
<span v-if="q" :class="$style.emojiName" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span>
|
||||||
|
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
@pointerenter="computeButtonTitle"
|
@pointerenter="computeButtonTitle"
|
||||||
@click="emit('chosen', emoji, $event)"
|
@click="emit('chosen', emoji, $event)"
|
||||||
>
|
>
|
||||||
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/>
|
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true" :fallbackToImage="true"/>
|
||||||
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/>
|
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click="chosen(emoji, $event)"
|
@click="chosen(emoji, $event)"
|
||||||
>
|
>
|
||||||
<MkCustomEmoji class="emoji" :name="emoji.name"/>
|
<MkCustomEmoji class="emoji" :name="emoji.name" :fallbackToImage="true"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="searchResultUnicode.length > 0" class="body">
|
<div v-if="searchResultUnicode.length > 0" class="body">
|
||||||
|
|
|
@ -66,7 +66,7 @@ import * as os from '@/os.js';
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
import { hms } from '@/filters/hms.js';
|
import { hms } from '@/filters/hms.js';
|
||||||
import MkMediaRange from '@/components/MkMediaRange.vue';
|
import MkMediaRange from '@/components/MkMediaRange.vue';
|
||||||
import { iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
audio: Misskey.entities.DriveFile;
|
audio: Misskey.entities.DriveFile;
|
||||||
|
@ -96,8 +96,6 @@ function showMenu(ev: MouseEvent) {
|
||||||
|
|
||||||
if (iAmModerator) {
|
if (iAmModerator) {
|
||||||
menu.push({
|
menu.push({
|
||||||
type: 'divider',
|
|
||||||
}, {
|
|
||||||
text: props.audio.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
|
text: props.audio.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
|
||||||
icon: props.audio.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
|
icon: props.audio.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
|
||||||
danger: true,
|
danger: true,
|
||||||
|
@ -105,6 +103,17 @@ function showMenu(ev: MouseEvent) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($i?.id === props.audio.userId) {
|
||||||
|
menu.push({
|
||||||
|
type: 'divider',
|
||||||
|
}, {
|
||||||
|
type: 'link' as const,
|
||||||
|
text: i18n.ts._fileViewer.title,
|
||||||
|
icon: 'ti ti-info-circle',
|
||||||
|
to: `/my/drive/file/${props.audio.id}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
menuShowing.value = true;
|
menuShowing.value = true;
|
||||||
os.popupMenu(menu, ev.currentTarget ?? ev.target, {
|
os.popupMenu(menu, ev.currentTarget ?? ev.target, {
|
||||||
align: 'right',
|
align: 'right',
|
||||||
|
|
|
@ -59,7 +59,7 @@ import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
image: Misskey.entities.DriveFile;
|
image: Misskey.entities.DriveFile;
|
||||||
|
@ -114,6 +114,13 @@ function showMenu(ev: MouseEvent) {
|
||||||
action: () => {
|
action: () => {
|
||||||
os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true });
|
os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true });
|
||||||
},
|
},
|
||||||
|
}] : []), ...($i?.id === props.image.userId ? [{
|
||||||
|
type: 'divider' as const,
|
||||||
|
}, {
|
||||||
|
type: 'link' as const,
|
||||||
|
text: i18n.ts._fileViewer.title,
|
||||||
|
icon: 'ti ti-info-circle',
|
||||||
|
to: `/my/drive/file/${props.image.id}`,
|
||||||
}] : [])], ev.currentTarget ?? ev.target);
|
}] : [])], ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ import * as os from '@/os.js';
|
||||||
import { isFullscreenNotSupported } from '@/scripts/device-kind.js';
|
import { isFullscreenNotSupported } from '@/scripts/device-kind.js';
|
||||||
import hasAudio from '@/scripts/media-has-audio.js';
|
import hasAudio from '@/scripts/media-has-audio.js';
|
||||||
import MkMediaRange from '@/components/MkMediaRange.vue';
|
import MkMediaRange from '@/components/MkMediaRange.vue';
|
||||||
import { iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
video: Misskey.entities.DriveFile;
|
video: Misskey.entities.DriveFile;
|
||||||
|
@ -122,8 +122,6 @@ function showMenu(ev: MouseEvent) {
|
||||||
|
|
||||||
if (iAmModerator) {
|
if (iAmModerator) {
|
||||||
menu.push({
|
menu.push({
|
||||||
type: 'divider',
|
|
||||||
}, {
|
|
||||||
text: props.video.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
|
text: props.video.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
|
||||||
icon: props.video.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
|
icon: props.video.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
|
||||||
danger: true,
|
danger: true,
|
||||||
|
@ -131,6 +129,17 @@ function showMenu(ev: MouseEvent) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($i?.id === props.video.userId) {
|
||||||
|
menu.push({
|
||||||
|
type: 'divider',
|
||||||
|
}, {
|
||||||
|
type: 'link' as const,
|
||||||
|
text: i18n.ts._fileViewer.title,
|
||||||
|
icon: 'ti ti-info-circle',
|
||||||
|
to: `/my/drive/file/${props.video.id}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
menuShowing.value = true;
|
menuShowing.value = true;
|
||||||
os.popupMenu(menu, ev.currentTarget ?? ev.target, {
|
os.popupMenu(menu, ev.currentTarget ?? ev.target, {
|
||||||
align: 'right',
|
align: 'right',
|
||||||
|
|
|
@ -93,7 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
|
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
|
||||||
</div>
|
</div>
|
||||||
<MkReactionsViewer :note="appearNote" :maxNumber="16" @mockUpdateMyReaction="emitUpdReaction">
|
<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @mockUpdateMyReaction="emitUpdReaction">
|
||||||
<template #more>
|
<template #more>
|
||||||
<div :class="$style.reactionOmitted">{{ i18n.ts.more }}</div>
|
<div :class="$style.reactionOmitted">{{ i18n.ts.more }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -101,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<footer :class="$style.footer">
|
<footer :class="$style.footer">
|
||||||
<button :class="$style.footerButton" class="_button" @click="reply()">
|
<button :class="$style.footerButton" class="_button" @click="reply()">
|
||||||
<i class="ti ti-arrow-back-up"></i>
|
<i class="ti ti-arrow-back-up"></i>
|
||||||
<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
|
<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.repliesCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canRenote"
|
v-if="canRenote"
|
||||||
|
@ -111,17 +111,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
@mousedown="renote()"
|
@mousedown="renote()"
|
||||||
>
|
>
|
||||||
<i class="ti ti-repeat"></i>
|
<i class="ti ti-repeat"></i>
|
||||||
<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p>
|
<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.renoteCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button v-else :class="$style.footerButton" class="_button" disabled>
|
<button v-else :class="$style.footerButton" class="_button" disabled>
|
||||||
<i class="ti ti-ban"></i>
|
<i class="ti ti-ban"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()">
|
<button ref="reactButton" :class="$style.footerButton" class="_button" @click="toggleReact()">
|
||||||
<i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
<i v-if="appearNote.reactionAcceptance === 'likeOnly' && appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
|
||||||
|
<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i>
|
||||||
|
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||||
<i v-else class="ti ti-plus"></i>
|
<i v-else class="ti ti-plus"></i>
|
||||||
</button>
|
<p v-if="appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
||||||
<button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
|
|
||||||
<i class="ti ti-minus"></i>
|
|
||||||
</button>
|
</button>
|
||||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown="clip()">
|
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown="clip()">
|
||||||
<i class="ti ti-paperclip"></i>
|
<i class="ti ti-paperclip"></i>
|
||||||
|
@ -175,6 +175,7 @@ import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
||||||
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
|
import number from '@/filters/number.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
@ -420,6 +421,14 @@ function undoReact(targetNote: Misskey.entities.Note): void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleReact() {
|
||||||
|
if (appearNote.value.myReaction == null) {
|
||||||
|
react();
|
||||||
|
} else {
|
||||||
|
undoReact(appearNote.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onContextmenu(ev: MouseEvent): void {
|
function onContextmenu(ev: MouseEvent): void {
|
||||||
if (props.mock) {
|
if (props.mock) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -106,10 +106,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
||||||
</MkA>
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
|
<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" :note="appearNote"/>
|
||||||
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
||||||
<i class="ti ti-arrow-back-up"></i>
|
<i class="ti ti-arrow-back-up"></i>
|
||||||
<p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.repliesCount }}</p>
|
<p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.repliesCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canRenote"
|
v-if="canRenote"
|
||||||
|
@ -119,17 +119,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
@mousedown="renote()"
|
@mousedown="renote()"
|
||||||
>
|
>
|
||||||
<i class="ti ti-repeat"></i>
|
<i class="ti ti-repeat"></i>
|
||||||
<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.renoteCount }}</p>
|
<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button v-else class="_button" :class="$style.noteFooterButton" disabled>
|
<button v-else class="_button" :class="$style.noteFooterButton" disabled>
|
||||||
<i class="ti ti-ban"></i>
|
<i class="ti ti-ban"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.noteFooterButton" class="_button" @mousedown="react()">
|
<button ref="reactButton" :class="$style.noteFooterButton" class="_button" @click="toggleReact()">
|
||||||
<i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
<i v-if="appearNote.reactionAcceptance === 'likeOnly' && appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--eventReactionHeart);"></i>
|
||||||
|
<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--accent);"></i>
|
||||||
|
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||||
<i v-else class="ti ti-plus"></i>
|
<i v-else class="ti ti-plus"></i>
|
||||||
</button>
|
<p v-if="appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
||||||
<button v-if="appearNote.myReaction != null" ref="reactButton" class="_button" :class="[$style.noteFooterButton, $style.reacted]" @click="undoReact(appearNote)">
|
|
||||||
<i class="ti ti-minus"></i>
|
|
||||||
</button>
|
</button>
|
||||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()">
|
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()">
|
||||||
<i class="ti ti-paperclip"></i>
|
<i class="ti ti-paperclip"></i>
|
||||||
|
@ -209,6 +209,7 @@ import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
|
import number from '@/filters/number.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
@ -401,14 +402,22 @@ function react(viaKeyboard = false): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function undoReact(note): void {
|
function undoReact(targetNote: Misskey.entities.Note): void {
|
||||||
const oldReaction = note.myReaction;
|
const oldReaction = targetNote.myReaction;
|
||||||
if (!oldReaction) return;
|
if (!oldReaction) return;
|
||||||
misskeyApi('notes/reactions/delete', {
|
misskeyApi('notes/reactions/delete', {
|
||||||
noteId: note.id,
|
noteId: targetNote.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleReact() {
|
||||||
|
if (appearNote.value.myReaction == null) {
|
||||||
|
react();
|
||||||
|
} else {
|
||||||
|
undoReact(appearNote.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onContextmenu(ev: MouseEvent): void {
|
function onContextmenu(ev: MouseEvent): void {
|
||||||
const isLink = (el: HTMLElement): boolean => {
|
const isLink = (el: HTMLElement): boolean => {
|
||||||
if (el.tagName === 'A') return true;
|
if (el.tagName === 'A') return true;
|
||||||
|
|
|
@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.head">
|
<div :class="$style.head">
|
||||||
<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
|
<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
|
||||||
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
||||||
|
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
||||||
<img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/>
|
<img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/>
|
||||||
|
@ -57,6 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
|
<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
|
||||||
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
|
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
|
||||||
<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
||||||
|
<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: notification.reactions.length }) }}</span>
|
||||||
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
|
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
|
||||||
<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
|
<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
|
||||||
<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
|
<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
|
||||||
|
@ -201,6 +203,7 @@ const rejectFollowRequest = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon_reactionGroup,
|
.icon_reactionGroup,
|
||||||
|
.icon_reactionGroupHeart,
|
||||||
.icon_renoteGroup {
|
.icon_renoteGroup {
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -213,11 +216,15 @@ const rejectFollowRequest = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon_reactionGroup {
|
.icon_reactionGroup {
|
||||||
background: #e99a0b;
|
background: var(--eventReaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_reactionGroupHeart {
|
||||||
|
background: var(--eventReactionHeart);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon_renoteGroup {
|
.icon_renoteGroup {
|
||||||
background: #36d298;
|
background: var(--eventRenote);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon_app {
|
.icon_app {
|
||||||
|
@ -246,49 +253,49 @@ const rejectFollowRequest = () => {
|
||||||
|
|
||||||
.t_follow, .t_followRequestAccepted, .t_receiveFollowRequest {
|
.t_follow, .t_followRequestAccepted, .t_receiveFollowRequest {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #36aed2;
|
background: var(--eventFollow);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_renote {
|
.t_renote {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #36d298;
|
background: var(--eventRenote);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_quote {
|
.t_quote {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #36d298;
|
background: var(--eventRenote);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_reply {
|
.t_reply {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #007aff;
|
background: var(--eventReply);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_mention {
|
.t_mention {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #88a6b7;
|
background: var(--eventOther);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_pollEnded {
|
.t_pollEnded {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #88a6b7;
|
background: var(--eventOther);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_achievementEarned {
|
.t_achievementEarned {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #cb9a11;
|
background: var(--eventAchievement);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_roleAssigned {
|
.t_roleAssigned {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #88a6b7;
|
background: var(--eventOther);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkCustomEmoji v-if="reaction[0] === ':'" ref="elRef" :name="reaction" :normal="true" :noStyle="noStyle" :url="emojiUrl"/>
|
<MkCustomEmoji v-if="reaction[0] === ':'" ref="elRef" :name="reaction" :normal="true" :noStyle="noStyle" :url="emojiUrl" :fallbackToImage="true"/>
|
||||||
<MkEmoji v-else ref="elRef" :emoji="reaction" :normal="true" :noStyle="noStyle"/>
|
<MkEmoji v-else ref="elRef" :emoji="reaction" :normal="true" :noStyle="noStyle"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ const exampleNote = reactive<Misskey.entities.Note>({
|
||||||
reactionAcceptance: null,
|
reactionAcceptance: null,
|
||||||
renoteCount: 0,
|
renoteCount: 0,
|
||||||
repliesCount: 1,
|
repliesCount: 1,
|
||||||
|
reactionCount: 0,
|
||||||
reactions: {},
|
reactions: {},
|
||||||
reactionEmojis: {},
|
reactionEmojis: {},
|
||||||
fileIds: [],
|
fileIds: [],
|
||||||
|
|
|
@ -68,6 +68,7 @@ const exampleCWNote = reactive<Misskey.entities.Note>({
|
||||||
reactionAcceptance: null,
|
reactionAcceptance: null,
|
||||||
renoteCount: 0,
|
renoteCount: 0,
|
||||||
repliesCount: 1,
|
repliesCount: 1,
|
||||||
|
reactionCount: 0,
|
||||||
reactions: {},
|
reactions: {},
|
||||||
reactionEmojis: {},
|
reactionEmojis: {},
|
||||||
fileIds: [],
|
fileIds: [],
|
||||||
|
|
|
@ -58,6 +58,7 @@ const exampleNote = reactive<Misskey.entities.Note>({
|
||||||
reactionAcceptance: null,
|
reactionAcceptance: null,
|
||||||
renoteCount: 0,
|
renoteCount: 0,
|
||||||
repliesCount: 1,
|
repliesCount: 1,
|
||||||
|
reactionCount: 0,
|
||||||
reactions: {},
|
reactions: {},
|
||||||
reactionEmojis: {},
|
reactionEmojis: {},
|
||||||
fileIds: ['0000000002'],
|
fileIds: ['0000000002'],
|
||||||
|
|
|
@ -48,10 +48,18 @@ export const Missing = {
|
||||||
name: Default.args.name,
|
name: Default.args.name,
|
||||||
},
|
},
|
||||||
} satisfies StoryObj<typeof MkCustomEmoji>;
|
} satisfies StoryObj<typeof MkCustomEmoji>;
|
||||||
export const Error = {
|
export const ErrorToText = {
|
||||||
...Default,
|
...Default,
|
||||||
args: {
|
args: {
|
||||||
url: 'https://example.com/404',
|
url: 'https://example.com/404',
|
||||||
name: Default.args.name,
|
name: Default.args.name,
|
||||||
},
|
},
|
||||||
} satisfies StoryObj<typeof MkCustomEmoji>;
|
} satisfies StoryObj<typeof MkCustomEmoji>;
|
||||||
|
export const ErrorToImage = {
|
||||||
|
...Default,
|
||||||
|
args: {
|
||||||
|
url: 'https://example.com/404',
|
||||||
|
name: Default.args.name,
|
||||||
|
fallbackToImage: true,
|
||||||
|
},
|
||||||
|
} satisfies StoryObj<typeof MkCustomEmoji>;
|
||||||
|
|
|
@ -5,11 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<img
|
<img
|
||||||
v-if="errored"
|
v-if="errored && fallbackToImage"
|
||||||
:class="[$style.root, { [$style.normal]: normal, [$style.noStyle]: noStyle }]"
|
:class="[$style.root, { [$style.normal]: normal, [$style.noStyle]: noStyle }]"
|
||||||
src="/client-assets/dummy.png"
|
src="/client-assets/dummy.png"
|
||||||
:title="alt"
|
:title="alt"
|
||||||
/>
|
/>
|
||||||
|
<span v-else-if="errored">:{{ customEmojiName }}:</span>
|
||||||
<img
|
<img
|
||||||
v-else
|
v-else
|
||||||
:class="[$style.root, { [$style.normal]: normal, [$style.noStyle]: noStyle }]"
|
:class="[$style.root, { [$style.normal]: normal, [$style.noStyle]: noStyle }]"
|
||||||
|
@ -44,6 +45,7 @@ const props = defineProps<{
|
||||||
useOriginalSize?: boolean;
|
useOriginalSize?: boolean;
|
||||||
menu?: boolean;
|
menu?: boolean;
|
||||||
menuReaction?: boolean;
|
menuReaction?: boolean;
|
||||||
|
fallbackToImage?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const react = inject<((name: string) => void) | null>('react', null);
|
const react = inject<((name: string) => void) | null>('react', null);
|
||||||
|
|
|
@ -407,6 +407,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
|
||||||
useOriginalSize: scale >= 2.5,
|
useOriginalSize: scale >= 2.5,
|
||||||
menu: props.enableEmojiMenu,
|
menu: props.enableEmojiMenu,
|
||||||
menuReaction: props.enableEmojiMenuReaction,
|
menuReaction: props.enableEmojiMenuReaction,
|
||||||
|
fallbackToImage: false,
|
||||||
})];
|
})];
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
|
|
@ -373,7 +373,7 @@ export class Router extends EventEmitter<RouterEvent> implements IRouter {
|
||||||
this.currentRoute.value = res.route;
|
this.currentRoute.value = res.route;
|
||||||
this.currentKey = res.route.globalCacheKey ?? key ?? path;
|
this.currentKey = res.route.globalCacheKey ?? key ?? path;
|
||||||
|
|
||||||
if (emitChange) {
|
if (emitChange && res.route.path !== '/:(*)') {
|
||||||
this.emit('change', {
|
this.emit('change', {
|
||||||
beforePath,
|
beforePath,
|
||||||
path,
|
path,
|
||||||
|
@ -408,6 +408,9 @@ export class Router extends EventEmitter<RouterEvent> implements IRouter {
|
||||||
if (cancel) return;
|
if (cancel) return;
|
||||||
}
|
}
|
||||||
const res = this.navigate(path, null);
|
const res = this.navigate(path, null);
|
||||||
|
if (res.route.path === '/:(*)') {
|
||||||
|
location.href = path;
|
||||||
|
} else {
|
||||||
this.emit('push', {
|
this.emit('push', {
|
||||||
beforePath,
|
beforePath,
|
||||||
path: res._parsedRoute.fullPath,
|
path: res._parsedRoute.fullPath,
|
||||||
|
@ -416,6 +419,7 @@ export class Router extends EventEmitter<RouterEvent> implements IRouter {
|
||||||
key: this.currentKey,
|
key: this.currentKey,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public replace(path: string, key?: string | null) {
|
public replace(path: string, key?: string | null) {
|
||||||
const res = this.navigate(path, key);
|
const res = this.navigate(path, key);
|
||||||
|
|
|
@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="misskey">Misskey</div>
|
<div class="misskey">Misskey</div>
|
||||||
<div class="version">v{{ version }}</div>
|
<div class="version">v{{ version }}</div>
|
||||||
<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }">
|
<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }">
|
||||||
<MkCustomEmoji v-if="emoji.emoji[0] === ':'" class="emoji" :name="emoji.emoji" :normal="true" :noStyle="true"/>
|
<MkCustomEmoji v-if="emoji.emoji[0] === ':'" class="emoji" :name="emoji.emoji" :normal="true" :noStyle="true" :fallbackToImage="true"/>
|
||||||
<MkEmoji v-else class="emoji" :emoji="emoji.emoji" :normal="true" :noStyle="true"/>
|
<MkEmoji v-else class="emoji" :emoji="emoji.emoji" :normal="true" :noStyle="true"/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
>
|
>
|
||||||
<template #item="{element}">
|
<template #item="{element}">
|
||||||
<button class="_button" :class="$style.emojisItem" @click="removeReaction(element, $event)">
|
<button class="_button" :class="$style.emojisItem" @click="removeReaction(element, $event)">
|
||||||
<MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true"/>
|
<MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true" :fallbackToImage="true"/>
|
||||||
<MkEmoji v-else :emoji="element" :normal="true"/>
|
<MkEmoji v-else :emoji="element" :normal="true"/>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -63,7 +63,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
>
|
>
|
||||||
<template #item="{element}">
|
<template #item="{element}">
|
||||||
<button class="_button" :class="$style.emojisItem" @click="removeEmoji(element, $event)">
|
<button class="_button" :class="$style.emojisItem" @click="removeEmoji(element, $event)">
|
||||||
<MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true"/>
|
<MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true" :fallbackToImage="true"/>
|
||||||
<MkEmoji v-else :emoji="element" :normal="true"/>
|
<MkEmoji v-else :emoji="element" :normal="true"/>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -35,6 +35,7 @@ export function useNoteCapture(props: {
|
||||||
const currentCount = (note.value.reactions || {})[reaction] || 0;
|
const currentCount = (note.value.reactions || {})[reaction] || 0;
|
||||||
|
|
||||||
note.value.reactions[reaction] = currentCount + 1;
|
note.value.reactions[reaction] = currentCount + 1;
|
||||||
|
note.value.reactionCount += 1;
|
||||||
|
|
||||||
if ($i && (body.userId === $i.id)) {
|
if ($i && (body.userId === $i.id)) {
|
||||||
note.value.myReaction = reaction;
|
note.value.myReaction = reaction;
|
||||||
|
@ -49,6 +50,7 @@ export function useNoteCapture(props: {
|
||||||
const currentCount = (note.value.reactions || {})[reaction] || 0;
|
const currentCount = (note.value.reactions || {})[reaction] || 0;
|
||||||
|
|
||||||
note.value.reactions[reaction] = Math.max(0, currentCount - 1);
|
note.value.reactions[reaction] = Math.max(0, currentCount - 1);
|
||||||
|
note.value.reactionCount = Math.max(0, note.value.reactionCount - 1);
|
||||||
if (note.value.reactions[reaction] === 0) delete note.value.reactions[reaction];
|
if (note.value.reactions[reaction] === 0) delete note.value.reactions[reaction];
|
||||||
|
|
||||||
if ($i && (body.userId === $i.id)) {
|
if ($i && (body.userId === $i.id)) {
|
||||||
|
|
|
@ -22,6 +22,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
//--ad: rgb(255 169 0 / 10%);
|
//--ad: rgb(255 169 0 / 10%);
|
||||||
|
--eventFollow: #36aed2;
|
||||||
|
--eventRenote: #36d298;
|
||||||
|
--eventReply: #007aff;
|
||||||
|
--eventReactionHeart: #dd2e44;
|
||||||
|
--eventReaction: #e99a0b;
|
||||||
|
--eventAchievement: #cb9a11;
|
||||||
|
--eventOther: #88a6b7;
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
|
|
|
@ -48,6 +48,9 @@ const devConfig = {
|
||||||
},
|
},
|
||||||
'/url': httpUrl,
|
'/url': httpUrl,
|
||||||
'/proxy': httpUrl,
|
'/proxy': httpUrl,
|
||||||
|
'/_info_card_': httpUrl,
|
||||||
|
'/bios': httpUrl,
|
||||||
|
'/cli': httpUrl,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"name": "misskey-js",
|
"name": "misskey-js",
|
||||||
"version": "2024.3.0",
|
"version": "2024.3.1",
|
||||||
"description": "Misskey SDK for JavaScript",
|
"description": "Misskey SDK for JavaScript",
|
||||||
"types": "./built/dts/index.d.ts",
|
"types": "./built/dts/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
@ -3987,6 +3987,7 @@ export type components = {
|
||||||
reactions: {
|
reactions: {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
};
|
};
|
||||||
|
reactionCount: number;
|
||||||
renoteCount: number;
|
renoteCount: number;
|
||||||
repliesCount: number;
|
repliesCount: number;
|
||||||
uri?: string;
|
uri?: string;
|
||||||
|
|
Loading…
Reference in New Issue