Compare commits

...

17 Commits
5.6.1 ... 5.6.2

Author SHA1 Message Date
23c32f1211 5.6.2 2018-07-28 11:43:11 +09:00
c8a5d693ed Merge pull request #2012 from syuilo/l10n_master
New Crowdin translations
2018-07-28 11:42:18 +09:00
4a54d01ca8 Merge pull request #2015 from syuilo/greenkeeper/@types/node-10.5.4
Update @types/node to the latest version 🚀
2018-07-28 11:42:11 +09:00
359a7a7b98 Merge pull request #2014 from syuilo/greenkeeper/@types/koa-router-7.0.31
Update @types/koa-router to the latest version 🚀
2018-07-28 11:42:04 +09:00
aaa25deaa9 fix(package): update @types/node to version 10.5.4 2018-07-28 00:57:57 +00:00
cd07ae4d2e fix(package): update @types/koa-router to version 7.0.31 2018-07-28 00:48:10 +00:00
1e8c1efe2f Fix #2013 2018-07-28 07:56:33 +09:00
ce405fc4f6 Fix #2007 2018-07-28 07:52:48 +09:00
50a6efd568 Fix #2000 2018-07-28 07:38:29 +09:00
2c6f881093 管理者用パスワードリセットコマンドを実装 2018-07-28 04:02:52 +09:00
e4bf0392af クラスタ数を制限するオプションを追加 2018-07-28 03:55:41 +09:00
fcb9133f27 New translations ja.yml (French) 2018-07-27 22:12:20 +09:00
5c6f24dc39 Merge pull request #2011 from syuilo/greenkeeper/webpack-4.16.3
Update webpack to the latest version 🚀
2018-07-27 19:31:42 +09:00
ce562f3bca fix(package): update webpack to version 4.16.3 2018-07-27 10:24:24 +00:00
9ef477f04b Merge pull request #2010 from acid-chicken/acid-chicken-patch-1
Minify Mk-III
2018-07-27 19:17:15 +09:00
5268fee5b5 Fix bug 2018-07-27 19:15:38 +09:00
68e28faedc 2018-07-27 19:12:16 +09:00
14 changed files with 112 additions and 48 deletions

View File

@ -131,3 +131,6 @@ drive:
# Ghost account is an account used for the purpose of delegating # Ghost account is an account used for the purpose of delegating
# followers when putting users in the list. # followers when putting users in the list.
# ghost: user-id-of-your-ghost-account # ghost: user-id-of-your-ghost-account
# Clustering
# clusterLimit: 1

29
cli/reset-password.js Normal file
View File

@ -0,0 +1,29 @@
const mongo = require('mongodb');
const bcrypt = require('bcryptjs');
const User = require('../built/models/user').default;
const args = process.argv.slice(2);
const user = args[0];
const q = user.startsWith('@') ? {
username: user.split('@')[1],
host: user.split('@')[2] || null
} : { _id: new mongo.ObjectID(user) };
console.log(`Resetting password for ${user}...`);
const passwd = 'yo';
// Generate hash of password
const hash = bcrypt.hashSync(passwd);
User.update(q, {
$set: {
password: hash
}
}).then(() => {
console.log(`Password of ${user} is now '${passwd}'`);
}, e => {
console.error(e);
});

View File

@ -29,6 +29,11 @@ node cli/suspend @syuilo
node cli/suspend @syuilo@misskey.xyz node cli/suspend @syuilo@misskey.xyz
``` ```
## Reset password
``` shell
node cli/reset-password (User-ID or Username)
```
## Clean up cached remote files ## Clean up cached remote files
``` shell ``` shell
node cli/clean-cached-remote-files node cli/clean-cached-remote-files

View File

@ -29,6 +29,11 @@ node cli/suspend @syuilo
node cli/suspend @syuilo@misskey.xyz node cli/suspend @syuilo@misskey.xyz
``` ```
## ユーザーのパスワードをリセットする
``` shell
node cli/reset-password (ユーザーID または ユーザー名)
```
## キャッシュされたリモートファイルをクリーンアップする ## キャッシュされたリモートファイルをクリーンアップする
``` shell ``` shell
node cli/clean-cached-remote-files node cli/clean-cached-remote-files

