Compare commits

..

18 Commits

Author SHA1 Message Date
syuilo
e97951fc51 10.95.0 2019-03-15 13:54:08 +09:00
syuilo
dfabdef60f Resolve #4501 2019-03-15 13:51:23 +09:00
syuilo
5a87763193 New Crowdin translations (#4481)
* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (English)
2019-03-15 13:48:46 +09:00
syuilo
6bb90f56fa ジョブを一覧できるように 2019-03-15 13:48:17 +09:00
syuilo
c883ae1350 🎨 2019-03-15 13:14:50 +09:00
syuilo
09e25e6a02 Better queue chart 2019-03-15 13:09:19 +09:00
syuilo
bf5d43054b Fix bug 2019-03-15 13:09:05 +09:00
MeiMei
63b3c65691 ファビコンが保存されないのを修正 (#4500)
* Fix ファビコン保存されない

* Fix meta
2019-03-15 12:40:10 +09:00
syuilo
f193da7f67 🎨 2019-03-15 02:17:10 +09:00
syuilo
40f38c2c0a Improve queue page 2019-03-15 01:56:40 +09:00
syuilo
db439ef804 🎨 2019-03-15 01:43:11 +09:00
MeiMei
56eb896a03 Accept Article object (#4499) 2019-03-15 00:23:24 +09:00
Acid Chicken (硫酸鶏)
68d43e43b6 Fix hashtag style 2019-03-15 00:03:24 +09:00
Acid Chicken (硫酸鶏)
c60517e49a Follow #3676 2019-03-14 22:18:31 +09:00
Acid Chicken (硫酸鶏)
3f59d261f2 Follow #3676 2019-03-14 22:18:10 +09:00
Acid Chicken (硫酸鶏)
4068d220e5 Follow #3676 2019-03-14 22:17:26 +09:00
syuilo
18968e7208 Fix bug 2019-03-14 21:51:33 +09:00
Acid Chicken (硫酸鶏)
38656103c0 Add angle bracket covered url syntax to mfm (#4483)
* Add angle bracket covered url syntax to mfm

* Fix path

* Fix match

* Fix index
2019-03-14 21:23:15 +09:00
42 changed files with 226 additions and 62 deletions

View File

@@ -5,6 +5,16 @@ If you encounter any problems with updating, please try the following:
1. `npm run clean` or `npm run cleanall`
2. Retry update (Don't forget `npm i`)
10.95.0
----------
* ジョブを一覧できるように
* MFMでURLを明示する構文の追加
* Articleタイプのアクティビティを受け入れるように
* 凍結されたユーザーをサジェストしないように
* ファビコンが保存されないのを修正
* キューのジョブクリアの動作を修正
* デザインの調整
10.94.0
----------
* Faviconを設定できるように

View File

@@ -304,6 +304,7 @@ common/views/pages/explore.vue:
explore: "Prozkoumat {host}"
common/views/components/url-preview.vue:
enable-player: "Otevřít v přehrávači"
disable-player: "Zavřít přehrávač"
common/views/components/user-list.vue:
no-users: "Žádní uživatelé"
common/views/components/games/reversi/reversi.vue:
@@ -848,8 +849,6 @@ admin/views/dashboard.vue:
instances: "Instance"
this-instance: "Tato instance"
federated: "Z fediversu"
admin/views/queue.vue:
operation: "Akce"
admin/views/abuse.vue:
details: "Popis"
remove-report: "Odstranit"

View File

@@ -169,9 +169,9 @@ common:
deck-column-align-flexible: "Flexible"
deck-column-width: "Deck column width"
deck-column-width-narrow: "Narrow"
deck-column-width-narrower: "Somewhat narrow"
deck-column-width-narrower: "Narrower"
deck-column-width-normal: "Regular"
deck-column-width-wider: "Somewhat wide"
deck-column-width-wider: "Slightly wide"
deck-column-width-wide: "Wide"
use-shadow: "Use shadows in the UI"
rounded-corners: "Round the corners of the UI"
@@ -1057,7 +1057,7 @@ admin/views/dashboard.vue:
this-instance: "This instance"
federated: "Federated"
admin/views/queue.vue:
operation: "Action(s)"
title: "Queue"
remove-all-jobs: "Clear all queued jobs"
admin/views/abuse.vue:
title: "Abuse"

View File

@@ -927,7 +927,6 @@ admin/views/dashboard.vue:
this-instance: "Cette instance"
federated: "Fédérées"
admin/views/queue.vue:
operation: "Action(s)"
remove-all-jobs: "Enlever toutes les tâches en attente"
admin/views/abuse.vue:
title: "Abus"

View File

@@ -860,8 +860,6 @@ admin/views/dashboard.vue:
instances: "インスタンス"
this-instance: "ワイのインスタンス"
federated: "連合"
admin/views/queue.vue:
operation: "操作"
admin/views/abuse.vue:
details: "もっと"
remove-report: "削除"

View File

@@ -314,6 +314,7 @@ common/views/pages/explore.vue:
users-info: "현재 {users} 사용자가 등록되어 있습니다"
common/views/components/url-preview.vue:
enable-player: "플레이어 열기"
disable-player: "플레이어 닫기"
common/views/components/user-list.vue:
no-users: "사용자가 없습니다"
common/views/components/games/reversi/reversi.vue:
@@ -1056,7 +1057,7 @@ admin/views/dashboard.vue:
this-instance: "이 인스턴스"
federated: "연합"
admin/views/queue.vue:
operation: "동작"
title: ""
remove-all-jobs: "모든 작업 제거"
admin/views/abuse.vue:
title: "스팸 신고"

View File

@@ -121,12 +121,15 @@ common:
other: "Inne"
appearance: "Wygląd"
behavior: "Zachowanie"
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
note-visibility: "Widoczność wpisów"
web-search-engine: "Wyszukiwarka internetowa"
line-width-thin: "Cienka"
line-width-normal: "Normalna"
line-width-thick: "Gruba"
font-size: "Rozmiar tekstu"
font-size-medium: "Normalna"
font-size-large: "Trochę duży"
font-size-x-large: "Duży"
deck-column-align-center: "Po środku"
deck-column-align-left: "Z lewej"
@@ -137,6 +140,8 @@ common:
deck-column-width-normal: "Normalna"
deck-column-width-wider: "Trochę szerokie"
deck-column-width-wide: "Szeroka"
wallpaper: "Tapeta"
choose-wallpaper: "Wybierz tapetę"
timeline: "Oś czasu"
navbar-position-left: "Z lewej"
search: "Szukaj"

View File

@@ -314,6 +314,7 @@ common/views/pages/explore.vue:
users-info: "当前有{users}个注册用户"
common/views/components/url-preview.vue:
enable-player: "打开播放器"
disable-player: "关闭播放器"
common/views/components/user-list.vue:
no-users: "无用户"
common/views/components/games/reversi/reversi.vue:
@@ -1056,7 +1057,7 @@ admin/views/dashboard.vue:
this-instance: "此实例"
federated: "联合"
admin/views/queue.vue:
operation: "操作"
title: "队列"
remove-all-jobs: "清除所有作业"
admin/views/abuse.vue:
title: "举报垃圾信息"

View File

@@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.94.0",
"version": "10.95.0",
"codename": "nighthike",
"repository": {
"type": "git",

View File

@@ -181,7 +181,12 @@ export default Vue.extend({
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
borderColor: 'rgba(0, 0, 0, 0.1)',
xaxis: {
lines: {
show: true,
}
},
},
stroke: {
curve: 'straight',

View File

@@ -270,7 +270,7 @@ export default Vue.extend({
mascotImageUrl: this.mascotImageUrl,
bannerUrl: this.bannerUrl,
errorImageUrl: this.errorImageUrl,
iconImageUrl: this.iconImageUrl,
iconUrl: this.iconUrl,
name: this.name,
description: this.description,
langs: this.languages.split(' '),

View File

@@ -1,14 +1,15 @@
<template>
<div>
<ui-card>
<template #title><fa :icon="faTasks"/> {{ $t('title') }}</template>
<template #title><fa :icon="faChartBar"/> {{ $t('title') }}</template>
<section class="wptihjuy">
<header><fa :icon="faPaperPlane"/> Deliver</header>
<ui-info warn v-if="latestStats && latestStats.deliver.waiting > 0">The queue is jammed.</ui-info>
<ui-horizon-group inputs v-if="latestStats" class="fit-bottom">
<ui-input :value="latestStats.deliver.activeSincePrevTick | number" type="text" readonly>
<span>Process</span>
<template #prefix><fa :icon="fasPlayCircle"/></template>
<template #suffix>jobs/s</template>
<template #suffix>jobs/tick</template>
</ui-input>
<ui-input :value="latestStats.deliver.active | number" type="text" readonly>
<span>Active</span>
@@ -30,11 +31,12 @@
</section>
<section class="wptihjuy">
<header><fa :icon="faInbox"/> Inbox</header>
<ui-info warn v-if="latestStats && latestStats.inbox.waiting > 0">The queue is jammed.</ui-info>
<ui-horizon-group inputs v-if="latestStats" class="fit-bottom">
<ui-input :value="latestStats.inbox.activeSincePrevTick | number" type="text" readonly>
<span>Process</span>
<template #prefix><fa :icon="fasPlayCircle"/></template>
<template #suffix>jobs/s</template>
<template #suffix>jobs/tick</template>
</ui-input>
<ui-input :value="latestStats.inbox.active | number" type="text" readonly>
<span>Active</span>
@@ -58,6 +60,35 @@
<ui-button @click="removeAllJobs">{{ $t('remove-all-jobs') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faTasks"/> {{ $t('jobs') }}</template>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-select v-model="domain">
<template #label>{{ $t('queue') }}</template>
<option value="deliver">{{ $t('domains.deliver') }}</option>
<option value="inbox">{{ $t('domains.inbox') }}</option>
</ui-select>
<ui-select v-model="state">
<template #label>{{ $t('state') }}</template>
<option value="delayed">{{ $t('states.delayed') }}</option>
</ui-select>
</ui-horizon-group>
<sequential-entrance animation="entranceFromTop" delay="25">
<div class="xvvuvgsv" v-for="job in jobs">
<b>{{ job.id }}</b>
<template v-if="domain === 'deliver'">
<span>{{ job.data.to }}</span>
</template>
<template v-if="domain === 'inbox'">
<span>{{ job.activity.id }}</span>
</template>
</div>
</sequential-entrance>
<ui-info v-if="jobs.length == jobsLimit">{{ $t('result-is-truncated', { n: jobsLimit }) }}</ui-info>
</section>
</ui-card>
</div>
</template>
@@ -67,7 +98,7 @@ import i18n from '../../i18n';
import ApexCharts from 'apexcharts';
import * as tinycolor from 'tinycolor2';
import { faTasks, faInbox, faStopwatch, faPlayCircle as fasPlayCircle } from '@fortawesome/free-solid-svg-icons';
import { faPaperPlane, faStopCircle, faPlayCircle as farPlayCircle } from '@fortawesome/free-regular-svg-icons';
import { faPaperPlane, faStopCircle, faPlayCircle as farPlayCircle, faChartBar } from '@fortawesome/free-regular-svg-icons';
const limit = 150;
@@ -79,7 +110,11 @@ export default Vue.extend({
stats: [],
deliverChart: null,
inboxChart: null,
faTasks, faPaperPlane, faInbox, faStopwatch, faStopCircle, farPlayCircle, fasPlayCircle
jobs: [],
jobsLimit: 50,
domain: 'deliver',
state: 'delayed',
faTasks, faPaperPlane, faInbox, faStopwatch, faStopCircle, farPlayCircle, fasPlayCircle, faChartBar
};
},
@@ -125,12 +160,26 @@ export default Vue.extend({
type: 'line',
data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed }))
}]);
}
},
domain() {
this.jobs = [];
this.fetchJobs();
},
state() {
this.jobs = [];
this.fetchJobs();
},
},
mounted() {
const chartOpts = {
this.fetchJobs();
const chartOpts = id => ({
chart: {
id,
group: 'queue',
type: 'area',
height: 200,
animations: {
@@ -150,7 +199,12 @@ export default Vue.extend({
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
borderColor: 'rgba(0, 0, 0, 0.1)',
xaxis: {
lines: {
show: true,
}
},
},
stroke: {
curve: 'straight',
@@ -179,10 +233,10 @@ export default Vue.extend({
show: false,
min: 0,
}
};
});
this.inboxChart = new ApexCharts(this.$refs.inboxChart, chartOpts);
this.deliverChart = new ApexCharts(this.$refs.deliverChart, chartOpts);
this.inboxChart = new ApexCharts(this.$refs.inboxChart, chartOpts('a'));
this.deliverChart = new ApexCharts(this.$refs.deliverChart, chartOpts('b'));
this.inboxChart.render();
this.deliverChart.render();
@@ -229,7 +283,17 @@ export default Vue.extend({
for (const stats of statsLog.reverse()) {
this.onStats(stats);
}
}
},
fetchJobs() {
this.$root.api('admin/queue/jobs', {
domain: this.domain,
state: this.state,
limit: this.jobsLimit
}).then(jobs => {
this.jobs = jobs;
});
},
}
});
</script>
@@ -238,5 +302,10 @@ export default Vue.extend({
.wptihjuy
> .chart
min-height 200px !important
margin 0 -8px
.xvvuvgsv
> b
margin-right 16px
</style>

View File

@@ -69,7 +69,7 @@ export default Vue.extend({
},
plotOptions: {
bar: {
columnWidth: '90%'
columnWidth: '80%'
}
},
grid: {

View File

@@ -93,12 +93,17 @@ export default Vue.extend({
},
plotOptions: {
bar: {
columnWidth: '90%'
columnWidth: '80%'
}
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
borderColor: 'rgba(0, 0, 0, 0.1)',
xaxis: {
lines: {
show: true,
}
},
},
tooltip: {
shared: true,

View File

@@ -172,7 +172,7 @@ export default Vue.extend({
},
plotOptions: {
bar: {
columnWidth: '90%'
columnWidth: '80%'
}
},
grid: {

View File

@@ -4,7 +4,7 @@ import { deliverQueue, inboxQueue } from '../queue';
const ev = new Xev();
const interval = 1000;
const interval = 2000;
/**
* Report queue stats regularly

View File

@@ -1,5 +1,6 @@
import { parseFragment, DefaultTreeDocumentFragment } from 'parse5';
import { URL } from 'url';
import { urlRegex } from './prelude';
export function fromHtml(html: string): string {
if (html == null) return null;
@@ -14,7 +15,7 @@ export function fromHtml(html: string): string {
return text.trim();
function getText(node: any) {
function getText(node: any): string {
if (node.nodeName == '#text') return node.value;
if (node.childNodes) {
@@ -38,10 +39,11 @@ export function fromHtml(html: string): string {
const txt = getText(node);
const rel = node.attrs.find((x: any) => x.name == 'rel');
const href = node.attrs.find((x: any) => x.name == 'href');
const isHashtag = rel && rel.value.match('tag') !== null;
// ハッシュタグ / hrefがない / txtがURL
if ((rel && rel.value.match('tag') !== null) || !href || href.value == txt) {
text += txt;
if (isHashtag || !href || href.value == txt) {
text += isHashtag || txt.match(urlRegex) ? txt : `<${txt}>`;
// メンション
} else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) {
const part = txt.split('@');

View File

@@ -1,5 +1,5 @@
import * as P from 'parsimmon';
import { createLeaf, createTree } from './types';
import { createLeaf, createTree, urlRegex } from './prelude';
import { takeWhile, cumulativeSum } from '../prelude/array';
import parseAcct from '../misc/acct/parse';
import { toUnicode } from 'punycode';
@@ -154,9 +154,16 @@ export const mfmLanguage = P.createLanguage({
url: () => {
return P((input, i) => {
const text = input.substr(i);
const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/);
if (!match) return P.makeFailure(i, 'not a url');
let url = match[0];
const match = text.match(urlRegex);
let url: string;
if (!match) {
const match = text.match(/^<(https?:\/\/.*?)>/);
if (!match)
return P.makeFailure(i, 'not a url');
url = match[1];
i += 2;
} else
url = match[0];
url = removeOrphanedBrackets(url);
if (url.endsWith('.')) url = url.substr(0, url.lastIndexOf('.'));
if (url.endsWith(',')) url = url.substr(0, url.lastIndexOf(','));

View File

@@ -1,6 +1,6 @@
import * as A from '../prelude/array';
import * as S from '../prelude/string';
import { MfmForest, MfmTree } from './types';
import { MfmForest, MfmTree } from './prelude';
import { createTree, createLeaf } from '../prelude/tree';
function isEmptyTextTree(t: MfmTree): boolean {

View File

@@ -1,5 +1,5 @@
import { mfmLanguage } from './language';
import { MfmForest } from './types';
import { MfmForest } from './prelude';
import { normalize } from './normalize';
export function parse(source: string): MfmForest {

View File

@@ -35,3 +35,5 @@ export function createLeaf(type: string, props: any): MfmTree {
export function createTree(type: string, children: MfmForest, props: any): MfmTree {
return T.createTree({ type, props }, children);
}
export const urlRegex = /^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/;

View File

@@ -2,7 +2,7 @@ import { JSDOM } from 'jsdom';
import config from '../config';
import { INote } from '../models/note';
import { intersperse } from '../prelude/array';
import { MfmForest, MfmTree } from './types';
import { MfmForest, MfmTree } from './prelude';
export function toHtml(tokens: MfmForest, mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) {
if (tokens == null) {

View File

@@ -1,4 +1,4 @@
import { EmojiNode, MfmForest } from '../mfm/types';
import { EmojiNode, MfmForest } from '../mfm/prelude';
import { preorderF } from '../prelude/tree';
import { unique } from '../prelude/array';

View File

@@ -1,4 +1,4 @@
import { HashtagNode, MfmForest } from '../mfm/types';
import { HashtagNode, MfmForest } from '../mfm/prelude';
import { preorderF } from '../prelude/tree';
import { unique } from '../prelude/array';

View File

@@ -1,6 +1,6 @@
// test is located in test/extract-mentions
import { MentionNode, MfmForest } from '../mfm/types';
import { MentionNode, MfmForest } from '../mfm/prelude';
import { preorderF } from '../prelude/tree';
export default function(mfmForest: MfmForest): MentionNode['props'][] {

View File

@@ -41,6 +41,7 @@ export type INote = {
replyId: mongo.ObjectID;
renoteId: mongo.ObjectID;
poll: IPoll;
name?: string;
text: string;
tags: string[];
tagsLower: string[];
@@ -391,6 +392,10 @@ export const pack = async (
}
//#endregion
if (_note.name) {
_note.text = `${_note.name}\n${_note.text}`;
}
if (_note.user.isCat && _note.text) {
_note.text = (_note.text
// ja-JP

View File

@@ -20,6 +20,7 @@ User.createIndex('createdAt');
User.createIndex('updatedAt');
User.createIndex('followersCount');
User.createIndex('tags');
User.createIndex('isSuspended');
User.createIndex('username');
User.createIndex('usernameLower');
User.createIndex('host');

View File

@@ -178,10 +178,10 @@ export function destroy() {
deliverQueue.once('cleaned', (jobs, status) => {
deliverLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
});
deliverQueue.clean(0, 'wait');
deliverQueue.clean(0, 'delayed');
inboxQueue.once('cleaned', (jobs, status) => {
inboxLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
});
inboxQueue.clean(0, 'wait');
inboxQueue.clean(0, 'delayed');
}

View File

@@ -24,10 +24,8 @@ export default async (actor: IRemoteUser, activity: IAnnounce): Promise<void> =>
switch (object.type) {
case 'Note':
announceNote(resolver, actor, activity, object as INote);
break;
case 'Question':
case 'Article':
announceNote(resolver, actor, activity, object as INote);
break;

View File

@@ -29,10 +29,8 @@ export default async (actor: IRemoteUser, activity: ICreate): Promise<void> => {
break;
case 'Note':
createNote(resolver, actor, object);
break;
case 'Question':
case 'Article':
createNote(resolver, actor, object);
break;

View File

@@ -21,10 +21,8 @@ export default async (actor: IRemoteUser, activity: IDelete): Promise<void> => {
switch (object.type) {
case 'Note':
deleteNote(actor, uri);
break;
case 'Question':
case 'Article':
deleteNote(actor, uri);
break;

View File

@@ -1,3 +1,3 @@
import { remoteLogger } from "../logger";
import { remoteLogger } from '../logger';
export const apLogger = remoteLogger.createSubLogger('ap', 'magenta');

View File

@@ -57,7 +57,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
const object: any = await resolver.resolve(value);
if (!object || !['Note', 'Question'].includes(object.type)) {
if (!object || !['Note', 'Question', 'Article'].includes(object.type)) {
logger.error(`invalid note: ${value}`, {
resolver: {
history: resolver.getHistory()
@@ -199,6 +199,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
files,
reply,
renote: quote,
name: note.name,
cw,
text,
viaMobile: false,

View File

@@ -0,0 +1,40 @@
import $ from 'cafy';
import define from '../../../define';
import { deliverQueue, inboxQueue } from '../../../../../queue';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
params: {
domain: {
validator: $.str,
},
state: {
validator: $.str,
},
limit: {
validator: $.optional.num,
default: 50
},
}
};
export default define(meta, async (ps) => {
const queue =
ps.domain === 'deliver' ? deliverQueue :
ps.domain === 'inbox' ? inboxQueue :
null;
const jobs = await queue.getJobs([ps.state], 0, ps.limit);
return jobs.map(job => ({
id: job.id,
data: job.data,
attempts: job.attemptsMade,
}));
});

View File

@@ -103,7 +103,7 @@ async function fetchAny(uri: string) {
};
}
if (['Note', 'Question'].includes(object.type)) {
if (['Note', 'Question', 'Article'].includes(object.type)) {
const note = await createNote(object.id);
return {
type: 'Note',

View File

@@ -116,6 +116,7 @@ export default define(meta, async (ps, me) => {
mascotImageUrl: instance.mascotImageUrl,
bannerUrl: instance.bannerUrl,
errorImageUrl: instance.errorImageUrl,
iconUrl: instance.iconUrl,
maxNoteTextLength: instance.maxNoteTextLength,
emojis: emojis,
enableEmail: instance.enableEmail,

View File

@@ -70,7 +70,8 @@ export default define(meta, async (ps, me) => {
users = await User
.find({
host: null,
usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase()))
usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase())),
isSuspended: false
}, {
limit: ps.limit,
skip: ps.offset
@@ -80,7 +81,8 @@ export default define(meta, async (ps, me) => {
const otherUsers = await User
.find({
host: { $ne: null },
usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase()))
usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase())),
isSuspended: false
}, {
limit: ps.limit - users.length
});

View File

@@ -1,3 +1,3 @@
import Logger from "../../services/logger";
import Logger from '../../services/logger';
export const apiLogger = new Logger('api');

View File

@@ -10,6 +10,7 @@ html
meta(charset='utf-8')
meta(name='application-name' content= title || 'Misskey')
meta(name='referrer' content='origin')
meta(name='theme-color' content='#105779')
meta(property='og:site_name' content= title || 'Misskey')
link(rel='icon' href= icon || '/favicon.ico')
link(rel='manifest' href='/manifest.json')

View File

@@ -1,3 +1,3 @@
import Logger from "../logger";
import Logger from '../logger';
export const driveLogger = new Logger('drive', 'blue');

View File

@@ -91,6 +91,7 @@ class NotificationManager {
type Option = {
createdAt?: Date;
name?: string;
text?: string;
reply?: INote;
renote?: INote;
@@ -437,6 +438,7 @@ async function insertNote(user: IUser, data: Option, tags: string[], emojis: str
fileIds: data.files ? data.files.map(file => file._id) : [],
replyId: data.reply ? data.reply._id : null,
renoteId: data.renote ? data.renote._id : null,
name: data.name,
text: data.text,
poll: data.poll,
cw: data.cw == null ? null : data.cw,

View File

@@ -12,7 +12,7 @@ import * as assert from 'assert';
import { parse, parsePlain } from '../src/mfm/parse';
import { toHtml } from '../src/mfm/toHtml';
import { createTree as tree, createLeaf as leaf, MfmTree } from '../src/mfm/types';
import { createTree as tree, createLeaf as leaf, MfmTree } from '../src/mfm/prelude';
import { removeOrphanedBrackets } from '../src/mfm/language';
function text(text: string): MfmTree {
@@ -840,6 +840,20 @@ describe('MFM', () => {
text(')')
]);
});
it('ignore non-ascii characters contained url without angle brackets', () => {
const tokens = parse('https://大石泉すき.example.com');
assert.deepStrictEqual(tokens, [
text('https://大石泉すき.example.com')
]);
});
it('match non-ascii characters contained url with angle brackets', () => {
const tokens = parse('<https://大石泉すき.example.com>');
assert.deepStrictEqual(tokens, [
leaf('url', { url: 'https://大石泉すき.example.com' })
]);
});
});
describe('link', () => {