Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
c55237d09c | |||
ed698b7b82 | |||
d4ff19f013 | |||
972fb8eb40 | |||
4de75448b6 | |||
e8ef8f0004 | |||
a319b30382 | |||
8278616eeb | |||
771f011506 | |||
826865869a | |||
3c77ae7b62 | |||
60c30ece10 | |||
76a0d0fee9 | |||
d50624f0a0 |
@ -1,6 +1,12 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
10.91.1
|
||||
----------
|
||||
* ログビューを強化
|
||||
* テーマの切り替えをなめらかに
|
||||
* SVGの判定を修正
|
||||
|
||||
10.91.0
|
||||
----------
|
||||
* ログを管理画面で見れるように
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -972,7 +972,7 @@ desktop/views/components/timeline.vue:
|
||||
messages: "Messages"
|
||||
list: "Lists"
|
||||
hashtag: "Hashtag"
|
||||
add-tag-timeline: "Add hashtag tl"
|
||||
add-tag-timeline: "Add hashtag cloud"
|
||||
add-list: "Add list"
|
||||
list-name: "List name"
|
||||
desktop/views/components/ui.header.vue:
|
||||
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "Hashtags"
|
||||
abuse: "Abuse"
|
||||
queue: "Job Queue"
|
||||
logs: "Logs"
|
||||
back-to-misskey: "Back to Misskey"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "Dashboard"
|
||||
@ -1558,8 +1559,8 @@ deck:
|
||||
stack-left: "Stack to the left"
|
||||
pop-right: "Dock on the right"
|
||||
disabled-timeline:
|
||||
title: "Timeline has been disabled"
|
||||
description: "Timeline has been disabled by the administrator."
|
||||
title: "The timeline has been disabled"
|
||||
description: "This timeline has been disabled by the server's administrator."
|
||||
deck/deck.tl-column.vue:
|
||||
is-media-only: "Only media posts"
|
||||
edit: "Options"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "Hashtags"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Volver a Misskey"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "Panel de Control"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "Hashtags"
|
||||
abuse: "Abus"
|
||||
queue: "File d’attente"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Retour vers Misskey"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "Tableau de bord"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "해시태그"
|
||||
abuse: "스팸 신고"
|
||||
queue: "작업 대기열"
|
||||
logs: "로그"
|
||||
back-to-misskey: "Misskey로 돌아가기"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "대시보드"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -30,9 +30,9 @@ common:
|
||||
2fa: "Uwierzytelnienie dwuetapowe"
|
||||
customize-home: "Dostosuj stronę główną"
|
||||
featured-notes: "ハイライト"
|
||||
dark-mode: "ダークモード"
|
||||
signin: "ログイン"
|
||||
signup: "新規登録"
|
||||
dark-mode: "Tryb ciemny"
|
||||
signin: "Zaloguj się"
|
||||
signup: "Rejestracja"
|
||||
signout: "ログアウト"
|
||||
reload-to-apply-the-setting: "この設定を反映するにはページをリロードする必要があります。今すぐリロードしますか?"
|
||||
got-it: "Rozumiem!"
|
||||
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "Hashtagi"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "ハッシュタグ"
|
||||
abuse: "スパム報告"
|
||||
queue: "ジョブキュー"
|
||||
logs: "ログ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
|
@ -1023,6 +1023,7 @@ admin/views/index.vue:
|
||||
hashtags: "标签"
|
||||
abuse: "举报垃圾信息"
|
||||
queue: "作业队列"
|
||||
logs: "登录"
|
||||
back-to-misskey: "返回 Misskey"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "Dashboard"
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "10.91.0",
|
||||
"version": "10.91.1",
|
||||
"codename": "nighthike",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -227,6 +227,7 @@
|
||||
"url-loader": "1.1.2",
|
||||
"uuid": "3.3.2",
|
||||
"v-animate-css": "0.0.3",
|
||||
"v-debounce": "0.1.2",
|
||||
"video-thumbnail-generator": "1.1.3",
|
||||
"vue": "2.6.8",
|
||||
"vue-color": "2.7.0",
|
||||
@ -234,6 +235,7 @@
|
||||
"vue-cropperjs": "3.0.0",
|
||||
"vue-i18n": "8.8.2",
|
||||
"vue-js-modal": "1.3.28",
|
||||
"vue-json-viewer": "2.0.6",
|
||||
"vue-loader": "15.7.0",
|
||||
"vue-marquee-text-component": "1.1.1",
|
||||
"vue-prism-component": "1.1.1",
|
||||
|
@ -4,7 +4,7 @@
|
||||
<template #title><fa :icon="faStream"/> {{ $t('logs') }}</template>
|
||||
<section class="fit-top">
|
||||
<ui-horizon-group inputs>
|
||||
<ui-input v-model="domain">
|
||||
<ui-input v-model="domain" debounce>
|
||||
<span>{{ $t('domain') }}</span>
|
||||
</ui-input>
|
||||
<ui-select v-model="level">
|
||||
@ -20,7 +20,10 @@
|
||||
|
||||
<div class="nqjzuvev">
|
||||
<code v-for="log in logs" :key="log._id" :class="log.level">
|
||||
<mk-time :time="log.createdAt"/> [{{ log.domain.join(' ') }}] {{ log.message }}
|
||||
<details>
|
||||
<summary><mk-time :time="log.createdAt"/> [{{ log.domain.join('.') }}] {{ log.message }}</summary>
|
||||
<json-viewer v-if="log.data" :value="log.data"></json-viewer>
|
||||
</details>
|
||||
</code>
|
||||
</div>
|
||||
</section>
|
||||
@ -32,10 +35,15 @@
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../i18n';
|
||||
import { faStream } from '@fortawesome/free-solid-svg-icons';
|
||||
import JsonViewer from 'vue-json-viewer';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('admin/views/logs.vue'),
|
||||
|
||||
components: {
|
||||
JsonViewer
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
logs: [],
|
||||
@ -66,9 +74,9 @@ export default Vue.extend({
|
||||
this.$root.api('admin/logs', {
|
||||
level: this.level === 'all' ? null : this.level,
|
||||
domain: this.domain === '' ? null : this.domain,
|
||||
limit: 50
|
||||
limit: 100
|
||||
}).then(logs => {
|
||||
this.logs = logs;
|
||||
this.logs = logs.reverse();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +179,7 @@
|
||||
<x-mute-and-block/>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
<template v-if="page == null || page == 'apps'">
|
||||
<ui-card>
|
||||
<template #title><fa icon="puzzle-piece"/> {{ $t('@._settings.apps') }}</template>
|
||||
@ -187,6 +188,7 @@
|
||||
</section>
|
||||
</ui-card>
|
||||
</template>
|
||||
-->
|
||||
|
||||
<template v-if="page == null || page == 'security'">
|
||||
<ui-card>
|
||||
@ -203,12 +205,14 @@
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<!--
|
||||
<ui-card>
|
||||
<template #title><fa icon="sign-in-alt"/> {{ $t('@._settings.signin') }}</template>
|
||||
<section>
|
||||
<x-signins/>
|
||||
</section>
|
||||
</ui-card>
|
||||
-->
|
||||
</template>
|
||||
|
||||
<template v-if="page == null || page == 'api'">
|
||||
|
@ -9,7 +9,22 @@
|
||||
<span class="title" ref="title"><slot name="title"></slot></span>
|
||||
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
|
||||
<template v-if="type != 'file'">
|
||||
<input ref="input"
|
||||
<input v-if="debounce" ref="input"
|
||||
v-debounce="500"
|
||||
:type="type"
|
||||
v-model.lazy="v"
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
:readonly="readonly"
|
||||
:placeholder="placeholder"
|
||||
:pattern="pattern"
|
||||
:autocomplete="autocomplete"
|
||||
:spellcheck="spellcheck"
|
||||
@focus="focused = true"
|
||||
@blur="focused = false"
|
||||
@keydown="$emit('keydown', $event)"
|
||||
>
|
||||
<input v-else ref="input"
|
||||
:type="type"
|
||||
v-model="v"
|
||||
:disabled="disabled"
|
||||
@ -51,9 +66,13 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import debounce from 'v-debounce';
|
||||
const getPasswordStrength = require('syuilo-password-strength');
|
||||
|
||||
export default Vue.extend({
|
||||
directives: {
|
||||
debounce
|
||||
},
|
||||
inject: {
|
||||
horizonGrouped: {
|
||||
default: false
|
||||
@ -98,6 +117,9 @@ export default Vue.extend({
|
||||
spellcheck: {
|
||||
required: false
|
||||
},
|
||||
debounce: {
|
||||
required: false
|
||||
},
|
||||
withPasswordMeter: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
@ -389,7 +389,7 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS], os: MiOS)
|
||||
});
|
||||
//#endregion
|
||||
|
||||
// Reapply current theme
|
||||
/*// Reapply current theme
|
||||
try {
|
||||
const themeName = os.store.state.device.darkmode ? os.store.state.device.darkTheme : os.store.state.device.lightTheme;
|
||||
const themes = os.store.state.device.themes.concat(builtinThemes);
|
||||
@ -399,7 +399,7 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS], os: MiOS)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`Cannot reapply theme. ${e}`);
|
||||
}
|
||||
}*/
|
||||
|
||||
//#region line width
|
||||
document.documentElement.style.setProperty('--lineWidth', `${os.store.state.device.lineWidth}px`);
|
||||
|
@ -43,6 +43,12 @@ export const builtinThemes = [
|
||||
];
|
||||
|
||||
export function applyTheme(theme: Theme, persisted = true) {
|
||||
document.documentElement.classList.add('change-theme');
|
||||
|
||||
setTimeout(() => {
|
||||
document.documentElement.classList.remove('change-theme');
|
||||
}, 500);
|
||||
|
||||
// Deep copy
|
||||
const _theme = JSON.parse(JSON.stringify(theme));
|
||||
|
||||
|
@ -20,6 +20,12 @@ html, body
|
||||
text-size-adjust 100%
|
||||
font-family sans-serif
|
||||
|
||||
html.change-theme
|
||||
&, *
|
||||
transition-property all
|
||||
transition-duration 0.5s
|
||||
transition-timing-function ease
|
||||
|
||||
a
|
||||
text-decoration none
|
||||
color var(--link)
|
||||
|
12
src/misc/check-svg.ts
Normal file
12
src/misc/check-svg.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import * as fs from 'fs';
|
||||
import * as isSvg from 'is-svg';
|
||||
|
||||
export default function(path: string) {
|
||||
try {
|
||||
const size = fs.statSync(path).size;
|
||||
if (size > 1 * 1024 * 1024) return false;
|
||||
return isSvg(fs.readFileSync(path));
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ export default class Resolver {
|
||||
}
|
||||
|
||||
if (this.history.has(value)) {
|
||||
logger.error(`cannot resolve already resolved one`);
|
||||
logger.error(`cannot resolve already resolved one: ${value}`);
|
||||
throw new Error('cannot resolve already resolved one');
|
||||
}
|
||||
|
||||
@ -65,7 +65,10 @@ export default class Resolver {
|
||||
},
|
||||
json: true
|
||||
}).catch(e => {
|
||||
logger.error(`request error: ${e.message}`);
|
||||
logger.error(`request error: ${value}: ${e.message}`, {
|
||||
url: value,
|
||||
e: e
|
||||
});
|
||||
throw new Error(`request error: ${e.message}`);
|
||||
});
|
||||
|
||||
@ -74,7 +77,10 @@ export default class Resolver {
|
||||
!object['@context'].includes('https://www.w3.org/ns/activitystreams') :
|
||||
object['@context'] !== 'https://www.w3.org/ns/activitystreams'
|
||||
)) {
|
||||
logger.error(`invalid response: ${value}`);
|
||||
logger.error(`invalid response: ${value}`, {
|
||||
url: value,
|
||||
object: object
|
||||
});
|
||||
throw new Error('invalid response');
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,11 @@ export default async (endpoint: string, user: IUser, app: IApp, data: any, file?
|
||||
if (e instanceof ApiError) {
|
||||
throw e;
|
||||
} else {
|
||||
apiLogger.error(e);
|
||||
apiLogger.error(`Internal error occurred in ${ep.name}`, {
|
||||
ep: ep.name,
|
||||
ps: data,
|
||||
e: e
|
||||
});
|
||||
throw new ApiError(null, {
|
||||
e: {
|
||||
message: e.message,
|
||||
|
@ -34,11 +34,27 @@ export default define(meta, async (ps) => {
|
||||
|
||||
if (ps.level) query.level = ps.level;
|
||||
if (ps.domain) {
|
||||
let i = 0;
|
||||
for (const d of ps.domain.split(' ')) {
|
||||
query[`domain.${i}`] = d;
|
||||
const qs: any[] = [];
|
||||
let i = 0;
|
||||
for (const sd of (d.startsWith('-') ? d.substr(1) : d).split('.')) {
|
||||
qs.push({
|
||||
[`domain.${i}`]: d.startsWith('-') ? { $ne: sd } : sd
|
||||
});
|
||||
i++;
|
||||
}
|
||||
if (d.startsWith('-')) {
|
||||
if (query['$and'] == null) query['$and'] = [];
|
||||
query['$and'].push({
|
||||
$and: qs
|
||||
});
|
||||
} else {
|
||||
if (query['$or'] == null) query['$or'] = [];
|
||||
query['$or'].push({
|
||||
$and: qs
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const logs = await Log
|
||||
|
@ -4,10 +4,10 @@ import * as tmp from 'tmp';
|
||||
import * as Koa from 'koa';
|
||||
import * as request from 'request';
|
||||
import * as fileType from 'file-type';
|
||||
import * as isSvg from 'is-svg';
|
||||
import { serverLogger } from '..';
|
||||
import config from '../../config';
|
||||
import { IImage, ConvertToPng } from '../../services/drive/image-processor';
|
||||
import checkSvg from '../../misc/check-svg';
|
||||
|
||||
export async function proxyMedia(ctx: Koa.BaseContext) {
|
||||
const url = 'url' in ctx.query ? ctx.query.url : 'https://' + ctx.params.url;
|
||||
@ -102,7 +102,7 @@ async function detectMine(path: string) {
|
||||
const type = fileType(buffer);
|
||||
if (type) {
|
||||
res([type.mime, type.ext]);
|
||||
} else if (isSvg(buffer)) {
|
||||
} else if (checkSvg(path)) {
|
||||
res(['image/svg+xml', 'svg']);
|
||||
} else {
|
||||
// 種類が同定できなかったら application/octet-stream にする
|
||||
|
@ -7,7 +7,6 @@ import * as Minio from 'minio';
|
||||
import * as uuid from 'uuid';
|
||||
import * as sharp from 'sharp';
|
||||
import * as fileType from 'file-type';
|
||||
import * as isSvg from 'is-svg';
|
||||
|
||||
import DriveFile, { IMetadata, getDriveFileBucket, IDriveFile } from '../../models/drive-file';
|
||||
import DriveFolder from '../../models/drive-folder';
|
||||
@ -26,6 +25,7 @@ import { GenerateVideoThumbnail } from './generate-video-thumbnail';
|
||||
import { driveLogger } from './logger';
|
||||
import { IImage, ConvertToJpeg, ConvertToWebp, ConvertToPng } from './image-processor';
|
||||
import Instance from '../../models/instance';
|
||||
import checkSvg from '../../misc/check-svg';
|
||||
|
||||
const logger = driveLogger.createSubLogger('register', 'yellow');
|
||||
|
||||
@ -311,7 +311,7 @@ export default async function(
|
||||
const type = fileType(buffer);
|
||||
if (type) {
|
||||
res([type.mime, type.ext]);
|
||||
} else if (isSvg(buffer)) {
|
||||
} else if (checkSvg(path)) {
|
||||
res(['image/svg+xml', 'svg']);
|
||||
} else {
|
||||
// 種類が同定できなかったら application/octet-stream にする
|
||||
@ -378,7 +378,7 @@ export default async function(
|
||||
return 0;
|
||||
});
|
||||
|
||||
logger.info(`drive usage is ${usage}`);
|
||||
logger.debug(`drive usage is ${usage}`);
|
||||
|
||||
const instance = await fetchMeta();
|
||||
const driveCapacity = 1024 * 1024 * (isLocalUser(user) ? instance.localDriveCapacityMb : instance.remoteDriveCapacityMb);
|
||||
|
@ -47,7 +47,10 @@ export default async (
|
||||
});
|
||||
|
||||
writable.on('error', error => {
|
||||
logger.error(error);
|
||||
logger.error(`Download failed: ${chalk.cyan(url)}: ${error}`, {
|
||||
url: url,
|
||||
e: error
|
||||
});
|
||||
rej(error);
|
||||
});
|
||||
|
||||
@ -73,7 +76,10 @@ export default async (
|
||||
});
|
||||
|
||||
req.on('error', error => {
|
||||
logger.error(error);
|
||||
logger.error(`Failed to start download: ${chalk.cyan(url)}: ${error}`, {
|
||||
url: url,
|
||||
e: error
|
||||
});
|
||||
writable.close();
|
||||
rej(error);
|
||||
});
|
||||
@ -87,7 +93,10 @@ export default async (
|
||||
logger.succ(`Got: ${driveFile._id}`);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
logger.error(`Failed: ${e}`);
|
||||
logger.error(`Failed to create drive file: ${e}`, {
|
||||
url: url,
|
||||
e: e
|
||||
});
|
||||
}
|
||||
|
||||
// clean-up
|
||||
|
Reference in New Issue
Block a user