View File

@ -218,8 +218,8 @@ common/views/components/visibility-chooser.vue:
public: "Public" public: "Public"
home: "Accueil" home: "Accueil"
home-desc: "Publier sur le fil d'Accueil uniquement" home-desc: "Publier sur le fil d'Accueil uniquement"
followers: "Abonnés" followers: "Abonné·e·s"
followers-desc: "Publier à vos abonnés uniquement" followers-desc: "Publier à vos abonné·e·s uniquement"
specified: "Direct" specified: "Direct"
specified-desc: "Publier aux utilisateurs mentionnés" specified-desc: "Publier aux utilisateurs mentionnés"
private: "Privé" private: "Privé"
@ -346,9 +346,9 @@ desktop/views/components/follow-button.vue:
request-pending: "En attente d'approbation" request-pending: "En attente d'approbation"
follow-request: "Demande d'abonnement" follow-request: "Demande d'abonnement"
desktop/views/components/followers-window.vue: desktop/views/components/followers-window.vue:
followers: "{} abonnés" followers: "{} abonné·e·s"
desktop/views/components/followers.vue: desktop/views/components/followers.vue:
empty: "Il semble que vous n'avez pas encore d'abonnés." empty: "Il semble que vous n'avez pas encore d'abonné·e·s."
desktop/views/components/following-window.vue: desktop/views/components/following-window.vue:
following: "Suit {}" following: "Suit {}"
desktop/views/components/following.vue: desktop/views/components/following.vue:
@ -604,7 +604,7 @@ desktop/views/components/user-lists-window.vue:
desktop/views/components/user-preview.vue: desktop/views/components/user-preview.vue:
notes: "Publications" notes: "Publications"
following: "Abonné à" following: "Abonné à"
followers: "Abonnés" followers: "Abonné·e·s"
desktop/views/components/users-list.vue: desktop/views/components/users-list.vue:
all: "Tout" all: "Tout"
iknow: "Vous connaissez" iknow: "Vous connaissez"
@ -650,7 +650,7 @@ desktop/views/pages/user-list.users.vue:
add-user: "Ajouter un utilisateur" add-user: "Ajouter un utilisateur"
username: "Nom d'utilisateur" username: "Nom d'utilisateur"
desktop/views/pages/user/user.followers-you-know.vue: desktop/views/pages/user/user.followers-you-know.vue:
title: "Abonnés que vous connaissez" title: "Abonné·e·s que vous connaissez"
loading: "Chargement en cours" loading: "Chargement en cours"
no-users: "Pas d'utilisateurs" no-users: "Pas d'utilisateurs"
desktop/views/pages/user/user.friends.vue: desktop/views/pages/user/user.friends.vue:
@ -678,7 +678,7 @@ desktop/views/pages/user/user.profile.vue:
desktop/views/pages/user/user.header.vue: desktop/views/pages/user/user.header.vue:
posts: "Notes" posts: "Notes"
following: "Suit" following: "Suit"
followers: "Abonnés" followers: "Abonné·e·s"
is-bot: "Ce compte est un Bot" is-bot: "Ce compte est un Bot"
desktop/views/pages/user/user.timeline.vue: desktop/views/pages/user/user.timeline.vue:
default: "Publications" default: "Publications"
@ -831,7 +831,7 @@ mobile/views/pages/drive.vue:
drive: "Drive" drive: "Drive"
more: "Afficher plus ..." more: "Afficher plus ..."
mobile/views/pages/followers.vue: mobile/views/pages/followers.vue:
followers-of: "Abonnés de {}" followers-of: "Abonné·e·s de {}"
mobile/views/pages/following.vue: mobile/views/pages/following.vue:
following-of: "Abonnements de {}" following-of: "Abonnements de {}"
mobile/views/pages/home.vue: mobile/views/pages/home.vue:
@ -914,7 +914,7 @@ mobile/views/pages/settings.vue:
mobile/views/pages/user.vue: mobile/views/pages/user.vue:
follows-you: "vous suit" follows-you: "vous suit"
following: "Abonnements" following: "Abonnements"
followers: "Abonnés" followers: "Abonné·e·s"
notes: "Posts" notes: "Posts"
overview: "Aperçu" overview: "Aperçu"
timeline: "Fil d'actualité" timeline: "Fil d'actualité"
@ -929,7 +929,7 @@ mobile/views/pages/user/home.vue:
keywords: "Mot clés" keywords: "Mot clés"
domains: "Domaines" domains: "Domaines"
frequently-replied-users: "Utilisateurs qui interagissent souvent" frequently-replied-users: "Utilisateurs qui interagissent souvent"
followers-you-know: "Abonnés que vous connaissez" followers-you-know: "Abonné·e·s que vous connaissez"
last-used-at: "Dernière connexion il y a" last-used-at: "Dernière connexion il y a"
mobile/views/pages/user/home.followers-you-know.vue: mobile/views/pages/user/home.followers-you-know.vue:
loading: "Chargement" loading: "Chargement"

