1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-07-10 13:54:47 +02:00

Compare commits

..

7 Commits

Author SHA1 Message Date
syuilo
86b0dfdd33 2.29.0 2018-06-07 06:16:11 +09:00
syuilo
ab04f2fce0 ✌️ 2018-06-07 06:15:57 +09:00
syuilo
be9f836b21 やった 2018-06-07 06:13:57 +09:00
syuilo
818bc96aab 2.28.0 2018-06-07 05:15:05 +09:00
syuilo
14d12c21f2 nanka iroiro 2018-06-07 05:14:37 +09:00
syuilo
2053a041e5 Fix 2018-06-07 04:33:39 +09:00
syuilo
0534a0a41e ✌️ 2018-06-07 04:31:49 +09:00
19 changed files with 227 additions and 24 deletions

View File

@@ -3,16 +3,21 @@ const User = require('../built/models/user').default;
const args = process.argv.slice(2);
const userId = new mongo.ObjectID(args[0]);
const user = args[0];
console.log(`Suspending ${userId}...`);
const q = user.startsWith('@') ? {
username: user.split('@')[1],
host: user.split('@')[2] || null
} : { _id: new mongo.ObjectID(user) };
User.update({ _id: userId }, {
console.log(`Suspending ${user}...`);
User.update(q, {
$set: {
isSuspended: true
}
}).then(() => {
console.log(`Suspended ${userId}`);
console.log(`Suspended ${user}`);
}, e => {
console.error(e);
});

View File

@@ -87,6 +87,7 @@ common:
swap-right: "右に移動"
remove: "カラムを削除"
add-column: "カラムを追加"
rename: "名前を変更"
common/views/components/connect-failed.vue:
title: "サーバーに接続できません"

View File

@@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "2.27.3",
"clientVersion": "1.0.6188",
"version": "2.29.0",
"clientVersion": "1.0.6195",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,

View File

@@ -40,6 +40,8 @@
<button class="ui button" @click="customizeHome" style="margin-bottom: 16px">%i18n:@customize%</button>
</div>
<div class="div">
<button class="ui" @click="updateWallpaper">%i18n:@choose-wallpaper%</button>
<button class="ui" @click="deleteWallpaper">%i18n:@delete-wallpaper%</button>
<mk-switch v-model="darkmode" text="%i18n:@dark-mode%"/>
<mk-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons" text="%i18n:@circle-icons%"/>
<mk-switch v-model="$store.state.settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/>
@@ -293,6 +295,20 @@ export default Vue.extend({
this.$router.push('/i/customize-home');
this.$emit('done');
},
updateWallpaper() {
(this as any).apis.chooseDriveFile({
multiple: false
}).then(file => {
(this as any).api('i/update', {
wallpaperId: file.id
});
});
},
deleteWallpaper() {
(this as any).api('i/update', {
wallpaperId: null
});
},
onChangeFetchOnScroll(v) {
this.$store.dispatch('settings/set', {
key: 'fetchOnScroll',

View File

@@ -1,5 +1,5 @@
<template>
<div class="mk-ui">
<div class="mk-ui" :style="style">
<x-header class="header"/>
<div class="content">
<slot></slot>
@@ -16,6 +16,15 @@ export default Vue.extend({
components: {
XHeader
},
computed: {
style(): any {
if (!this.$store.getters.isSignedIn || this.$store.state.i.wallpaperUrl == null) return {};
return {
backgroundColor: this.$store.state.i.wallpaperColor && this.$store.state.i.wallpaperColor.length == 3 ? `rgb(${ this.$store.state.i.wallpaperColor.join(',') })` : null,
backgroundImage: `url(${ this.$store.state.i.wallpaperUrl })`
};
}
},
mounted() {
document.addEventListener('keydown', this.onKeydown);
},
@@ -40,6 +49,9 @@ export default Vue.extend({
display flex
flex-direction column
flex 1
background-size cover
background-position center
background-attachment fixed
> .header
@media (max-width 1000px)

View File

@@ -20,6 +20,10 @@ export default Vue.extend({
type: String,
required: false
},
name: {
type: String,
required: false
},
menu: {
type: Array,
required: false
@@ -75,6 +79,17 @@ export default Vue.extend({
showMenu() {
const items = [{
content: '%fa:pencil-alt% %i18n:common.deck.rename%',
onClick: () => {
(this as any).apis.input({
title: '%i18n:common.deck.rename%',
default: this.name,
allowEmpty: false
}).then(name => {
this.$store.dispatch('settings/renameDeckColumn', { id: this.id, name });
});
}
}, null, {
content: '%fa:arrow-left% %i18n:common.deck.swap-left%',
onClick: () => {
this.$store.dispatch('settings/swapLeftDeckColumn', this.id);
@@ -84,7 +99,7 @@ export default Vue.extend({
onClick: () => {
this.$store.dispatch('settings/swapRightDeckColumn', this.id);
}
}, {
}, null, {
content: '%fa:trash-alt R% %i18n:common.deck.remove%',
onClick: () => {
this.$store.dispatch('settings/removeDeckColumn', this.id);
@@ -140,6 +155,7 @@ root(isDark)
z-index 1
line-height $header-height
padding 0 16px
font-size 14px
color isDark ? #e3e5e8 : #888
background isDark ? #313543 : #fff
box-shadow 0 1px rgba(#000, 0.15)

View File

@@ -18,6 +18,11 @@ export default Vue.extend({
list: {
type: Object,
required: true
},
mediaOnly: {
type: Boolean,
required: false,
default: false
}
},
@@ -30,6 +35,12 @@ export default Vue.extend({
};
},
watch: {
mediaOnly() {
this.fetch();
}
},
mounted() {
if (this.connection) this.connection.close();
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
@@ -52,6 +63,7 @@ export default Vue.extend({
(this as any).api('notes/user-list-timeline', {
listId: this.list.id,
limit: fetchLimit + 1,
mediaOnly: this.mediaOnly,
includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => {
@@ -72,6 +84,7 @@ export default Vue.extend({
listId: this.list.id,
limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id,
mediaOnly: this.mediaOnly,
includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
});
@@ -89,6 +102,8 @@ export default Vue.extend({
return promise;
},
onNote(note) {
if (this.mediaOnly && note.media.length == 0) return;
// Prepend a note
(this.$refs.timeline as any).prepend(note);
},

View File

@@ -1,7 +1,7 @@
<template>
<div>
<x-column :id="id">
<span slot="header">%fa:bell R%%i18n:common.deck.notifications%</span>
<x-column :id="column.id" :name="name">
<span slot="header">%fa:bell R%{{ name }}</span>
<x-notifications/>
</x-column>
@@ -20,10 +20,17 @@ export default Vue.extend({
},
props: {
id: {
type: String,
column: {
type: Object,
required: true
}
}
},
computed: {
name(): string {
if (this.column.name) return this.column.name;
return '%i18n:common.deck.notifications%';
}
},
});
</script>

View File

@@ -1,15 +1,20 @@
<template>
<div>
<x-column :id="column.id">
<x-column :id="column.id" :menu="menu" :name="name">
<span slot="header">
<template v-if="column.type == 'home'">%fa:home%%i18n:common.deck.home%</template>
<template v-if="column.type == 'local'">%fa:R comments%%i18n:common.deck.local%</template>
<template v-if="column.type == 'global'">%fa:globe%%i18n:common.deck.global%</template>
<template v-if="column.type == 'list'">%fa:list%{{ column.list.title }}</template>
<template v-if="column.type == 'home'">%fa:home%</template>
<template v-if="column.type == 'local'">%fa:R comments%</template>
<template v-if="column.type == 'global'">%fa:globe%</template>
<template v-if="column.type == 'list'">%fa:list%</template>
<span>{{ name }}</span>
</span>
<x-list-tl v-if="column.type == 'list'" :list="column.list"/>
<x-tl v-else :src="column.type"/>
<div class="editor" v-if="edit">
<mk-switch v-model="column.isMediaOnly" @change="onChangeSettings" text="%i18n:@is-media-only%"/>
<mk-switch v-model="column.isMediaView" @change="onChangeSettings" text="%i18n:@is-media-view%"/>
</div>
<x-list-tl v-if="column.type == 'list'" :list="column.list" :media-only="column.isMediaOnly"/>
<x-tl v-else :src="column.type" :media-only="column.isMediaOnly"/>
</x-column>
</div>
</template>
@@ -32,6 +37,37 @@ export default Vue.extend({
type: Object,
required: true
}
},
data() {
return {
edit: false,
menu: [{
content: '%fa:cog% %i18n:@edit%',
onClick: () => {
this.edit = !this.edit;
}
}]
}
},
computed: {
name(): string {
if (this.column.name) return this.column.name;
switch (this.column.type) {
case 'home': return '%i18n:common.deck.home%';
case 'local': return '%i18n:common.deck.local%';
case 'global': return '%i18n:common.deck.global%';
case 'list': return this.column.list.title;
}
}
},
methods: {
onChangeSettings(v) {
this.$store.dispatch('settings/saveDeck');
}
}
});
</script>

View File

@@ -18,6 +18,11 @@ export default Vue.extend({
type: String,
required: false,
default: 'home'
},
mediaOnly: {
type: Boolean,
required: false,
default: false
}
},
@@ -31,6 +36,12 @@ export default Vue.extend({
};
},
watch: {
mediaOnly() {
this.fetch();
}
},
computed: {
stream(): any {
return this.src == 'home'
@@ -78,6 +89,7 @@ export default Vue.extend({
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
(this as any).api(this.endpoint, {
limit: fetchLimit + 1,
mediaOnly: this.mediaOnly,
includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => {
@@ -97,6 +109,7 @@ export default Vue.extend({
const promise = (this as any).api(this.endpoint, {
limit: fetchLimit + 1,
mediaOnly: this.mediaOnly,
untilId: (this.$refs.timeline as any).tail().id,
includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
@@ -116,6 +129,8 @@ export default Vue.extend({
},
onNote(note) {
if (this.mediaOnly && note.media.length == 0) return;
// Prepend a note
(this.$refs.timeline as any).prepend(note);
},

View File

@@ -3,7 +3,7 @@
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode">
<template v-for="column in columns">
<x-widgets-column v-if="column.type == 'widgets'" :key="column.id" :column="column"/>
<x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :id="column.id"/>
<x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :column="column"/>
<x-tl-column v-if="column.type == 'home'" :key="column.id" :column="column"/>
<x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/>
<x-tl-column v-if="column.type == 'global'" :key="column.id" :column="column"/>
@@ -150,7 +150,6 @@ export default Vue.extend({
root(isDark)
display flex
flex 1
justify-content center
padding 16px 0 16px 16px
overflow auto
@@ -160,6 +159,13 @@ root(isDark)
&:last-of-type
margin-right 0
> *
&:first-child
margin-left auto
&:last-child
margin-right auto
> button
padding 0 16px
color isDark ? #93a0a5 : #888

View File

@@ -1,7 +1,7 @@
<template>
<div class="wtdtxvecapixsepjtcupubtsmometobz">
<x-column :id="column.id" :menu="menu" :naked="true" :narrow="true">
<span slot="header">%fa:calculator%%i18n:common.deck.widgets%</span>
<x-column :id="column.id" :menu="menu" :naked="true" :narrow="true" :name="name">
<span slot="header">%fa:calculator%{{ name }}</span>
<div class="gqpwvtwtprsbmnssnbicggtwqhmylhnq">
<template v-if="edit">
@@ -81,6 +81,13 @@ export default Vue.extend({
}
},
computed: {
name(): string {
if (this.column.name) return this.column.name;
return '%i18n:common.deck.widgets%';
}
},
created() {
this.menu = [{
content: '%fa:cog% %i18n:@edit%',

View File

@@ -222,6 +222,12 @@ export default (os: MiOS) => new Vuex.Store({
const column = state.deck.columns.find(c => c.id == x.id);
if (column == null) return;
column.widgets = column.widgets.filter(w => w.id != x.widget.id);
},
renameDeckColumn(state, x) {
const column = state.deck.columns.find(c => c.id == x.id);
if (column == null) return;
column.name = x.name;
}
},
@@ -281,6 +287,11 @@ export default (os: MiOS) => new Vuex.Store({
ctx.dispatch('saveDeck');
},
renameDeckColumn(ctx, x) {
ctx.commit('renameDeckColumn', x);
ctx.dispatch('saveDeck');
},
addHomeWidget(ctx, widget) {
ctx.commit('addHomeWidget', widget);

View File

@@ -48,6 +48,7 @@ type IUserBase = {
usernameLower: string;
avatarId: mongo.ObjectID;
bannerId: mongo.ObjectID;
wallpaperId: mongo.ObjectID;
data: any;
description: string;
pinnedNoteId: mongo.ObjectID;
@@ -412,6 +413,10 @@ export const pack = (
? `${config.drive_url}/${_user.bannerId}`
: null;
_user.wallpaperUrl = _user.wallpaperId != null
? `${config.drive_url}/${_user.wallpaperId}`
: null;
if (!meId || !meId.equals(_user.id) || !opts.detail) {
delete _user.avatarId;
delete _user.bannerId;

View File

@@ -45,6 +45,11 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
if (bannerIdErr) return rej('invalid bannerId param');
if (bannerId !== undefined) updates.bannerId = bannerId;
// Get 'wallpaperId' parameter
const [wallpaperId, wallpaperIdErr] = $.type(ID).optional().nullable().get(params.wallpaperId);
if (wallpaperIdErr) return rej('invalid wallpaperId param');
if (wallpaperId !== undefined) updates.wallpaperId = wallpaperId;
// Get 'isLocked' parameter
const [isLocked, isLockedErr] = $.bool.optional().get(params.isLocked);
if (isLockedErr) return rej('invalid isLocked param');
@@ -85,6 +90,16 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
}
}
if (wallpaperId) {
const wallpaper = await DriveFile.findOne({
_id: wallpaperId
});
if (wallpaper != null && wallpaper.metadata.properties.avgColor) {
updates.wallpaperColor = wallpaper.metadata.properties.avgColor;
}
}
await User.update(user._id, {
$set: updates
});

View File

@@ -35,6 +35,10 @@ module.exports = async (params, user) => {
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
}
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
// ミュートしているユーザーを取得
const mutedUserIds = user ? (await Mute.find({
muterId: user._id
@@ -64,6 +68,10 @@ module.exports = async (params, user) => {
};
}
if (mediaOnly) {
query.mediaIds = { $exists: true, $ne: [] };
}
if (sinceId) {
sort._id = 1;
query._id = {

View File

@@ -35,6 +35,10 @@ module.exports = async (params, user) => {
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
}
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
// ミュートしているユーザーを取得
const mutedUserIds = user ? (await Mute.find({
muterId: user._id
@@ -67,6 +71,10 @@ module.exports = async (params, user) => {
};
}
if (mediaOnly) {
query.mediaIds = { $exists: true, $ne: [] };
}
if (sinceId) {
sort._id = 1;
query._id = {

View File

@@ -44,6 +44,10 @@ module.exports = async (params, user, app) => {
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
const [followings, mutedUserIds] = await Promise.all([
// フォローを取得
// Fetch following
@@ -137,6 +141,12 @@ module.exports = async (params, user, app) => {
});
}
if (mediaOnly) {
query.$and.push({
mediaIds: { $exists: true, $ne: [] }
});
}
if (sinceId) {
sort._id = 1;
query._id = {

View File

@@ -44,6 +44,10 @@ module.exports = async (params, user, app) => {
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
// Get 'listId' parameter
const [listId, listIdErr] = $.type(ID).get(params.listId);
if (listIdErr) throw 'invalid listId param';
@@ -146,6 +150,12 @@ module.exports = async (params, user, app) => {
});
}
if (mediaOnly) {
query.$and.push({
mediaIds: { $exists: true, $ne: [] }
});
}
if (sinceId) {
sort._id = 1;
query._id = {