Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
0f65b1bcc5 | |||
a628821834 | |||
6ceff60c1e | |||
d762a6ce58 | |||
75a8037a46 | |||
1179920790 | |||
b323a160e3 | |||
b157e9535e | |||
7668475bd6 | |||
8bda2a1fb7 | |||
b092086b5b | |||
69a0d9034f |
@ -5,6 +5,14 @@ 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.94.0
|
||||
----------
|
||||
* Faviconを設定できるように
|
||||
* アカウントを凍結したときすべてのフォローを解除するように
|
||||
* シェアページが機能していない問題を修正
|
||||
* インスタンスブロックをしていてもRenote等すると取得されてしまう問題を修正
|
||||
* デザインの調整
|
||||
|
||||
10.93.1
|
||||
----------
|
||||
* データのエクスポートとインポートの動作を修正
|
||||
|
@ -14,6 +14,7 @@ const merge = (...args) => args.reduce((a, c) => ({
|
||||
}), {});
|
||||
|
||||
const languages = [
|
||||
'cs-CZ',
|
||||
'de-DE',
|
||||
'en-US',
|
||||
'es-ES',
|
||||
@ -24,9 +25,11 @@ const languages = [
|
||||
'nl-NL',
|
||||
'pl-PL',
|
||||
'zh-CN',
|
||||
'zh-TW',
|
||||
];
|
||||
|
||||
const primaries = {
|
||||
'en': 'US',
|
||||
'ja': 'JP',
|
||||
'zh': 'CN',
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "10.93.1",
|
||||
"version": "10.94.0",
|
||||
"codename": "nighthike",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -23,6 +23,8 @@ import { faInbox } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
|
||||
import ApexCharts from 'apexcharts';
|
||||
|
||||
const limit = 150;
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
@ -124,7 +126,7 @@ export default Vue.extend({
|
||||
connection.on('statsLog', this.onStatsLog);
|
||||
connection.send('requestLog', {
|
||||
id: Math.random().toString().substr(2, 8),
|
||||
length: 100
|
||||
length: limit
|
||||
});
|
||||
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
@ -137,7 +139,7 @@ export default Vue.extend({
|
||||
methods: {
|
||||
onStats(stats) {
|
||||
this.stats.push(stats);
|
||||
if (this.stats.length > 100) this.stats.shift();
|
||||
if (this.stats.length > limit) this.stats.shift();
|
||||
},
|
||||
|
||||
onStatsLog(statsLog) {
|
||||
|
@ -92,8 +92,8 @@ import Vue from 'vue';
|
||||
import i18n from '../../i18n';
|
||||
import XCpuMemory from "./dashboard.cpu-memory.vue";
|
||||
import XQueue from "./dashboard.queue-charts.vue";
|
||||
import XCharts from "./charts.vue";
|
||||
import XApLog from "./ap-log.vue";
|
||||
import XCharts from "./dashboard.charts.vue";
|
||||
import XApLog from "./dashboard.ap-log.vue";
|
||||
import { faDatabase } from '@fortawesome/free-solid-svg-icons';
|
||||
import MarqueeText from 'vue-marquee-text-component';
|
||||
import randomColor from 'randomcolor';
|
||||
|
@ -6,6 +6,7 @@
|
||||
<ui-input :value="host" readonly>{{ $t('host') }}</ui-input>
|
||||
<ui-input v-model="name">{{ $t('instance-name') }}</ui-input>
|
||||
<ui-textarea v-model="description">{{ $t('instance-description') }}</ui-textarea>
|
||||
<ui-input v-model="iconUrl"><template #icon><fa icon="link"/></template>{{ $t('icon-url') }}</ui-input>
|
||||
<ui-input v-model="mascotImageUrl"><template #icon><fa icon="link"/></template>{{ $t('logo-url') }}</ui-input>
|
||||
<ui-input v-model="bannerUrl"><template #icon><fa icon="link"/></template>{{ $t('banner-url') }}</ui-input>
|
||||
<ui-input v-model="errorImageUrl"><template #icon><fa icon="link"/></template>{{ $t('error-image-url') }}</ui-input>
|
||||
@ -157,6 +158,7 @@ export default Vue.extend({
|
||||
mascotImageUrl: null,
|
||||
bannerUrl: null,
|
||||
errorImageUrl: null,
|
||||
iconUrl: null,
|
||||
name: null,
|
||||
description: null,
|
||||
languages: null,
|
||||
@ -207,6 +209,7 @@ export default Vue.extend({
|
||||
this.mascotImageUrl = meta.mascotImageUrl;
|
||||
this.bannerUrl = meta.bannerUrl;
|
||||
this.errorImageUrl = meta.errorImageUrl;
|
||||
this.iconUrl = meta.iconUrl;
|
||||
this.name = meta.name;
|
||||
this.description = meta.description;
|
||||
this.languages = meta.langs.join(' ');
|
||||
@ -267,6 +270,7 @@ export default Vue.extend({
|
||||
mascotImageUrl: this.mascotImageUrl,
|
||||
bannerUrl: this.bannerUrl,
|
||||
errorImageUrl: this.errorImageUrl,
|
||||
iconImageUrl: this.iconImageUrl,
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
langs: this.languages.split(' '),
|
||||
|
@ -69,6 +69,8 @@ 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';
|
||||
|
||||
const limit = 150;
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('admin/views/queue.vue'),
|
||||
|
||||
@ -91,28 +93,36 @@ export default Vue.extend({
|
||||
stats(stats) {
|
||||
this.inboxChart.updateSeries([{
|
||||
name: 'Process',
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.activeSincePrevTick }))
|
||||
}, {
|
||||
name: 'Active',
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.active }))
|
||||
}, {
|
||||
name: 'Waiting',
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.waiting }))
|
||||
}, {
|
||||
name: 'Delayed',
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.delayed }))
|
||||
}]);
|
||||
this.deliverChart.updateSeries([{
|
||||
name: 'Process',
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.activeSincePrevTick }))
|
||||
}, {
|
||||
name: 'Active',
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.active }))
|
||||
}, {
|
||||
name: 'Waiting',
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.waiting }))
|
||||
}, {
|
||||
name: 'Delayed',
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed }))
|
||||
}]);
|
||||
}
|
||||
@ -182,7 +192,7 @@ export default Vue.extend({
|
||||
connection.on('statsLog', this.onStatsLog);
|
||||
connection.send('requestLog', {
|
||||
id: Math.random().toString().substr(2, 8),
|
||||
length: 100
|
||||
length: limit
|
||||
});
|
||||
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
@ -212,7 +222,7 @@ export default Vue.extend({
|
||||
|
||||
onStats(stats) {
|
||||
this.stats.push(stats);
|
||||
if (this.stats.length > 100) this.stats.shift();
|
||||
if (this.stats.length > limit) this.stats.shift();
|
||||
},
|
||||
|
||||
onStatsLog(statsLog) {
|
||||
|
@ -366,9 +366,6 @@ root(fill)
|
||||
&[type='file']
|
||||
display none
|
||||
|
||||
&[type='number']
|
||||
text-align right
|
||||
|
||||
> .prefix
|
||||
> .suffix
|
||||
display block
|
||||
|
@ -28,10 +28,10 @@ export default Vue.extend({
|
||||
computed: {
|
||||
template(): string {
|
||||
let t = '';
|
||||
if (this.title && this.url) t += `【[${title}](${url})】\n`;
|
||||
if (this.title && !this.url) t += `【${title}】\n`;
|
||||
if (this.text) t += `${text}\n`;
|
||||
if (!this.title && this.url) t += `${url}`;
|
||||
if (this.title && this.url) t += `【[${this.title}](${this.url})】\n`;
|
||||
if (this.title && !this.url) t += `【${this.title}】\n`;
|
||||
if (this.text) t += `${this.text}\n`;
|
||||
if (!this.title && this.url) t += `${this.url}`;
|
||||
return t.trim();
|
||||
}
|
||||
},
|
||||
|
@ -42,21 +42,29 @@ export default define({
|
||||
watch: {
|
||||
stats(stats) {
|
||||
this.inChart.updateSeries([{
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.activeSincePrevTick }))
|
||||
}, {
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.active }))
|
||||
}, {
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.waiting }))
|
||||
}, {
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.inbox.delayed }))
|
||||
}]);
|
||||
this.outChart.updateSeries([{
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.activeSincePrevTick }))
|
||||
}, {
|
||||
type: 'area',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.active }))
|
||||
}, {
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.waiting }))
|
||||
}, {
|
||||
type: 'line',
|
||||
data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed }))
|
||||
}]);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import config from '../config';
|
||||
import { toUnicode, toASCII } from 'punycode';
|
||||
import { URL } from 'url';
|
||||
|
||||
export function getFullApAccount(username: string, host: string) {
|
||||
return host ? `${username}@${toApHost(host)}` : `${username}@${toApHost(config.host)}`;
|
||||
@ -10,6 +11,11 @@ export function isSelfHost(host: string) {
|
||||
return toApHost(config.host) === toApHost(host);
|
||||
}
|
||||
|
||||
export function extractDbHost(uri: string) {
|
||||
const url = new URL(uri);
|
||||
return toDbHost(url.hostname);
|
||||
}
|
||||
|
||||
export function toDbHost(host: string) {
|
||||
if (host == null) return null;
|
||||
return toUnicode(host.toLowerCase());
|
||||
|
@ -198,6 +198,7 @@ export type IMeta = {
|
||||
mascotImageUrl?: string;
|
||||
bannerUrl?: string;
|
||||
errorImageUrl?: string;
|
||||
iconUrl?: string;
|
||||
|
||||
cacheRemoteFiles?: boolean;
|
||||
|
||||
|
@ -5,6 +5,8 @@ import { IAnnounce, INote } from '../../type';
|
||||
import { fetchNote, resolveNote } from '../../models/note';
|
||||
import { resolvePerson } from '../../models/person';
|
||||
import { apLogger } from '../../logger';
|
||||
import { extractDbHost } from '../../../../misc/convert-host';
|
||||
import Instance from '../../../../models/instance';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
@ -23,6 +25,11 @@ export default async function(resolver: Resolver, actor: IRemoteUser, activity:
|
||||
throw new Error('invalid announce');
|
||||
}
|
||||
|
||||
// アナウンス先をブロックしてたら中断
|
||||
// TODO: いちいちデータベースにアクセスするのはコスト高そうなのでどっかにキャッシュしておく
|
||||
const instance = await Instance.findOne({ host: extractDbHost(uri) });
|
||||
if (instance && instance.isBlocked) return;
|
||||
|
||||
// 既に同じURIを持つものが登録されていないかチェック
|
||||
const exist = await fetchNote(uri);
|
||||
if (exist) {
|
||||
|
@ -19,6 +19,8 @@ import vote from '../../../services/note/polls/vote';
|
||||
import { apLogger } from '../logger';
|
||||
import { IDriveFile } from '../../../models/drive-file';
|
||||
import { deliverQuestionUpdate } from '../../../services/note/polls/update';
|
||||
import Instance from '../../../models/instance';
|
||||
import { extractDbHost } from '../../../misc/convert-host';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
@ -132,7 +134,15 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
let quote: INote;
|
||||
|
||||
if (note._misskey_quote && typeof note._misskey_quote == 'string') {
|
||||
quote = await resolveNote(note._misskey_quote).catch(() => null);
|
||||
quote = await resolveNote(note._misskey_quote).catch(e => {
|
||||
// 4xxの場合は引用してないことにする
|
||||
if (e.statusCode >= 400 && e.statusCode < 500) {
|
||||
logger.warn(`Ignored quote target ${note.inReplyTo} - ${e.statusCode} `);
|
||||
return null;
|
||||
}
|
||||
logger.warn(`Error in quote target ${note.inReplyTo} - ${e.statusCode || e}`);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
const cw = note.summary === '' ? null : note.summary;
|
||||
@ -214,6 +224,11 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||
export async function resolveNote(value: string | IObject, resolver?: Resolver): Promise<INote> {
|
||||
const uri = typeof value == 'string' ? value : value.id;
|
||||
|
||||
// ブロックしてたら中断
|
||||
// TODO: いちいちデータベースにアクセスするのはコスト高そうなのでどっかにキャッシュしておく
|
||||
const instance = await Instance.findOne({ host: extractDbHost(uri) });
|
||||
if (instance && instance.isBlocked) throw { statusCode: 451 };
|
||||
|
||||
//#region このサーバーに既に登録されていたらそれを返す
|
||||
const exist = await fetchNote(uri);
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
import Logger from "../services/logger";
|
||||
import Logger from '../services/logger';
|
||||
|
||||
export const remoteLogger = new Logger('remote', 'cyan');
|
||||
|
@ -1,7 +1,9 @@
|
||||
import $ from 'cafy';
|
||||
import ID, { transform } from '../../../../misc/cafy-id';
|
||||
import define from '../../define';
|
||||
import User from '../../../../models/user';
|
||||
import User, { IUser } from '../../../../models/user';
|
||||
import Following from '../../../../models/following';
|
||||
import deleteFollowing from '../../../../services/following/delete';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
@ -51,5 +53,25 @@ export default define(meta, async (ps) => {
|
||||
}
|
||||
});
|
||||
|
||||
unFollowAll(user);
|
||||
|
||||
return;
|
||||
});
|
||||
|
||||
async function unFollowAll(follower: IUser) {
|
||||
const followings = await Following.find({
|
||||
followerId: follower._id
|
||||
});
|
||||
|
||||
for (const following of followings) {
|
||||
const followee = await User.findOne({
|
||||
_id: following.followeeId
|
||||
});
|
||||
|
||||
if (followee == null) {
|
||||
throw `Cant find followee ${following.followeeId}`;
|
||||
}
|
||||
|
||||
await deleteFollowing(follower, followee, true);
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,13 @@ export const meta = {
|
||||
}
|
||||
},
|
||||
|
||||
iconUrl: {
|
||||
validator: $.optional.nullable.str,
|
||||
desc: {
|
||||
'ja-JP': 'インスタンスのアイコンURL'
|
||||
}
|
||||
},
|
||||
|
||||
name: {
|
||||
validator: $.optional.nullable.str,
|
||||
desc: {
|
||||
@ -356,6 +363,10 @@ export default define(meta, async (ps) => {
|
||||
set.bannerUrl = ps.bannerUrl;
|
||||
}
|
||||
|
||||
if (ps.iconUrl !== undefined) {
|
||||
set.iconUrl = ps.iconUrl;
|
||||
}
|
||||
|
||||
if (ps.name !== undefined) {
|
||||
set.name = ps.name;
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import Note, { pack as packNote, INote } from '../../../../models/note';
|
||||
import { createNote } from '../../../../remote/activitypub/models/note';
|
||||
import Resolver from '../../../../remote/activitypub/resolver';
|
||||
import { ApiError } from '../../error';
|
||||
import Instance from '../../../../models/instance';
|
||||
import { extractDbHost } from '../../../../misc/convert-host';
|
||||
|
||||
export const meta = {
|
||||
tags: ['federation'],
|
||||
@ -61,6 +63,10 @@ async function fetchAny(uri: string) {
|
||||
if (packed !== null) return packed;
|
||||
}
|
||||
|
||||
// ブロックしてたら中断
|
||||
const instance = await Instance.findOne({ host: extractDbHost(uri) });
|
||||
if (instance && instance.isBlocked) return null;
|
||||
|
||||
// URI(AP Object id)としてDB検索
|
||||
{
|
||||
const [user, note] = await Promise.all([
|
||||
|
@ -250,7 +250,10 @@ router.get('/reversi', async ctx => ctx.redirect(override(ctx.URL.pathname, 'gam
|
||||
router.get('*', async ctx => {
|
||||
const meta = await fetchMeta();
|
||||
await ctx.render('base', {
|
||||
img: meta.bannerUrl
|
||||
img: meta.bannerUrl,
|
||||
title: meta.name,
|
||||
desc: meta.description,
|
||||
icon: meta.iconUrl
|
||||
});
|
||||
ctx.set('Cache-Control', 'public, max-age=300');
|
||||
});
|
||||
|
@ -8,17 +8,18 @@ html
|
||||
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
meta(name='application-name' content='Misskey')
|
||||
meta(name='application-name' content= title || 'Misskey')
|
||||
meta(name='referrer' content='origin')
|
||||
meta(property='og:site_name' content='Misskey')
|
||||
meta(property='og:site_name' content= title || 'Misskey')
|
||||
link(rel='icon' href= icon || '/favicon.ico')
|
||||
link(rel='manifest' href='/manifest.json')
|
||||
|
||||
title
|
||||
block title
|
||||
| Misskey
|
||||
= title || 'Misskey'
|
||||
|
||||
block desc
|
||||
meta(name='description' content='✨🌎✨ A federated blogging platform ✨🚀✨')
|
||||
meta(name='description' content= desc || '✨🌎✨ A federated blogging platform ✨🚀✨')
|
||||
|
||||
block meta
|
||||
|
||||
|
@ -13,7 +13,7 @@ import instanceChart from '../../services/chart/instance';
|
||||
|
||||
const logger = new Logger('following/delete');
|
||||
|
||||
export default async function(follower: IUser, followee: IUser) {
|
||||
export default async function(follower: IUser, followee: IUser, silent = false) {
|
||||
const following = await Following.findOne({
|
||||
followerId: follower._id,
|
||||
followeeId: followee._id
|
||||
@ -71,7 +71,7 @@ export default async function(follower: IUser, followee: IUser) {
|
||||
perUserFollowingChart.update(follower, followee, false);
|
||||
|
||||
// Publish unfollow event
|
||||
if (isLocalUser(follower)) {
|
||||
if (!silent && isLocalUser(follower)) {
|
||||
packUser(followee, follower, {
|
||||
detail: true
|
||||
}).then(packed => publishMainStream(follower._id, 'unfollow', packed));
|
||||
|
Reference in New Issue
Block a user