View File

@ -1,8 +1,8 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "5.6.1", "version": "5.6.2",
"clientVersion": "1.0.7624", "clientVersion": "1.0.7643",
"codename": "nighthike", "codename": "nighthike",
"main": "./built/index.js", "main": "./built/index.js",
"private": true, "private": true,
@ -51,7 +51,7 @@
"@types/koa-logger": "3.1.0", "@types/koa-logger": "3.1.0",
"@types/koa-mount": "3.0.1", "@types/koa-mount": "3.0.1",
"@types/koa-multer": "1.0.0", "@types/koa-multer": "1.0.0",
"@types/koa-router": "7.0.30", "@types/koa-router": "7.0.31",
"@types/koa-send": "4.1.1", "@types/koa-send": "4.1.1",
"@types/koa-views": "2.0.3", "@types/koa-views": "2.0.3",
"@types/koa__cors": "2.2.2", "@types/koa__cors": "2.2.2",
@ -60,7 +60,7 @@
"@types/mocha": "5.2.3", "@types/mocha": "5.2.3",
"@types/mongodb": "3.1.2", "@types/mongodb": "3.1.2",
"@types/ms": "0.7.30", "@types/ms": "0.7.30",
"@types/node": "10.5.3", "@types/node": "10.5.4",
"@types/parse5": "5.0.0", "@types/parse5": "5.0.0",
"@types/portscanner": "2.1.0", "@types/portscanner": "2.1.0",
"@types/pug": "2.0.4", "@types/pug": "2.0.4",
@ -214,7 +214,7 @@
"vuex-persistedstate": "2.5.4", "vuex-persistedstate": "2.5.4",
"web-push": "3.3.2", "web-push": "3.3.2",
"webfinger.js": "2.6.6", "webfinger.js": "2.6.6",
"webpack": "4.16.2", "webpack": "4.16.3",
"webpack-cli": "3.1.0", "webpack-cli": "3.1.0",
"websocket": "1.0.26", "websocket": "1.0.26",
"ws": "6.0.0", "ws": "6.0.0",

View File

@ -69,25 +69,25 @@ class Autocomplete {
*/ */
private onInput() { private onInput() {
const caretPos = this.textarea.selectionStart; const caretPos = this.textarea.selectionStart;
const text = this.text.substr(0, caretPos); const text = this.text.substr(0, caretPos).split('\n').pop();
const mentionIndex = text.lastIndexOf('@'); const mentionIndex = text.lastIndexOf('@');
const hashtagIndex = text.lastIndexOf('#'); const hashtagIndex = text.lastIndexOf('#');
const emojiIndex = text.lastIndexOf(':'); const emojiIndex = text.lastIndexOf(':');
const start = Math.min( const max = Math.max(
mentionIndex == -1 ? Infinity : mentionIndex, mentionIndex,
hashtagIndex == -1 ? Infinity : hashtagIndex, hashtagIndex,
emojiIndex == -1 ? Infinity : emojiIndex); emojiIndex);
if (start == Infinity) { if (max == -1) {
this.close(); this.close();
return; return;
} }
const isMention = mentionIndex == start; const isMention = mentionIndex != -1;
const isHashtag = hashtagIndex == start; const isHashtag = hashtagIndex != -1;
const isEmoji = emojiIndex == start; const isEmoji = emojiIndex != -1;
let opened = false; let opened = false;
@ -99,15 +99,15 @@ class Autocomplete {
} }
} }
if (isHashtag || opened == false) { if (isHashtag && opened == false) {
const hashtag = text.substr(hashtagIndex + 1); const hashtag = text.substr(hashtagIndex + 1);
if (!hashtag.includes(' ') && !hashtag.includes('\n')) { if (!hashtag.includes(' ')) {
this.open('hashtag', hashtag); this.open('hashtag', hashtag);
opened = true; opened = true;
} }
} }
if (isEmoji || opened == false) { if (isEmoji && opened == false) {
const emoji = text.substr(emojiIndex + 1); const emoji = text.substr(emojiIndex + 1);
if (emoji != '' && emoji.match(/^[\+\-a-z0-9_]+$/)) { if (emoji != '' && emoji.match(/^[\+\-a-z0-9_]+$/)) {
this.open('emoji', emoji); this.open('emoji', emoji);

View File

@ -110,8 +110,8 @@ export default Vue.extend({
this.cpuPolylinePoints = cpuPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' '); this.cpuPolylinePoints = cpuPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
this.memPolylinePoints = memPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' '); this.memPolylinePoints = memPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
this.cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.cpuPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`; this.cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${this.viewBoxY} ${this.cpuPolylinePoints} ${this.viewBoxX},${this.viewBoxY}`;
this.memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.memPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`; this.memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${this.viewBoxY} ${this.memPolylinePoints} ${this.viewBoxX},${this.viewBoxY}`;
this.cpuHeadX = cpuPolylinePoints[cpuPolylinePoints.length - 1][0]; this.cpuHeadX = cpuPolylinePoints[cpuPolylinePoints.length - 1][0];
this.cpuHeadY = cpuPolylinePoints[cpuPolylinePoints.length - 1][1]; this.cpuHeadY = cpuPolylinePoints[cpuPolylinePoints.length - 1][1];

View File

@ -35,7 +35,7 @@ import Vue from 'vue';
const eachMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; const eachMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
function isLeapYear(year) { function isLeapYear(year) {
return !(year & (year % 25 ? 3 : 5)); return !(year & (year % 25 ? 3 : 15));
} }
export default Vue.extend({ export default Vue.extend({

View File

@ -92,6 +92,8 @@ export type Source = {
}; };
google_maps_api_key: string; google_maps_api_key: string;
clusterLimit?: number;
}; };
/** /**

View File

@ -66,7 +66,7 @@ async function masterMain() {
Logger.succ('Misskey initialized'); Logger.succ('Misskey initialized');
spawnWorkers(() => { spawnWorkers(config.clusterLimit, () => {
Logger.succ('All workers started'); Logger.succ('All workers started');
Logger.info(`Now listening on port ${config.port} on ${config.url}`); Logger.info(`Now listening on port ${config.port} on ${config.url}`);
}); });
@ -137,14 +137,16 @@ async function init(): Promise<Config> {
return config; return config;
} }
function spawnWorkers(onComplete: Function) { function spawnWorkers(limit: number, onComplete: Function) {
// Count the machine's CPUs // Count the machine's CPUs
const cpuCount = os.cpus().length; const cpuCount = os.cpus().length;
const progress = new ProgressBar(cpuCount, 'Starting workers'); const count = limit || cpuCount;
const progress = new ProgressBar(count, 'Starting workers');
// Create a worker for each CPU // Create a worker for each CPU
for (let i = 0; i < cpuCount; i++) { for (let i = 0; i < count; i++) {
const worker = cluster.fork(); const worker = cluster.fork();
worker.on('message', message => { worker.on('message', message => {
if (message === 'ready') { if (message === 'ready') {

View File

@ -50,6 +50,7 @@ type IUserBase = {
avatarUrl?: string; avatarUrl?: string;
bannerUrl?: string; bannerUrl?: string;
wallpaperId: mongo.ObjectID; wallpaperId: mongo.ObjectID;
wallpaperUrl?: string;
data: any; data: any;
description: string; description: string;
pinnedNoteId: mongo.ObjectID; pinnedNoteId: mongo.ObjectID;
@ -400,21 +401,19 @@ export const pack = (
} }
if (_user.avatarUrl == null) { if (_user.avatarUrl == null) {
_user.avatarUrl = _user.avatarId != null _user.avatarUrl = `${config.drive_url}/default-avatar.jpg`;
? `${config.drive_url}/${_user.avatarId}`
: `${config.drive_url}/default-avatar.jpg`; // 互換性のため
if (_user.avatarId) {
_user.avatarUrl = `${config.drive_url}/${_user.avatarId}`;
}
} }
if (_user.bannerUrl == null) { // 互換性のため
_user.bannerUrl = _user.bannerId != null if (_user.bannerId && _user.bannerUrl == null) {
? `${config.drive_url}/${_user.bannerId}` _user.bannerUrl = `${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) { if (!meId || !meId.equals(_user.id) || !opts.detail) {
delete _user.avatarId; delete _user.avatarId;
delete _user.bannerId; delete _user.bannerId;

View File

@ -4,6 +4,7 @@ import event from '../../../../stream';
import DriveFile from '../../../../models/drive-file'; import DriveFile from '../../../../models/drive-file';
import acceptAllFollowRequests from '../../../../services/following/requests/accept-all'; import acceptAllFollowRequests from '../../../../services/following/requests/accept-all';
import { IApp } from '../../../../models/app'; import { IApp } from '../../../../models/app';
import config from '../../../../config';
export const meta = { export const meta = {
desc: { desc: {
@ -81,7 +82,11 @@ export default async (params: any, user: ILocalUser, app: IApp) => new Promise(a
_id: avatarId _id: avatarId
}); });
if (avatar != null && avatar.metadata.properties.avgColor) { if (avatar == null) return rej('avatar not found');
updates.avatarUrl = avatar.metadata.url || `${config.drive_url}/${avatar._id}`;
if (avatar.metadata.properties.avgColor) {
updates.avatarColor = avatar.metadata.properties.avgColor; updates.avatarColor = avatar.metadata.properties.avgColor;
} }
} }
@ -91,7 +96,11 @@ export default async (params: any, user: ILocalUser, app: IApp) => new Promise(a
_id: bannerId _id: bannerId
}); });
if (banner != null && banner.metadata.properties.avgColor) { if (banner == null) return rej('banner not found');
updates.bannerUrl = banner.metadata.url || `${config.drive_url}/${banner._id}`;
if (banner.metadata.properties.avgColor) {
updates.bannerColor = banner.metadata.properties.avgColor; updates.bannerColor = banner.metadata.properties.avgColor;
} }
} }
@ -101,7 +110,11 @@ export default async (params: any, user: ILocalUser, app: IApp) => new Promise(a
_id: wallpaperId _id: wallpaperId
}); });
if (wallpaper != null && wallpaper.metadata.properties.avgColor) { if (wallpaper == null) return rej('wallpaper not found');
updates.wallpaperUrl = wallpaper.metadata.url || `${config.drive_url}/${wallpaper._id}`;
if (wallpaper.metadata.properties.avgColor) {
updates.wallpaperColor = wallpaper.metadata.properties.avgColor; updates.wallpaperColor = wallpaper.metadata.properties.avgColor;
} }
} }

View File

@ -66,6 +66,12 @@ export default async function(followee: IUser, follower: IUser) {
}); });
//#endregion //#endregion
await User.update({ _id: followee._id }, {
$inc: {
pendingReceivedFollowRequestsCount: -1
}
});
packUser(followee, followee, { packUser(followee, followee, {
detail: true detail: true
}).then(packed => event(followee._id, 'meUpdated', packed)); }).then(packed => event(followee._id, 'meUpdated', packed));