From 78487934c7e55b36b07f30b73127577ddec31f32 Mon Sep 17 00:00:00 2001 From: otofune Date: Sun, 5 Nov 2017 21:11:16 +0900 Subject: selializers - posts: unneed async-await Promise.all resolves all Promise, and selializeDriveFile returns Promise. --- src/api/serializers/post.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index 7c3690ef79..b2c54e9df8 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -84,8 +84,8 @@ const self = ( // Populate media if (_post.media_ids) { - _post.media = await Promise.all(_post.media_ids.map(async fileId => - await serializeDriveFile(fileId) + _post.media = await Promise.all(_post.media_ids.map(fileId => + serializeDriveFile(fileId) )); } -- cgit v1.2.3-freya From 11190f56ad85a12faaa3653f8743dd75948ff11e Mon Sep 17 00:00:00 2001 From: otofune Date: Sun, 5 Nov 2017 22:13:28 +0900 Subject: serializers/post - run promises in parallel now w/ opts.detail, returns my_reaction field as 'null' w/ no reaction (before: field appears w/ some reaction) --- package.json | 1 + src/api/serializers/post.ts | 128 +++++++++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/package.json b/package.json index 051eb1cb83..1e6e8d8136 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "webpack": "3.8.1" }, "dependencies": { + "@prezzemolo/rap": "^0.1.0", "accesses": "2.5.0", "animejs": "2.2.0", "autwh": "0.0.1", diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index b2c54e9df8..352932acff 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -12,6 +12,7 @@ import serializeChannel from './channel'; import serializeUser from './user'; import serializeDriveFile from './drive-file'; import parse from '../common/text'; +import rap from '@prezzemolo/rap' /** * Serialize a post @@ -70,21 +71,21 @@ const self = ( } // Populate user - _post.user = await serializeUser(_post.user_id, meId); + _post.user = serializeUser(_post.user_id, meId); // Populate app if (_post.app_id) { - _post.app = await serializeApp(_post.app_id); + _post.app = serializeApp(_post.app_id); } // Populate channel if (_post.channel_id) { - _post.channel = await serializeChannel(_post.channel_id); + _post.channel = serializeChannel(_post.channel_id); } // Populate media if (_post.media_ids) { - _post.media = await Promise.all(_post.media_ids.map(fileId => + _post.media = Promise.all(_post.media_ids.map(fileId => serializeDriveFile(fileId) )); } @@ -92,82 +93,97 @@ const self = ( // When requested a detailed post data if (opts.detail) { // Get previous post info - const prev = await Post.findOne({ - user_id: _post.user_id, - _id: { - $lt: id - } - }, { - fields: { - _id: true - }, - sort: { - _id: -1 - } - }); - _post.prev = prev ? prev._id : null; + _post.prev = (async () => { + const prev = Post.findOne({ + user_id: _post.user_id, + _id: { + $lt: id + } + }, { + fields: { + _id: true + }, + sort: { + _id: -1 + } + }); + return prev ? prev._id : null; + })() // Get next post info - const next = await Post.findOne({ - user_id: _post.user_id, - _id: { - $gt: id - } - }, { - fields: { - _id: true - }, - sort: { - _id: 1 - } - }); - _post.next = next ? next._id : null; + _post.next = (async () => { + const next = await Post.findOne({ + user_id: _post.user_id, + _id: { + $gt: id + } + }, { + fields: { + _id: true + }, + sort: { + _id: 1 + } + }); + return next ? next._id : null; + })() if (_post.reply_id) { // Populate reply to post - _post.reply = await self(_post.reply_id, meId, { + _post.reply = self(_post.reply_id, meId, { detail: false }); } if (_post.repost_id) { // Populate repost - _post.repost = await self(_post.repost_id, meId, { + _post.repost = self(_post.repost_id, meId, { detail: _post.text == null }); } // Poll if (meId && _post.poll) { - const vote = await Vote - .findOne({ - user_id: meId, - post_id: id - }); - - if (vote != null) { - const myChoice = _post.poll.choices - .filter(c => c.id == vote.choice)[0]; - - myChoice.is_voted = true; - } + _post.poll = (async (poll) => { + const vote = await Vote + .findOne({ + user_id: meId, + post_id: id + }); + + if (vote != null) { + const myChoice = poll.choices + .filter(c => c.id == vote.choice)[0]; + + myChoice.is_voted = true; + } + + return poll + })(_post.poll) } // Fetch my reaction if (meId) { - const reaction = await Reaction - .findOne({ - user_id: meId, - post_id: id, - deleted_at: { $exists: false } - }); - - if (reaction) { - _post.my_reaction = reaction.reaction; - } + _post.my_reaction = (async () => { + const reaction = await Reaction + .findOne({ + user_id: meId, + post_id: id, + deleted_at: { $exists: false } + }); + + if (reaction) { + return reaction.reaction; + } + + return null + })(); } } + // resolve promises in _post object + _post = await rap(_post) + resolve(_post); }); -- cgit v1.2.3-freya From 5aa5e5cc7074003cec3417636ea1972b6d88150d Mon Sep 17 00:00:00 2001 From: otofune Date: Sun, 5 Nov 2017 22:22:49 +0900 Subject: serializers - user: run promises in parallel as possible --- src/api/serializers/post.ts | 2 +- src/api/serializers/user.ts | 40 +++++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index 352932acff..99e9bb667c 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -12,7 +12,7 @@ import serializeChannel from './channel'; import serializeUser from './user'; import serializeDriveFile from './drive-file'; import parse from '../common/text'; -import rap from '@prezzemolo/rap' +import rap from '@prezzemolo/rap'; /** * Serialize a post diff --git a/src/api/serializers/user.ts b/src/api/serializers/user.ts index 3deff2d003..3527921ded 100644 --- a/src/api/serializers/user.ts +++ b/src/api/serializers/user.ts @@ -8,6 +8,7 @@ import serializePost from './post'; import Following from '../models/following'; import getFriends from '../common/get-friends'; import config from '../../conf'; +import rap from '@prezzemolo/rap'; /** * Serialize a user @@ -104,26 +105,30 @@ export default ( if (meId && !meId.equals(_user.id)) { // If the user is following - const follow = await Following.findOne({ - follower_id: meId, - followee_id: _user.id, - deleted_at: { $exists: false } - }); - _user.is_following = follow !== null; + _user.is_following = (async () => { + const follow = await Following.findOne({ + follower_id: meId, + followee_id: _user.id, + deleted_at: { $exists: false } + }); + return follow !== null; + })() // If the user is followed - const follow2 = await Following.findOne({ - follower_id: _user.id, - followee_id: meId, - deleted_at: { $exists: false } - }); - _user.is_followed = follow2 !== null; + _user.is_followed = (async () => { + const follow2 = await Following.findOne({ + follower_id: _user.id, + followee_id: meId, + deleted_at: { $exists: false } + }); + return follow2 !== null; + })() } if (opts.detail) { if (_user.pinned_post_id) { // Populate pinned post - _user.pinned_post = await serializePost(_user.pinned_post_id, meId, { + _user.pinned_post = serializePost(_user.pinned_post_id, meId, { detail: true }); } @@ -132,23 +137,24 @@ export default ( const myFollowingIds = await getFriends(meId); // Get following you know count - const followingYouKnowCount = await Following.count({ + _user.following_you_know_count = Following.count({ followee_id: { $in: myFollowingIds }, follower_id: _user.id, deleted_at: { $exists: false } }); - _user.following_you_know_count = followingYouKnowCount; // Get followers you know count - const followersYouKnowCount = await Following.count({ + _user.followers_you_know_count = Following.count({ followee_id: _user.id, follower_id: { $in: myFollowingIds }, deleted_at: { $exists: false } }); - _user.followers_you_know_count = followersYouKnowCount; } } + // resolve promises in _user object + _user = await rap(_user) + resolve(_user); }); /* -- cgit v1.2.3-freya From 7cd6b1c666605c7a256e4a8dd8db5edeb02da6db Mon Sep 17 00:00:00 2001 From: otofune Date: Sun, 5 Nov 2017 22:26:16 +0900 Subject: follow lint --- src/api/serializers/post.ts | 12 ++++++------ src/api/serializers/user.ts | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index 99e9bb667c..e1ab784359 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -108,7 +108,7 @@ const self = ( } }); return prev ? prev._id : null; - })() + })(); // Get next post info _post.next = (async () => { @@ -126,7 +126,7 @@ const self = ( } }); return next ? next._id : null; - })() + })(); if (_post.reply_id) { // Populate reply to post @@ -158,8 +158,8 @@ const self = ( myChoice.is_voted = true; } - return poll - })(_post.poll) + return poll; + })(_post.poll); } // Fetch my reaction @@ -176,13 +176,13 @@ const self = ( return reaction.reaction; } - return null + return null; })(); } } // resolve promises in _post object - _post = await rap(_post) + _post = await rap(_post); resolve(_post); }); diff --git a/src/api/serializers/user.ts b/src/api/serializers/user.ts index 3527921ded..d00f073897 100644 --- a/src/api/serializers/user.ts +++ b/src/api/serializers/user.ts @@ -112,7 +112,7 @@ export default ( deleted_at: { $exists: false } }); return follow !== null; - })() + })(); // If the user is followed _user.is_followed = (async () => { @@ -122,7 +122,7 @@ export default ( deleted_at: { $exists: false } }); return follow2 !== null; - })() + })(); } if (opts.detail) { @@ -153,7 +153,7 @@ export default ( } // resolve promises in _user object - _user = await rap(_user) + _user = await rap(_user); resolve(_user); }); -- cgit v1.2.3-freya From 7e81e0db6ac1289ae9504f7e3da5db6e56f41a51 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 14:37:00 +0900 Subject: support GridFS --- src/api/common/add-file-to-drive.ts | 37 +++++++++++++++++++++++-------------- src/api/models/drive-file.ts | 15 +++++++++++++-- src/db/mongodb.ts | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 67 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index 714eeb520d..f48f0cbcf5 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -4,14 +4,27 @@ import * as gm from 'gm'; import * as debug from 'debug'; import fileType = require('file-type'); import prominence = require('prominence'); -import DriveFile from '../models/drive-file'; +import DriveFile, { getGridFSBucket } from '../models/drive-file'; import DriveFolder from '../models/drive-folder'; import serialize from '../serializers/drive-file'; import event from '../event'; import config from '../../conf'; +import { Duplex } from 'stream'; const log = debug('misskey:register-drive-file'); +const addToGridFS = (name, binary, metadata): Promise => new Promise(async (resolve, reject) => { + const dataStream = new Duplex() + dataStream.push(binary) + dataStream.push(null) + + const bucket = await getGridFSBucket() + const writeStream = bucket.openUploadStream(name, { metadata }) + writeStream.once('finish', (doc) => { resolve(doc) }) + writeStream.on('error', reject) + dataStream.pipe(writeStream) +}) + /** * Add file to drive * @@ -58,7 +71,7 @@ export default ( // Generate hash const hash = crypto - .createHash('sha256') + .createHash('md5') .update(data) .digest('hex') as string; @@ -67,8 +80,10 @@ export default ( if (!force) { // Check if there is a file with the same hash const much = await DriveFile.findOne({ - user_id: user._id, - hash: hash + md5: hash, + metadata: { + user_id: user._id + } }); if (much !== null) { @@ -82,13 +97,13 @@ export default ( // Calculate drive usage const usage = ((await DriveFile .aggregate([ - { $match: { user_id: user._id } }, + { $match: { metadata: { user_id: user._id } } }, { $project: { - datasize: true + length: true }}, { $group: { _id: null, - usage: { $sum: '$datasize' } + usage: { $sum: '$length' } }} ]))[0] || { usage: 0 @@ -131,21 +146,15 @@ export default ( } // Create DriveFile document - const file = await DriveFile.insert({ - created_at: new Date(), + const file = await addToGridFS(`${user._id}/${name}`, data, { user_id: user._id, folder_id: folder !== null ? folder._id : null, - data: data, - datasize: size, type: mime, name: name, comment: comment, - hash: hash, properties: properties }); - delete file.data; - log(`drive file has been created ${file._id}`); resolve(file); diff --git a/src/api/models/drive-file.ts b/src/api/models/drive-file.ts index 8d158cf563..79a87f6572 100644 --- a/src/api/models/drive-file.ts +++ b/src/api/models/drive-file.ts @@ -1,11 +1,22 @@ -import db from '../../db/mongodb'; +import * as mongodb from 'mongodb'; +import monkDb, { nativeDbConn } from '../../db/mongodb'; -const collection = db.get('drive_files'); +const collection = monkDb.get('drive_files.files'); (collection as any).createIndex('hash'); // fuck type definition export default collection as any; // fuck type definition +const getGridFSBucket = async (): Promise => { + const db = await nativeDbConn() + const bucket = new mongodb.GridFSBucket(db, { + bucketName: 'drive_files' + }) + return bucket +} + +export { getGridFSBucket } + export function validateFileName(name: string): boolean { return ( (name.trim().length > 0) && diff --git a/src/db/mongodb.ts b/src/db/mongodb.ts index 6ee7f4534f..75f1a1d3c6 100644 --- a/src/db/mongodb.ts +++ b/src/db/mongodb.ts @@ -1,11 +1,38 @@ -import * as mongo from 'monk'; - import config from '../conf'; const uri = config.mongodb.user && config.mongodb.pass - ? `mongodb://${config.mongodb.user}:${config.mongodb.pass}@${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}` - : `mongodb://${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}`; +? `mongodb://${config.mongodb.user}:${config.mongodb.pass}@${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}` +: `mongodb://${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}`; + +/** + * monk + */ +import * as mongo from 'monk'; const db = mongo(uri); export default db; + +/** + * MongoDB native module (officialy) + */ +import * as mongodb from 'mongodb' + +let mdb: mongodb.Db; + +const nativeDbConn = async (): Promise => { + if (mdb) return mdb; + + const db = await ((): Promise => new Promise((resolve, reject) => { + mongodb.MongoClient.connect(uri, (e, db) => { + if (e) return reject(e) + resolve(db) + }) + }))() + + mdb = db + + return db +} + +export { nativeDbConn } -- cgit v1.2.3-freya From 18b1ef29adc6166c2b1a327b378c3e159a18b80c Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:18:45 +0900 Subject: migration to GridFS's DriveFile --- src/api/common/add-file-to-drive.ts | 1 + src/api/endpoints/drive.ts | 6 ++--- src/api/endpoints/drive/files.ts | 9 ++++--- src/api/endpoints/drive/files/find.ts | 10 ++++---- src/api/endpoints/drive/files/show.ts | 6 ++--- src/api/endpoints/drive/files/update.ts | 31 ++++++++++++++---------- src/api/endpoints/messaging/messages/create.ts | 6 ++--- src/api/endpoints/posts/create.ts | 6 ++--- src/api/endpoints/posts/timeline.ts | 24 +++++++++---------- src/api/serializers/drive-file.ts | 33 ++++++++++---------------- src/api/serializers/drive-folder.ts | 4 +++- 11 files changed, 66 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index f48f0cbcf5..376c470e93 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -154,6 +154,7 @@ export default ( comment: comment, properties: properties }); + console.dir(file) log(`drive file has been created ${file._id}`); diff --git a/src/api/endpoints/drive.ts b/src/api/endpoints/drive.ts index 41ad6301d7..b9c4e3e506 100644 --- a/src/api/endpoints/drive.ts +++ b/src/api/endpoints/drive.ts @@ -14,16 +14,16 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Calculate drive usage const usage = ((await DriveFile .aggregate([ - { $match: { user_id: user._id } }, + { $match: { metadata: { user_id: user._id } } }, { $project: { - datasize: true + length: true } }, { $group: { _id: null, - usage: { $sum: '$datasize' } + usage: { $sum: '$length' } } } ]))[0] || { diff --git a/src/api/endpoints/drive/files.ts b/src/api/endpoints/drive/files.ts index a68ae34817..eb0bfe6ba5 100644 --- a/src/api/endpoints/drive/files.ts +++ b/src/api/endpoints/drive/files.ts @@ -40,8 +40,10 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { _id: -1 }; const query = { - user_id: user._id, - folder_id: folderId + metadata: { + user_id: user._id, + folder_id: folderId + } } as any; if (sinceId) { sort._id = 1; @@ -57,9 +59,6 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { // Issue query const files = await DriveFile .find(query, { - fields: { - data: false - }, limit: limit, sort: sort }); diff --git a/src/api/endpoints/drive/files/find.ts b/src/api/endpoints/drive/files/find.ts index cd0b33f2ca..255faf94ec 100644 --- a/src/api/endpoints/drive/files/find.ts +++ b/src/api/endpoints/drive/files/find.ts @@ -24,12 +24,10 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Issue query const files = await DriveFile .find({ - name: name, - user_id: user._id, - folder_id: folderId - }, { - fields: { - data: false + metadata: { + name: name, + user_id: user._id, + folder_id: folderId } }); diff --git a/src/api/endpoints/drive/files/show.ts b/src/api/endpoints/drive/files/show.ts index 8dbc297e4f..9135a04c57 100644 --- a/src/api/endpoints/drive/files/show.ts +++ b/src/api/endpoints/drive/files/show.ts @@ -21,10 +21,8 @@ module.exports = (params, user) => new Promise(async (res, rej) => { const file = await DriveFile .findOne({ _id: fileId, - user_id: user._id - }, { - fields: { - data: false + metadata: { + user_id: user._id } }); diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index 1cfbdd8f0b..c4d2673688 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -20,25 +20,29 @@ module.exports = (params, user) => new Promise(async (res, rej) => { const [fileId, fileIdErr] = $(params.file_id).id().$; if (fileIdErr) return rej('invalid file_id param'); + console.dir(user) + // Fetch file const file = await DriveFile .findOne({ _id: fileId, - user_id: user._id - }, { - fields: { - data: false + metadata: { + user_id: user._id } }); + console.dir(file) + if (file === null) { return rej('file-not-found'); } + const updateQuery: any = {} + // Get 'name' parameter const [name, nameErr] = $(params.name).optional.string().pipe(validateFileName).$; if (nameErr) return rej('invalid name param'); - if (name) file.name = name; + if (name) updateQuery.name = name; // Get 'folder_id' parameter const [folderId, folderIdErr] = $(params.folder_id).optional.nullable.id().$; @@ -46,7 +50,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { if (folderId !== undefined) { if (folderId === null) { - file.folder_id = null; + updateQuery.folder_id = null; } else { // Fetch folder const folder = await DriveFolder @@ -59,19 +63,20 @@ module.exports = (params, user) => new Promise(async (res, rej) => { return rej('folder-not-found'); } - file.folder_id = folder._id; + updateQuery.folder_id = folder._id; } } - DriveFile.update(file._id, { - $set: { - name: file.name, - folder_id: file.folder_id - } + const updated = await DriveFile.update(file._id, { + $set: { metadata: updateQuery } }); + console.dir(updated) + // Serialize - const fileObj = await serialize(file); + const fileObj = await serialize(updated); + + console.dir(fileObj) // Response res(fileObj); diff --git a/src/api/endpoints/messaging/messages/create.ts b/src/api/endpoints/messaging/messages/create.ts index 8af55d850c..1d186268fb 100644 --- a/src/api/endpoints/messaging/messages/create.ts +++ b/src/api/endpoints/messaging/messages/create.ts @@ -54,9 +54,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => { if (fileId !== undefined) { file = await DriveFile.findOne({ _id: fileId, - user_id: user._id - }, { - data: false + metadata: { + user_id: user._id + } }); if (file === null) { diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index f982b9ee93..1507639776 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -44,9 +44,9 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { // SELECT _id const entity = await DriveFile.findOne({ _id: mediaId, - user_id: user._id - }, { - _id: true + metadata: { + user_id: user._id + } }); if (entity === null) { diff --git a/src/api/endpoints/posts/timeline.ts b/src/api/endpoints/posts/timeline.ts index aa5aff5ba5..496de62b69 100644 --- a/src/api/endpoints/posts/timeline.ts +++ b/src/api/endpoints/posts/timeline.ts @@ -2,6 +2,7 @@ * Module dependencies */ import $ from 'cafy'; +import rap from '@prezzemolo/rap'; import Post from '../../models/post'; import ChannelWatching from '../../models/channel-watching'; import getFriends from '../../common/get-friends'; @@ -33,14 +34,15 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { return rej('cannot set since_id and max_id'); } - // ID list of the user itself and other users who the user follows - const followingIds = await getFriends(user._id); - - // Watchしているチャンネルを取得 - const watches = await ChannelWatching.find({ - user_id: user._id, - // 削除されたドキュメントは除く - deleted_at: { $exists: false } + const { followingIds, watchChannelIds } = await rap({ + // ID list of the user itself and other users who the user follows + followingIds: getFriends(user._id), + // Watchしているチャンネルを取得 + watchChannelIds: ChannelWatching.find({ + user_id: user._id, + // 削除されたドキュメントは除く + deleted_at: { $exists: false } + }).then(watches => watches.map(w => w.channel_id)) }); //#region Construct query @@ -65,7 +67,7 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { }, { // Watchしているチャンネルへの投稿 channel_id: { - $in: watches.map(w => w.channel_id) + $in: watchChannelIds } }] } as any; @@ -90,7 +92,5 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { }); // Serialize - res(await Promise.all(timeline.map(async post => - await serialize(post, user) - ))); + res(Promise.all(timeline.map(post => serialize(post, user)))); }); diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index b4e2ab064a..4c750f4c6b 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -31,44 +31,37 @@ export default ( if (mongo.ObjectID.prototype.isPrototypeOf(file)) { _file = await DriveFile.findOne({ _id: file - }, { - fields: { - data: false - } - }); + }); } else if (typeof file === 'string') { _file = await DriveFile.findOne({ _id: new mongo.ObjectID(file) - }, { - fields: { - data: false - } - }); + }); } else { _file = deepcopy(file); } - // Rename _id to id - _file.id = _file._id; - delete _file._id; + // rendered target + let _target: any = {}; + + _target.id = _file._id; - delete _file.data; + _target = Object.assign(_target, _file.metadata); - _file.url = `${config.drive_url}/${_file.id}/${encodeURIComponent(_file.name)}`; + _target.url = `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`; - if (opts.detail && _file.folder_id) { + if (opts.detail && _target.folder_id) { // Populate folder - _file.folder = await serializeDriveFolder(_file.folder_id, { + _target.folder = await serializeDriveFolder(_target.folder_id, { detail: true }); } - if (opts.detail && _file.tags) { + if (opts.detail && _target.tags) { // Populate tags - _file.tags = await _file.tags.map(async (tag: any) => + _target.tags = await _target.tags.map(async (tag: any) => await serializeDriveTag(tag) ); } - resolve(_file); + resolve(_target); }); diff --git a/src/api/serializers/drive-folder.ts b/src/api/serializers/drive-folder.ts index a428464108..3b5f61aeed 100644 --- a/src/api/serializers/drive-folder.ts +++ b/src/api/serializers/drive-folder.ts @@ -44,7 +44,9 @@ const self = ( }); const childFilesCount = await DriveFile.count({ - folder_id: _folder.id + metadata: { + folder_id: _folder.id + } }); _folder.folders_count = childFoldersCount; -- cgit v1.2.3-freya From d0dab265f40a37cd715b7d4b64a364c78a7a35b9 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:27:16 +0900 Subject: serializers - drive-file: add created_at field by uploadedDate --- src/api/serializers/drive-file.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index 4c750f4c6b..f98cdaa599 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -44,6 +44,7 @@ export default ( let _target: any = {}; _target.id = _file._id; + _target.created_at = _file.uploadDate _target = Object.assign(_target, _file.metadata); -- cgit v1.2.3-freya From a5160a1bbaa3dd75d7ef45b305a90020317e95a8 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:35:20 +0900 Subject: fileserver - support DriveFile w/ GridFS --- src/file/server.ts | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/file/server.ts b/src/file/server.ts index ee67cf7860..bd29e13c5c 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -9,7 +9,7 @@ import * as cors from 'cors'; import * as mongodb from 'mongodb'; import * as gm from 'gm'; -import File from '../api/models/drive-file'; +import DriveFile, { getGridFSBucket } from '../api/models/drive-file'; /** * Init app @@ -97,17 +97,28 @@ app.get('/:id', async (req, res) => { return; } - const file = await File.findOne({ _id: new mongodb.ObjectID(req.params.id) }); + const fileId = new mongodb.ObjectID(req.params.id) + const file = await DriveFile.findOne({ _id: fileId }); if (file == null) { res.status(404).sendFile(`${__dirname} / assets / dummy.png`); return; - } else if (file.data == null) { - res.sendStatus(400); - return; } - send(file.data.buffer, file.type, req, res); + const bucket = await getGridFSBucket() + + const buffer = await ((id): Promise => new Promise((resolve, reject) => { + const chunks = [] + const readableStream = bucket.openDownloadStream(id) + readableStream.on('data', chunk => { + chunks.push(chunk); + }) + readableStream.on('end', () => { + resolve(Buffer.concat(chunks)) + }) + }))(fileId) + + send(buffer, file.metadata.type, req, res); }); app.get('/:id/:name', async (req, res) => { -- cgit v1.2.3-freya From 2ce3179d5000501391b020dd98385aab9fed8094 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:37:04 +0900 Subject: fileserver - fix dummy path --- src/file/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/file/server.ts b/src/file/server.ts index bd29e13c5c..068e88546b 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -101,7 +101,7 @@ app.get('/:id', async (req, res) => { const file = await DriveFile.findOne({ _id: fileId }); if (file == null) { - res.status(404).sendFile(`${__dirname} / assets / dummy.png`); + res.status(404).sendFile(`${__dirname}/assets/dummy.png`); return; } -- cgit v1.2.3-freya From 28a39bccf96549a35ef77c10dce5f90f9f8cc654 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:39:16 +0900 Subject: file-server - support new DriveFile w/ GridFS on '/:id/:name' --- src/file/server.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/file/server.ts b/src/file/server.ts index 068e88546b..f38599b89c 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -128,17 +128,28 @@ app.get('/:id/:name', async (req, res) => { return; } - const file = await File.findOne({ _id: new mongodb.ObjectID(req.params.id) }); + const fileId = new mongodb.ObjectID(req.params.id) + const file = await DriveFile.findOne({ _id: fileId }); if (file == null) { res.status(404).sendFile(`${__dirname}/assets/dummy.png`); return; - } else if (file.data == null) { - res.sendStatus(400); - return; } - send(file.data.buffer, file.type, req, res); + const bucket = await getGridFSBucket() + + const buffer = await ((id): Promise => new Promise((resolve, reject) => { + const chunks = [] + const readableStream = bucket.openDownloadStream(id) + readableStream.on('data', chunk => { + chunks.push(chunk); + }) + readableStream.on('end', () => { + resolve(Buffer.concat(chunks)) + }) + }))(fileId) + + send(buffer, file.metadata.type, req, res); }); module.exports = app; -- cgit v1.2.3-freya From 0ee6d6592113c5b2df071f4451cb1c1697b59d61 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:45:21 +0900 Subject: fix timeline --- src/api/endpoints/posts/timeline.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/api/endpoints/posts/timeline.ts b/src/api/endpoints/posts/timeline.ts index 496de62b69..19578e59b1 100644 --- a/src/api/endpoints/posts/timeline.ts +++ b/src/api/endpoints/posts/timeline.ts @@ -92,5 +92,5 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { }); // Serialize - res(Promise.all(timeline.map(post => serialize(post, user)))); + res(await Promise.all(timeline.map(post => serialize(post, user)))); }); -- cgit v1.2.3-freya From 7553c6dd38c6f8574894a009238d946d50c53477 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:52:09 +0900 Subject: serializers - posts: no need Promise wrapping --- src/api/serializers/post.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index e1ab784359..d1dcb66002 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -22,13 +22,13 @@ import rap from '@prezzemolo/rap'; * @param options? serialize options * @return response */ -const self = ( +const self = async ( post: string | mongo.ObjectID | IPost, me?: string | mongo.ObjectID | IUser, options?: { detail: boolean } -) => new Promise(async (resolve, reject) => { +) => { const opts = options || { detail: true, }; @@ -184,7 +184,7 @@ const self = ( // resolve promises in _post object _post = await rap(_post); - resolve(_post); -}); + return _post; +}; export default self; -- cgit v1.2.3-freya From 7b1fc2c5d62e229542e9411a29e078236a9d96db Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:55:47 +0900 Subject: api - endpoint:timeline: unneed promise wrapping --- src/api/endpoints/posts/timeline.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/api/endpoints/posts/timeline.ts b/src/api/endpoints/posts/timeline.ts index 19578e59b1..978825a109 100644 --- a/src/api/endpoints/posts/timeline.ts +++ b/src/api/endpoints/posts/timeline.ts @@ -16,22 +16,22 @@ import serialize from '../../serializers/post'; * @param {any} app * @return {Promise} */ -module.exports = (params, user, app) => new Promise(async (res, rej) => { +module.exports = async (params, user, app) => { // Get 'limit' parameter const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$; - if (limitErr) return rej('invalid limit param'); + if (limitErr) throw 'invalid limit param'; // Get 'since_id' parameter const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$; - if (sinceIdErr) return rej('invalid since_id param'); + if (sinceIdErr) throw 'invalid since_id param'; // Get 'max_id' parameter const [maxId, maxIdErr] = $(params.max_id).optional.id().$; - if (maxIdErr) return rej('invalid max_id param'); + if (maxIdErr) throw 'invalid max_id param'; // Check if both of since_id and max_id is specified if (sinceId && maxId) { - return rej('cannot set since_id and max_id'); + throw 'cannot set since_id and max_id'; } const { followingIds, watchChannelIds } = await rap({ @@ -92,5 +92,6 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { }); // Serialize - res(await Promise.all(timeline.map(post => serialize(post, user)))); -}); + const _timeline = await Promise.all(timeline.map(post => serialize(post, user))) + return _timeline +}; -- cgit v1.2.3-freya From b50813649afed671b75189551342b179d8cd60f7 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 15:58:39 +0900 Subject: serializers - posts: fix awaiting --- src/api/serializers/post.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index d1dcb66002..5788b226f4 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -94,7 +94,7 @@ const self = async ( if (opts.detail) { // Get previous post info _post.prev = (async () => { - const prev = Post.findOne({ + const prev = await Post.findOne({ user_id: _post.user_id, _id: { $lt: id -- cgit v1.2.3-freya From 5279d062df205514f1f3cf95e3aab4fee425a3e4 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 16:09:51 +0900 Subject: fix --- src/api/endpoints/drive/files.ts | 18 +++++++++--------- src/api/endpoints/drive/files/show.ts | 14 ++++++++------ src/api/endpoints/drive/folders/find.ts | 3 +-- src/api/serializers/drive-file.ts | 2 ++ 4 files changed, 20 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/api/endpoints/drive/files.ts b/src/api/endpoints/drive/files.ts index eb0bfe6ba5..41687c4993 100644 --- a/src/api/endpoints/drive/files.ts +++ b/src/api/endpoints/drive/files.ts @@ -13,27 +13,27 @@ import serialize from '../../serializers/drive-file'; * @param {any} app * @return {Promise} */ -module.exports = (params, user, app) => new Promise(async (res, rej) => { +module.exports = async (params, user, app) => { // Get 'limit' parameter const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$; - if (limitErr) return rej('invalid limit param'); + if (limitErr) throw 'invalid limit param'; // Get 'since_id' parameter const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$; - if (sinceIdErr) return rej('invalid since_id param'); + if (sinceIdErr) throw 'invalid since_id param'; // Get 'max_id' parameter const [maxId, maxIdErr] = $(params.max_id).optional.id().$; - if (maxIdErr) return rej('invalid max_id param'); + if (maxIdErr) throw 'invalid max_id param'; // Check if both of since_id and max_id is specified if (sinceId && maxId) { - return rej('cannot set since_id and max_id'); + throw 'cannot set since_id and max_id'; } // Get 'folder_id' parameter const [folderId = null, folderIdErr] = $(params.folder_id).optional.nullable.id().$; - if (folderIdErr) return rej('invalid folder_id param'); + if (folderIdErr) throw 'invalid folder_id param'; // Construct query const sort = { @@ -64,6 +64,6 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { }); // Serialize - res(await Promise.all(files.map(async file => - await serialize(file)))); -}); + const _files = await Promise.all(files.map(file => serialize(file))); + return _files +}; diff --git a/src/api/endpoints/drive/files/show.ts b/src/api/endpoints/drive/files/show.ts index 9135a04c57..8830346008 100644 --- a/src/api/endpoints/drive/files/show.ts +++ b/src/api/endpoints/drive/files/show.ts @@ -12,10 +12,10 @@ import serialize from '../../../serializers/drive-file'; * @param {any} user * @return {Promise} */ -module.exports = (params, user) => new Promise(async (res, rej) => { +module.exports = async (params, user) => { // Get 'file_id' parameter const [fileId, fileIdErr] = $(params.file_id).id().$; - if (fileIdErr) return rej('invalid file_id param'); + if (fileIdErr) throw 'invalid file_id param'; // Fetch file const file = await DriveFile @@ -27,11 +27,13 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); if (file === null) { - return rej('file-not-found'); + throw 'file-not-found'; } // Serialize - res(await serialize(file, { + const _file = await serialize(file, { detail: true - })); -}); + }); + + return _file +}; diff --git a/src/api/endpoints/drive/folders/find.ts b/src/api/endpoints/drive/folders/find.ts index cdf055839a..a5eb8e015d 100644 --- a/src/api/endpoints/drive/folders/find.ts +++ b/src/api/endpoints/drive/folders/find.ts @@ -30,6 +30,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Serialize - res(await Promise.all(folders.map(async folder => - await serialize(folder)))); + res(await Promise.all(folders.map(folder => serialize(folder)))); }); diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index f98cdaa599..9858c3b3c7 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -25,6 +25,8 @@ export default ( detail: false }, options); + if (!file) return reject('invalid file arg.') + let _file: any; // Populate the file if 'file' is ID -- cgit v1.2.3-freya From b266ed3e4f98ab16d95e52cff517d6519b78742a Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 16:11:24 +0900 Subject: fix --- src/api/serializers/drive-file.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index 9858c3b3c7..e749f80387 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -25,8 +25,6 @@ export default ( detail: false }, options); - if (!file) return reject('invalid file arg.') - let _file: any; // Populate the file if 'file' is ID @@ -42,6 +40,8 @@ export default ( _file = deepcopy(file); } + if (!_file) return reject('invalid file arg.') + // rendered target let _target: any = {}; -- cgit v1.2.3-freya From 64be0d6deddef4b8caced377dc22f94425cc4358 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 16:22:18 +0900 Subject: MongoDBの階層構造検索に関する思い違いの修正 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/endpoints/drive.ts | 2 +- src/api/endpoints/drive/files.ts | 6 ++---- src/api/endpoints/drive/files/find.ts | 8 +++----- src/api/endpoints/drive/files/show.ts | 4 +--- src/api/endpoints/drive/files/update.ts | 19 +++++-------------- src/api/endpoints/messaging/messages/create.ts | 4 +--- src/api/endpoints/posts/create.ts | 4 +--- src/api/serializers/drive-folder.ts | 4 +--- 8 files changed, 15 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/api/endpoints/drive.ts b/src/api/endpoints/drive.ts index b9c4e3e506..d92473633a 100644 --- a/src/api/endpoints/drive.ts +++ b/src/api/endpoints/drive.ts @@ -14,7 +14,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Calculate drive usage const usage = ((await DriveFile .aggregate([ - { $match: { metadata: { user_id: user._id } } }, + { $match: { 'metadata.user_id': user._id } }, { $project: { length: true diff --git a/src/api/endpoints/drive/files.ts b/src/api/endpoints/drive/files.ts index 41687c4993..035916b309 100644 --- a/src/api/endpoints/drive/files.ts +++ b/src/api/endpoints/drive/files.ts @@ -40,10 +40,8 @@ module.exports = async (params, user, app) => { _id: -1 }; const query = { - metadata: { - user_id: user._id, - folder_id: folderId - } + 'metadata.user_id': user._id, + 'metadata.folder_id': folderId } as any; if (sinceId) { sort._id = 1; diff --git a/src/api/endpoints/drive/files/find.ts b/src/api/endpoints/drive/files/find.ts index 255faf94ec..1c818131d7 100644 --- a/src/api/endpoints/drive/files/find.ts +++ b/src/api/endpoints/drive/files/find.ts @@ -24,11 +24,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Issue query const files = await DriveFile .find({ - metadata: { - name: name, - user_id: user._id, - folder_id: folderId - } + 'metadata.name': name, + 'metadata.user_id': user._id, + 'metadata.folder_id': folderId }); // Serialize diff --git a/src/api/endpoints/drive/files/show.ts b/src/api/endpoints/drive/files/show.ts index 8830346008..0a19b19939 100644 --- a/src/api/endpoints/drive/files/show.ts +++ b/src/api/endpoints/drive/files/show.ts @@ -21,9 +21,7 @@ module.exports = async (params, user) => { const file = await DriveFile .findOne({ _id: fileId, - metadata: { - user_id: user._id - } + 'metadata.user_id': user._id }); if (file === null) { diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index c4d2673688..7a6d2562fb 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -20,19 +20,14 @@ module.exports = (params, user) => new Promise(async (res, rej) => { const [fileId, fileIdErr] = $(params.file_id).id().$; if (fileIdErr) return rej('invalid file_id param'); - console.dir(user) // Fetch file const file = await DriveFile .findOne({ _id: fileId, - metadata: { - user_id: user._id - } + 'metadata.user_id': user._id }); - console.dir(file) - if (file === null) { return rej('file-not-found'); } @@ -42,7 +37,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Get 'name' parameter const [name, nameErr] = $(params.name).optional.string().pipe(validateFileName).$; if (nameErr) return rej('invalid name param'); - if (name) updateQuery.name = name; + if (name) updateQuery['metadata.name'] = name; // Get 'folder_id' parameter const [folderId, folderIdErr] = $(params.folder_id).optional.nullable.id().$; @@ -50,7 +45,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { if (folderId !== undefined) { if (folderId === null) { - updateQuery.folder_id = null; + updateQuery['metadata.folder_id'] = null; } else { // Fetch folder const folder = await DriveFolder @@ -63,21 +58,17 @@ module.exports = (params, user) => new Promise(async (res, rej) => { return rej('folder-not-found'); } - updateQuery.folder_id = folder._id; + updateQuery['metadata.folder_id'] = folder._id; } } const updated = await DriveFile.update(file._id, { - $set: { metadata: updateQuery } + $set: { updateQuery } }); - console.dir(updated) - // Serialize const fileObj = await serialize(updated); - console.dir(fileObj) - // Response res(fileObj); diff --git a/src/api/endpoints/messaging/messages/create.ts b/src/api/endpoints/messaging/messages/create.ts index 1d186268fb..149852c093 100644 --- a/src/api/endpoints/messaging/messages/create.ts +++ b/src/api/endpoints/messaging/messages/create.ts @@ -54,9 +54,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { if (fileId !== undefined) { file = await DriveFile.findOne({ _id: fileId, - metadata: { - user_id: user._id - } + 'metadata.user_id': user._id }); if (file === null) { diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index 1507639776..4f4b7e2e83 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -44,9 +44,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { // SELECT _id const entity = await DriveFile.findOne({ _id: mediaId, - metadata: { - user_id: user._id - } + 'metadata.user_id': user._id }); if (entity === null) { diff --git a/src/api/serializers/drive-folder.ts b/src/api/serializers/drive-folder.ts index 3b5f61aeed..6ebf454a28 100644 --- a/src/api/serializers/drive-folder.ts +++ b/src/api/serializers/drive-folder.ts @@ -44,9 +44,7 @@ const self = ( }); const childFilesCount = await DriveFile.count({ - metadata: { - folder_id: _folder.id - } + 'metadata.folder_id': _folder.id }); _folder.folders_count = childFoldersCount; -- cgit v1.2.3-freya From 4c5a4d259738ba617bf29d2158d180cc5fa8401c Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 16:26:17 +0900 Subject: core - fix metadata searching --- src/api/common/add-file-to-drive.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index 376c470e93..1f882389ac 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -81,9 +81,7 @@ export default ( // Check if there is a file with the same hash const much = await DriveFile.findOne({ md5: hash, - metadata: { - user_id: user._id - } + 'metadata.user_id': user._id }); if (much !== null) { @@ -97,7 +95,7 @@ export default ( // Calculate drive usage const usage = ((await DriveFile .aggregate([ - { $match: { metadata: { user_id: user._id } } }, + { $match: { 'metadata.user_id': user._id } }, { $project: { length: true }}, -- cgit v1.2.3-freya From 04648db1c235b0de14d3e0a2dc83f9346d0408f8 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 16:29:13 +0900 Subject: remove console --- src/api/common/add-file-to-drive.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index 1f882389ac..dff2d52356 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -152,7 +152,6 @@ export default ( comment: comment, properties: properties }); - console.dir(file) log(`drive file has been created ${file._id}`); -- cgit v1.2.3-freya From d5cc4cc9c28eb6a981ce37859def97cd7c57abc6 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 16:32:01 +0900 Subject: fix lint (automattic) --- src/api/common/add-file-to-drive.ts | 20 +++++++++--------- src/api/endpoints/drive/files.ts | 2 +- src/api/endpoints/drive/files/show.ts | 2 +- src/api/endpoints/drive/files/update.ts | 3 +-- src/api/endpoints/posts/timeline.ts | 4 ++-- src/api/models/drive-file.ts | 10 ++++----- src/api/serializers/drive-file.ts | 4 ++-- src/db/mongodb.ts | 18 ++++++++--------- src/file/server.ts | 36 ++++++++++++++++----------------- 9 files changed, 49 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index dff2d52356..f9c22ccacd 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -14,16 +14,16 @@ import { Duplex } from 'stream'; const log = debug('misskey:register-drive-file'); const addToGridFS = (name, binary, metadata): Promise => new Promise(async (resolve, reject) => { - const dataStream = new Duplex() - dataStream.push(binary) - dataStream.push(null) - - const bucket = await getGridFSBucket() - const writeStream = bucket.openUploadStream(name, { metadata }) - writeStream.once('finish', (doc) => { resolve(doc) }) - writeStream.on('error', reject) - dataStream.pipe(writeStream) -}) + const dataStream = new Duplex(); + dataStream.push(binary); + dataStream.push(null); + + const bucket = await getGridFSBucket(); + const writeStream = bucket.openUploadStream(name, { metadata }); + writeStream.once('finish', (doc) => { resolve(doc); }); + writeStream.on('error', reject); + dataStream.pipe(writeStream); +}); /** * Add file to drive diff --git a/src/api/endpoints/drive/files.ts b/src/api/endpoints/drive/files.ts index 035916b309..53b48a8bec 100644 --- a/src/api/endpoints/drive/files.ts +++ b/src/api/endpoints/drive/files.ts @@ -63,5 +63,5 @@ module.exports = async (params, user, app) => { // Serialize const _files = await Promise.all(files.map(file => serialize(file))); - return _files + return _files; }; diff --git a/src/api/endpoints/drive/files/show.ts b/src/api/endpoints/drive/files/show.ts index 0a19b19939..3c7cf774f9 100644 --- a/src/api/endpoints/drive/files/show.ts +++ b/src/api/endpoints/drive/files/show.ts @@ -33,5 +33,5 @@ module.exports = async (params, user) => { detail: true }); - return _file + return _file; }; diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index 7a6d2562fb..4e56b30ace 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -20,7 +20,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { const [fileId, fileIdErr] = $(params.file_id).id().$; if (fileIdErr) return rej('invalid file_id param'); - // Fetch file const file = await DriveFile .findOne({ @@ -32,7 +31,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { return rej('file-not-found'); } - const updateQuery: any = {} + const updateQuery: any = {}; // Get 'name' parameter const [name, nameErr] = $(params.name).optional.string().pipe(validateFileName).$; diff --git a/src/api/endpoints/posts/timeline.ts b/src/api/endpoints/posts/timeline.ts index 978825a109..203413e23a 100644 --- a/src/api/endpoints/posts/timeline.ts +++ b/src/api/endpoints/posts/timeline.ts @@ -92,6 +92,6 @@ module.exports = async (params, user, app) => { }); // Serialize - const _timeline = await Promise.all(timeline.map(post => serialize(post, user))) - return _timeline + const _timeline = await Promise.all(timeline.map(post => serialize(post, user))); + return _timeline; }; diff --git a/src/api/models/drive-file.ts b/src/api/models/drive-file.ts index 79a87f6572..8968d065cd 100644 --- a/src/api/models/drive-file.ts +++ b/src/api/models/drive-file.ts @@ -8,14 +8,14 @@ const collection = monkDb.get('drive_files.files'); export default collection as any; // fuck type definition const getGridFSBucket = async (): Promise => { - const db = await nativeDbConn() + const db = await nativeDbConn(); const bucket = new mongodb.GridFSBucket(db, { bucketName: 'drive_files' - }) - return bucket -} + }); + return bucket; +}; -export { getGridFSBucket } +export { getGridFSBucket }; export function validateFileName(name: string): boolean { return ( diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index e749f80387..2af7db5726 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -40,13 +40,13 @@ export default ( _file = deepcopy(file); } - if (!_file) return reject('invalid file arg.') + if (!_file) return reject('invalid file arg.'); // rendered target let _target: any = {}; _target.id = _file._id; - _target.created_at = _file.uploadDate + _target.created_at = _file.uploadDate; _target = Object.assign(_target, _file.metadata); diff --git a/src/db/mongodb.ts b/src/db/mongodb.ts index 75f1a1d3c6..c978e6460f 100644 --- a/src/db/mongodb.ts +++ b/src/db/mongodb.ts @@ -16,7 +16,7 @@ export default db; /** * MongoDB native module (officialy) */ -import * as mongodb from 'mongodb' +import * as mongodb from 'mongodb'; let mdb: mongodb.Db; @@ -25,14 +25,14 @@ const nativeDbConn = async (): Promise => { const db = await ((): Promise => new Promise((resolve, reject) => { mongodb.MongoClient.connect(uri, (e, db) => { - if (e) return reject(e) - resolve(db) - }) - }))() + if (e) return reject(e); + resolve(db); + }); + }))(); - mdb = db + mdb = db; - return db -} + return db; +}; -export { nativeDbConn } +export { nativeDbConn }; diff --git a/src/file/server.ts b/src/file/server.ts index f38599b89c..375f29487d 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -97,7 +97,7 @@ app.get('/:id', async (req, res) => { return; } - const fileId = new mongodb.ObjectID(req.params.id) + const fileId = new mongodb.ObjectID(req.params.id); const file = await DriveFile.findOne({ _id: fileId }); if (file == null) { @@ -105,18 +105,18 @@ app.get('/:id', async (req, res) => { return; } - const bucket = await getGridFSBucket() + const bucket = await getGridFSBucket(); const buffer = await ((id): Promise => new Promise((resolve, reject) => { - const chunks = [] - const readableStream = bucket.openDownloadStream(id) - readableStream.on('data', chunk => { + const chunks = []; + const readableStream = bucket.openDownloadStream(id); + readableStream.on('data', chunk => { chunks.push(chunk); - }) + }); readableStream.on('end', () => { - resolve(Buffer.concat(chunks)) - }) - }))(fileId) + resolve(Buffer.concat(chunks)); + }); + }))(fileId); send(buffer, file.metadata.type, req, res); }); @@ -128,7 +128,7 @@ app.get('/:id/:name', async (req, res) => { return; } - const fileId = new mongodb.ObjectID(req.params.id) + const fileId = new mongodb.ObjectID(req.params.id); const file = await DriveFile.findOne({ _id: fileId }); if (file == null) { @@ -136,18 +136,18 @@ app.get('/:id/:name', async (req, res) => { return; } - const bucket = await getGridFSBucket() + const bucket = await getGridFSBucket(); const buffer = await ((id): Promise => new Promise((resolve, reject) => { - const chunks = [] - const readableStream = bucket.openDownloadStream(id) - readableStream.on('data', chunk => { + const chunks = []; + const readableStream = bucket.openDownloadStream(id); + readableStream.on('data', chunk => { chunks.push(chunk); - }) + }); readableStream.on('end', () => { - resolve(Buffer.concat(chunks)) - }) - }))(fileId) + resolve(Buffer.concat(chunks)); + }); + }))(fileId); send(buffer, file.metadata.type, req, res); }); -- cgit v1.2.3-freya From 3be69a8cb7bacca181fa400f234fd77c1d1d5bde Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 16:49:07 +0900 Subject: /drive/files/update - return collectly value --- src/api/endpoints/drive/files/update.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index 4e56b30ace..d7b858c2ba 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -31,12 +31,10 @@ module.exports = (params, user) => new Promise(async (res, rej) => { return rej('file-not-found'); } - const updateQuery: any = {}; - // Get 'name' parameter const [name, nameErr] = $(params.name).optional.string().pipe(validateFileName).$; if (nameErr) return rej('invalid name param'); - if (name) updateQuery['metadata.name'] = name; + if (name) file.metadata.name = name; // Get 'folder_id' parameter const [folderId, folderIdErr] = $(params.folder_id).optional.nullable.id().$; @@ -44,7 +42,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { if (folderId !== undefined) { if (folderId === null) { - updateQuery['metadata.folder_id'] = null; + file.metadata.folder_id = null; } else { // Fetch folder const folder = await DriveFolder @@ -57,16 +55,19 @@ module.exports = (params, user) => new Promise(async (res, rej) => { return rej('folder-not-found'); } - updateQuery['metadata.folder_id'] = folder._id; + file.metadata.folder_id = folder._id; } } - const updated = await DriveFile.update(file._id, { - $set: { updateQuery } + await DriveFile.update(file._id, { + $set: { + 'metadata.name': file.metadata.name, + 'metadata.folder_id': file.metadata.folder_id + } }); // Serialize - const fileObj = await serialize(updated); + const fileObj = await serialize(file); // Response res(fileObj); -- cgit v1.2.3-freya From c1fc3b9f6ec176999932958a7856d160317b7762 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 18:30:49 +0900 Subject: add safety guard to serializers & fix importing uncorrect serializer --- src/api/endpoints/drive/folders/update.ts | 2 +- src/api/serializers/post.ts | 2 ++ src/api/serializers/user.ts | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/api/endpoints/drive/folders/update.ts b/src/api/endpoints/drive/folders/update.ts index eec2757878..4f2e3d2a7a 100644 --- a/src/api/endpoints/drive/folders/update.ts +++ b/src/api/endpoints/drive/folders/update.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import DriveFolder from '../../../models/drive-folder'; import { isValidFolderName } from '../../../models/drive-folder'; -import serialize from '../../../serializers/drive-file'; +import serialize from '../../../serializers/drive-folder'; import event from '../../../event'; /** diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index 5788b226f4..5a63384f0e 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -57,6 +57,8 @@ const self = async ( _post = deepcopy(post); } + if (!_post) throw 'invalid post arg.'; + const id = _post._id; // Rename _id to id diff --git a/src/api/serializers/user.ts b/src/api/serializers/user.ts index d00f073897..0d24d6cc04 100644 --- a/src/api/serializers/user.ts +++ b/src/api/serializers/user.ts @@ -56,6 +56,8 @@ export default ( _user = deepcopy(user); } + if (!_user) return reject('invalid user arg.'); + // Me const meId: mongo.ObjectID = me ? mongo.ObjectID.prototype.isPrototypeOf(me) -- cgit v1.2.3-freya From d7e1ffb0055f0786a707015350a14351b8a0fbf0 Mon Sep 17 00:00:00 2001 From: otofune Date: Mon, 6 Nov 2017 18:38:59 +0900 Subject: remove whitespace --- src/api/serializers/post.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index 5a63384f0e..03fd120772 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -57,7 +57,7 @@ const self = async ( _post = deepcopy(post); } - if (!_post) throw 'invalid post arg.'; + if (!_post) throw 'invalid post arg.'; const id = _post._id; -- cgit v1.2.3-freya From 7940c0901d4acff93169f62f4b80d58b287ca48e Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 6 Nov 2017 19:59:14 +0900 Subject: :v: --- gulpfile.ts | 4 ++-- package.json | 3 --- src/index.ts | 2 +- src/utils/cli/progressbar.ts | 2 +- src/utils/logger.ts | 4 ++-- 5 files changed, 6 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/gulpfile.ts b/gulpfile.ts index 4ee5fbce0e..448b6b7fef 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -13,7 +13,7 @@ import cssnano = require('gulp-cssnano'); import * as uglifyComposer from 'gulp-uglify/composer'; import pug = require('gulp-pug'); import * as rimraf from 'rimraf'; -import * as chalk from 'chalk'; +import chalk from 'chalk'; import imagemin = require('gulp-imagemin'); import * as rename from 'gulp-rename'; import * as mocha from 'gulp-mocha'; @@ -123,7 +123,7 @@ gulp.task('build:client:script', () => .pipe(replace('VERSION', JSON.stringify(version))) .pipe(isProduction ? uglify({ toplevel: true - }) : gutil.noop()) + } as any) : gutil.noop()) .pipe(gulp.dest('./built/web/assets/')) as any ); diff --git a/package.json b/package.json index da5badc94d..606ce9f0f0 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,6 @@ "@types/riot": "3.6.1", "@types/serve-favicon": "2.2.29", "@types/uuid": "3.4.3", - "@types/webpack": "3.0.14", - "@types/uuid": "3.4.3", "@types/webpack": "3.0.13", "@types/webpack-stream": "3.2.8", "@types/websocket": "0.0.34", @@ -91,7 +89,6 @@ "swagger-jsdoc": "1.9.7", "tslint": "5.8.0", "uglify-es": "3.0.27", - "uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony", "uglifyjs-webpack-plugin": "1.0.1", "webpack": "3.8.1" }, diff --git a/src/index.ts b/src/index.ts index aa53c91239..218455d6f4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as cluster from 'cluster'; import * as debug from 'debug'; -import * as chalk from 'chalk'; +import chalk from 'chalk'; // import portUsed = require('tcp-port-used'); import isRoot = require('is-root'); import { master } from 'accesses'; diff --git a/src/utils/cli/progressbar.ts b/src/utils/cli/progressbar.ts index 4afb4b0904..72496fdedc 100644 --- a/src/utils/cli/progressbar.ts +++ b/src/utils/cli/progressbar.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'events'; import * as readline from 'readline'; -import * as chalk from 'chalk'; +import chalk from 'chalk'; /** * Progress bar diff --git a/src/utils/logger.ts b/src/utils/logger.ts index ecfacbc952..fae1042c39 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,8 +1,8 @@ -import * as chalk from 'chalk'; +import chalk, { Chalk } from 'chalk'; export type LogLevel = 'Error' | 'Warn' | 'Info'; -function toLevelColor(level: LogLevel): chalk.ChalkStyle { +function toLevelColor(level: LogLevel): Chalk { switch (level) { case 'Error': return chalk.red; case 'Warn': return chalk.yellow; -- cgit v1.2.3-freya From 26d4ebfe1a22615f4f69bf94cc6872659e6e4125 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 6 Nov 2017 20:03:50 +0900 Subject: Refactor --- src/api/endpoints/posts/timeline.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/api/endpoints/posts/timeline.ts b/src/api/endpoints/posts/timeline.ts index 203413e23a..7af435e82a 100644 --- a/src/api/endpoints/posts/timeline.ts +++ b/src/api/endpoints/posts/timeline.ts @@ -34,11 +34,11 @@ module.exports = async (params, user, app) => { throw 'cannot set since_id and max_id'; } - const { followingIds, watchChannelIds } = await rap({ + const { followingIds, watchingChannelIds } = await rap({ // ID list of the user itself and other users who the user follows followingIds: getFriends(user._id), // Watchしているチャンネルを取得 - watchChannelIds: ChannelWatching.find({ + watchingChannelIds: ChannelWatching.find({ user_id: user._id, // 削除されたドキュメントは除く deleted_at: { $exists: false } @@ -67,7 +67,7 @@ module.exports = async (params, user, app) => { }, { // Watchしているチャンネルへの投稿 channel_id: { - $in: watchChannelIds + $in: watchingChannelIds } }] } as any; @@ -92,6 +92,5 @@ module.exports = async (params, user, app) => { }); // Serialize - const _timeline = await Promise.all(timeline.map(post => serialize(post, user))); - return _timeline; + return await Promise.all(timeline.map(post => serialize(post, user))); }; -- cgit v1.2.3-freya From 6df3db23d6277e48e68bd4a9ee78d1ac4576332c Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 6 Nov 2017 22:10:40 +0900 Subject: Fix index creation --- src/api/models/drive-file.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/api/models/drive-file.ts b/src/api/models/drive-file.ts index 8968d065cd..976c97e188 100644 --- a/src/api/models/drive-file.ts +++ b/src/api/models/drive-file.ts @@ -3,7 +3,7 @@ import monkDb, { nativeDbConn } from '../../db/mongodb'; const collection = monkDb.get('drive_files.files'); -(collection as any).createIndex('hash'); // fuck type definition +(collection as any).createIndex('md5'); // fuck type definition export default collection as any; // fuck type definition -- cgit v1.2.3-freya From b06950d5e70bc9b6321f6e144042caf1f3397d0d Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 6 Nov 2017 22:22:48 +0900 Subject: ハッシュ値はMongoDB側で管理されているから手動でインデックスを明示する必要はなさそうだ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/models/drive-file.ts | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/api/models/drive-file.ts b/src/api/models/drive-file.ts index 976c97e188..802ee5a5fe 100644 --- a/src/api/models/drive-file.ts +++ b/src/api/models/drive-file.ts @@ -3,8 +3,6 @@ import monkDb, { nativeDbConn } from '../../db/mongodb'; const collection = monkDb.get('drive_files.files'); -(collection as any).createIndex('md5'); // fuck type definition - export default collection as any; // fuck type definition const getGridFSBucket = async (): Promise => { -- cgit v1.2.3-freya From f80283a94f4fb08f1df7d2ad95848591420f8478 Mon Sep 17 00:00:00 2001 From: otofune Date: Tue, 7 Nov 2017 09:04:16 +0900 Subject: add 'format' script to use autofix w/ tslint --- gulpfile.ts | 9 +++++++++ package.json | 3 ++- src/file/server.ts | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/gulpfile.ts b/gulpfile.ts index 448b6b7fef..04bd2b1c43 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -81,6 +81,15 @@ gulp.task('lint', () => .pipe(tslint.report()) ); +gulp.task('format', () => +gulp.src('./src/**/*.ts') + .pipe(tslint({ + formatter: 'verbose', + fix: true + })) + .pipe(tslint.report()) +); + gulp.task('mocha', () => gulp.src([]) .pipe(mocha({ diff --git a/package.json b/package.json index c384edb22b..1593cd7d00 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "clean": "gulp clean", "cleanall": "gulp cleanall", "lint": "gulp lint", - "test": "gulp test" + "test": "gulp test", + "format": "gulp format" }, "devDependencies": { "@types/bcryptjs": "2.4.1", diff --git a/src/file/server.ts b/src/file/server.ts index 375f29487d..39e21d10ec 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -110,7 +110,7 @@ app.get('/:id', async (req, res) => { const buffer = await ((id): Promise => new Promise((resolve, reject) => { const chunks = []; const readableStream = bucket.openDownloadStream(id); - readableStream.on('data', chunk => { + readableStream.on('data', chunk => { chunks.push(chunk); }); readableStream.on('end', () => { @@ -141,7 +141,7 @@ app.get('/:id/:name', async (req, res) => { const buffer = await ((id): Promise => new Promise((resolve, reject) => { const chunks = []; const readableStream = bucket.openDownloadStream(id); - readableStream.on('data', chunk => { + readableStream.on('data', chunk => { chunks.push(chunk); }); readableStream.on('end', () => { -- cgit v1.2.3-freya From 8e62cc1efd6dc1710e7faa7d3ad2086425573cf5 Mon Sep 17 00:00:00 2001 From: otofune Date: Tue, 7 Nov 2017 09:14:39 +0900 Subject: file - unify '/:id' & '/:id/:name' --- src/file/server.ts | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/file/server.ts b/src/file/server.ts index 39e21d10ec..e83acd4f24 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -86,11 +86,7 @@ function send(data: Buffer, type: string, req: express.Request, res: express.Res } } -/** - * Routing - */ - -app.get('/:id', async (req, res) => { +async function sendFileById (req: express.Request, res: express.Response): Promise { // Validate id if (!mongodb.ObjectID.isValid(req.params.id)) { res.status(400).send('incorrect id'); @@ -119,37 +115,13 @@ app.get('/:id', async (req, res) => { }))(fileId); send(buffer, file.metadata.type, req, res); -}); - -app.get('/:id/:name', async (req, res) => { - // Validate id - if (!mongodb.ObjectID.isValid(req.params.id)) { - res.status(400).send('incorrect id'); - return; - } - - const fileId = new mongodb.ObjectID(req.params.id); - const file = await DriveFile.findOne({ _id: fileId }); - - if (file == null) { - res.status(404).sendFile(`${__dirname}/assets/dummy.png`); - return; - } - - const bucket = await getGridFSBucket(); +} - const buffer = await ((id): Promise => new Promise((resolve, reject) => { - const chunks = []; - const readableStream = bucket.openDownloadStream(id); - readableStream.on('data', chunk => { - chunks.push(chunk); - }); - readableStream.on('end', () => { - resolve(Buffer.concat(chunks)); - }); - }))(fileId); +/** + * Routing + */ - send(buffer, file.metadata.type, req, res); -}); +app.get('/:id', sendFileById); +app.get('/:id/:name', sendFileById); module.exports = app; -- cgit v1.2.3-freya From a7762aea4fa0cade3614323a83d6f8d74ade924a Mon Sep 17 00:00:00 2001 From: otofune Date: Tue, 7 Nov 2017 09:18:40 +0900 Subject: file - if 'name' param given, validate --- src/file/server.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/file/server.ts b/src/file/server.ts index e83acd4f24..1152b650be 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -86,7 +86,7 @@ function send(data: Buffer, type: string, req: express.Request, res: express.Res } } -async function sendFileById (req: express.Request, res: express.Response): Promise { +async function sendFileById(req: express.Request, res: express.Response): Promise { // Validate id if (!mongodb.ObjectID.isValid(req.params.id)) { res.status(400).send('incorrect id'); @@ -96,6 +96,12 @@ async function sendFileById (req: express.Request, res: express.Response): Promi const fileId = new mongodb.ObjectID(req.params.id); const file = await DriveFile.findOne({ _id: fileId }); + // validate name + if (req.params.name !== undefined && req.params.name !== file.metadata.name) { + res.status(404).send('there is no file has given name'); + return; + } + if (file == null) { res.status(404).sendFile(`${__dirname}/assets/dummy.png`); return; -- cgit v1.2.3-freya From fb422b4d603c53a70712caba55b35a48a8c2e619 Mon Sep 17 00:00:00 2001 From: otofune Date: Tue, 7 Nov 2017 09:30:51 +0900 Subject: use 'name' param as GridFS file's 'filename' --- src/api/common/add-file-to-drive.ts | 3 +-- src/api/endpoints/drive/files/find.ts | 2 +- src/api/endpoints/drive/files/update.ts | 4 ++-- src/api/serializers/drive-file.ts | 1 + src/file/server.ts | 2 +- tools/migration/use-gridfs.js | 4 +++- 6 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index f9c22ccacd..e1baf08191 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -144,11 +144,10 @@ export default ( } // Create DriveFile document - const file = await addToGridFS(`${user._id}/${name}`, data, { + const file = await addToGridFS(name, data, { user_id: user._id, folder_id: folder !== null ? folder._id : null, type: mime, - name: name, comment: comment, properties: properties }); diff --git a/src/api/endpoints/drive/files/find.ts b/src/api/endpoints/drive/files/find.ts index 1c818131d7..a1cdf1643e 100644 --- a/src/api/endpoints/drive/files/find.ts +++ b/src/api/endpoints/drive/files/find.ts @@ -24,7 +24,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Issue query const files = await DriveFile .find({ - 'metadata.name': name, + filename: name, 'metadata.user_id': user._id, 'metadata.folder_id': folderId }); diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index d7b858c2ba..f265142c4d 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -34,7 +34,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Get 'name' parameter const [name, nameErr] = $(params.name).optional.string().pipe(validateFileName).$; if (nameErr) return rej('invalid name param'); - if (name) file.metadata.name = name; + if (name) file.filename = name; // Get 'folder_id' parameter const [folderId, folderIdErr] = $(params.folder_id).optional.nullable.id().$; @@ -61,7 +61,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { await DriveFile.update(file._id, { $set: { - 'metadata.name': file.metadata.name, + filename: file.filename, 'metadata.folder_id': file.metadata.folder_id } }); diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index 2af7db5726..57b74cd975 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -47,6 +47,7 @@ export default ( _target.id = _file._id; _target.created_at = _file.uploadDate; + _target.name = _file.filename; _target = Object.assign(_target, _file.metadata); diff --git a/src/file/server.ts b/src/file/server.ts index 1152b650be..39c2cdd2a1 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -97,7 +97,7 @@ async function sendFileById(req: express.Request, res: express.Response): Promis const file = await DriveFile.findOne({ _id: fileId }); // validate name - if (req.params.name !== undefined && req.params.name !== file.metadata.name) { + if (req.params.name !== undefined && req.params.name !== file.filename) { res.status(404).send('there is no file has given name'); return; } diff --git a/tools/migration/use-gridfs.js b/tools/migration/use-gridfs.js index d41514416c..148f9be261 100644 --- a/tools/migration/use-gridfs.js +++ b/tools/migration/use-gridfs.js @@ -21,15 +21,17 @@ const migrateToGridFS = async (doc) => { const id = doc._id const buffer = doc.data.buffer const created_at = doc.created_at + const name = doc.name delete doc._id delete doc.created_at delete doc.datasize delete doc.hash delete doc.data + delete doc.name const bucket = await getGridFSBucket() - const added = await writeToGridFS(bucket, buffer, id, `${id}/${doc.name}`, { metadata: doc }) + const added = await writeToGridFS(bucket, buffer, id, name, { metadata: doc }) const result = await DriveFile.update(id, { $set: { -- cgit v1.2.3-freya From a85d5ac4bbfe35652be1bef47f59a79ace7b2c73 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 7 Nov 2017 21:04:32 +0900 Subject: #882 --- src/api/common/add-file-to-drive.ts | 7 +++--- src/api/serializers/drive-file.ts | 1 + tools/migration/issue_882.js | 44 +++++++++++++++++++++++++++++++++++++ tools/migration/use-gridfs.js | 4 +++- 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 tools/migration/issue_882.js (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index e1baf08191..a96906d291 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -13,13 +13,13 @@ import { Duplex } from 'stream'; const log = debug('misskey:register-drive-file'); -const addToGridFS = (name, binary, metadata): Promise => new Promise(async (resolve, reject) => { +const addToGridFS = (name, binary, type, metadata): Promise => new Promise(async (resolve, reject) => { const dataStream = new Duplex(); dataStream.push(binary); dataStream.push(null); const bucket = await getGridFSBucket(); - const writeStream = bucket.openUploadStream(name, { metadata }); + const writeStream = bucket.openUploadStream(name, { contentType: type, metadata }); writeStream.once('finish', (doc) => { resolve(doc); }); writeStream.on('error', reject); dataStream.pipe(writeStream); @@ -144,10 +144,9 @@ export default ( } // Create DriveFile document - const file = await addToGridFS(name, data, { + const file = await addToGridFS(name, data, mime, { user_id: user._id, folder_id: folder !== null ? folder._id : null, - type: mime, comment: comment, properties: properties }); diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index 57b74cd975..3b76979a44 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -48,6 +48,7 @@ export default ( _target.id = _file._id; _target.created_at = _file.uploadDate; _target.name = _file.filename; + _target.type = _file.contentType; _target = Object.assign(_target, _file.metadata); diff --git a/tools/migration/issue_882.js b/tools/migration/issue_882.js new file mode 100644 index 0000000000..67a1551e04 --- /dev/null +++ b/tools/migration/issue_882.js @@ -0,0 +1,44 @@ +// for Node.js interpret + +const { default: DriveFile } = require('../../built/api/models/drive-file') + +const migrate = async (doc) => { + const result = await DriveFile.update(doc._id, { + $set: { + contentType: doc.metadata.type + }, + $unset: { + 'metadata.type': '' + } + }) + return result.ok === 1 +} + +async function main() { + let i = 0; + + const count = await db.get('drive_files').count({}); + + const iterate = async () => { + if (i == count) return true; + console.log(`${i} / ${count}`); + const doc = (await db.get('drive_files').find({}, { limit: 1, skip: i }))[0] + const res = await migrate(doc); + if (!res) { + return false; + } else { + i++ + return await iterate(); + } + } + + const res = await iterate(); + + if (res) { + return 'ok'; + } else { + throw 'something happened'; + } +} + +main().then(console.dir).catch(console.error) diff --git a/tools/migration/use-gridfs.js b/tools/migration/use-gridfs.js index c5883e4562..106cbd3889 100644 --- a/tools/migration/use-gridfs.js +++ b/tools/migration/use-gridfs.js @@ -22,6 +22,7 @@ const migrateToGridFS = async (doc) => { const buffer = doc.data ? doc.data.buffer : Buffer.from([0x00]) // アップロードのバグなのか知らないけどなぜか data が存在しない drive_file ドキュメントがまれにあることがわかったので const created_at = doc.created_at const name = doc.name + const type = doc.type delete doc._id delete doc.created_at @@ -29,9 +30,10 @@ const migrateToGridFS = async (doc) => { delete doc.hash delete doc.data delete doc.name + delete doc.type const bucket = await getGridFSBucket() - const added = await writeToGridFS(bucket, buffer, id, name, { metadata: doc }) + const added = await writeToGridFS(bucket, buffer, id, name, { contentType: type, metadata: doc }) const result = await DriveFile.update(id, { $set: { -- cgit v1.2.3-freya From bb8fd5b90f2f1c4545cb66e2b2865461d6403a5d Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 7 Nov 2017 21:16:13 +0900 Subject: Fix bug --- src/file/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/file/server.ts b/src/file/server.ts index 39c2cdd2a1..2007667a83 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -120,7 +120,7 @@ async function sendFileById(req: express.Request, res: express.Response): Promis }); }))(fileId); - send(buffer, file.metadata.type, req, res); + send(buffer, file.contentType, req, res); } /** -- cgit v1.2.3-freya From 6b0db9b8778e39b0c5b0ddcf8afc7068d1d80076 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 7 Nov 2017 21:23:09 +0900 Subject: :v: --- src/file/assets/not-an-image.png | Bin 0 -> 4711 bytes src/file/server.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/file/assets/not-an-image.png (limited to 'src') diff --git a/src/file/assets/not-an-image.png b/src/file/assets/not-an-image.png new file mode 100644 index 0000000000..bf98b293f7 Binary files /dev/null and b/src/file/assets/not-an-image.png differ diff --git a/src/file/server.ts b/src/file/server.ts index 2007667a83..449fa2d740 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -54,7 +54,7 @@ async function raw(data: Buffer, type: string, download: boolean, res: express.R async function thumbnail(data: Buffer, type: string, resize: number, res: express.Response): Promise { if (!/^image\/.*$/.test(type)) { - data = fs.readFileSync(`${__dirname}/assets/dummy.png`); + data = fs.readFileSync(`${__dirname}/assets/not-an-image.png`); } let g = gm(data); -- cgit v1.2.3-freya From 253747ecfb8245d94fe0110e01d8f2ca65a28f5d Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 8 Nov 2017 14:43:42 +0900 Subject: Fix bugs --- src/api/endpoints/drive/stream.ts | 5 +---- src/api/serializers/drive-file.ts | 2 ++ src/web/app/mobile/tags/drive/file-viewer.tag | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/api/endpoints/drive/stream.ts b/src/api/endpoints/drive/stream.ts index 32f7ac7e0a..58e7d11678 100644 --- a/src/api/endpoints/drive/stream.ts +++ b/src/api/endpoints/drive/stream.ts @@ -52,15 +52,12 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }; } if (type) { - query.type = new RegExp(`^${type.replace(/\*/g, '.+?')}$`); + query.contentType = new RegExp(`^${type.replace(/\*/g, '.+?')}$`); } // Issue query const files = await DriveFile .find(query, { - fields: { - data: false - }, limit: limit, sort: sort }); diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts index 3b76979a44..dcdaa01fab 100644 --- a/src/api/serializers/drive-file.ts +++ b/src/api/serializers/drive-file.ts @@ -49,6 +49,8 @@ export default ( _target.created_at = _file.uploadDate; _target.name = _file.filename; _target.type = _file.contentType; + _target.datasize = _file.length; + _target.md5 = _file.md5; _target = Object.assign(_target, _file.metadata); diff --git a/src/web/app/mobile/tags/drive/file-viewer.tag b/src/web/app/mobile/tags/drive/file-viewer.tag index e6129652b0..8dc49a0865 100644 --- a/src/web/app/mobile/tags/drive/file-viewer.tag +++ b/src/web/app/mobile/tags/drive/file-viewer.tag @@ -44,7 +44,7 @@

%i18n:mobile.tags.mk-drive-file-viewer.hash%

- { file.hash } + { file.md5 } + + diff --git a/src/web/app/desktop/tags/pages/selectdrive.tag b/src/web/app/desktop/tags/pages/selectdrive.tag index 63fc588fac..9c3ac16eb1 100644 --- a/src/web/app/desktop/tags/pages/selectdrive.tag +++ b/src/web/app/desktop/tags/pages/selectdrive.tag @@ -1,15 +1,16 @@
- - - + + +
diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js index 7997bcc7f2..c36a06e499 100644 --- a/src/web/app/desktop/tags/index.js +++ b/src/web/app/desktop/tags/index.js @@ -57,6 +57,7 @@ require('./pages/entrance.tag'); require('./pages/entrance/signin.tag'); require('./pages/entrance/signup.tag'); require('./pages/home.tag'); +require('./pages/home-customize.tag'); require('./pages/user.tag'); require('./pages/post.tag'); require('./pages/search.tag'); diff --git a/src/web/app/desktop/tags/pages/home-customize.tag b/src/web/app/desktop/tags/pages/home-customize.tag new file mode 100644 index 0000000000..4434015615 --- /dev/null +++ b/src/web/app/desktop/tags/pages/home-customize.tag @@ -0,0 +1,14 @@ + + + + + + + diff --git a/src/web/app/desktop/tags/settings.tag b/src/web/app/desktop/tags/settings.tag index eabddfb432..4c16f9eaa8 100644 --- a/src/web/app/desktop/tags/settings.tag +++ b/src/web/app/desktop/tags/settings.tag @@ -38,6 +38,7 @@

デザイン

+ ホームをカスタマイズ
diff --git a/src/web/app/desktop/tags/ui.tag b/src/web/app/desktop/tags/ui.tag index 0a3e8d9c53..6a4982877f 100644 --- a/src/web/app/desktop/tags/ui.tag +++ b/src/web/app/desktop/tags/ui.tag @@ -37,7 +37,7 @@ - +
diff --git a/src/web/app/init.js b/src/web/app/init.js index 5a6899ed4f..7e3c2ee377 100644 --- a/src/web/app/init.js +++ b/src/web/app/init.js @@ -11,7 +11,6 @@ import checkForUpdate from './common/scripts/check-for-update'; import Connection from './common/scripts/home-stream'; import Progress from './common/scripts/loading'; import mixin from './common/mixins'; -import generateDefaultUserdata from './common/scripts/generate-default-userdata'; import CONFIG from './common/scripts/config'; require('./common/tags'); @@ -156,9 +155,7 @@ function fetchme(token, cb) { res.json().then(i => { me = i; me.token = token; - - // initialize it if user data is empty - me.data ? done() : init(); + done(); }); }, () => { // When failure // Render the error screen @@ -170,17 +167,6 @@ function fetchme(token, cb) { function done() { if (cb) cb(me); } - - // Initialize user data - function init() { - const data = generateDefaultUserdata(); - api(token, 'i/appdata/set', { - data - }).then(() => { - me.data = data; - done(); - }); - } } // BSoD diff --git a/tools/migration/node.2017-11-08..js b/tools/migration/node.2017-11-08..js new file mode 100644 index 0000000000..e25b83b3f3 --- /dev/null +++ b/tools/migration/node.2017-11-08..js @@ -0,0 +1,89 @@ +const uuid = require('uuid'); +const { default: User } = require('../../built/api/models/user') +const { default: zip } = require('@prezzemolo/zip') + +const home = { + left: [ + 'profile', + 'calendar', + 'activity', + 'rss-reader', + 'trends', + 'photo-stream', + 'version' + ], + right: [ + 'broadcast', + 'notifications', + 'user-recommendation', + 'recommended-polls', + 'server', + 'donation', + 'nav', + 'tips' + ] +}; + + +const migrate = async (doc) => { + + //#region Construct home data + const homeData = []; + + home.left.forEach(widget => { + homeData.push({ + name: widget, + id: uuid(), + place: 'left', + data: {} + }); + }); + + home.right.forEach(widget => { + homeData.push({ + name: widget, + id: uuid(), + place: 'right', + data: {} + }); + }); + //#endregion + + const result = await User.update(doc._id, { + $unset: { + data: '' + }, + $set: { + 'settings': {}, + 'client_settings.home': homeData, + 'client_settings.show_donation': false + } + }) + + return added && result.ok === 1 +} + +async function main() { + const count = await db.get('users').count(); + + console.log(`there are ${count} users.`) + + const dop = Number.parseInt(process.argv[2]) || 5 + const idop = ((count - (count % dop)) / dop) + 1 + + return zip( + 1, + async (time) => { + console.log(`${time} / ${idop}`) + const docs = await db.get('users').find({}, { limit: dop, skip: time * dop }) + return Promise.all(docs.map(migrate)) + }, + idop + ).then(a => { + const rv = [] + a.forEach(e => rv.push(...e)) + return rv + }) +} + +main().then(console.dir).catch(console.error) -- cgit v1.2.3-freya From bdffc00dca64672b837f7e4b20a3e0a1aaaf766f Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 9 Nov 2017 02:28:01 +0900 Subject: Clean up --- locales/en.yml | 1 - locales/ja.yml | 1 - src/web/app/desktop/tags/drive/file.tag | 3 --- 3 files changed, 5 deletions(-) (limited to 'src') diff --git a/locales/en.yml b/locales/en.yml index 6796510336..9e19728af6 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -225,7 +225,6 @@ desktop: mk-drive-browser-file: avatar: "Avatar" banner: "Banner" - wallpaper: "Wallpaper" mk-drive-browser-folder-contextmenu: move-to-this-folder: "Move to this folder" diff --git a/locales/ja.yml b/locales/ja.yml index c146475b2b..39cc41d0a2 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -225,7 +225,6 @@ desktop: mk-drive-browser-file: avatar: "アバター" banner: "バナー" - wallpaper: "壁紙" mk-drive-browser-folder-contextmenu: move-to-this-folder: "このフォルダへ移動" diff --git a/src/web/app/desktop/tags/drive/file.tag b/src/web/app/desktop/tags/drive/file.tag index 64838d6814..bf9d38bd2f 100644 --- a/src/web/app/desktop/tags/drive/file.tag +++ b/src/web/app/desktop/tags/drive/file.tag @@ -5,9 +5,6 @@

%i18n:desktop.tags.mk-drive-browser-file.banner%

-
-

%i18n:desktop.tags.mk-drive-browser-file.wallpaper%

-

{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }{ file.name.substr(file.name.lastIndexOf('.')) }

+ + diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index f0c71a7ea8..531adca4ce 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -9,6 +9,7 @@ + diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js index c36a06e499..75bbdae95a 100644 --- a/src/web/app/desktop/tags/index.js +++ b/src/web/app/desktop/tags/index.js @@ -12,6 +12,7 @@ require('./drive/nav-folder.tag'); require('./drive/browser-window.tag'); require('./drive/browser.tag'); require('./select-file-from-drive-window.tag'); +require('./select-folder-from-drive-window.tag'); require('./crop-window.tag'); require('./settings.tag'); require('./settings-window.tag'); @@ -38,6 +39,7 @@ require('./home-widgets/recommended-polls.tag'); require('./home-widgets/trends.tag'); require('./home-widgets/activity.tag'); require('./home-widgets/server.tag'); +require('./home-widgets/slideshow.tag'); require('./timeline.tag'); require('./messaging/window.tag'); require('./messaging/room-window.tag'); diff --git a/src/web/app/desktop/tags/select-folder-from-drive-window.tag b/src/web/app/desktop/tags/select-folder-from-drive-window.tag new file mode 100644 index 0000000000..375f428bfc --- /dev/null +++ b/src/web/app/desktop/tags/select-folder-from-drive-window.tag @@ -0,0 +1,112 @@ + + + + + + + +
+ + +
+
+
+ + +
-- cgit v1.2.3-freya From f7408f4e82f0c6c94fb8b27dbfc0f9bdd2a62b5d Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 9 Nov 2017 03:05:26 +0900 Subject: Fix glitch --- src/web/app/desktop/tags/home-widgets/slideshow.tag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/home-widgets/slideshow.tag b/src/web/app/desktop/tags/home-widgets/slideshow.tag index da65bf91bd..f702388606 100644 --- a/src/web/app/desktop/tags/home-widgets/slideshow.tag +++ b/src/web/app/desktop/tags/home-widgets/slideshow.tag @@ -1,7 +1,7 @@

クリックしてフォルダを指定してください

-

このフォルダには画像がありません

+

このフォルダには画像がありません

@@ -55,7 +55,7 @@ this.size = this.opts.data.hasOwnProperty('size') ? this.opts.data.size : 0; this.folder = this.opts.data.hasOwnProperty('folder') ? this.opts.data.folder : undefined; this.images = []; - this.fetching = false; + this.fetching = true; this.on('mount', () => { this.applySize(); -- cgit v1.2.3-freya From 173ee4bb0eb970b0f619233ee7cec649e90d510f Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 9 Nov 2017 13:33:41 +0900 Subject: スライドショーをランダムに MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/web/app/desktop/tags/home-widgets/slideshow.tag | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/home-widgets/slideshow.tag b/src/web/app/desktop/tags/home-widgets/slideshow.tag index f702388606..aa1e45fad3 100644 --- a/src/web/app/desktop/tags/home-widgets/slideshow.tag +++ b/src/web/app/desktop/tags/home-widgets/slideshow.tag @@ -100,14 +100,12 @@ this.change = () => { if (this.images.length == 0) return; - if (this.index >= this.images.length) this.index = 0; - const img = `url(${ this.images[this.index].url }?thumbnail&size=1024)`; + const index = Math.floor(Math.random() * this.images.length); + const img = `url(${ this.images[index].url }?thumbnail&size=1024)`; this.refs.slideB.style.backgroundImage = img; - this.index++; - anime({ targets: this.refs.slideB, opacity: 1, @@ -136,8 +134,7 @@ }).then(images => { this.update({ fetching: false, - images: images, - index: 0 + images: images }); this.refs.slideA.style.backgroundImage = ''; this.refs.slideB.style.backgroundImage = ''; -- cgit v1.2.3-freya From 70ba9c57a7440a82a279e422afba7102f00f080e Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 9 Nov 2017 15:07:09 +0900 Subject: #886 --- CHANGELOG.md | 4 + locales/en.yml | 4 + locales/ja.yml | 4 + src/web/app/desktop/tags/home-widgets/channel.tag | 309 ++++++++++++++++++++++ src/web/app/desktop/tags/home.tag | 1 + src/web/app/desktop/tags/index.js | 1 + 6 files changed, 323 insertions(+) create mode 100644 src/web/app/desktop/tags/home-widgets/channel.tag (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 81b0246f08..da2b187d10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ChangeLog (Release Notes) ========================= 主に notable な changes を書いていきます +unlereased +----------------- +* チャンネルウィジェットを追加 + 2984 (2017/11/09) ----------------- * スライドショーウィジェットを追加 diff --git a/locales/en.yml b/locales/en.yml index 9e19728af6..c69dc22b1d 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -365,6 +365,10 @@ desktop: title: "Donation" text: "To manage Misskey we spend money for our domain server etc.. There's no incomes for us so we need your tip. If you're interested contact {}. Thank you for your contribution!" + mk-channel-home-widget: + title: "Channel" + settings: "Widget settings" + mk-repost-form: quote: "Quote..." cancel: "Cancel" diff --git a/locales/ja.yml b/locales/ja.yml index 39cc41d0a2..782b87bd83 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -365,6 +365,10 @@ desktop: title: "寄付のお願い" text: "Misskeyの運営にはドメイン、サーバー等のコストが掛かります。Misskeyは広告を掲載したりしないため、収入を皆様からの寄付に頼っています。もしご興味があれば、{}までご連絡ください。ご協力ありがとうございます。" + mk-channel-home-widget: + title: "チャンネル" + settings: "ウィジェットの設定" + mk-repost-form: quote: "引用する..." cancel: "キャンセル" diff --git a/src/web/app/desktop/tags/home-widgets/channel.tag b/src/web/app/desktop/tags/home-widgets/channel.tag new file mode 100644 index 0000000000..b855790453 --- /dev/null +++ b/src/web/app/desktop/tags/home-widgets/channel.tag @@ -0,0 +1,309 @@ + +

{ + channel ? channel.title : '%i18n:desktop.tags.mk-channel-home-widget.title%' + }

+ + + + +
+ + +

読み込み中

+
+

まだ投稿がありません

+ +
+ + + +
+ + +
+ { post.index }: + { post.user.name } + ID:{ post.user.username } +
+
+ >>{ post.reply.index } + { post.text } +
+ + + { + + +
+
+ + +
+ + +

>>{ reply.index } ({ reply.user.name }): [x]

+ + + +
diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index 531adca4ce..5fc5e0d6a7 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -15,6 +15,7 @@ + diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js index 75bbdae95a..ff513657ac 100644 --- a/src/web/app/desktop/tags/index.js +++ b/src/web/app/desktop/tags/index.js @@ -40,6 +40,7 @@ require('./home-widgets/trends.tag'); require('./home-widgets/activity.tag'); require('./home-widgets/server.tag'); require('./home-widgets/slideshow.tag'); +require('./home-widgets/channel.tag'); require('./timeline.tag'); require('./messaging/window.tag'); require('./messaging/room-window.tag'); -- cgit v1.2.3-freya From 515a8740816ab6f3a2a8754b8a85001b0c844bc8 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 9 Nov 2017 21:19:08 +0900 Subject: :art: --- src/web/app/desktop/tags/home-widgets/channel.tag | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/home-widgets/channel.tag b/src/web/app/desktop/tags/home-widgets/channel.tag index b855790453..0434b6e886 100644 --- a/src/web/app/desktop/tags/home-widgets/channel.tag +++ b/src/web/app/desktop/tags/home-widgets/channel.tag @@ -103,11 +103,20 @@ -

>>{ reply.index } ({ reply.user.name }): [x]

+ + diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index ecfe23adee..452499d70c 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -5,6 +5,7 @@ +
+

Tip: 一部のウィジェットは、クリックすることで表示を変更することができます。

@@ -213,11 +215,22 @@ break; } - this.home.push(riot.mount(el, { + const tag = riot.mount(el, { id: widget.id, data: widget.data, tl: this.refs.tl - })[0]); + })[0]; + + this.home.push(tag); + + if (this.opts.customize) { + actualEl.oncontextmenu = e => { + e.preventDefault(); + e.stopImmediatePropagation(); + if (tag.func) tag.func(); + return false; + }; + } }; this.addWidget = () => { -- cgit v1.2.3-freya From 0ff8c11ee1a932b90b400c2d239dbee14ad233ba Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Nov 2017 05:38:48 +0900 Subject: :v: --- src/web/app/desktop/mixins/widget.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/web/app/desktop/mixins/widget.js b/src/web/app/desktop/mixins/widget.js index d21811fa2c..2bf858ebe6 100644 --- a/src/web/app/desktop/mixins/widget.js +++ b/src/web/app/desktop/mixins/widget.js @@ -16,6 +16,7 @@ riot.mixin('widget', { }, save: function() { + this.update(); this.api('i/update_home', { id: this.id, data: this.data -- cgit v1.2.3-freya From 393113a2822a55e77e195a8a34a486528f335fa4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Nov 2017 05:52:35 +0900 Subject: Improve widgets --- src/web/app/desktop/tags/home-widgets/channel.tag | 18 ++++++--- src/web/app/desktop/tags/home-widgets/profile.tag | 43 ++++++++++++++++++++-- .../tags/home-widgets/recommended-polls.tag | 17 +++++++-- .../app/desktop/tags/home-widgets/rss-reader.tag | 17 ++++++++- src/web/app/desktop/tags/home-widgets/trends.tag | 17 +++++++-- 5 files changed, 96 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/home-widgets/channel.tag b/src/web/app/desktop/tags/home-widgets/channel.tag index c1a29f60bc..b5a57277f6 100644 --- a/src/web/app/desktop/tags/home-widgets/channel.tag +++ b/src/web/app/desktop/tags/home-widgets/channel.tag @@ -1,8 +1,10 @@ -

{ - channel ? channel.title : '%i18n:desktop.tags.mk-channel-home-widget.title%' - }

- + +

{ + channel ? channel.title : '%i18n:desktop.tags.mk-channel-home-widget.title%' + }

+ +

%i18n:desktop.tags.mk-channel-home-widget.get-started%

diff --git a/src/web/app/desktop/tags/home-widgets/profile.tag b/src/web/app/desktop/tags/home-widgets/profile.tag index e6a8752113..3fdf4343e0 100644 --- a/src/web/app/desktop/tags/home-widgets/profile.tag +++ b/src/web/app/desktop/tags/home-widgets/profile.tag @@ -1,5 +1,7 @@ - - avatar{ I.name } + + + avatar + { I.name }

@{ I.username }

diff --git a/src/web/app/desktop/tags/home-widgets/rss-reader.tag b/src/web/app/desktop/tags/home-widgets/rss-reader.tag index e9b740762e..9c213cf792 100644 --- a/src/web/app/desktop/tags/home-widgets/rss-reader.tag +++ b/src/web/app/desktop/tags/home-widgets/rss-reader.tag @@ -1,6 +1,8 @@ -

RSS

- + +

RSS

+ +
@@ -62,6 +64,12 @@
diff --git a/src/web/app/desktop/tags/home-widgets/trends.tag b/src/web/app/desktop/tags/home-widgets/trends.tag index 021df3f728..f824d89cfd 100644 --- a/src/web/app/desktop/tags/home-widgets/trends.tag +++ b/src/web/app/desktop/tags/home-widgets/trends.tag @@ -1,6 +1,8 @@ -

%i18n:desktop.tags.mk-trends-home-widget.title%

- + +

%i18n:desktop.tags.mk-trends-home-widget.title%

+ +

{ post.text }

@{ post.user.username }

@@ -72,7 +74,11 @@ -- cgit v1.2.3-freya From 64c66daa02ae3ea550a2b34cafc8d09cf92d8b42 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Nov 2017 06:06:09 +0900 Subject: :art: --- src/web/app/desktop/tags/home-widgets/channel.tag | 1 + src/web/app/desktop/tags/home-widgets/profile.tag | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/home-widgets/channel.tag b/src/web/app/desktop/tags/home-widgets/channel.tag index b5a57277f6..8f3d39d0e1 100644 --- a/src/web/app/desktop/tags/home-widgets/channel.tag +++ b/src/web/app/desktop/tags/home-widgets/channel.tag @@ -11,6 +11,7 @@ :scope display block background #fff + overflow hidden > .title z-index 2 diff --git a/src/web/app/desktop/tags/home-widgets/profile.tag b/src/web/app/desktop/tags/home-widgets/profile.tag index 3fdf4343e0..1439a423b2 100644 --- a/src/web/app/desktop/tags/home-widgets/profile.tag +++ b/src/web/app/desktop/tags/home-widgets/profile.tag @@ -1,6 +1,6 @@ - avatar + avatar { I.name }

@{ I.username }

diff --git a/src/web/app/desktop/tags/home-widgets/photo-stream.tag b/src/web/app/desktop/tags/home-widgets/photo-stream.tag index 7f8dd8563a..84d0020a6b 100644 --- a/src/web/app/desktop/tags/home-widgets/photo-stream.tag +++ b/src/web/app/desktop/tags/home-widgets/photo-stream.tag @@ -1,5 +1,5 @@ - - + +

%i18n:desktop.tags.mk-photo-stream-home-widget.title%

%i18n:common.loading%

@@ -14,6 +14,17 @@ display block background #fff + &[data-melt] + background transparent !important + border none !important + + > .stream + padding 0 + + > .img + border solid 4px transparent + border-radius 8px + > .title z-index 1 margin 0 @@ -58,7 +69,7 @@ diff --git a/src/web/app/desktop/tags/home-widgets/profile.tag b/src/web/app/desktop/tags/home-widgets/profile.tag index 1439a423b2..7d4cf862f6 100644 --- a/src/web/app/desktop/tags/home-widgets/profile.tag +++ b/src/web/app/desktop/tags/home-widgets/profile.tag @@ -1,4 +1,4 @@ - + avatar { I.name } @@ -36,6 +36,20 @@ > .username display none + &[data-melt] + background transparent !important + border none !important + + > .banner + visibility hidden + + > .avatar + box-shadow none + + > .name + color #666 + text-shadow none + > .banner height 100px background-color #f5f5f5 @@ -77,7 +91,7 @@ import updateBanner from '../../scripts/update-banner'; this.data = { - compact: false + design: 0 }; this.mixin('widget'); @@ -93,7 +107,7 @@ }; this.func = () => { - this.data.compact = !this.data.compact; + if (++this.data.design == 3) this.data.design = 0; this.save(); }; diff --git a/src/web/app/desktop/tags/home-widgets/server.tag b/src/web/app/desktop/tags/home-widgets/server.tag index b2e3b9d904..094af87594 100644 --- a/src/web/app/desktop/tags/home-widgets/server.tag +++ b/src/web/app/desktop/tags/home-widgets/server.tag @@ -1,5 +1,5 @@ - - + +

%i18n:desktop.tags.mk-server-home-widget.title%

@@ -15,6 +15,10 @@ display block background #fff + &[data-melt] + background transparent !important + border none !important + > .title z-index 1 margin 0 @@ -60,7 +64,7 @@ this.data = { view: 0, - compact: false + design: 0 }; this.mixin('widget'); @@ -90,7 +94,7 @@ }; this.func = () => { - this.data.compact = !this.data.compact; + if (++this.data.design == 3) this.data.design = 0; this.save(); }; diff --git a/src/web/app/desktop/tags/home-widgets/timemachine.tag b/src/web/app/desktop/tags/home-widgets/timemachine.tag index 75e9f3a339..984258d2ba 100644 --- a/src/web/app/desktop/tags/home-widgets/timemachine.tag +++ b/src/web/app/desktop/tags/home-widgets/timemachine.tag @@ -1,10 +1,12 @@ - - -

{ '%i18n:desktop.tags.mk-timemachine-home-widget.title%'.replace('{1}', year).replace('{2}', month) }

- + + + +

{ '%i18n:desktop.tags.mk-timemachine-home-widget.title%'.replace('{1}', year).replace('{2}', month) }

+ +
-
{ weekdayText[i] }
@@ -22,6 +24,10 @@ color #777 background #fff + &[data-melt] + background transparent !important + border none !important + > .title z-index 1 margin 0 @@ -130,6 +136,12 @@ -- cgit v1.2.3-freya From 800d409949e990047dd0dd712a135fe957db7488 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Nov 2017 16:26:09 +0900 Subject: Refactor --- src/web/app/desktop/tags/home-widgets/profile.tag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/home-widgets/profile.tag b/src/web/app/desktop/tags/home-widgets/profile.tag index 7d4cf862f6..ddb6472a8f 100644 --- a/src/web/app/desktop/tags/home-widgets/profile.tag +++ b/src/web/app/desktop/tags/home-widgets/profile.tag @@ -18,8 +18,8 @@ background rgba(0, 0, 0, 0.5) > .avatar - top 21px - left 21px + top ((100px - 58px) / 2) + left ((100px - 58px) / 2) border none border-radius 100% box-shadow 0 0 16px rgba(0, 0, 0, 0.5) -- cgit v1.2.3-freya From ca26fc736308e0bc17465c97396fd67eedb7af8f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Nov 2017 18:23:33 +0900 Subject: :v: --- locales/en.yml | 5 + locales/ja.yml | 5 + src/web/app/desktop/mixins/widget.js | 9 +- .../app/desktop/tags/home-widgets/broadcast.tag | 7 +- src/web/app/desktop/tags/home-widgets/donation.tag | 5 +- src/web/app/desktop/tags/home-widgets/nav.tag | 3 + .../app/desktop/tags/home-widgets/post-form.tag | 101 +++++++++++++++++++++ src/web/app/desktop/tags/home-widgets/tips.tag | 2 + src/web/app/desktop/tags/home-widgets/version.tag | 2 + src/web/app/desktop/tags/home.tag | 55 +++++++++-- src/web/app/desktop/tags/index.js | 1 + 11 files changed, 179 insertions(+), 16 deletions(-) create mode 100644 src/web/app/desktop/tags/home-widgets/post-form.tag (limited to 'src') diff --git a/locales/en.yml b/locales/en.yml index 2845eec6a1..574af26a68 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -385,6 +385,11 @@ desktop: next: "Next month" go: "Click to travel" + mk-post-form-home-widget: + title: "Post" + post: "Post" + placeholder: "What's happening?" + mk-repost-form: quote: "Quote..." cancel: "Cancel" diff --git a/locales/ja.yml b/locales/ja.yml index 2d9aceb2db..9e6251d0d7 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -385,6 +385,11 @@ desktop: next: "来月" go: "クリックして時間遡行" + mk-post-form-home-widget: + title: "投稿" + post: "投稿" + placeholder: "いまどうしてる?" + mk-repost-form: quote: "引用する..." cancel: "キャンセル" diff --git a/src/web/app/desktop/mixins/widget.js b/src/web/app/desktop/mixins/widget.js index 2bf858ebe6..cb04295fc5 100644 --- a/src/web/app/desktop/mixins/widget.js +++ b/src/web/app/desktop/mixins/widget.js @@ -9,10 +9,13 @@ riot.mixin('widget', { this.mixin('api'); this.id = this.opts.id; + this.place = this.opts.place; - Object.keys(this.data).forEach(prop => { - this.data[prop] = this.opts.data.hasOwnProperty(prop) ? this.opts.data[prop] : this.data[prop]; - }); + if (this.data) { + Object.keys(this.data).forEach(prop => { + this.data[prop] = this.opts.data.hasOwnProperty(prop) ? this.opts.data[prop] : this.data[prop]; + }); + } }, save: function() { diff --git a/src/web/app/desktop/tags/home-widgets/broadcast.tag b/src/web/app/desktop/tags/home-widgets/broadcast.tag index 1102e22c7f..c33c5f367b 100644 --- a/src/web/app/desktop/tags/home-widgets/broadcast.tag +++ b/src/web/app/desktop/tags/home-widgets/broadcast.tag @@ -75,9 +75,8 @@ a color #555 - - - - + diff --git a/src/web/app/desktop/tags/home-widgets/donation.tag b/src/web/app/desktop/tags/home-widgets/donation.tag index d533e82831..9d56d12f04 100644 --- a/src/web/app/desktop/tags/home-widgets/donation.tag +++ b/src/web/app/desktop/tags/home-widgets/donation.tag @@ -28,5 +28,8 @@ color #999 - + diff --git a/src/web/app/desktop/tags/home-widgets/nav.tag b/src/web/app/desktop/tags/home-widgets/nav.tag index 54bfb87a11..1061b36f41 100644 --- a/src/web/app/desktop/tags/home-widgets/nav.tag +++ b/src/web/app/desktop/tags/home-widgets/nav.tag @@ -14,4 +14,7 @@ color #ccc + diff --git a/src/web/app/desktop/tags/home-widgets/post-form.tag b/src/web/app/desktop/tags/home-widgets/post-form.tag new file mode 100644 index 0000000000..2aa3cda502 --- /dev/null +++ b/src/web/app/desktop/tags/home-widgets/post-form.tag @@ -0,0 +1,101 @@ + + + + +

%i18n:desktop.tags.mk-post-form-home-widget.title%

+
+ + +
+ + +
diff --git a/src/web/app/desktop/tags/home-widgets/tips.tag b/src/web/app/desktop/tags/home-widgets/tips.tag index 5a535099ab..fd5ec801f5 100644 --- a/src/web/app/desktop/tags/home-widgets/tips.tag +++ b/src/web/app/desktop/tags/home-widgets/tips.tag @@ -31,6 +31,8 @@ diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index 60625bde64..8da58eb51c 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -16,6 +16,7 @@ + @@ -32,12 +33,13 @@
-
-
+
+
+
-
+
+ diff --git a/src/web/app/desktop/tags/window.tag b/src/web/app/desktop/tags/window.tag index aefb6499b7..cc8dc4c1a4 100644 --- a/src/web/app/desktop/tags/window.tag +++ b/src/web/app/desktop/tags/window.tag @@ -4,7 +4,10 @@

- +
+ + +
@@ -117,8 +120,12 @@ box-shadow 0 2px 6px 0 rgba(0, 0, 0, 0.2) > header + $header-height = 40px + z-index 128 + height $header-height overflow hidden + white-space nowrap cursor move background #fff border-radius 6px 6px 0 0 @@ -130,39 +137,45 @@ > h1 pointer-events none display block - margin 0 - height 40px + margin 0 auto + width s('calc(100% - (%s * 2))', $header-height) + overflow hidden + text-overflow ellipsis text-align center font-size 1em - line-height 40px + line-height $header-height font-weight normal color #666 - > .close - cursor pointer - display block + > div:last-child position absolute top 0 right 0 + display block z-index 1 - margin 0 - padding 0 - font-size 1.2em - color rgba(#000, 0.4) - border none - outline none - background transparent - &:hover - color rgba(#000, 0.6) + > * + display inline-block + margin 0 + padding 0 + cursor pointer + font-size 1.2em + color rgba(#000, 0.4) + border none + outline none + background transparent - &:active - color darken(#000, 30%) + &:hover + color rgba(#000, 0.6) - > i - padding 0 - width 40px - line-height 40px + &:active + color darken(#000, 30%) + + > i + padding 0 + width $header-height + line-height $header-height + text-align center > .content height 100% @@ -181,6 +194,8 @@ this.isModal = this.opts.isModal != null ? this.opts.isModal : false; this.canClose = this.opts.canClose != null ? this.opts.canClose : true; + this.popoutOption = this.opts.popoutOption; + console.log(this.popoutOption); this.isFlexible = this.opts.height == null; this.canResize = !this.isFlexible; @@ -247,6 +262,19 @@ }, 300); }; + this.popout = () => { + const position = this.refs.main.getBoundingClientRect(); + + const x = window.screenX + position.left; + const y = window.screenY + position.top; + + window.open(this.popoutOption.url, + this.popoutOption.url, + `height=${this.popoutOption.height},width=${this.popoutOption.width},left=${x},top=${y}`); + + this.close(); + }; + this.close = () => { this.trigger('closing'); -- cgit v1.2.3-freya From 178a861e6652fd9b8b77d6a65f378143df3cc1b5 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Nov 2017 07:46:33 +0900 Subject: Fix glitch --- src/web/app/desktop/tags/pages/messaging-room.tag | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/pages/messaging-room.tag b/src/web/app/desktop/tags/pages/messaging-room.tag index 9aba6c95d4..9747b4b835 100644 --- a/src/web/app/desktop/tags/pages/messaging-room.tag +++ b/src/web/app/desktop/tags/pages/messaging-room.tag @@ -4,9 +4,6 @@ @@ -21,6 +18,8 @@ this.on('mount', () => { Progress.start(); + document.documentElement.style.background = '#fff'; + this.api('users/show', { username: this.opts.user }).then(user => { -- cgit v1.2.3-freya From 94835583722bf00ef182cadb4b8fd5d3949f2764 Mon Sep 17 00:00:00 2001 From: こぴなたみぽ Date: Mon, 13 Nov 2017 08:53:38 +0900 Subject: :v: --- src/web/app/desktop/tags/messaging/room-window.tag | 8 ++------ src/web/app/desktop/tags/window.tag | 13 +++++++------ 2 files changed, 9 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/messaging/room-window.tag b/src/web/app/desktop/tags/messaging/room-window.tag index 4d4f5c626d..dca0172be3 100644 --- a/src/web/app/desktop/tags/messaging/room-window.tag +++ b/src/web/app/desktop/tags/messaging/room-window.tag @@ -1,5 +1,5 @@ - + メッセージ: { parent.user.name } @@ -23,11 +23,7 @@ this.user = this.opts.user; - this.popout = { - url: `${CONFIG.url}/i/messaging/${this.user.username}`, - width: 420, - height: 540 - }; + this.popout = `${CONFIG.url}/i/messaging/${this.user.username}`; this.on('mount', () => { this.refs.window.on('closed', () => { diff --git a/src/web/app/desktop/tags/window.tag b/src/web/app/desktop/tags/window.tag index cc8dc4c1a4..f0e1a3fdd1 100644 --- a/src/web/app/desktop/tags/window.tag +++ b/src/web/app/desktop/tags/window.tag @@ -5,7 +5,7 @@

- +
@@ -194,8 +194,7 @@ this.isModal = this.opts.isModal != null ? this.opts.isModal : false; this.canClose = this.opts.canClose != null ? this.opts.canClose : true; - this.popoutOption = this.opts.popoutOption; - console.log(this.popoutOption); + this.popoutUrl = this.opts.popout; this.isFlexible = this.opts.height == null; this.canResize = !this.isFlexible; @@ -265,12 +264,14 @@ this.popout = () => { const position = this.refs.main.getBoundingClientRect(); + const width = parseInt(getComputedStyle(this.refs.main, '').width, 10); + const left = parseInt(getComputedStyle(this.refs.main, '').left, 10); const x = window.screenX + position.left; const y = window.screenY + position.top; - window.open(this.popoutOption.url, - this.popoutOption.url, - `height=${this.popoutOption.height},width=${this.popoutOption.width},left=${x},top=${y}`); + window.open(this.popoutUrl, + this.popoutUrl, + `height=${height},width=${width},left=${x},top=${y}`); this.close(); }; -- cgit v1.2.3-freya From f8dddc81e25ceb47d8969505e6ef19267907afa7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Nov 2017 15:04:20 +0900 Subject: :v: --- src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server.ts b/src/server.ts index 240800c1e2..3e9bd44eef 100644 --- a/src/server.ts +++ b/src/server.ts @@ -35,7 +35,7 @@ app.use(morgan(process.env.NODE_ENV == 'production' ? 'combined' : 'dev', { stream: config.accesslog ? fs.createWriteStream(config.accesslog) : null })); -// Drop request that without 'Host' header +// Drop request when without 'Host' header app.use((req, res, next) => { if (!req.headers['host']) { res.sendStatus(400); -- cgit v1.2.3-freya From bc9a8283c66d7588f931d4b802f7ab1fa7aa3226 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Nov 2017 18:05:35 +0900 Subject: なんかもうめっちゃ変えた MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 7 +- src/web/app/auth/script.js | 23 --- src/web/app/auth/script.ts | 23 +++ src/web/app/auth/tags/index.js | 2 - src/web/app/auth/tags/index.ts | 2 + src/web/app/ch/router.js | 32 ---- src/web/app/ch/router.ts | 32 ++++ src/web/app/ch/script.js | 18 -- src/web/app/ch/script.ts | 18 ++ src/web/app/ch/tags/channel.tag | 4 +- src/web/app/ch/tags/index.js | 3 - src/web/app/ch/tags/index.ts | 3 + src/web/app/common/mixins/api.js | 8 - src/web/app/common/mixins/api.ts | 8 + src/web/app/common/mixins/i.js | 20 --- src/web/app/common/mixins/i.ts | 20 +++ src/web/app/common/mixins/index.js | 13 -- src/web/app/common/mixins/index.ts | 14 ++ src/web/app/common/scripts/api.js | 46 ----- src/web/app/common/scripts/api.ts | 46 +++++ src/web/app/common/scripts/bytes-to-size.js | 6 - src/web/app/common/scripts/bytes-to-size.ts | 6 + src/web/app/common/scripts/channel-stream.js | 16 -- src/web/app/common/scripts/channel-stream.ts | 16 ++ src/web/app/common/scripts/check-for-update.js | 14 -- src/web/app/common/scripts/check-for-update.ts | 16 ++ src/web/app/common/scripts/config.js | 25 --- src/web/app/common/scripts/config.ts | 25 +++ src/web/app/common/scripts/contains.js | 8 - src/web/app/common/scripts/contains.ts | 8 + src/web/app/common/scripts/copy-to-clipboard.js | 13 -- src/web/app/common/scripts/copy-to-clipboard.ts | 13 ++ src/web/app/common/scripts/date-stringify.js | 13 -- src/web/app/common/scripts/date-stringify.ts | 13 ++ src/web/app/common/scripts/gcd.js | 2 - src/web/app/common/scripts/gcd.ts | 2 + src/web/app/common/scripts/get-kao.js | 5 - src/web/app/common/scripts/get-kao.ts | 5 + src/web/app/common/scripts/home-stream.js | 29 --- src/web/app/common/scripts/home-stream.ts | 29 +++ src/web/app/common/scripts/is-promise.js | 1 - src/web/app/common/scripts/is-promise.ts | 1 + src/web/app/common/scripts/loading.js | 21 --- src/web/app/common/scripts/loading.ts | 21 +++ src/web/app/common/scripts/messaging-stream.js | 23 --- src/web/app/common/scripts/messaging-stream.ts | 23 +++ .../app/common/scripts/server-stream-manager.ts | 31 +--- src/web/app/common/scripts/server-stream.js | 14 -- src/web/app/common/scripts/server-stream.ts | 14 ++ src/web/app/common/scripts/signout.js | 7 - src/web/app/common/scripts/signout.ts | 7 + src/web/app/common/scripts/stream-manager.ts | 33 ++++ src/web/app/common/scripts/stream.js | 100 ----------- src/web/app/common/scripts/stream.ts | 99 +++++++++++ src/web/app/common/scripts/text-compiler.js | 47 ----- src/web/app/common/scripts/text-compiler.ts | 47 +++++ src/web/app/common/tags/index.js | 30 ---- src/web/app/common/tags/index.ts | 30 ++++ src/web/app/common/tags/messaging/message.tag | 2 +- src/web/app/desktop/mixins/index.js | 2 - src/web/app/desktop/mixins/index.ts | 2 + src/web/app/desktop/mixins/user-preview.js | 66 ------- src/web/app/desktop/mixins/user-preview.ts | 66 +++++++ src/web/app/desktop/mixins/widget.js | 31 ---- src/web/app/desktop/mixins/widget.ts | 31 ++++ src/web/app/desktop/router.js | 99 ----------- src/web/app/desktop/router.ts | 99 +++++++++++ src/web/app/desktop/script.js | 91 ---------- src/web/app/desktop/script.ts | 91 ++++++++++ src/web/app/desktop/scripts/autocomplete.js | 130 -------------- src/web/app/desktop/scripts/autocomplete.ts | 132 ++++++++++++++ src/web/app/desktop/scripts/dialog.js | 16 -- src/web/app/desktop/scripts/dialog.ts | 16 ++ src/web/app/desktop/scripts/fuck-ad-block.js | 18 -- src/web/app/desktop/scripts/fuck-ad-block.ts | 20 +++ src/web/app/desktop/scripts/input-dialog.js | 12 -- src/web/app/desktop/scripts/input-dialog.ts | 12 ++ .../desktop/scripts/not-implemented-exception.js | 8 - .../desktop/scripts/not-implemented-exception.ts | 8 + src/web/app/desktop/scripts/notify.js | 8 - src/web/app/desktop/scripts/notify.ts | 8 + src/web/app/desktop/scripts/password-dialog.js | 11 -- src/web/app/desktop/scripts/password-dialog.ts | 11 ++ src/web/app/desktop/scripts/update-avatar.js | 87 --------- src/web/app/desktop/scripts/update-avatar.ts | 87 +++++++++ src/web/app/desktop/scripts/update-banner.js | 87 --------- src/web/app/desktop/scripts/update-banner.ts | 87 +++++++++ .../app/desktop/tags/autocomplete-suggestion.tag | 2 +- src/web/app/desktop/tags/drive/browser.tag | 4 +- src/web/app/desktop/tags/drive/folder.tag | 2 +- src/web/app/desktop/tags/drive/nav-folder.tag | 2 +- src/web/app/desktop/tags/index.js | 93 ---------- src/web/app/desktop/tags/index.ts | 93 ++++++++++ src/web/app/desktop/tags/post-detail-sub.tag | 2 +- src/web/app/desktop/tags/post-detail.tag | 2 +- src/web/app/desktop/tags/post-form.tag | 6 +- src/web/app/desktop/tags/sub-post-content.tag | 2 +- src/web/app/desktop/tags/timeline.tag | 2 +- src/web/app/dev/router.js | 42 ----- src/web/app/dev/router.ts | 42 +++++ src/web/app/dev/script.js | 18 -- src/web/app/dev/script.ts | 18 ++ src/web/app/dev/tags/index.js | 5 - src/web/app/dev/tags/index.ts | 5 + src/web/app/init.js | 196 --------------------- src/web/app/init.ts | 178 +++++++++++++++++++ src/web/app/mobile/router.js | 147 ---------------- src/web/app/mobile/router.ts | 147 ++++++++++++++++ src/web/app/mobile/script.js | 21 --- src/web/app/mobile/script.ts | 21 +++ src/web/app/mobile/scripts/open-post-form.js | 15 -- src/web/app/mobile/scripts/open-post-form.ts | 15 ++ src/web/app/mobile/scripts/ui-event.js | 5 - src/web/app/mobile/scripts/ui-event.ts | 5 + src/web/app/mobile/tags/drive.tag | 2 +- src/web/app/mobile/tags/index.js | 51 ------ src/web/app/mobile/tags/index.ts | 51 ++++++ src/web/app/mobile/tags/post-detail.tag | 2 +- src/web/app/mobile/tags/post-form.tag | 4 +- src/web/app/mobile/tags/sub-post-content.tag | 2 +- src/web/app/mobile/tags/timeline.tag | 2 +- src/web/app/stats/script.js | 23 --- src/web/app/stats/script.ts | 23 +++ src/web/app/stats/tags/index.js | 1 - src/web/app/stats/tags/index.ts | 1 + src/web/app/status/script.js | 23 --- src/web/app/status/script.ts | 23 +++ src/web/app/status/tags/index.js | 1 - src/web/app/status/tags/index.ts | 1 + tslint.json | 1 + webpack/webpack.config.ts | 21 ++- 131 files changed, 1910 insertions(+), 1905 deletions(-) delete mode 100644 src/web/app/auth/script.js create mode 100644 src/web/app/auth/script.ts delete mode 100644 src/web/app/auth/tags/index.js create mode 100644 src/web/app/auth/tags/index.ts delete mode 100644 src/web/app/ch/router.js create mode 100644 src/web/app/ch/router.ts delete mode 100644 src/web/app/ch/script.js create mode 100644 src/web/app/ch/script.ts delete mode 100644 src/web/app/ch/tags/index.js create mode 100644 src/web/app/ch/tags/index.ts delete mode 100644 src/web/app/common/mixins/api.js create mode 100644 src/web/app/common/mixins/api.ts delete mode 100644 src/web/app/common/mixins/i.js create mode 100644 src/web/app/common/mixins/i.ts delete mode 100644 src/web/app/common/mixins/index.js create mode 100644 src/web/app/common/mixins/index.ts delete mode 100644 src/web/app/common/scripts/api.js create mode 100644 src/web/app/common/scripts/api.ts delete mode 100644 src/web/app/common/scripts/bytes-to-size.js create mode 100644 src/web/app/common/scripts/bytes-to-size.ts delete mode 100644 src/web/app/common/scripts/channel-stream.js create mode 100644 src/web/app/common/scripts/channel-stream.ts delete mode 100644 src/web/app/common/scripts/check-for-update.js create mode 100644 src/web/app/common/scripts/check-for-update.ts delete mode 100644 src/web/app/common/scripts/config.js create mode 100644 src/web/app/common/scripts/config.ts delete mode 100644 src/web/app/common/scripts/contains.js create mode 100644 src/web/app/common/scripts/contains.ts delete mode 100644 src/web/app/common/scripts/copy-to-clipboard.js create mode 100644 src/web/app/common/scripts/copy-to-clipboard.ts delete mode 100644 src/web/app/common/scripts/date-stringify.js create mode 100644 src/web/app/common/scripts/date-stringify.ts delete mode 100644 src/web/app/common/scripts/gcd.js create mode 100644 src/web/app/common/scripts/gcd.ts delete mode 100644 src/web/app/common/scripts/get-kao.js create mode 100644 src/web/app/common/scripts/get-kao.ts delete mode 100644 src/web/app/common/scripts/home-stream.js create mode 100644 src/web/app/common/scripts/home-stream.ts delete mode 100644 src/web/app/common/scripts/is-promise.js create mode 100644 src/web/app/common/scripts/is-promise.ts delete mode 100644 src/web/app/common/scripts/loading.js create mode 100644 src/web/app/common/scripts/loading.ts delete mode 100644 src/web/app/common/scripts/messaging-stream.js create mode 100644 src/web/app/common/scripts/messaging-stream.ts delete mode 100644 src/web/app/common/scripts/server-stream.js create mode 100644 src/web/app/common/scripts/server-stream.ts delete mode 100644 src/web/app/common/scripts/signout.js create mode 100644 src/web/app/common/scripts/signout.ts create mode 100644 src/web/app/common/scripts/stream-manager.ts delete mode 100644 src/web/app/common/scripts/stream.js create mode 100644 src/web/app/common/scripts/stream.ts delete mode 100644 src/web/app/common/scripts/text-compiler.js create mode 100644 src/web/app/common/scripts/text-compiler.ts delete mode 100644 src/web/app/common/tags/index.js create mode 100644 src/web/app/common/tags/index.ts delete mode 100644 src/web/app/desktop/mixins/index.js create mode 100644 src/web/app/desktop/mixins/index.ts delete mode 100644 src/web/app/desktop/mixins/user-preview.js create mode 100644 src/web/app/desktop/mixins/user-preview.ts delete mode 100644 src/web/app/desktop/mixins/widget.js create mode 100644 src/web/app/desktop/mixins/widget.ts delete mode 100644 src/web/app/desktop/router.js create mode 100644 src/web/app/desktop/router.ts delete mode 100644 src/web/app/desktop/script.js create mode 100644 src/web/app/desktop/script.ts delete mode 100644 src/web/app/desktop/scripts/autocomplete.js create mode 100644 src/web/app/desktop/scripts/autocomplete.ts delete mode 100644 src/web/app/desktop/scripts/dialog.js create mode 100644 src/web/app/desktop/scripts/dialog.ts delete mode 100644 src/web/app/desktop/scripts/fuck-ad-block.js create mode 100644 src/web/app/desktop/scripts/fuck-ad-block.ts delete mode 100644 src/web/app/desktop/scripts/input-dialog.js create mode 100644 src/web/app/desktop/scripts/input-dialog.ts delete mode 100644 src/web/app/desktop/scripts/not-implemented-exception.js create mode 100644 src/web/app/desktop/scripts/not-implemented-exception.ts delete mode 100644 src/web/app/desktop/scripts/notify.js create mode 100644 src/web/app/desktop/scripts/notify.ts delete mode 100644 src/web/app/desktop/scripts/password-dialog.js create mode 100644 src/web/app/desktop/scripts/password-dialog.ts delete mode 100644 src/web/app/desktop/scripts/update-avatar.js create mode 100644 src/web/app/desktop/scripts/update-avatar.ts delete mode 100644 src/web/app/desktop/scripts/update-banner.js create mode 100644 src/web/app/desktop/scripts/update-banner.ts delete mode 100644 src/web/app/desktop/tags/index.js create mode 100644 src/web/app/desktop/tags/index.ts delete mode 100644 src/web/app/dev/router.js create mode 100644 src/web/app/dev/router.ts delete mode 100644 src/web/app/dev/script.js create mode 100644 src/web/app/dev/script.ts delete mode 100644 src/web/app/dev/tags/index.js create mode 100644 src/web/app/dev/tags/index.ts delete mode 100644 src/web/app/init.js create mode 100644 src/web/app/init.ts delete mode 100644 src/web/app/mobile/router.js create mode 100644 src/web/app/mobile/router.ts delete mode 100644 src/web/app/mobile/script.js create mode 100644 src/web/app/mobile/script.ts delete mode 100644 src/web/app/mobile/scripts/open-post-form.js create mode 100644 src/web/app/mobile/scripts/open-post-form.ts delete mode 100644 src/web/app/mobile/scripts/ui-event.js create mode 100644 src/web/app/mobile/scripts/ui-event.ts delete mode 100644 src/web/app/mobile/tags/index.js create mode 100644 src/web/app/mobile/tags/index.ts delete mode 100644 src/web/app/stats/script.js create mode 100644 src/web/app/stats/script.ts delete mode 100644 src/web/app/stats/tags/index.js create mode 100644 src/web/app/stats/tags/index.ts delete mode 100644 src/web/app/status/script.js create mode 100644 src/web/app/status/script.ts delete mode 100644 src/web/app/status/tags/index.js create mode 100644 src/web/app/status/tags/index.ts (limited to 'src') diff --git a/package.json b/package.json index 2861fd9f04..879f4af92e 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,9 @@ "@types/ms": "0.7.30", "@types/multer": "1.3.5", "@types/node": "8.0.49", + "@types/page": "1.5.32", + "@types/proxy-addr": "2.0.0", + "@types/seedrandom": "2.4.27", "@types/ratelimiter": "2.1.28", "@types/redis": "2.8.1", "@types/request": "2.0.7", @@ -92,8 +95,8 @@ "webpack": "3.8.1" }, "dependencies": { - "@prezzemolo/zip": "0.0.3", "@prezzemolo/rap": "0.1.2", + "@prezzemolo/zip": "0.0.3", "accesses": "2.5.0", "animejs": "2.2.0", "autwh": "0.0.1", @@ -131,6 +134,7 @@ "page": "1.7.1", "pictograph": "2.0.4", "prominence": "0.2.0", + "proxy-addr": "^2.0.2", "pug": "2.0.0-rc.4", "ratelimiter": "3.0.3", "recaptcha-promise": "0.1.3", @@ -141,6 +145,7 @@ "riot": "3.7.4", "rndstr": "1.0.0", "s-age": "1.1.0", + "seedrandom": "^2.4.3", "serve-favicon": "2.4.5", "sortablejs": "1.7.0", "summaly": "2.0.3", diff --git a/src/web/app/auth/script.js b/src/web/app/auth/script.js deleted file mode 100644 index fe7f9befe8..0000000000 --- a/src/web/app/auth/script.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Authorize Form - */ - -// Style -import './style.styl'; - -import * as riot from 'riot'; -require('./tags'); -import init from '../init'; - -document.title = 'Misskey | アプリの連携'; - -/** - * init - */ -init(me => { - mount(document.createElement('mk-index')); -}); - -function mount(content) { - riot.mount(document.getElementById('app').appendChild(content)); -} diff --git a/src/web/app/auth/script.ts b/src/web/app/auth/script.ts new file mode 100644 index 0000000000..fe7f9befe8 --- /dev/null +++ b/src/web/app/auth/script.ts @@ -0,0 +1,23 @@ +/** + * Authorize Form + */ + +// Style +import './style.styl'; + +import * as riot from 'riot'; +require('./tags'); +import init from '../init'; + +document.title = 'Misskey | アプリの連携'; + +/** + * init + */ +init(me => { + mount(document.createElement('mk-index')); +}); + +function mount(content) { + riot.mount(document.getElementById('app').appendChild(content)); +} diff --git a/src/web/app/auth/tags/index.js b/src/web/app/auth/tags/index.js deleted file mode 100644 index 42dffe67d9..0000000000 --- a/src/web/app/auth/tags/index.js +++ /dev/null @@ -1,2 +0,0 @@ -require('./index.tag'); -require('./form.tag'); diff --git a/src/web/app/auth/tags/index.ts b/src/web/app/auth/tags/index.ts new file mode 100644 index 0000000000..42dffe67d9 --- /dev/null +++ b/src/web/app/auth/tags/index.ts @@ -0,0 +1,2 @@ +require('./index.tag'); +require('./form.tag'); diff --git a/src/web/app/ch/router.js b/src/web/app/ch/router.js deleted file mode 100644 index 424158f403..0000000000 --- a/src/web/app/ch/router.js +++ /dev/null @@ -1,32 +0,0 @@ -import * as riot from 'riot'; -const route = require('page'); -let page = null; - -export default me => { - route('/', index); - route('/:channel', channel); - route('*', notFound); - - function index() { - mount(document.createElement('mk-index')); - } - - function channel(ctx) { - const el = document.createElement('mk-channel'); - el.setAttribute('id', ctx.params.channel); - mount(el); - } - - function notFound() { - mount(document.createElement('mk-not-found')); - } - - // EXEC - route(); -}; - -function mount(content) { - if (page) page.unmount(); - const body = document.getElementById('app'); - page = riot.mount(body.appendChild(content))[0]; -} diff --git a/src/web/app/ch/router.ts b/src/web/app/ch/router.ts new file mode 100644 index 0000000000..fe014d4e31 --- /dev/null +++ b/src/web/app/ch/router.ts @@ -0,0 +1,32 @@ +import * as riot from 'riot'; +import * as route from 'page'; +let page = null; + +export default me => { + route('/', index); + route('/:channel', channel); + route('*', notFound); + + function index() { + mount(document.createElement('mk-index')); + } + + function channel(ctx) { + const el = document.createElement('mk-channel'); + el.setAttribute('id', ctx.params.channel); + mount(el); + } + + function notFound() { + mount(document.createElement('mk-not-found')); + } + + // EXEC + (route as any)(); +}; + +function mount(content) { + if (page) page.unmount(); + const body = document.getElementById('app'); + page = riot.mount(body.appendChild(content))[0]; +} diff --git a/src/web/app/ch/script.js b/src/web/app/ch/script.js deleted file mode 100644 index 760d405c52..0000000000 --- a/src/web/app/ch/script.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Channels - */ - -// Style -import './style.styl'; - -require('./tags'); -import init from '../init'; -import route from './router'; - -/** - * init - */ -init(me => { - // Start routing - route(me); -}); diff --git a/src/web/app/ch/script.ts b/src/web/app/ch/script.ts new file mode 100644 index 0000000000..760d405c52 --- /dev/null +++ b/src/web/app/ch/script.ts @@ -0,0 +1,18 @@ +/** + * Channels + */ + +// Style +import './style.styl'; + +require('./tags'); +import init from '../init'; +import route from './router'; + +/** + * init + */ +init(me => { + // Start routing + route(me); +}); diff --git a/src/web/app/ch/tags/channel.tag b/src/web/app/ch/tags/channel.tag index 4ae62e7b39..48c5c705d3 100644 --- a/src/web/app/ch/tags/channel.tag +++ b/src/web/app/ch/tags/channel.tag @@ -343,7 +343,7 @@ }; this.changeFile = () => { - this.refs.file.files.forEach(this.upload); + Array.from(this.refs.file.files).forEach(this.upload); }; this.selectFile = () => { @@ -367,7 +367,7 @@ }; this.onpaste = e => { - e.clipboardData.items.forEach(item => { + Array.from(e.clipboardData.items).forEach(item => { if (item.kind == 'file') { this.upload(item.getAsFile()); } diff --git a/src/web/app/ch/tags/index.js b/src/web/app/ch/tags/index.js deleted file mode 100644 index 12ffdaeb84..0000000000 --- a/src/web/app/ch/tags/index.js +++ /dev/null @@ -1,3 +0,0 @@ -require('./index.tag'); -require('./channel.tag'); -require('./header.tag'); diff --git a/src/web/app/ch/tags/index.ts b/src/web/app/ch/tags/index.ts new file mode 100644 index 0000000000..12ffdaeb84 --- /dev/null +++ b/src/web/app/ch/tags/index.ts @@ -0,0 +1,3 @@ +require('./index.tag'); +require('./channel.tag'); +require('./header.tag'); diff --git a/src/web/app/common/mixins/api.js b/src/web/app/common/mixins/api.js deleted file mode 100644 index 42d96db559..0000000000 --- a/src/web/app/common/mixins/api.js +++ /dev/null @@ -1,8 +0,0 @@ -import * as riot from 'riot'; -import api from '../scripts/api'; - -export default me => { - riot.mixin('api', { - api: api.bind(null, me ? me.token : null) - }); -}; diff --git a/src/web/app/common/mixins/api.ts b/src/web/app/common/mixins/api.ts new file mode 100644 index 0000000000..9726caf510 --- /dev/null +++ b/src/web/app/common/mixins/api.ts @@ -0,0 +1,8 @@ +import * as riot from 'riot'; +import api from '../scripts/api'; + +export default me => { + (riot as any).mixin('api', { + api: api.bind(null, me ? me.token : null) + }); +}; diff --git a/src/web/app/common/mixins/i.js b/src/web/app/common/mixins/i.js deleted file mode 100644 index 5225147766..0000000000 --- a/src/web/app/common/mixins/i.js +++ /dev/null @@ -1,20 +0,0 @@ -import * as riot from 'riot'; - -export default me => { - riot.mixin('i', { - init: function() { - this.I = me; - this.SIGNIN = me != null; - - if (this.SIGNIN) { - this.on('mount', () => { - me.on('updated', this.update); - }); - this.on('unmount', () => { - me.off('updated', this.update); - }); - } - }, - me: me - }); -}; diff --git a/src/web/app/common/mixins/i.ts b/src/web/app/common/mixins/i.ts new file mode 100644 index 0000000000..0879d02d3d --- /dev/null +++ b/src/web/app/common/mixins/i.ts @@ -0,0 +1,20 @@ +import * as riot from 'riot'; + +export default me => { + (riot as any).mixin('i', { + init: function() { + this.I = me; + this.SIGNIN = me != null; + + if (this.SIGNIN) { + this.on('mount', () => { + me.on('updated', this.update); + }); + this.on('unmount', () => { + me.off('updated', this.update); + }); + } + }, + me: me + }); +}; diff --git a/src/web/app/common/mixins/index.js b/src/web/app/common/mixins/index.js deleted file mode 100644 index 19e0690d72..0000000000 --- a/src/web/app/common/mixins/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import * as riot from 'riot'; - -import activateMe from './i'; -import activateApi from './api'; - -export default (me, stream, serverStreamManager) => { - activateMe(me); - activateApi(me); - - riot.mixin('stream', { stream }); - - riot.mixin('server-stream', { serverStream: serverStreamManager }); -}; diff --git a/src/web/app/common/mixins/index.ts b/src/web/app/common/mixins/index.ts new file mode 100644 index 0000000000..45427fb9d3 --- /dev/null +++ b/src/web/app/common/mixins/index.ts @@ -0,0 +1,14 @@ +import * as riot from 'riot'; + +import activateMe from './i'; +import activateApi from './api'; +import ServerStreamManager from '../scripts/server-stream-manager'; + +export default (me, stream) => { + activateMe(me); + activateApi(me); + + (riot as any).mixin('stream', { stream }); + + (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); +}; diff --git a/src/web/app/common/scripts/api.js b/src/web/app/common/scripts/api.js deleted file mode 100644 index 4855f736c7..0000000000 --- a/src/web/app/common/scripts/api.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * API Request - */ - -import CONFIG from './config'; - -let spinner = null; -let pending = 0; - -/** - * Send a request to API - * @param {string|Object} i Credential - * @param {string} endpoint Endpoint - * @param {any} [data={}] Data - * @return {Promise} Response - */ -export default (i, endpoint, data = {}) => { - if (++pending === 1) { - spinner = document.createElement('div'); - spinner.setAttribute('id', 'wait'); - document.body.appendChild(spinner); - } - - // Append the credential - if (i != null) data.i = typeof i === 'object' ? i.token : i; - - return new Promise((resolve, reject) => { - // Send request - fetch(endpoint.indexOf('://') > -1 ? endpoint : `${CONFIG.apiUrl}/${endpoint}`, { - method: 'POST', - body: JSON.stringify(data), - credentials: endpoint === 'signin' ? 'include' : 'omit' - }).then(res => { - if (--pending === 0) spinner.parentNode.removeChild(spinner); - if (res.status === 200) { - res.json().then(resolve); - } else if (res.status === 204) { - resolve(); - } else { - res.json().then(err => { - reject(err.error); - }); - } - }).catch(reject); - }); -}; diff --git a/src/web/app/common/scripts/api.ts b/src/web/app/common/scripts/api.ts new file mode 100644 index 0000000000..2a9d78e87d --- /dev/null +++ b/src/web/app/common/scripts/api.ts @@ -0,0 +1,46 @@ +/** + * API Request + */ + +import CONFIG from './config'; + +let spinner = null; +let pending = 0; + +/** + * Send a request to API + * @param {string|Object} i Credential + * @param {string} endpoint Endpoint + * @param {any} [data={}] Data + * @return {Promise} Response + */ +export default (i, endpoint, data = {}): Promise => { + if (++pending === 1) { + spinner = document.createElement('div'); + spinner.setAttribute('id', 'wait'); + document.body.appendChild(spinner); + } + + // Append the credential + if (i != null) (data as any).i = typeof i === 'object' ? i.token : i; + + return new Promise((resolve, reject) => { + // Send request + fetch(endpoint.indexOf('://') > -1 ? endpoint : `${CONFIG.apiUrl}/${endpoint}`, { + method: 'POST', + body: JSON.stringify(data), + credentials: endpoint === 'signin' ? 'include' : 'omit' + }).then(res => { + if (--pending === 0) spinner.parentNode.removeChild(spinner); + if (res.status === 200) { + res.json().then(resolve); + } else if (res.status === 204) { + resolve(); + } else { + res.json().then(err => { + reject(err.error); + }); + } + }).catch(reject); + }); +}; diff --git a/src/web/app/common/scripts/bytes-to-size.js b/src/web/app/common/scripts/bytes-to-size.js deleted file mode 100644 index af0268dbd0..0000000000 --- a/src/web/app/common/scripts/bytes-to-size.js +++ /dev/null @@ -1,6 +0,0 @@ -export default (bytes, digits = 0) => { - var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (bytes == 0) return '0Byte'; - var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); - return (bytes / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '') + sizes[i]; -}; diff --git a/src/web/app/common/scripts/bytes-to-size.ts b/src/web/app/common/scripts/bytes-to-size.ts new file mode 100644 index 0000000000..1d2b1e7ce3 --- /dev/null +++ b/src/web/app/common/scripts/bytes-to-size.ts @@ -0,0 +1,6 @@ +export default (bytes, digits = 0) => { + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + if (bytes == 0) return '0Byte'; + const i = Math.floor(Math.log(bytes) / Math.log(1024)); + return (bytes / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '') + sizes[i]; +}; diff --git a/src/web/app/common/scripts/channel-stream.js b/src/web/app/common/scripts/channel-stream.js deleted file mode 100644 index 17944dbe45..0000000000 --- a/src/web/app/common/scripts/channel-stream.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -import Stream from './stream'; - -/** - * Channel stream connection - */ -class Connection extends Stream { - constructor(channelId) { - super('channel', { - channel: channelId - }); - } -} - -export default Connection; diff --git a/src/web/app/common/scripts/channel-stream.ts b/src/web/app/common/scripts/channel-stream.ts new file mode 100644 index 0000000000..17944dbe45 --- /dev/null +++ b/src/web/app/common/scripts/channel-stream.ts @@ -0,0 +1,16 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Channel stream connection + */ +class Connection extends Stream { + constructor(channelId) { + super('channel', { + channel: channelId + }); + } +} + +export default Connection; diff --git a/src/web/app/common/scripts/check-for-update.js b/src/web/app/common/scripts/check-for-update.js deleted file mode 100644 index 7cb7839d29..0000000000 --- a/src/web/app/common/scripts/check-for-update.js +++ /dev/null @@ -1,14 +0,0 @@ -import CONFIG from './config'; - -export default function() { - fetch(CONFIG.apiUrl + '/meta', { - method: 'POST' - }).then(res => { - res.json().then(meta => { - if (meta.version != VERSION) { - localStorage.setItem('should-refresh', 'true'); - alert('%i18n:common.update-available%'.replace('{newer}', meta.version).replace('{current}', VERSION)); - } - }); - }); -}; diff --git a/src/web/app/common/scripts/check-for-update.ts b/src/web/app/common/scripts/check-for-update.ts new file mode 100644 index 0000000000..99d8b5d059 --- /dev/null +++ b/src/web/app/common/scripts/check-for-update.ts @@ -0,0 +1,16 @@ +import CONFIG from './config'; + +declare var VERSION: string; + +export default function() { + fetch(CONFIG.apiUrl + '/meta', { + method: 'POST' + }).then(res => { + res.json().then(meta => { + if (meta.version != VERSION) { + localStorage.setItem('should-refresh', 'true'); + alert('%i18n:common.update-available%'.replace('{newer}', meta.version).replace('{current}', VERSION)); + } + }); + }); +} diff --git a/src/web/app/common/scripts/config.js b/src/web/app/common/scripts/config.js deleted file mode 100644 index c5015622f0..0000000000 --- a/src/web/app/common/scripts/config.js +++ /dev/null @@ -1,25 +0,0 @@ -const Url = new URL(location.href); - -const isRoot = Url.host.split('.')[0] == 'misskey'; - -const host = isRoot ? Url.host : Url.host.substring(Url.host.indexOf('.') + 1, Url.host.length); -const scheme = Url.protocol; -const url = `${scheme}//${host}`; -const apiUrl = `${scheme}//api.${host}`; -const chUrl = `${scheme}//ch.${host}`; -const devUrl = `${scheme}//dev.${host}`; -const aboutUrl = `${scheme}//about.${host}`; -const statsUrl = `${scheme}//stats.${host}`; -const statusUrl = `${scheme}//status.${host}`; - -export default { - host, - scheme, - url, - apiUrl, - chUrl, - devUrl, - aboutUrl, - statsUrl, - statusUrl -}; diff --git a/src/web/app/common/scripts/config.ts b/src/web/app/common/scripts/config.ts new file mode 100644 index 0000000000..c5015622f0 --- /dev/null +++ b/src/web/app/common/scripts/config.ts @@ -0,0 +1,25 @@ +const Url = new URL(location.href); + +const isRoot = Url.host.split('.')[0] == 'misskey'; + +const host = isRoot ? Url.host : Url.host.substring(Url.host.indexOf('.') + 1, Url.host.length); +const scheme = Url.protocol; +const url = `${scheme}//${host}`; +const apiUrl = `${scheme}//api.${host}`; +const chUrl = `${scheme}//ch.${host}`; +const devUrl = `${scheme}//dev.${host}`; +const aboutUrl = `${scheme}//about.${host}`; +const statsUrl = `${scheme}//stats.${host}`; +const statusUrl = `${scheme}//status.${host}`; + +export default { + host, + scheme, + url, + apiUrl, + chUrl, + devUrl, + aboutUrl, + statsUrl, + statusUrl +}; diff --git a/src/web/app/common/scripts/contains.js b/src/web/app/common/scripts/contains.js deleted file mode 100644 index a5071b3f25..0000000000 --- a/src/web/app/common/scripts/contains.js +++ /dev/null @@ -1,8 +0,0 @@ -export default (parent, child) => { - let node = child.parentNode; - while (node) { - if (node == parent) return true; - node = node.parentNode; - } - return false; -}; diff --git a/src/web/app/common/scripts/contains.ts b/src/web/app/common/scripts/contains.ts new file mode 100644 index 0000000000..a5071b3f25 --- /dev/null +++ b/src/web/app/common/scripts/contains.ts @@ -0,0 +1,8 @@ +export default (parent, child) => { + let node = child.parentNode; + while (node) { + if (node == parent) return true; + node = node.parentNode; + } + return false; +}; diff --git a/src/web/app/common/scripts/copy-to-clipboard.js b/src/web/app/common/scripts/copy-to-clipboard.js deleted file mode 100644 index 3d2741f8d7..0000000000 --- a/src/web/app/common/scripts/copy-to-clipboard.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Clipboardに値をコピー(TODO: 文字列以外も対応) - */ -export default val => { - const form = document.createElement('textarea'); - form.textContent = val; - document.body.appendChild(form); - form.select(); - const result = document.execCommand('copy'); - document.body.removeChild(form); - - return result; -}; diff --git a/src/web/app/common/scripts/copy-to-clipboard.ts b/src/web/app/common/scripts/copy-to-clipboard.ts new file mode 100644 index 0000000000..3d2741f8d7 --- /dev/null +++ b/src/web/app/common/scripts/copy-to-clipboard.ts @@ -0,0 +1,13 @@ +/** + * Clipboardに値をコピー(TODO: 文字列以外も対応) + */ +export default val => { + const form = document.createElement('textarea'); + form.textContent = val; + document.body.appendChild(form); + form.select(); + const result = document.execCommand('copy'); + document.body.removeChild(form); + + return result; +}; diff --git a/src/web/app/common/scripts/date-stringify.js b/src/web/app/common/scripts/date-stringify.js deleted file mode 100644 index e51de8833d..0000000000 --- a/src/web/app/common/scripts/date-stringify.js +++ /dev/null @@ -1,13 +0,0 @@ -export default date => { - if (typeof date == 'string') date = new Date(date); - return ( - date.getFullYear() + '年' + - (date.getMonth() + 1) + '月' + - date.getDate() + '日' + - ' ' + - date.getHours() + '時' + - date.getMinutes() + '分' + - ' ' + - `(${['日', '月', '火', '水', '木', '金', '土'][date.getDay()]})` - ); -}; diff --git a/src/web/app/common/scripts/date-stringify.ts b/src/web/app/common/scripts/date-stringify.ts new file mode 100644 index 0000000000..e51de8833d --- /dev/null +++ b/src/web/app/common/scripts/date-stringify.ts @@ -0,0 +1,13 @@ +export default date => { + if (typeof date == 'string') date = new Date(date); + return ( + date.getFullYear() + '年' + + (date.getMonth() + 1) + '月' + + date.getDate() + '日' + + ' ' + + date.getHours() + '時' + + date.getMinutes() + '分' + + ' ' + + `(${['日', '月', '火', '水', '木', '金', '土'][date.getDay()]})` + ); +}; diff --git a/src/web/app/common/scripts/gcd.js b/src/web/app/common/scripts/gcd.js deleted file mode 100644 index 9a19f9da66..0000000000 --- a/src/web/app/common/scripts/gcd.js +++ /dev/null @@ -1,2 +0,0 @@ -const gcd = (a, b) => !b ? a : gcd(b, a % b); -export default gcd; diff --git a/src/web/app/common/scripts/gcd.ts b/src/web/app/common/scripts/gcd.ts new file mode 100644 index 0000000000..9a19f9da66 --- /dev/null +++ b/src/web/app/common/scripts/gcd.ts @@ -0,0 +1,2 @@ +const gcd = (a, b) => !b ? a : gcd(b, a % b); +export default gcd; diff --git a/src/web/app/common/scripts/get-kao.js b/src/web/app/common/scripts/get-kao.js deleted file mode 100644 index 0b77ee285a..0000000000 --- a/src/web/app/common/scripts/get-kao.js +++ /dev/null @@ -1,5 +0,0 @@ -export default () => [ - '(=^・・^=)', - 'v(‘ω’)v', - '🐡( '-' 🐡 )フグパンチ!!!!' -][Math.floor(Math.random() * 3)]; diff --git a/src/web/app/common/scripts/get-kao.ts b/src/web/app/common/scripts/get-kao.ts new file mode 100644 index 0000000000..2168c5be88 --- /dev/null +++ b/src/web/app/common/scripts/get-kao.ts @@ -0,0 +1,5 @@ +export default () => [ + '(=^・・^=)', + 'v(‘ω’)v', + '🐡( \'-\' 🐡 )フグパンチ!!!!' +][Math.floor(Math.random() * 3)]; diff --git a/src/web/app/common/scripts/home-stream.js b/src/web/app/common/scripts/home-stream.js deleted file mode 100644 index de9ceb3b51..0000000000 --- a/src/web/app/common/scripts/home-stream.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -import Stream from './stream'; -import signout from './signout'; - -/** - * Home stream connection - */ -class Connection extends Stream { - constructor(me) { - super('', { - i: me.token - }); - - // 最終利用日時を更新するため定期的にaliveメッセージを送信 - setInterval(() => { - this.send({ type: 'alive' }); - }, 1000 * 60); - - this.on('i_updated', me.update); - - this.on('my_token_regenerated', () => { - alert('%i18n:common.my-token-regenerated%'); - signout(); - }); - } -} - -export default Connection; diff --git a/src/web/app/common/scripts/home-stream.ts b/src/web/app/common/scripts/home-stream.ts new file mode 100644 index 0000000000..c549f2b936 --- /dev/null +++ b/src/web/app/common/scripts/home-stream.ts @@ -0,0 +1,29 @@ +'use strict'; + +import Stream from './stream'; +import signout from './signout'; + +/** + * Home stream connection + */ +class Connection extends Stream { + constructor(me) { + super('', { + i: me.token + }); + + // 最終利用日時を更新するため定期的にaliveメッセージを送信 + setInterval(() => { + this.send({ type: 'alive' }); + }, 1000 * 60); + + (this as any).on('i_updated', me.update); + + (this as any).on('my_token_regenerated', () => { + alert('%i18n:common.my-token-regenerated%'); + signout(); + }); + } +} + +export default Connection; diff --git a/src/web/app/common/scripts/is-promise.js b/src/web/app/common/scripts/is-promise.js deleted file mode 100644 index 3b4cd70b49..0000000000 --- a/src/web/app/common/scripts/is-promise.js +++ /dev/null @@ -1 +0,0 @@ -export default x => typeof x.then == 'function'; diff --git a/src/web/app/common/scripts/is-promise.ts b/src/web/app/common/scripts/is-promise.ts new file mode 100644 index 0000000000..3b4cd70b49 --- /dev/null +++ b/src/web/app/common/scripts/is-promise.ts @@ -0,0 +1 @@ +export default x => typeof x.then == 'function'; diff --git a/src/web/app/common/scripts/loading.js b/src/web/app/common/scripts/loading.js deleted file mode 100644 index c48e626648..0000000000 --- a/src/web/app/common/scripts/loading.js +++ /dev/null @@ -1,21 +0,0 @@ -const NProgress = require('nprogress'); -NProgress.configure({ - trickleSpeed: 500, - showSpinner: false -}); - -const root = document.getElementsByTagName('html')[0]; - -export default { - start: () => { - root.classList.add('progress'); - NProgress.start(); - }, - done: () => { - root.classList.remove('progress'); - NProgress.done(); - }, - set: val => { - NProgress.set(val); - } -}; diff --git a/src/web/app/common/scripts/loading.ts b/src/web/app/common/scripts/loading.ts new file mode 100644 index 0000000000..c48e626648 --- /dev/null +++ b/src/web/app/common/scripts/loading.ts @@ -0,0 +1,21 @@ +const NProgress = require('nprogress'); +NProgress.configure({ + trickleSpeed: 500, + showSpinner: false +}); + +const root = document.getElementsByTagName('html')[0]; + +export default { + start: () => { + root.classList.add('progress'); + NProgress.start(); + }, + done: () => { + root.classList.remove('progress'); + NProgress.done(); + }, + set: val => { + NProgress.set(val); + } +}; diff --git a/src/web/app/common/scripts/messaging-stream.js b/src/web/app/common/scripts/messaging-stream.js deleted file mode 100644 index 261525d5f6..0000000000 --- a/src/web/app/common/scripts/messaging-stream.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -import Stream from './stream'; - -/** - * Messaging stream connection - */ -class Connection extends Stream { - constructor(me, otherparty) { - super('messaging', { - i: me.token, - otherparty - }); - - this.on('_connected_', () => { - this.send({ - i: me.token - }); - }); - } -} - -export default Connection; diff --git a/src/web/app/common/scripts/messaging-stream.ts b/src/web/app/common/scripts/messaging-stream.ts new file mode 100644 index 0000000000..63830f7b17 --- /dev/null +++ b/src/web/app/common/scripts/messaging-stream.ts @@ -0,0 +1,23 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Messaging stream connection + */ +class Connection extends Stream { + constructor(me, otherparty) { + super('messaging', { + i: me.token, + otherparty + }); + + (this as any).on('_connected_', () => { + this.send({ + i: me.token + }); + }); + } +} + +export default Connection; diff --git a/src/web/app/common/scripts/server-stream-manager.ts b/src/web/app/common/scripts/server-stream-manager.ts index 54333c8cf5..a170daebb9 100644 --- a/src/web/app/common/scripts/server-stream-manager.ts +++ b/src/web/app/common/scripts/server-stream-manager.ts @@ -1,14 +1,7 @@ +import StreamManager from './stream-manager'; import Connection from './server-stream'; -import * as uuid from 'uuid'; - -export default class ServerStreamManager { - private connection = null; - - /** - * コネクションを必要としているユーザー - */ - private users = []; +export default class ServerStreamManager extends StreamManager { public getConnection() { if (this.connection == null) { this.connection = new Connection(); @@ -16,24 +9,4 @@ export default class ServerStreamManager { return this.connection; } - - public use() { - // ユーザーID生成 - const userId = uuid(); - - this.users.push(userId); - - return userId; - } - - public dispose(userId) { - this.users = this.users.filter(id => id != userId); - - // 誰もコネクションの利用者がいなくなったら - if (this.users.length == 0) { - // コネクションを切断する - this.connection.close(); - this.connection = null; - } - } } diff --git a/src/web/app/common/scripts/server-stream.js b/src/web/app/common/scripts/server-stream.js deleted file mode 100644 index a1c466b35d..0000000000 --- a/src/web/app/common/scripts/server-stream.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -import Stream from './stream'; - -/** - * Server stream connection - */ -class Connection extends Stream { - constructor() { - super('server'); - } -} - -export default Connection; diff --git a/src/web/app/common/scripts/server-stream.ts b/src/web/app/common/scripts/server-stream.ts new file mode 100644 index 0000000000..a1c466b35d --- /dev/null +++ b/src/web/app/common/scripts/server-stream.ts @@ -0,0 +1,14 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Server stream connection + */ +class Connection extends Stream { + constructor() { + super('server'); + } +} + +export default Connection; diff --git a/src/web/app/common/scripts/signout.js b/src/web/app/common/scripts/signout.js deleted file mode 100644 index 6c95cfbc9c..0000000000 --- a/src/web/app/common/scripts/signout.js +++ /dev/null @@ -1,7 +0,0 @@ -import CONFIG from './config'; - -export default () => { - localStorage.removeItem('me'); - document.cookie = `i=; domain=.${CONFIG.host}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`; - location.href = '/'; -}; diff --git a/src/web/app/common/scripts/signout.ts b/src/web/app/common/scripts/signout.ts new file mode 100644 index 0000000000..6c95cfbc9c --- /dev/null +++ b/src/web/app/common/scripts/signout.ts @@ -0,0 +1,7 @@ +import CONFIG from './config'; + +export default () => { + localStorage.removeItem('me'); + document.cookie = `i=; domain=.${CONFIG.host}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`; + location.href = '/'; +}; diff --git a/src/web/app/common/scripts/stream-manager.ts b/src/web/app/common/scripts/stream-manager.ts new file mode 100644 index 0000000000..4eaf0f9a45 --- /dev/null +++ b/src/web/app/common/scripts/stream-manager.ts @@ -0,0 +1,33 @@ +import * as uuid from 'uuid'; +import Connection from './stream'; + +export default abstract class StreamManager { + protected connection: T = null; + + /** + * コネクションを必要としているユーザー + */ + private users = []; + + public abstract getConnection(): T; + + public use() { + // ユーザーID生成 + const userId = uuid(); + + this.users.push(userId); + + return userId; + } + + public dispose(userId) { + this.users = this.users.filter(id => id != userId); + + // 誰もコネクションの利用者がいなくなったら + if (this.users.length == 0) { + // コネクションを切断する + this.connection.close(); + this.connection = null; + } + } +} diff --git a/src/web/app/common/scripts/stream.js b/src/web/app/common/scripts/stream.js deleted file mode 100644 index a03b7bf200..0000000000 --- a/src/web/app/common/scripts/stream.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; - -import * as ReconnectingWebsocket from 'reconnecting-websocket'; -import * as riot from 'riot'; -import CONFIG from './config'; - -/** - * Misskey stream connection - */ -class Connection { - constructor(endpoint, params) { - // BIND ----------------------------------- - this.onOpen = this.onOpen.bind(this); - this.onClose = this.onClose.bind(this); - this.onMessage = this.onMessage.bind(this); - this.send = this.send.bind(this); - this.close = this.close.bind(this); - // ---------------------------------------- - - riot.observable(this); - - this.state = 'initializing'; - this.buffer = []; - - const host = CONFIG.apiUrl.replace('http', 'ws'); - const query = params - ? Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&') - : null; - - this.socket = new ReconnectingWebsocket(`${host}/${endpoint}${query ? '?' + query : ''}`); - this.socket.addEventListener('open', this.onOpen); - this.socket.addEventListener('close', this.onClose); - this.socket.addEventListener('message', this.onMessage); - } - - /** - * Callback of when open connection - * @private - */ - onOpen() { - this.state = 'connected'; - this.trigger('_connected_'); - - // バッファーを処理 - const _buffer = [].concat(this.buffer); // Shallow copy - this.buffer = []; // Clear buffer - _buffer.forEach(message => { - this.send(message); // Resend each buffered messages - }); - } - - /** - * Callback of when close connection - * @private - */ - onClose() { - this.state = 'reconnecting'; - this.trigger('_closed_'); - } - - /** - * Callback of when received a message from connection - * @private - */ - onMessage(message) { - try { - const msg = JSON.parse(message.data); - if (msg.type) this.trigger(msg.type, msg.body); - } catch(e) { - // noop - } - } - - /** - * Send a message to connection - * @public - */ - send(message) { - // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する - if (this.state != 'connected') { - this.buffer.push(message); - return; - }; - - this.socket.send(JSON.stringify(message)); - } - - /** - * Close this connection - * @public - */ - close() { - this.socket.removeEventListener('open', this.onOpen); - this.socket.removeEventListener('message', this.onMessage); - } -} - -export default Connection; diff --git a/src/web/app/common/scripts/stream.ts b/src/web/app/common/scripts/stream.ts new file mode 100644 index 0000000000..9595246879 --- /dev/null +++ b/src/web/app/common/scripts/stream.ts @@ -0,0 +1,99 @@ +'use strict'; + +import * as ReconnectingWebsocket from 'reconnecting-websocket'; +import * as riot from 'riot'; +import CONFIG from './config'; + +/** + * Misskey stream connection + */ +class Connection { + private state: string; + private buffer: any[]; + private socket: ReconnectingWebsocket; + + constructor(endpoint, params?) { + // BIND ----------------------------------- + this.onOpen = this.onOpen.bind(this); + this.onClose = this.onClose.bind(this); + this.onMessage = this.onMessage.bind(this); + this.send = this.send.bind(this); + this.close = this.close.bind(this); + // ---------------------------------------- + + riot.observable(this); + + this.state = 'initializing'; + this.buffer = []; + + const host = CONFIG.apiUrl.replace('http', 'ws'); + const query = params + ? Object.keys(params) + .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) + .join('&') + : null; + + this.socket = new ReconnectingWebsocket(`${host}/${endpoint}${query ? '?' + query : ''}`); + this.socket.addEventListener('open', this.onOpen); + this.socket.addEventListener('close', this.onClose); + this.socket.addEventListener('message', this.onMessage); + } + + /** + * Callback of when open connection + */ + private onOpen() { + this.state = 'connected'; + (this as any).trigger('_connected_'); + + // バッファーを処理 + const _buffer = [].concat(this.buffer); // Shallow copy + this.buffer = []; // Clear buffer + _buffer.forEach(message => { + this.send(message); // Resend each buffered messages + }); + } + + /** + * Callback of when close connection + */ + private onClose() { + this.state = 'reconnecting'; + (this as any).trigger('_closed_'); + } + + /** + * Callback of when received a message from connection + */ + private onMessage(message) { + try { + const msg = JSON.parse(message.data); + if (msg.type) (this as any).trigger(msg.type, msg.body); + } catch (e) { + // noop + } + } + + /** + * Send a message to connection + */ + public send(message) { + // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する + if (this.state != 'connected') { + this.buffer.push(message); + return; + } + + this.socket.send(JSON.stringify(message)); + } + + /** + * Close this connection + */ + public close() { + this.socket.removeEventListener('open', this.onOpen); + this.socket.removeEventListener('message', this.onMessage); + } +} + +export default Connection; diff --git a/src/web/app/common/scripts/text-compiler.js b/src/web/app/common/scripts/text-compiler.js deleted file mode 100644 index 0a9b8022df..0000000000 --- a/src/web/app/common/scripts/text-compiler.js +++ /dev/null @@ -1,47 +0,0 @@ -import * as riot from 'riot'; -const pictograph = require('pictograph'); -import CONFIG from './config'; - -const escape = text => - text - .replace(/>/g, '>') - .replace(/ { - if (shouldBreak == null) { - shouldBreak = true; - } - - const me = riot.mixin('i').me; - - let text = tokens.map(token => { - switch (token.type) { - case 'text': - return escape(token.content) - .replace(/(\r\n|\n|\r)/g, shouldBreak ? '
' : ' '); - case 'bold': - return `${escape(token.bold)}`; - case 'url': - return ``; - case 'link': - return `${escape(token.title)}`; - case 'mention': - return `${token.content}`; - case 'hashtag': // TODO - return `${escape(token.content)}`; - case 'code': - return `
${token.html}
`; - case 'inline-code': - return `${token.html}`; - case 'emoji': - return pictograph.dic[token.emoji] || token.content; - } - }).join(''); - - // Remove needless whitespaces - text = text - .replace(/ /g, '').replace(/<\/code> /g, '') - .replace(/
/g, '
').replace(/<\/code><\/pre>
/g, '
'); - - return text; -}; diff --git a/src/web/app/common/scripts/text-compiler.ts b/src/web/app/common/scripts/text-compiler.ts new file mode 100644 index 0000000000..8c65d6a068 --- /dev/null +++ b/src/web/app/common/scripts/text-compiler.ts @@ -0,0 +1,47 @@ +import * as riot from 'riot'; +import * as pictograph from 'pictograph'; +import CONFIG from './config'; + +const escape = text => + text + .replace(/>/g, '>') + .replace(/ { + if (shouldBreak == null) { + shouldBreak = true; + } + + const me = (riot as any).mixin('i').me; + + let text = tokens.map(token => { + switch (token.type) { + case 'text': + return escape(token.content) + .replace(/(\r\n|\n|\r)/g, shouldBreak ? '
' : ' '); + case 'bold': + return `${escape(token.bold)}`; + case 'url': + return ``; + case 'link': + return `${escape(token.title)}`; + case 'mention': + return `${token.content}`; + case 'hashtag': // TODO + return `${escape(token.content)}`; + case 'code': + return `
${token.html}
`; + case 'inline-code': + return `${token.html}`; + case 'emoji': + return pictograph.dic[token.emoji] || token.content; + } + }).join(''); + + // Remove needless whitespaces + text = text + .replace(/ /g, '').replace(/<\/code> /g, '') + .replace(/
/g, '
').replace(/<\/code><\/pre>
/g, '
'); + + return text; +}; diff --git a/src/web/app/common/tags/index.js b/src/web/app/common/tags/index.js deleted file mode 100644 index 35a9f4586e..0000000000 --- a/src/web/app/common/tags/index.js +++ /dev/null @@ -1,30 +0,0 @@ -require('./error.tag'); -require('./url.tag'); -require('./url-preview.tag'); -require('./time.tag'); -require('./file-type-icon.tag'); -require('./uploader.tag'); -require('./ellipsis.tag'); -require('./raw.tag'); -require('./number.tag'); -require('./special-message.tag'); -require('./signin.tag'); -require('./signup.tag'); -require('./forkit.tag'); -require('./introduction.tag'); -require('./copyright.tag'); -require('./signin-history.tag'); -require('./twitter-setting.tag'); -require('./authorized-apps.tag'); -require('./poll.tag'); -require('./poll-editor.tag'); -require('./messaging/room.tag'); -require('./messaging/message.tag'); -require('./messaging/index.tag'); -require('./messaging/form.tag'); -require('./stream-indicator.tag'); -require('./activity-table.tag'); -require('./reaction-picker.tag'); -require('./reactions-viewer.tag'); -require('./reaction-icon.tag'); -require('./post-menu.tag'); diff --git a/src/web/app/common/tags/index.ts b/src/web/app/common/tags/index.ts new file mode 100644 index 0000000000..35a9f4586e --- /dev/null +++ b/src/web/app/common/tags/index.ts @@ -0,0 +1,30 @@ +require('./error.tag'); +require('./url.tag'); +require('./url-preview.tag'); +require('./time.tag'); +require('./file-type-icon.tag'); +require('./uploader.tag'); +require('./ellipsis.tag'); +require('./raw.tag'); +require('./number.tag'); +require('./special-message.tag'); +require('./signin.tag'); +require('./signup.tag'); +require('./forkit.tag'); +require('./introduction.tag'); +require('./copyright.tag'); +require('./signin-history.tag'); +require('./twitter-setting.tag'); +require('./authorized-apps.tag'); +require('./poll.tag'); +require('./poll-editor.tag'); +require('./messaging/room.tag'); +require('./messaging/message.tag'); +require('./messaging/index.tag'); +require('./messaging/form.tag'); +require('./stream-indicator.tag'); +require('./activity-table.tag'); +require('./reaction-picker.tag'); +require('./reactions-viewer.tag'); +require('./reaction-icon.tag'); +require('./post-menu.tag'); diff --git a/src/web/app/common/tags/messaging/message.tag b/src/web/app/common/tags/messaging/message.tag index d6db9070e2..ea1ea2310b 100644 --- a/src/web/app/common/tags/messaging/message.tag +++ b/src/web/app/common/tags/messaging/message.tag @@ -219,7 +219,7 @@ this.refs.text.innerHTML = compile(tokens); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); diff --git a/src/web/app/desktop/mixins/index.js b/src/web/app/desktop/mixins/index.js deleted file mode 100644 index e0c94ec5ee..0000000000 --- a/src/web/app/desktop/mixins/index.js +++ /dev/null @@ -1,2 +0,0 @@ -require('./user-preview'); -require('./widget'); diff --git a/src/web/app/desktop/mixins/index.ts b/src/web/app/desktop/mixins/index.ts new file mode 100644 index 0000000000..e0c94ec5ee --- /dev/null +++ b/src/web/app/desktop/mixins/index.ts @@ -0,0 +1,2 @@ +require('./user-preview'); +require('./widget'); diff --git a/src/web/app/desktop/mixins/user-preview.js b/src/web/app/desktop/mixins/user-preview.js deleted file mode 100644 index 3f483beb3a..0000000000 --- a/src/web/app/desktop/mixins/user-preview.js +++ /dev/null @@ -1,66 +0,0 @@ -import * as riot from 'riot'; - -riot.mixin('user-preview', { - init: function() { - const scan = () => { - this.root.querySelectorAll('[data-user-preview]:not([data-user-preview-attached])') - .forEach(attach.bind(this)); - }; - this.on('mount', scan); - this.on('updated', scan); - } -}); - -function attach(el) { - el.setAttribute('data-user-preview-attached', true); - - const user = el.getAttribute('data-user-preview'); - let tag = null; - let showTimer = null; - let hideTimer = null; - - el.addEventListener('mouseover', () => { - clearTimeout(showTimer); - clearTimeout(hideTimer); - showTimer = setTimeout(show, 500); - }); - - el.addEventListener('mouseleave', () => { - clearTimeout(showTimer); - clearTimeout(hideTimer); - hideTimer = setTimeout(close, 500); - }); - - this.on('unmount', () => { - clearTimeout(showTimer); - clearTimeout(hideTimer); - close(); - }); - - const show = () => { - if (tag) return; - const preview = document.createElement('mk-user-preview'); - const rect = el.getBoundingClientRect(); - const x = rect.left + el.offsetWidth + window.pageXOffset; - const y = rect.top + window.pageYOffset; - preview.style.top = y + 'px'; - preview.style.left = x + 'px'; - preview.addEventListener('mouseover', () => { - clearTimeout(hideTimer); - }); - preview.addEventListener('mouseleave', () => { - clearTimeout(showTimer); - hideTimer = setTimeout(close, 500); - }); - tag = riot.mount(document.body.appendChild(preview), { - user: user - })[0]; - }; - - const close = () => { - if (tag) { - tag.close(); - tag = null; - } - }; -} diff --git a/src/web/app/desktop/mixins/user-preview.ts b/src/web/app/desktop/mixins/user-preview.ts new file mode 100644 index 0000000000..614de72bea --- /dev/null +++ b/src/web/app/desktop/mixins/user-preview.ts @@ -0,0 +1,66 @@ +import * as riot from 'riot'; + +riot.mixin('user-preview', { + init: function() { + const scan = () => { + this.root.querySelectorAll('[data-user-preview]:not([data-user-preview-attached])') + .forEach(attach.bind(this)); + }; + this.on('mount', scan); + this.on('updated', scan); + } +}); + +function attach(el) { + el.setAttribute('data-user-preview-attached', true); + + const user = el.getAttribute('data-user-preview'); + let tag = null; + let showTimer = null; + let hideTimer = null; + + el.addEventListener('mouseover', () => { + clearTimeout(showTimer); + clearTimeout(hideTimer); + showTimer = setTimeout(show, 500); + }); + + el.addEventListener('mouseleave', () => { + clearTimeout(showTimer); + clearTimeout(hideTimer); + hideTimer = setTimeout(close, 500); + }); + + this.on('unmount', () => { + clearTimeout(showTimer); + clearTimeout(hideTimer); + close(); + }); + + const show = () => { + if (tag) return; + const preview = document.createElement('mk-user-preview'); + const rect = el.getBoundingClientRect(); + const x = rect.left + el.offsetWidth + window.pageXOffset; + const y = rect.top + window.pageYOffset; + preview.style.top = y + 'px'; + preview.style.left = x + 'px'; + preview.addEventListener('mouseover', () => { + clearTimeout(hideTimer); + }); + preview.addEventListener('mouseleave', () => { + clearTimeout(showTimer); + hideTimer = setTimeout(close, 500); + }); + tag = (riot as any).mount(document.body.appendChild(preview), { + user: user + })[0]; + }; + + const close = () => { + if (tag) { + tag.close(); + tag = null; + } + }; +} diff --git a/src/web/app/desktop/mixins/widget.js b/src/web/app/desktop/mixins/widget.js deleted file mode 100644 index cb04295fc5..0000000000 --- a/src/web/app/desktop/mixins/widget.js +++ /dev/null @@ -1,31 +0,0 @@ -import * as riot from 'riot'; - -// ミックスインにオプションを渡せないのアレ -// SEE: https://github.com/riot/riot/issues/2434 - -riot.mixin('widget', { - init: function() { - this.mixin('i'); - this.mixin('api'); - - this.id = this.opts.id; - this.place = this.opts.place; - - if (this.data) { - Object.keys(this.data).forEach(prop => { - this.data[prop] = this.opts.data.hasOwnProperty(prop) ? this.opts.data[prop] : this.data[prop]; - }); - } - }, - - save: function() { - this.update(); - this.api('i/update_home', { - id: this.id, - data: this.data - }).then(() => { - this.I.client_settings.home.find(w => w.id == this.id).data = this.data; - this.I.update(); - }); - } -}); diff --git a/src/web/app/desktop/mixins/widget.ts b/src/web/app/desktop/mixins/widget.ts new file mode 100644 index 0000000000..04131cd8f0 --- /dev/null +++ b/src/web/app/desktop/mixins/widget.ts @@ -0,0 +1,31 @@ +import * as riot from 'riot'; + +// ミックスインにオプションを渡せないのアレ +// SEE: https://github.com/riot/riot/issues/2434 + +(riot as any).mixin('widget', { + init: function() { + this.mixin('i'); + this.mixin('api'); + + this.id = this.opts.id; + this.place = this.opts.place; + + if (this.data) { + Object.keys(this.data).forEach(prop => { + this.data[prop] = this.opts.data.hasOwnProperty(prop) ? this.opts.data[prop] : this.data[prop]; + }); + } + }, + + save: function() { + this.update(); + this.api('i/update_home', { + id: this.id, + data: this.data + }).then(() => { + this.I.client_settings.home.find(w => w.id == this.id).data = this.data; + this.I.update(); + }); + } +}); diff --git a/src/web/app/desktop/router.js b/src/web/app/desktop/router.js deleted file mode 100644 index 4675b967d6..0000000000 --- a/src/web/app/desktop/router.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Desktop App Router - */ - -import * as riot from 'riot'; -const route = require('page'); -let page = null; - -export default me => { - route('/', index); - route('/selectdrive', selectDrive); - route('/i/customize-home', customizeHome); - route('/i/drive', drive); - route('/i/drive/folder/:folder', drive); - route('/i/messaging/:user', messaging); - route('/i/mentions', mentions); - route('/post::post', post); - route('/search::query', search); - route('/:user', user.bind(null, 'home')); - route('/:user/graphs', user.bind(null, 'graphs')); - route('/:user/:post', post); - route('*', notFound); - - function index() { - me ? home() : entrance(); - } - - function home() { - mount(document.createElement('mk-home-page')); - } - - function customizeHome() { - mount(document.createElement('mk-home-customize-page')); - } - - function entrance() { - mount(document.createElement('mk-entrance')); - document.documentElement.setAttribute('data-page', 'entrance'); - } - - function mentions() { - const el = document.createElement('mk-home-page'); - el.setAttribute('mode', 'mentions'); - mount(el); - } - - function search(ctx) { - const el = document.createElement('mk-search-page'); - el.setAttribute('query', ctx.params.query); - mount(el); - } - - function user(page, ctx) { - const el = document.createElement('mk-user-page'); - el.setAttribute('user', ctx.params.user); - el.setAttribute('page', page); - mount(el); - } - - function post(ctx) { - const el = document.createElement('mk-post-page'); - el.setAttribute('post', ctx.params.post); - mount(el); - } - - function selectDrive() { - mount(document.createElement('mk-selectdrive-page')); - } - - function drive(ctx) { - const el = document.createElement('mk-drive-page'); - if (ctx.params.folder) el.setAttribute('folder', ctx.params.folder); - mount(el); - } - - function messaging(ctx) { - const el = document.createElement('mk-messaging-room-page'); - el.setAttribute('user', ctx.params.user); - mount(el); - } - - function notFound() { - mount(document.createElement('mk-not-found')); - } - - riot.mixin('page', { - page: route - }); - - // EXEC - route(); -}; - -function mount(content) { - document.documentElement.removeAttribute('data-page'); - if (page) page.unmount(); - const body = document.getElementById('app'); - page = riot.mount(body.appendChild(content))[0]; -} diff --git a/src/web/app/desktop/router.ts b/src/web/app/desktop/router.ts new file mode 100644 index 0000000000..a74299b281 --- /dev/null +++ b/src/web/app/desktop/router.ts @@ -0,0 +1,99 @@ +/** + * Desktop App Router + */ + +import * as riot from 'riot'; +import * as route from 'page'; +let page = null; + +export default me => { + route('/', index); + route('/selectdrive', selectDrive); + route('/i/customize-home', customizeHome); + route('/i/drive', drive); + route('/i/drive/folder/:folder', drive); + route('/i/messaging/:user', messaging); + route('/i/mentions', mentions); + route('/post::post', post); + route('/search::query', search); + route('/:user', user.bind(null, 'home')); + route('/:user/graphs', user.bind(null, 'graphs')); + route('/:user/:post', post); + route('*', notFound); + + function index() { + me ? home() : entrance(); + } + + function home() { + mount(document.createElement('mk-home-page')); + } + + function customizeHome() { + mount(document.createElement('mk-home-customize-page')); + } + + function entrance() { + mount(document.createElement('mk-entrance')); + document.documentElement.setAttribute('data-page', 'entrance'); + } + + function mentions() { + const el = document.createElement('mk-home-page'); + el.setAttribute('mode', 'mentions'); + mount(el); + } + + function search(ctx) { + const el = document.createElement('mk-search-page'); + el.setAttribute('query', ctx.params.query); + mount(el); + } + + function user(page, ctx) { + const el = document.createElement('mk-user-page'); + el.setAttribute('user', ctx.params.user); + el.setAttribute('page', page); + mount(el); + } + + function post(ctx) { + const el = document.createElement('mk-post-page'); + el.setAttribute('post', ctx.params.post); + mount(el); + } + + function selectDrive() { + mount(document.createElement('mk-selectdrive-page')); + } + + function drive(ctx) { + const el = document.createElement('mk-drive-page'); + if (ctx.params.folder) el.setAttribute('folder', ctx.params.folder); + mount(el); + } + + function messaging(ctx) { + const el = document.createElement('mk-messaging-room-page'); + el.setAttribute('user', ctx.params.user); + mount(el); + } + + function notFound() { + mount(document.createElement('mk-not-found')); + } + + (riot as any).mixin('page', { + page: route + }); + + // EXEC + (route as any)(); +}; + +function mount(content) { + document.documentElement.removeAttribute('data-page'); + if (page) page.unmount(); + const body = document.getElementById('app'); + page = riot.mount(body.appendChild(content))[0]; +} diff --git a/src/web/app/desktop/script.js b/src/web/app/desktop/script.js deleted file mode 100644 index 46a7fce700..0000000000 --- a/src/web/app/desktop/script.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Desktop Client - */ - -// Style -import './style.styl'; - -require('./tags'); -require('./mixins'); -import * as riot from 'riot'; -import init from '../init'; -import route from './router'; -import fuckAdBlock from './scripts/fuck-ad-block'; -import getPostSummary from '../../../common/get-post-summary.ts'; - -/** - * init - */ -init(async (me, stream) => { - /** - * Fuck AD Block - */ - fuckAdBlock(); - - /** - * Init Notification - */ - if ('Notification' in window) { - // 許可を得ていなかったらリクエスト - if (Notification.permission == 'default') { - await Notification.requestPermission(); - } - - if (Notification.permission == 'granted') { - registerNotifications(stream); - } - } - - // Start routing - route(me); -}); - -function registerNotifications(stream) { - if (stream == null) return; - - stream.on('drive_file_created', file => { - const n = new Notification('ファイルがアップロードされました', { - body: file.name, - icon: file.url + '?thumbnail&size=64' - }); - setTimeout(n.close.bind(n), 5000); - }); - - stream.on('mention', post => { - const n = new Notification(`${post.user.name}さんから:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' - }); - setTimeout(n.close.bind(n), 6000); - }); - - stream.on('reply', post => { - const n = new Notification(`${post.user.name}さんから返信:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' - }); - setTimeout(n.close.bind(n), 6000); - }); - - stream.on('quote', post => { - const n = new Notification(`${post.user.name}さんが引用:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' - }); - setTimeout(n.close.bind(n), 6000); - }); - - stream.on('unread_messaging_message', message => { - const n = new Notification(`${message.user.name}さんからメッセージ:`, { - body: message.text, // TODO: getMessagingMessageSummary(message), - icon: message.user.avatar_url + '?thumbnail&size=64' - }); - n.onclick = () => { - n.close(); - riot.mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { - user: message.user - }); - }; - setTimeout(n.close.bind(n), 7000); - }); -} diff --git a/src/web/app/desktop/script.ts b/src/web/app/desktop/script.ts new file mode 100644 index 0000000000..a0453865ec --- /dev/null +++ b/src/web/app/desktop/script.ts @@ -0,0 +1,91 @@ +/** + * Desktop Client + */ + +// Style +import './style.styl'; + +require('./tags'); +require('./mixins'); +import * as riot from 'riot'; +import init from '../init'; +import route from './router'; +import fuckAdBlock from './scripts/fuck-ad-block'; +import getPostSummary from '../../../common/get-post-summary'; + +/** + * init + */ +init(async (me, stream) => { + /** + * Fuck AD Block + */ + fuckAdBlock(); + + /** + * Init Notification + */ + if ('Notification' in window) { + // 許可を得ていなかったらリクエスト + if ((Notification as any).permission == 'default') { + await Notification.requestPermission(); + } + + if ((Notification as any).permission == 'granted') { + registerNotifications(stream); + } + } + + // Start routing + route(me); +}); + +function registerNotifications(stream) { + if (stream == null) return; + + stream.on('drive_file_created', file => { + const n = new Notification('ファイルがアップロードされました', { + body: file.name, + icon: file.url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 5000); + }); + + stream.on('mention', post => { + const n = new Notification(`${post.user.name}さんから:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); + }); + + stream.on('reply', post => { + const n = new Notification(`${post.user.name}さんから返信:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); + }); + + stream.on('quote', post => { + const n = new Notification(`${post.user.name}さんが引用:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); + }); + + stream.on('unread_messaging_message', message => { + const n = new Notification(`${message.user.name}さんからメッセージ:`, { + body: message.text, // TODO: getMessagingMessageSummary(message), + icon: message.user.avatar_url + '?thumbnail&size=64' + }); + n.onclick = () => { + n.close(); + (riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { + user: message.user + }); + }; + setTimeout(n.close.bind(n), 7000); + }); +} diff --git a/src/web/app/desktop/scripts/autocomplete.js b/src/web/app/desktop/scripts/autocomplete.js deleted file mode 100644 index 8ca516e2a9..0000000000 --- a/src/web/app/desktop/scripts/autocomplete.js +++ /dev/null @@ -1,130 +0,0 @@ -const getCaretCoordinates = require('textarea-caret'); -import * as riot from 'riot'; - -/** - * オートコンプリートを管理するクラス。 - */ -class Autocomplete { - - /** - * 対象のテキストエリアを与えてインスタンスを初期化します。 - */ - constructor(textarea) { - // BIND --------------------------------- - this.onInput = this.onInput.bind(this); - this.complete = this.complete.bind(this); - this.close = this.close.bind(this); - // -------------------------------------- - - this.suggestion = null; - this.textarea = textarea; - } - - /** - * このインスタンスにあるテキストエリアの入力のキャプチャを開始します。 - */ - attach() { - this.textarea.addEventListener('input', this.onInput); - } - - /** - * このインスタンスにあるテキストエリアの入力のキャプチャを解除します。 - */ - detach() { - this.textarea.removeEventListener('input', this.onInput); - this.close(); - } - - /** - * [Private] テキスト入力時 - */ - onInput() { - this.close(); - - const caret = this.textarea.selectionStart; - const text = this.textarea.value.substr(0, caret); - - const mentionIndex = text.lastIndexOf('@'); - - if (mentionIndex == -1) return; - - const username = text.substr(mentionIndex + 1); - - if (!username.match(/^[a-zA-Z0-9-]+$/)) return; - - this.open('user', username); - } - - /** - * [Private] サジェストを提示します。 - */ - open(type, q) { - // 既に開いているサジェストは閉じる - this.close(); - - // サジェスト要素作成 - const tag = document.createElement('mk-autocomplete-suggestion'); - - // ~ サジェストを表示すべき位置を計算 ~ - - const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart); - - const rect = this.textarea.getBoundingClientRect(); - - const x = rect.left + window.pageXOffset + caretPosition.left; - const y = rect.top + window.pageYOffset + caretPosition.top; - - tag.style.left = x + 'px'; - tag.style.top = y + 'px'; - - // 要素追加 - const el = document.body.appendChild(tag); - - // マウント - this.suggestion = riot.mount(el, { - textarea: this.textarea, - complete: this.complete, - close: this.close, - type: type, - q: q - })[0]; - } - - /** - * [Private] サジェストを閉じます。 - */ - close() { - if (this.suggestion == null) return; - - this.suggestion.unmount(); - this.suggestion = null; - - this.textarea.focus(); - } - - /** - * [Private] オートコンプリートする - */ - complete(user) { - this.close(); - - const value = user.username; - - const caret = this.textarea.selectionStart; - const source = this.textarea.value; - - const before = source.substr(0, caret); - const trimmedBefore = before.substring(0, before.lastIndexOf('@')); - const after = source.substr(caret); - - // 結果を挿入する - this.textarea.value = trimmedBefore + '@' + value + ' ' + after; - - // キャレットを戻す - this.textarea.focus(); - const pos = caret + value.length; - this.textarea.setSelectionRange(pos, pos); - } -} - -export default Autocomplete; diff --git a/src/web/app/desktop/scripts/autocomplete.ts b/src/web/app/desktop/scripts/autocomplete.ts new file mode 100644 index 0000000000..9df7aae08d --- /dev/null +++ b/src/web/app/desktop/scripts/autocomplete.ts @@ -0,0 +1,132 @@ +import getCaretCoordinates = require('textarea-caret'); +import * as riot from 'riot'; + +/** + * オートコンプリートを管理するクラス。 + */ +class Autocomplete { + private suggestion: any; + private textarea: any; + + /** + * 対象のテキストエリアを与えてインスタンスを初期化します。 + */ + constructor(textarea) { + // BIND --------------------------------- + this.onInput = this.onInput.bind(this); + this.complete = this.complete.bind(this); + this.close = this.close.bind(this); + // -------------------------------------- + + this.suggestion = null; + this.textarea = textarea; + } + + /** + * このインスタンスにあるテキストエリアの入力のキャプチャを開始します。 + */ + public attach() { + this.textarea.addEventListener('input', this.onInput); + } + + /** + * このインスタンスにあるテキストエリアの入力のキャプチャを解除します。 + */ + public detach() { + this.textarea.removeEventListener('input', this.onInput); + this.close(); + } + + /** + * テキスト入力時 + */ + private onInput() { + this.close(); + + const caret = this.textarea.selectionStart; + const text = this.textarea.value.substr(0, caret); + + const mentionIndex = text.lastIndexOf('@'); + + if (mentionIndex == -1) return; + + const username = text.substr(mentionIndex + 1); + + if (!username.match(/^[a-zA-Z0-9-]+$/)) return; + + this.open('user', username); + } + + /** + * サジェストを提示します。 + */ + private open(type, q) { + // 既に開いているサジェストは閉じる + this.close(); + + // サジェスト要素作成 + const tag = document.createElement('mk-autocomplete-suggestion'); + + // ~ サジェストを表示すべき位置を計算 ~ + + const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart); + + const rect = this.textarea.getBoundingClientRect(); + + const x = rect.left + window.pageXOffset + caretPosition.left; + const y = rect.top + window.pageYOffset + caretPosition.top; + + tag.style.left = x + 'px'; + tag.style.top = y + 'px'; + + // 要素追加 + const el = document.body.appendChild(tag); + + // マウント + this.suggestion = (riot as any).mount(el, { + textarea: this.textarea, + complete: this.complete, + close: this.close, + type: type, + q: q + })[0]; + } + + /** + * サジェストを閉じます。 + */ + private close() { + if (this.suggestion == null) return; + + this.suggestion.unmount(); + this.suggestion = null; + + this.textarea.focus(); + } + + /** + * オートコンプリートする + */ + private complete(user) { + this.close(); + + const value = user.username; + + const caret = this.textarea.selectionStart; + const source = this.textarea.value; + + const before = source.substr(0, caret); + const trimmedBefore = before.substring(0, before.lastIndexOf('@')); + const after = source.substr(caret); + + // 結果を挿入する + this.textarea.value = trimmedBefore + '@' + value + ' ' + after; + + // キャレットを戻す + this.textarea.focus(); + const pos = caret + value.length; + this.textarea.setSelectionRange(pos, pos); + } +} + +export default Autocomplete; diff --git a/src/web/app/desktop/scripts/dialog.js b/src/web/app/desktop/scripts/dialog.js deleted file mode 100644 index c502d3fcb8..0000000000 --- a/src/web/app/desktop/scripts/dialog.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as riot from 'riot'; - -export default (title, text, buttons, canThrough, onThrough) => { - const dialog = document.body.appendChild(document.createElement('mk-dialog')); - const controller = riot.observable(); - riot.mount(dialog, { - controller: controller, - title: title, - text: text, - buttons: buttons, - canThrough: canThrough, - onThrough: onThrough - }); - controller.trigger('open'); - return controller; -}; diff --git a/src/web/app/desktop/scripts/dialog.ts b/src/web/app/desktop/scripts/dialog.ts new file mode 100644 index 0000000000..816ba4b5f5 --- /dev/null +++ b/src/web/app/desktop/scripts/dialog.ts @@ -0,0 +1,16 @@ +import * as riot from 'riot'; + +export default (title, text, buttons, canThrough?, onThrough?) => { + const dialog = document.body.appendChild(document.createElement('mk-dialog')); + const controller = riot.observable(); + (riot as any).mount(dialog, { + controller: controller, + title: title, + text: text, + buttons: buttons, + canThrough: canThrough, + onThrough: onThrough + }); + controller.trigger('open'); + return controller; +}; diff --git a/src/web/app/desktop/scripts/fuck-ad-block.js b/src/web/app/desktop/scripts/fuck-ad-block.js deleted file mode 100644 index ccfc43ce6e..0000000000 --- a/src/web/app/desktop/scripts/fuck-ad-block.js +++ /dev/null @@ -1,18 +0,0 @@ -require('fuckadblock'); -import dialog from './dialog'; - -export default () => { - if (fuckAdBlock === undefined) { - adBlockDetected(); - } else { - fuckAdBlock.onDetected(adBlockDetected); - } -}; - -function adBlockDetected() { - dialog('広告ブロッカーを無効にしてください', - 'Misskeyは広告を掲載していませんが、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。', - [{ - text: 'OK' - }]); -} diff --git a/src/web/app/desktop/scripts/fuck-ad-block.ts b/src/web/app/desktop/scripts/fuck-ad-block.ts new file mode 100644 index 0000000000..3307ba2f30 --- /dev/null +++ b/src/web/app/desktop/scripts/fuck-ad-block.ts @@ -0,0 +1,20 @@ +require('fuckadblock'); +import dialog from './dialog'; + +declare var fuckAdBlock: any; + +export default () => { + if (fuckAdBlock === undefined) { + adBlockDetected(); + } else { + fuckAdBlock.onDetected(adBlockDetected); + } +}; + +function adBlockDetected() { + dialog('広告ブロッカーを無効にしてください', + 'Misskeyは広告を掲載していませんが、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。', + [{ + text: 'OK' + }]); +} diff --git a/src/web/app/desktop/scripts/input-dialog.js b/src/web/app/desktop/scripts/input-dialog.js deleted file mode 100644 index 954fabfb67..0000000000 --- a/src/web/app/desktop/scripts/input-dialog.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as riot from 'riot'; - -export default (title, placeholder, defaultValue, onOk, onCancel) => { - const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); - return riot.mount(dialog, { - title: title, - placeholder: placeholder, - 'default': defaultValue, - onOk: onOk, - onCancel: onCancel - }); -}; diff --git a/src/web/app/desktop/scripts/input-dialog.ts b/src/web/app/desktop/scripts/input-dialog.ts new file mode 100644 index 0000000000..b06d011c6b --- /dev/null +++ b/src/web/app/desktop/scripts/input-dialog.ts @@ -0,0 +1,12 @@ +import * as riot from 'riot'; + +export default (title, placeholder, defaultValue, onOk, onCancel) => { + const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); + return (riot as any).mount(dialog, { + title: title, + placeholder: placeholder, + 'default': defaultValue, + onOk: onOk, + onCancel: onCancel + }); +}; diff --git a/src/web/app/desktop/scripts/not-implemented-exception.js b/src/web/app/desktop/scripts/not-implemented-exception.js deleted file mode 100644 index dd00c7662f..0000000000 --- a/src/web/app/desktop/scripts/not-implemented-exception.js +++ /dev/null @@ -1,8 +0,0 @@ -import dialog from './dialog'; - -export default () => { - dialog('Not implemented yet', - '要求された操作は実装されていません。
Misskeyの開発に参加する', [{ - text: 'OK' - }]); -}; diff --git a/src/web/app/desktop/scripts/not-implemented-exception.ts b/src/web/app/desktop/scripts/not-implemented-exception.ts new file mode 100644 index 0000000000..dd00c7662f --- /dev/null +++ b/src/web/app/desktop/scripts/not-implemented-exception.ts @@ -0,0 +1,8 @@ +import dialog from './dialog'; + +export default () => { + dialog('Not implemented yet', + '要求された操作は実装されていません。
Misskeyの開発に参加する', [{ + text: 'OK' + }]); +}; diff --git a/src/web/app/desktop/scripts/notify.js b/src/web/app/desktop/scripts/notify.js deleted file mode 100644 index e58a8e4d36..0000000000 --- a/src/web/app/desktop/scripts/notify.js +++ /dev/null @@ -1,8 +0,0 @@ -import * as riot from 'riot'; - -export default message => { - const notification = document.body.appendChild(document.createElement('mk-ui-notification')); - riot.mount(notification, { - message: message - }); -}; diff --git a/src/web/app/desktop/scripts/notify.ts b/src/web/app/desktop/scripts/notify.ts new file mode 100644 index 0000000000..2e6cbdeed8 --- /dev/null +++ b/src/web/app/desktop/scripts/notify.ts @@ -0,0 +1,8 @@ +import * as riot from 'riot'; + +export default message => { + const notification = document.body.appendChild(document.createElement('mk-ui-notification')); + (riot as any).mount(notification, { + message: message + }); +}; diff --git a/src/web/app/desktop/scripts/password-dialog.js b/src/web/app/desktop/scripts/password-dialog.js deleted file mode 100644 index 2bdc93e421..0000000000 --- a/src/web/app/desktop/scripts/password-dialog.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as riot from 'riot'; - -export default (title, onOk, onCancel) => { - const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); - return riot.mount(dialog, { - title: title, - type: 'password', - onOk: onOk, - onCancel: onCancel - }); -}; diff --git a/src/web/app/desktop/scripts/password-dialog.ts b/src/web/app/desktop/scripts/password-dialog.ts new file mode 100644 index 0000000000..39d7f3db7a --- /dev/null +++ b/src/web/app/desktop/scripts/password-dialog.ts @@ -0,0 +1,11 @@ +import * as riot from 'riot'; + +export default (title, onOk, onCancel) => { + const dialog = document.body.appendChild(document.createElement('mk-input-dialog')); + return (riot as any).mount(dialog, { + title: title, + type: 'password', + onOk: onOk, + onCancel: onCancel + }); +}; diff --git a/src/web/app/desktop/scripts/update-avatar.js b/src/web/app/desktop/scripts/update-avatar.js deleted file mode 100644 index 165c90567c..0000000000 --- a/src/web/app/desktop/scripts/update-avatar.js +++ /dev/null @@ -1,87 +0,0 @@ -import * as riot from 'riot'; -import CONFIG from '../../common/scripts/config'; -import dialog from './dialog'; -import api from '../../common/scripts/api'; - -export default (I, cb, file = null) => { - const fileSelected = file => { - const cropper = riot.mount(document.body.appendChild(document.createElement('mk-crop-window')), { - file: file, - title: 'アバターとして表示する部分を選択', - aspectRatio: 1 / 1 - })[0]; - - cropper.on('cropped', blob => { - const data = new FormData(); - data.append('i', I.token); - data.append('file', blob, file.name + '.cropped.png'); - - api(I, 'drive/folders/find', { - name: 'アイコン' - }).then(iconFolder => { - if (iconFolder.length === 0) { - api(I, 'drive/folders/create', { - name: 'アイコン' - }).then(iconFolder => { - upload(data, iconFolder); - }); - } else { - upload(data, iconFolder[0]); - } - }); - }); - - cropper.on('skipped', () => { - set(file); - }); - }; - - const upload = (data, folder) => { - const progress = riot.mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { - title: '新しいアバターをアップロードしています' - })[0]; - - if (folder) data.append('folder_id', folder.id); - - const xhr = new XMLHttpRequest(); - xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); - xhr.onload = e => { - const file = JSON.parse(e.target.response); - progress.close(); - set(file); - }; - - xhr.upload.onprogress = e => { - if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); - }; - - xhr.send(data); - }; - - const set = file => { - api(I, 'i/update', { - avatar_id: file.id - }).then(i => { - dialog('アバターを更新しました', - '新しいアバターが反映されるまで時間がかかる場合があります。', - [{ - text: 'わかった' - }]); - - if (cb) cb(i); - }); - }; - - if (file) { - fileSelected(file); - } else { - const browser = riot.mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { - multiple: false, - title: 'アバターにする画像を選択' - })[0]; - - browser.one('selected', file => { - fileSelected(file); - }); - } -}; diff --git a/src/web/app/desktop/scripts/update-avatar.ts b/src/web/app/desktop/scripts/update-avatar.ts new file mode 100644 index 0000000000..5fd7f2d3d1 --- /dev/null +++ b/src/web/app/desktop/scripts/update-avatar.ts @@ -0,0 +1,87 @@ +import * as riot from 'riot'; +import CONFIG from '../../common/scripts/config'; +import dialog from './dialog'; +import api from '../../common/scripts/api'; + +export default (I, cb, file = null) => { + const fileSelected = file => { + const cropper = (riot as any).mount(document.body.appendChild(document.createElement('mk-crop-window')), { + file: file, + title: 'アバターとして表示する部分を選択', + aspectRatio: 1 / 1 + })[0]; + + cropper.on('cropped', blob => { + const data = new FormData(); + data.append('i', I.token); + data.append('file', blob, file.name + '.cropped.png'); + + api(I, 'drive/folders/find', { + name: 'アイコン' + }).then(iconFolder => { + if (iconFolder.length === 0) { + api(I, 'drive/folders/create', { + name: 'アイコン' + }).then(iconFolder => { + upload(data, iconFolder); + }); + } else { + upload(data, iconFolder[0]); + } + }); + }); + + cropper.on('skipped', () => { + set(file); + }); + }; + + const upload = (data, folder) => { + const progress = (riot as any).mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { + title: '新しいアバターをアップロードしています' + })[0]; + + if (folder) data.append('folder_id', folder.id); + + const xhr = new XMLHttpRequest(); + xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); + xhr.onload = e => { + const file = JSON.parse((e.target as any).response); + progress.close(); + set(file); + }; + + xhr.upload.onprogress = e => { + if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); + }; + + xhr.send(data); + }; + + const set = file => { + api(I, 'i/update', { + avatar_id: file.id + }).then(i => { + dialog('アバターを更新しました', + '新しいアバターが反映されるまで時間がかかる場合があります。', + [{ + text: 'わかった' + }]); + + if (cb) cb(i); + }); + }; + + if (file) { + fileSelected(file); + } else { + const browser = (riot as any).mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { + multiple: false, + title: 'アバターにする画像を選択' + })[0]; + + browser.one('selected', file => { + fileSelected(file); + }); + } +}; diff --git a/src/web/app/desktop/scripts/update-banner.js b/src/web/app/desktop/scripts/update-banner.js deleted file mode 100644 index d83b2bf1b1..0000000000 --- a/src/web/app/desktop/scripts/update-banner.js +++ /dev/null @@ -1,87 +0,0 @@ -import * as riot from 'riot'; -import CONFIG from '../../common/scripts/config'; -import dialog from './dialog'; -import api from '../../common/scripts/api'; - -export default (I, cb, file = null) => { - const fileSelected = file => { - const cropper = riot.mount(document.body.appendChild(document.createElement('mk-crop-window')), { - file: file, - title: 'バナーとして表示する部分を選択', - aspectRatio: 16 / 9 - })[0]; - - cropper.on('cropped', blob => { - const data = new FormData(); - data.append('i', I.token); - data.append('file', blob, file.name + '.cropped.png'); - - api(I, 'drive/folders/find', { - name: 'バナー' - }).then(iconFolder => { - if (iconFolder.length === 0) { - api(I, 'drive/folders/create', { - name: 'バナー' - }).then(iconFolder => { - upload(data, iconFolder); - }); - } else { - upload(data, iconFolder[0]); - } - }); - }); - - cropper.on('skipped', () => { - set(file); - }); - }; - - const upload = (data, folder) => { - const progress = riot.mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { - title: '新しいバナーをアップロードしています' - })[0]; - - if (folder) data.append('folder_id', folder.id); - - const xhr = new XMLHttpRequest(); - xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); - xhr.onload = e => { - const file = JSON.parse(e.target.response); - progress.close(); - set(file); - }; - - xhr.upload.onprogress = e => { - if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); - }; - - xhr.send(data); - }; - - const set = file => { - api(I, 'i/update', { - banner_id: file.id - }).then(i => { - dialog('バナーを更新しました', - '新しいバナーが反映されるまで時間がかかる場合があります。', - [{ - text: 'わかりました。' - }]); - - if (cb) cb(i); - }); - }; - - if (file) { - fileSelected(file); - } else { - const browser = riot.mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { - multiple: false, - title: 'バナーにする画像を選択' - })[0]; - - browser.one('selected', file => { - fileSelected(file); - }); - } -}; diff --git a/src/web/app/desktop/scripts/update-banner.ts b/src/web/app/desktop/scripts/update-banner.ts new file mode 100644 index 0000000000..23a671c44d --- /dev/null +++ b/src/web/app/desktop/scripts/update-banner.ts @@ -0,0 +1,87 @@ +import * as riot from 'riot'; +import CONFIG from '../../common/scripts/config'; +import dialog from './dialog'; +import api from '../../common/scripts/api'; + +export default (I, cb, file = null) => { + const fileSelected = file => { + const cropper = (riot as any).mount(document.body.appendChild(document.createElement('mk-crop-window')), { + file: file, + title: 'バナーとして表示する部分を選択', + aspectRatio: 16 / 9 + })[0]; + + cropper.on('cropped', blob => { + const data = new FormData(); + data.append('i', I.token); + data.append('file', blob, file.name + '.cropped.png'); + + api(I, 'drive/folders/find', { + name: 'バナー' + }).then(iconFolder => { + if (iconFolder.length === 0) { + api(I, 'drive/folders/create', { + name: 'バナー' + }).then(iconFolder => { + upload(data, iconFolder); + }); + } else { + upload(data, iconFolder[0]); + } + }); + }); + + cropper.on('skipped', () => { + set(file); + }); + }; + + const upload = (data, folder) => { + const progress = (riot as any).mount(document.body.appendChild(document.createElement('mk-progress-dialog')), { + title: '新しいバナーをアップロードしています' + })[0]; + + if (folder) data.append('folder_id', folder.id); + + const xhr = new XMLHttpRequest(); + xhr.open('POST', CONFIG.apiUrl + '/drive/files/create', true); + xhr.onload = e => { + const file = JSON.parse((e.target as any).response); + progress.close(); + set(file); + }; + + xhr.upload.onprogress = e => { + if (e.lengthComputable) progress.updateProgress(e.loaded, e.total); + }; + + xhr.send(data); + }; + + const set = file => { + api(I, 'i/update', { + banner_id: file.id + }).then(i => { + dialog('バナーを更新しました', + '新しいバナーが反映されるまで時間がかかる場合があります。', + [{ + text: 'わかりました。' + }]); + + if (cb) cb(i); + }); + }; + + if (file) { + fileSelected(file); + } else { + const browser = (riot as any).mount(document.body.appendChild(document.createElement('mk-select-file-from-drive-window')), { + multiple: false, + title: 'バナーにする画像を選択' + })[0]; + + browser.one('selected', file => { + fileSelected(file); + }); + } +}; diff --git a/src/web/app/desktop/tags/autocomplete-suggestion.tag b/src/web/app/desktop/tags/autocomplete-suggestion.tag index b936360402..7311606694 100644 --- a/src/web/app/desktop/tags/autocomplete-suggestion.tag +++ b/src/web/app/desktop/tags/autocomplete-suggestion.tag @@ -177,7 +177,7 @@ }; this.applySelect = () => { - this.refs.users.children.forEach(el => { + Array.from(this.refs.users.children).forEach(el => { el.removeAttribute('data-selected'); }); diff --git a/src/web/app/desktop/tags/drive/browser.tag b/src/web/app/desktop/tags/drive/browser.tag index be16a782d7..18e27f24bc 100644 --- a/src/web/app/desktop/tags/drive/browser.tag +++ b/src/web/app/desktop/tags/drive/browser.tag @@ -408,7 +408,7 @@ // ドロップされてきたものがファイルだったら if (e.dataTransfer.files.length > 0) { - e.dataTransfer.files.forEach(file => { + Array.from(e.dataTransfer.files).forEach(file => { this.upload(file, this.folder); }); return false; @@ -510,7 +510,7 @@ }; this.changeFileInput = () => { - this.refs.fileInput.files.forEach(file => { + Array.from(this.refs.fileInput.files).forEach(file => { this.upload(file, this.folder); }); }; diff --git a/src/web/app/desktop/tags/drive/folder.tag b/src/web/app/desktop/tags/drive/folder.tag index e03c4e3534..1c361c8e4d 100644 --- a/src/web/app/desktop/tags/drive/folder.tag +++ b/src/web/app/desktop/tags/drive/folder.tag @@ -109,7 +109,7 @@ // ファイルだったら if (e.dataTransfer.files.length > 0) { - e.dataTransfer.files.forEach(file => { + Array.from(e.dataTransfer.files).forEach(file => { this.browser.upload(file, this.folder); }); return false; diff --git a/src/web/app/desktop/tags/drive/nav-folder.tag b/src/web/app/desktop/tags/drive/nav-folder.tag index c89d9edc1c..0a9421353c 100644 --- a/src/web/app/desktop/tags/drive/nav-folder.tag +++ b/src/web/app/desktop/tags/drive/nav-folder.tag @@ -55,7 +55,7 @@ // ファイルだったら if (e.dataTransfer.files.length > 0) { - e.dataTransfer.files.forEach(file => { + Array.from(e.dataTransfer.files).forEach(file => { this.browser.upload(file, this.folder); }); return false; diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js deleted file mode 100644 index 15677471c3..0000000000 --- a/src/web/app/desktop/tags/index.js +++ /dev/null @@ -1,93 +0,0 @@ -require('./contextmenu.tag'); -require('./dialog.tag'); -require('./window.tag'); -require('./input-dialog.tag'); -require('./follow-button.tag'); -require('./drive/base-contextmenu.tag'); -require('./drive/file-contextmenu.tag'); -require('./drive/folder-contextmenu.tag'); -require('./drive/file.tag'); -require('./drive/folder.tag'); -require('./drive/nav-folder.tag'); -require('./drive/browser-window.tag'); -require('./drive/browser.tag'); -require('./select-file-from-drive-window.tag'); -require('./select-folder-from-drive-window.tag'); -require('./crop-window.tag'); -require('./settings.tag'); -require('./settings-window.tag'); -require('./analog-clock.tag'); -require('./notifications.tag'); -require('./post-form-window.tag'); -require('./post-form.tag'); -require('./post-preview.tag'); -require('./repost-form-window.tag'); -require('./home-widgets/user-recommendation.tag'); -require('./home-widgets/timeline.tag'); -require('./home-widgets/mentions.tag'); -require('./home-widgets/calendar.tag'); -require('./home-widgets/donation.tag'); -require('./home-widgets/tips.tag'); -require('./home-widgets/nav.tag'); -require('./home-widgets/profile.tag'); -require('./home-widgets/notifications.tag'); -require('./home-widgets/rss-reader.tag'); -require('./home-widgets/photo-stream.tag'); -require('./home-widgets/broadcast.tag'); -require('./home-widgets/version.tag'); -require('./home-widgets/recommended-polls.tag'); -require('./home-widgets/trends.tag'); -require('./home-widgets/activity.tag'); -require('./home-widgets/server.tag'); -require('./home-widgets/slideshow.tag'); -require('./home-widgets/channel.tag'); -require('./home-widgets/timemachine.tag'); -require('./home-widgets/post-form.tag'); -require('./timeline.tag'); -require('./messaging/window.tag'); -require('./messaging/room-window.tag'); -require('./following-setuper.tag'); -require('./ellipsis-icon.tag'); -require('./ui.tag'); -require('./home.tag'); -require('./user-header.tag'); -require('./user-profile.tag'); -require('./user-timeline.tag'); -require('./user.tag'); -require('./user-home.tag'); -require('./user-graphs.tag'); -require('./user-photos.tag'); -require('./big-follow-button.tag'); -require('./pages/entrance.tag'); -require('./pages/entrance/signin.tag'); -require('./pages/entrance/signup.tag'); -require('./pages/home.tag'); -require('./pages/home-customize.tag'); -require('./pages/user.tag'); -require('./pages/post.tag'); -require('./pages/search.tag'); -require('./pages/not-found.tag'); -require('./pages/selectdrive.tag'); -require('./pages/drive.tag'); -require('./pages/messaging-room.tag'); -require('./autocomplete-suggestion.tag'); -require('./progress-dialog.tag'); -require('./user-preview.tag'); -require('./post-detail.tag'); -require('./post-detail-sub.tag'); -require('./search.tag'); -require('./search-posts.tag'); -require('./set-avatar-suggestion.tag'); -require('./set-banner-suggestion.tag'); -require('./repost-form.tag'); -require('./sub-post-content.tag'); -require('./images-viewer.tag'); -require('./image-dialog.tag'); -require('./donation.tag'); -require('./users-list.tag'); -require('./user-following.tag'); -require('./user-followers.tag'); -require('./user-following-window.tag'); -require('./user-followers-window.tag'); -require('./list-user.tag'); -require('./detailed-post-window.tag'); diff --git a/src/web/app/desktop/tags/index.ts b/src/web/app/desktop/tags/index.ts new file mode 100644 index 0000000000..15677471c3 --- /dev/null +++ b/src/web/app/desktop/tags/index.ts @@ -0,0 +1,93 @@ +require('./contextmenu.tag'); +require('./dialog.tag'); +require('./window.tag'); +require('./input-dialog.tag'); +require('./follow-button.tag'); +require('./drive/base-contextmenu.tag'); +require('./drive/file-contextmenu.tag'); +require('./drive/folder-contextmenu.tag'); +require('./drive/file.tag'); +require('./drive/folder.tag'); +require('./drive/nav-folder.tag'); +require('./drive/browser-window.tag'); +require('./drive/browser.tag'); +require('./select-file-from-drive-window.tag'); +require('./select-folder-from-drive-window.tag'); +require('./crop-window.tag'); +require('./settings.tag'); +require('./settings-window.tag'); +require('./analog-clock.tag'); +require('./notifications.tag'); +require('./post-form-window.tag'); +require('./post-form.tag'); +require('./post-preview.tag'); +require('./repost-form-window.tag'); +require('./home-widgets/user-recommendation.tag'); +require('./home-widgets/timeline.tag'); +require('./home-widgets/mentions.tag'); +require('./home-widgets/calendar.tag'); +require('./home-widgets/donation.tag'); +require('./home-widgets/tips.tag'); +require('./home-widgets/nav.tag'); +require('./home-widgets/profile.tag'); +require('./home-widgets/notifications.tag'); +require('./home-widgets/rss-reader.tag'); +require('./home-widgets/photo-stream.tag'); +require('./home-widgets/broadcast.tag'); +require('./home-widgets/version.tag'); +require('./home-widgets/recommended-polls.tag'); +require('./home-widgets/trends.tag'); +require('./home-widgets/activity.tag'); +require('./home-widgets/server.tag'); +require('./home-widgets/slideshow.tag'); +require('./home-widgets/channel.tag'); +require('./home-widgets/timemachine.tag'); +require('./home-widgets/post-form.tag'); +require('./timeline.tag'); +require('./messaging/window.tag'); +require('./messaging/room-window.tag'); +require('./following-setuper.tag'); +require('./ellipsis-icon.tag'); +require('./ui.tag'); +require('./home.tag'); +require('./user-header.tag'); +require('./user-profile.tag'); +require('./user-timeline.tag'); +require('./user.tag'); +require('./user-home.tag'); +require('./user-graphs.tag'); +require('./user-photos.tag'); +require('./big-follow-button.tag'); +require('./pages/entrance.tag'); +require('./pages/entrance/signin.tag'); +require('./pages/entrance/signup.tag'); +require('./pages/home.tag'); +require('./pages/home-customize.tag'); +require('./pages/user.tag'); +require('./pages/post.tag'); +require('./pages/search.tag'); +require('./pages/not-found.tag'); +require('./pages/selectdrive.tag'); +require('./pages/drive.tag'); +require('./pages/messaging-room.tag'); +require('./autocomplete-suggestion.tag'); +require('./progress-dialog.tag'); +require('./user-preview.tag'); +require('./post-detail.tag'); +require('./post-detail-sub.tag'); +require('./search.tag'); +require('./search-posts.tag'); +require('./set-avatar-suggestion.tag'); +require('./set-banner-suggestion.tag'); +require('./repost-form.tag'); +require('./sub-post-content.tag'); +require('./images-viewer.tag'); +require('./image-dialog.tag'); +require('./donation.tag'); +require('./users-list.tag'); +require('./user-following.tag'); +require('./user-followers.tag'); +require('./user-following-window.tag'); +require('./user-followers-window.tag'); +require('./list-user.tag'); +require('./detailed-post-window.tag'); diff --git a/src/web/app/desktop/tags/post-detail-sub.tag b/src/web/app/desktop/tags/post-detail-sub.tag index 8a0ada5f2a..e22386df91 100644 --- a/src/web/app/desktop/tags/post-detail-sub.tag +++ b/src/web/app/desktop/tags/post-detail-sub.tag @@ -129,7 +129,7 @@ this.refs.text.innerHTML = compile(tokens); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); } diff --git a/src/web/app/desktop/tags/post-detail.tag b/src/web/app/desktop/tags/post-detail.tag index ce7f81e32c..1a0eefe13e 100644 --- a/src/web/app/desktop/tags/post-detail.tag +++ b/src/web/app/desktop/tags/post-detail.tag @@ -273,7 +273,7 @@ this.refs.text.innerHTML = compile(tokens); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); diff --git a/src/web/app/desktop/tags/post-form.tag b/src/web/app/desktop/tags/post-form.tag index 5041078bee..e49beeedbc 100644 --- a/src/web/app/desktop/tags/post-form.tag +++ b/src/web/app/desktop/tags/post-form.tag @@ -405,7 +405,7 @@ // ファイルだったら if (e.dataTransfer.files.length > 0) { - e.dataTransfer.files.forEach(this.upload); + Array.from(e.dataTransfer.files).forEach(this.upload); } }; @@ -414,7 +414,7 @@ }; this.onpaste = e => { - e.clipboardData.items.forEach(item => { + Array.from(e.clipboardData.items).forEach(item => { if (item.kind == 'file') { this.upload(item.getAsFile()); } @@ -435,7 +435,7 @@ }; this.changeFile = () => { - this.refs.file.files.forEach(this.upload); + Array.from(this.refs.file.files).forEach(this.upload); }; this.upload = file => { diff --git a/src/web/app/desktop/tags/sub-post-content.tag b/src/web/app/desktop/tags/sub-post-content.tag index c75ae2911c..86269fdbe9 100644 --- a/src/web/app/desktop/tags/sub-post-content.tag +++ b/src/web/app/desktop/tags/sub-post-content.tag @@ -45,7 +45,7 @@ const tokens = this.post.ast; this.refs.text.innerHTML = compile(tokens, false); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); } diff --git a/src/web/app/desktop/tags/timeline.tag b/src/web/app/desktop/tags/timeline.tag index 44f3d5d8ec..5e3b883b47 100644 --- a/src/web/app/desktop/tags/timeline.tag +++ b/src/web/app/desktop/tags/timeline.tag @@ -498,7 +498,7 @@ this.refs.text.innerHTML = this.refs.text.innerHTML.replace('

', compile(tokens)); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); diff --git a/src/web/app/dev/router.js b/src/web/app/dev/router.js deleted file mode 100644 index 7fde30fa5c..0000000000 --- a/src/web/app/dev/router.js +++ /dev/null @@ -1,42 +0,0 @@ -import * as riot from 'riot'; -const route = require('page'); -let page = null; - -export default me => { - route('/', index); - route('/apps', apps); - route('/app/new', newApp); - route('/app/:app', app); - route('*', notFound); - - function index() { - mount(document.createElement('mk-index')); - } - - function apps() { - mount(document.createElement('mk-apps-page')); - } - - function newApp() { - mount(document.createElement('mk-new-app-page')); - } - - function app(ctx) { - const el = document.createElement('mk-app-page'); - el.setAttribute('app', ctx.params.app); - mount(el); - } - - function notFound() { - mount(document.createElement('mk-not-found')); - } - - // EXEC - route(); -}; - -function mount(content) { - if (page) page.unmount(); - const body = document.getElementById('app'); - page = riot.mount(body.appendChild(content))[0]; -} diff --git a/src/web/app/dev/router.ts b/src/web/app/dev/router.ts new file mode 100644 index 0000000000..532ec23c73 --- /dev/null +++ b/src/web/app/dev/router.ts @@ -0,0 +1,42 @@ +import * as riot from 'riot'; +import * as route from 'page'; +let page = null; + +export default me => { + route('/', index); + route('/apps', apps); + route('/app/new', newApp); + route('/app/:app', app); + route('*', notFound); + + function index() { + mount(document.createElement('mk-index')); + } + + function apps() { + mount(document.createElement('mk-apps-page')); + } + + function newApp() { + mount(document.createElement('mk-new-app-page')); + } + + function app(ctx) { + const el = document.createElement('mk-app-page'); + el.setAttribute('app', ctx.params.app); + mount(el); + } + + function notFound() { + mount(document.createElement('mk-not-found')); + } + + // EXEC + (route as any)(); +}; + +function mount(content) { + if (page) page.unmount(); + const body = document.getElementById('app'); + page = riot.mount(body.appendChild(content))[0]; +} diff --git a/src/web/app/dev/script.js b/src/web/app/dev/script.js deleted file mode 100644 index 39d7fc891e..0000000000 --- a/src/web/app/dev/script.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Developer Center - */ - -// Style -import './style.styl'; - -require('./tags'); -import init from '../init'; -import route from './router'; - -/** - * init - */ -init(me => { - // Start routing - route(me); -}); diff --git a/src/web/app/dev/script.ts b/src/web/app/dev/script.ts new file mode 100644 index 0000000000..39d7fc891e --- /dev/null +++ b/src/web/app/dev/script.ts @@ -0,0 +1,18 @@ +/** + * Developer Center + */ + +// Style +import './style.styl'; + +require('./tags'); +import init from '../init'; +import route from './router'; + +/** + * init + */ +init(me => { + // Start routing + route(me); +}); diff --git a/src/web/app/dev/tags/index.js b/src/web/app/dev/tags/index.js deleted file mode 100644 index 1e0c73697e..0000000000 --- a/src/web/app/dev/tags/index.js +++ /dev/null @@ -1,5 +0,0 @@ -require('./pages/index.tag'); -require('./pages/apps.tag'); -require('./pages/app.tag'); -require('./pages/new-app.tag'); -require('./new-app-form.tag'); diff --git a/src/web/app/dev/tags/index.ts b/src/web/app/dev/tags/index.ts new file mode 100644 index 0000000000..1e0c73697e --- /dev/null +++ b/src/web/app/dev/tags/index.ts @@ -0,0 +1,5 @@ +require('./pages/index.tag'); +require('./pages/apps.tag'); +require('./pages/app.tag'); +require('./pages/new-app.tag'); +require('./new-app-form.tag'); diff --git a/src/web/app/init.js b/src/web/app/init.js deleted file mode 100644 index d3817fe971..0000000000 --- a/src/web/app/init.js +++ /dev/null @@ -1,196 +0,0 @@ -/** - * App initializer - */ - -'use strict'; - -import * as riot from 'riot'; -import api from './common/scripts/api'; -import signout from './common/scripts/signout'; -import checkForUpdate from './common/scripts/check-for-update'; -import Connection from './common/scripts/home-stream'; -import ServerStreamManager from './common/scripts/server-stream-manager.ts'; -import Progress from './common/scripts/loading'; -import mixin from './common/mixins'; -import CONFIG from './common/scripts/config'; -require('./common/tags'); - -/** - * APP ENTRY POINT! - */ - -console.info(`Misskey v${VERSION} (葵 aoi)`); - -{ // Set lang attr - const html = document.documentElement; - html.setAttribute('lang', LANG); -} - -{ // Set description meta tag - const head = document.getElementsByTagName('head')[0]; - const meta = document.createElement('meta'); - meta.setAttribute('name', 'description'); - meta.setAttribute('content', '%i18n:common.misskey%'); - head.appendChild(meta); -} - -document.domain = CONFIG.host; - -// Set global configuration -riot.mixin({ CONFIG }); - -// ↓ NodeList、HTMLCollection、FileList、DataTransferItemListで forEach を使えるようにする -if (NodeList.prototype.forEach === undefined) { - NodeList.prototype.forEach = Array.prototype.forEach; -} -if (HTMLCollection.prototype.forEach === undefined) { - HTMLCollection.prototype.forEach = Array.prototype.forEach; -} -if (FileList.prototype.forEach === undefined) { - FileList.prototype.forEach = Array.prototype.forEach; -} -if (window.DataTransferItemList && DataTransferItemList.prototype.forEach === undefined) { - DataTransferItemList.prototype.forEach = Array.prototype.forEach; -} - -// iOSでプライベートモードだとlocalStorageが使えないので既存のメソッドを上書きする -try { - localStorage.setItem('kyoppie', 'yuppie'); -} catch (e) { - Storage.prototype.setItem = () => { }; // noop -} - -// クライアントを更新すべきならする -if (localStorage.getItem('should-refresh') == 'true') { - localStorage.removeItem('should-refresh'); - location.reload(true); -} - -// 更新チェック -setTimeout(checkForUpdate, 3000); - -// ユーザーをフェッチしてコールバックする -export default callback => { - // Get cached account data - let cachedMe = JSON.parse(localStorage.getItem('me')); - - if (cachedMe) { - fetched(cachedMe); - - // 後から新鮮なデータをフェッチ - fetchme(cachedMe.token, freshData => { - Object.assign(cachedMe, freshData); - cachedMe.trigger('updated'); - }); - } else { - // Get token from cookie - const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1]; - - fetchme(i, fetched); - } - - // フェッチが完了したとき - function fetched(me) { - if (me) { - riot.observable(me); - - // この me オブジェクトを更新するメソッド - me.update = data => { - if (data) Object.assign(me, data); - me.trigger('updated'); - }; - - // ローカルストレージにキャッシュ - localStorage.setItem('me', JSON.stringify(me)); - - me.on('updated', () => { - // キャッシュ更新 - localStorage.setItem('me', JSON.stringify(me)); - }); - } - - // Init home stream connection - const stream = me ? new Connection(me) : null; - - // Init server stream connection manager - const serverStreamManager = new ServerStreamManager(); - - // ミックスイン初期化 - mixin(me, stream, serverStreamManager); - - // ローディング画面クリア - const ini = document.getElementById('ini'); - ini.parentNode.removeChild(ini); - - // アプリ基底要素マウント - const app = document.createElement('div'); - app.setAttribute('id', 'app'); - document.body.appendChild(app); - - try { - callback(me, stream); - } catch (e) { - panic(e); - } - } -}; - -// ユーザーをフェッチしてコールバックする -function fetchme(token, cb) { - let me = null; - - // Return when not signed in - if (token == null) { - return done(); - } - - // Fetch user - fetch(`${CONFIG.apiUrl}/i`, { - method: 'POST', - body: JSON.stringify({ - i: token - }) - }).then(res => { // When success - // When failed to authenticate user - if (res.status !== 200) { - return signout(); - } - - res.json().then(i => { - me = i; - me.token = token; - done(); - }); - }, () => { // When failure - // Render the error screen - document.body.innerHTML = ''; - riot.mount('*'); - Progress.done(); - }); - - function done() { - if (cb) cb(me); - } -} - -// BSoD -function panic(e) { - console.error(e); - - // Display blue screen - document.documentElement.style.background = '#1269e2'; - document.body.innerHTML = - '
' - + '

:( 致命的な問題が発生しました。

' - + '

お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。

' - + '
' - + `

エラーコード: ${e.toString()}

` - + `

ブラウザ バージョン: ${navigator.userAgent}

` - + `

クライアント バージョン: ${VERSION}

` - + '
' - + '

問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。

' - + '

Thank you for using Misskey.

' - + '
'; - - // TODO: Report the bug -} diff --git a/src/web/app/init.ts b/src/web/app/init.ts new file mode 100644 index 0000000000..e68a7c9152 --- /dev/null +++ b/src/web/app/init.ts @@ -0,0 +1,178 @@ +/** + * App initializer + */ + +declare var VERSION: string; +declare var LANG: string; + +import * as riot from 'riot'; +import signout from './common/scripts/signout'; +import checkForUpdate from './common/scripts/check-for-update'; +import Connection from './common/scripts/home-stream'; +import Progress from './common/scripts/loading'; +import mixin from './common/mixins'; +import CONFIG from './common/scripts/config'; +require('./common/tags'); + +/** + * APP ENTRY POINT! + */ + +console.info(`Misskey v${VERSION} (葵 aoi)`); + +{ // Set lang attr + const html = document.documentElement; + html.setAttribute('lang', LANG); +} + +{ // Set description meta tag + const head = document.getElementsByTagName('head')[0]; + const meta = document.createElement('meta'); + meta.setAttribute('name', 'description'); + meta.setAttribute('content', '%i18n:common.misskey%'); + head.appendChild(meta); +} + +document.domain = CONFIG.host; + +// Set global configuration +(riot as any).mixin({ CONFIG }); + +// iOSでプライベートモードだとlocalStorageが使えないので既存のメソッドを上書きする +try { + localStorage.setItem('kyoppie', 'yuppie'); +} catch (e) { + Storage.prototype.setItem = () => { }; // noop +} + +// クライアントを更新すべきならする +if (localStorage.getItem('should-refresh') == 'true') { + localStorage.removeItem('should-refresh'); + location.reload(true); +} + +// 更新チェック +setTimeout(checkForUpdate, 3000); + +// ユーザーをフェッチしてコールバックする +export default callback => { + // Get cached account data + const cachedMe = JSON.parse(localStorage.getItem('me')); + + if (cachedMe) { + fetched(cachedMe); + + // 後から新鮮なデータをフェッチ + fetchme(cachedMe.token, freshData => { + Object.assign(cachedMe, freshData); + cachedMe.trigger('updated'); + }); + } else { + // Get token from cookie + const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1]; + + fetchme(i, fetched); + } + + // フェッチが完了したとき + function fetched(me) { + if (me) { + riot.observable(me); + + // この me オブジェクトを更新するメソッド + me.update = data => { + if (data) Object.assign(me, data); + me.trigger('updated'); + }; + + // ローカルストレージにキャッシュ + localStorage.setItem('me', JSON.stringify(me)); + + me.on('updated', () => { + // キャッシュ更新 + localStorage.setItem('me', JSON.stringify(me)); + }); + } + + // Init home stream connection + const stream = me ? new Connection(me) : null; + + // ミックスイン初期化 + mixin(me, stream); + + // ローディング画面クリア + const ini = document.getElementById('ini'); + ini.parentNode.removeChild(ini); + + // アプリ基底要素マウント + const app = document.createElement('div'); + app.setAttribute('id', 'app'); + document.body.appendChild(app); + + try { + callback(me, stream); + } catch (e) { + panic(e); + } + } +}; + +// ユーザーをフェッチしてコールバックする +function fetchme(token, cb) { + let me = null; + + // Return when not signed in + if (token == null) { + return done(); + } + + // Fetch user + fetch(`${CONFIG.apiUrl}/i`, { + method: 'POST', + body: JSON.stringify({ + i: token + }) + }).then(res => { // When success + // When failed to authenticate user + if (res.status !== 200) { + return signout(); + } + + res.json().then(i => { + me = i; + me.token = token; + done(); + }); + }, () => { // When failure + // Render the error screen + document.body.innerHTML = ''; + riot.mount('*'); + Progress.done(); + }); + + function done() { + if (cb) cb(me); + } +} + +// BSoD +function panic(e) { + console.error(e); + + // Display blue screen + document.documentElement.style.background = '#1269e2'; + document.body.innerHTML = + '
' + + '

:( 致命的な問題が発生しました。

' + + '

お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。

' + + '
' + + `

エラーコード: ${e.toString()}

` + + `

ブラウザ バージョン: ${navigator.userAgent}

` + + `

クライアント バージョン: ${VERSION}

` + + '
' + + '

問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。

' + + '

Thank you for using Misskey.

' + + '
'; + + // TODO: Report the bug +} diff --git a/src/web/app/mobile/router.js b/src/web/app/mobile/router.js deleted file mode 100644 index 01eb3c8145..0000000000 --- a/src/web/app/mobile/router.js +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Mobile App Router - */ - -import * as riot from 'riot'; -const route = require('page'); -let page = null; - -export default me => { - route('/', index); - route('/selectdrive', selectDrive); - route('/i/notifications', notifications); - route('/i/messaging', messaging); - route('/i/messaging/:username', messaging); - route('/i/drive', drive); - route('/i/drive/folder/:folder', drive); - route('/i/drive/file/:file', drive); - route('/i/settings', settings); - route('/i/settings/profile', settingsProfile); - route('/i/settings/signin-history', settingsSignin); - route('/i/settings/api', settingsApi); - route('/i/settings/twitter', settingsTwitter); - route('/i/settings/authorized-apps', settingsAuthorizedApps); - route('/post/new', newPost); - route('/post::post', post); - route('/search::query', search); - route('/:user', user.bind(null, 'overview')); - route('/:user/graphs', user.bind(null, 'graphs')); - route('/:user/followers', userFollowers); - route('/:user/following', userFollowing); - route('/:user/:post', post); - route('*', notFound); - - function index() { - me ? home() : entrance(); - } - - function home() { - mount(document.createElement('mk-home-page')); - } - - function entrance() { - mount(document.createElement('mk-entrance')); - } - - function notifications() { - mount(document.createElement('mk-notifications-page')); - } - - function messaging(ctx) { - if (ctx.params.username) { - const el = document.createElement('mk-messaging-room-page'); - el.setAttribute('username', ctx.params.username); - mount(el); - } else { - mount(document.createElement('mk-messaging-page')); - } - } - - function newPost() { - mount(document.createElement('mk-new-post-page')); - } - - function settings() { - mount(document.createElement('mk-settings-page')); - } - - function settingsProfile() { - mount(document.createElement('mk-profile-setting-page')); - } - - function settingsSignin() { - mount(document.createElement('mk-signin-history-page')); - } - - function settingsApi() { - mount(document.createElement('mk-api-info-page')); - } - - function settingsTwitter() { - mount(document.createElement('mk-twitter-setting-page')); - } - - function settingsAuthorizedApps() { - mount(document.createElement('mk-authorized-apps-page')); - } - - function search(ctx) { - const el = document.createElement('mk-search-page'); - el.setAttribute('query', ctx.params.query); - mount(el); - } - - function user(page, ctx) { - const el = document.createElement('mk-user-page'); - el.setAttribute('user', ctx.params.user); - el.setAttribute('page', page); - mount(el); - } - - function userFollowing(ctx) { - const el = document.createElement('mk-user-following-page'); - el.setAttribute('user', ctx.params.user); - mount(el); - } - - function userFollowers(ctx) { - const el = document.createElement('mk-user-followers-page'); - el.setAttribute('user', ctx.params.user); - mount(el); - } - - function post(ctx) { - const el = document.createElement('mk-post-page'); - el.setAttribute('post', ctx.params.post); - mount(el); - } - - function drive(ctx) { - const el = document.createElement('mk-drive-page'); - if (ctx.params.folder) el.setAttribute('folder', ctx.params.folder); - if (ctx.params.file) el.setAttribute('file', ctx.params.file); - mount(el); - } - - function selectDrive() { - mount(document.createElement('mk-selectdrive-page')); - } - - function notFound() { - mount(document.createElement('mk-not-found')); - } - - riot.mixin('page', { - page: route - }); - - // EXEC - route(); -}; - -function mount(content) { - document.documentElement.style.background = '#fff'; - if (page) page.unmount(); - const body = document.getElementById('app'); - page = riot.mount(body.appendChild(content))[0]; -} diff --git a/src/web/app/mobile/router.ts b/src/web/app/mobile/router.ts new file mode 100644 index 0000000000..7fae9db547 --- /dev/null +++ b/src/web/app/mobile/router.ts @@ -0,0 +1,147 @@ +/** + * Mobile App Router + */ + +import * as riot from 'riot'; +import * as route from 'page'; +let page = null; + +export default me => { + route('/', index); + route('/selectdrive', selectDrive); + route('/i/notifications', notifications); + route('/i/messaging', messaging); + route('/i/messaging/:username', messaging); + route('/i/drive', drive); + route('/i/drive/folder/:folder', drive); + route('/i/drive/file/:file', drive); + route('/i/settings', settings); + route('/i/settings/profile', settingsProfile); + route('/i/settings/signin-history', settingsSignin); + route('/i/settings/api', settingsApi); + route('/i/settings/twitter', settingsTwitter); + route('/i/settings/authorized-apps', settingsAuthorizedApps); + route('/post/new', newPost); + route('/post::post', post); + route('/search::query', search); + route('/:user', user.bind(null, 'overview')); + route('/:user/graphs', user.bind(null, 'graphs')); + route('/:user/followers', userFollowers); + route('/:user/following', userFollowing); + route('/:user/:post', post); + route('*', notFound); + + function index() { + me ? home() : entrance(); + } + + function home() { + mount(document.createElement('mk-home-page')); + } + + function entrance() { + mount(document.createElement('mk-entrance')); + } + + function notifications() { + mount(document.createElement('mk-notifications-page')); + } + + function messaging(ctx) { + if (ctx.params.username) { + const el = document.createElement('mk-messaging-room-page'); + el.setAttribute('username', ctx.params.username); + mount(el); + } else { + mount(document.createElement('mk-messaging-page')); + } + } + + function newPost() { + mount(document.createElement('mk-new-post-page')); + } + + function settings() { + mount(document.createElement('mk-settings-page')); + } + + function settingsProfile() { + mount(document.createElement('mk-profile-setting-page')); + } + + function settingsSignin() { + mount(document.createElement('mk-signin-history-page')); + } + + function settingsApi() { + mount(document.createElement('mk-api-info-page')); + } + + function settingsTwitter() { + mount(document.createElement('mk-twitter-setting-page')); + } + + function settingsAuthorizedApps() { + mount(document.createElement('mk-authorized-apps-page')); + } + + function search(ctx) { + const el = document.createElement('mk-search-page'); + el.setAttribute('query', ctx.params.query); + mount(el); + } + + function user(page, ctx) { + const el = document.createElement('mk-user-page'); + el.setAttribute('user', ctx.params.user); + el.setAttribute('page', page); + mount(el); + } + + function userFollowing(ctx) { + const el = document.createElement('mk-user-following-page'); + el.setAttribute('user', ctx.params.user); + mount(el); + } + + function userFollowers(ctx) { + const el = document.createElement('mk-user-followers-page'); + el.setAttribute('user', ctx.params.user); + mount(el); + } + + function post(ctx) { + const el = document.createElement('mk-post-page'); + el.setAttribute('post', ctx.params.post); + mount(el); + } + + function drive(ctx) { + const el = document.createElement('mk-drive-page'); + if (ctx.params.folder) el.setAttribute('folder', ctx.params.folder); + if (ctx.params.file) el.setAttribute('file', ctx.params.file); + mount(el); + } + + function selectDrive() { + mount(document.createElement('mk-selectdrive-page')); + } + + function notFound() { + mount(document.createElement('mk-not-found')); + } + + (riot as any).mixin('page', { + page: route + }); + + // EXEC + (route as any)(); +}; + +function mount(content) { + document.documentElement.style.background = '#fff'; + if (page) page.unmount(); + const body = document.getElementById('app'); + page = riot.mount(body.appendChild(content))[0]; +} diff --git a/src/web/app/mobile/script.js b/src/web/app/mobile/script.js deleted file mode 100644 index 503e0fd673..0000000000 --- a/src/web/app/mobile/script.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Mobile Client - */ - -// Style -import './style.styl'; - -require('./tags'); -import init from '../init'; -import route from './router'; - -/** - * init - */ -init(me => { - // http://qiita.com/junya/items/3ff380878f26ca447f85 - document.body.setAttribute('ontouchstart', ''); - - // Start routing - route(me); -}); diff --git a/src/web/app/mobile/script.ts b/src/web/app/mobile/script.ts new file mode 100644 index 0000000000..503e0fd673 --- /dev/null +++ b/src/web/app/mobile/script.ts @@ -0,0 +1,21 @@ +/** + * Mobile Client + */ + +// Style +import './style.styl'; + +require('./tags'); +import init from '../init'; +import route from './router'; + +/** + * init + */ +init(me => { + // http://qiita.com/junya/items/3ff380878f26ca447f85 + document.body.setAttribute('ontouchstart', ''); + + // Start routing + route(me); +}); diff --git a/src/web/app/mobile/scripts/open-post-form.js b/src/web/app/mobile/scripts/open-post-form.js deleted file mode 100644 index e0fae4d8ca..0000000000 --- a/src/web/app/mobile/scripts/open-post-form.js +++ /dev/null @@ -1,15 +0,0 @@ -import * as riot from 'riot'; - -export default opts => { - const app = document.getElementById('app'); - app.style.display = 'none'; - - function recover() { - app.style.display = 'block'; - } - - const form = riot.mount(document.body.appendChild(document.createElement('mk-post-form')), opts)[0]; - form - .on('cancel', recover) - .on('post', recover); -}; diff --git a/src/web/app/mobile/scripts/open-post-form.ts b/src/web/app/mobile/scripts/open-post-form.ts new file mode 100644 index 0000000000..e0fae4d8ca --- /dev/null +++ b/src/web/app/mobile/scripts/open-post-form.ts @@ -0,0 +1,15 @@ +import * as riot from 'riot'; + +export default opts => { + const app = document.getElementById('app'); + app.style.display = 'none'; + + function recover() { + app.style.display = 'block'; + } + + const form = riot.mount(document.body.appendChild(document.createElement('mk-post-form')), opts)[0]; + form + .on('cancel', recover) + .on('post', recover); +}; diff --git a/src/web/app/mobile/scripts/ui-event.js b/src/web/app/mobile/scripts/ui-event.js deleted file mode 100644 index 2e406549a4..0000000000 --- a/src/web/app/mobile/scripts/ui-event.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as riot from 'riot'; - -const ev = riot.observable(); - -export default ev; diff --git a/src/web/app/mobile/scripts/ui-event.ts b/src/web/app/mobile/scripts/ui-event.ts new file mode 100644 index 0000000000..2e406549a4 --- /dev/null +++ b/src/web/app/mobile/scripts/ui-event.ts @@ -0,0 +1,5 @@ +import * as riot from 'riot'; + +const ev = riot.observable(); + +export default ev; diff --git a/src/web/app/mobile/tags/drive.tag b/src/web/app/mobile/tags/drive.tag index 6929c50ab1..870a451acb 100644 --- a/src/web/app/mobile/tags/drive.tag +++ b/src/web/app/mobile/tags/drive.tag @@ -561,7 +561,7 @@ }; this.changeLocalFile = () => { - this.refs.file.files.forEach(f => this.refs.uploader.upload(f, this.folder)); + Array.from(this.refs.file.files).forEach(f => this.refs.uploader.upload(f, this.folder)); }; diff --git a/src/web/app/mobile/tags/index.js b/src/web/app/mobile/tags/index.js deleted file mode 100644 index 19952c20cd..0000000000 --- a/src/web/app/mobile/tags/index.js +++ /dev/null @@ -1,51 +0,0 @@ -require('./ui.tag'); -require('./page/entrance.tag'); -require('./page/entrance/signin.tag'); -require('./page/entrance/signup.tag'); -require('./page/home.tag'); -require('./page/drive.tag'); -require('./page/notifications.tag'); -require('./page/user.tag'); -require('./page/user-followers.tag'); -require('./page/user-following.tag'); -require('./page/post.tag'); -require('./page/new-post.tag'); -require('./page/search.tag'); -require('./page/settings.tag'); -require('./page/settings/profile.tag'); -require('./page/settings/signin.tag'); -require('./page/settings/api.tag'); -require('./page/settings/authorized-apps.tag'); -require('./page/settings/twitter.tag'); -require('./page/messaging.tag'); -require('./page/messaging-room.tag'); -require('./page/selectdrive.tag'); -require('./home.tag'); -require('./home-timeline.tag'); -require('./timeline.tag'); -require('./post-preview.tag'); -require('./sub-post-content.tag'); -require('./images-viewer.tag'); -require('./drive.tag'); -require('./drive-selector.tag'); -require('./drive-folder-selector.tag'); -require('./drive/file.tag'); -require('./drive/folder.tag'); -require('./drive/file-viewer.tag'); -require('./post-form.tag'); -require('./notification.tag'); -require('./notifications.tag'); -require('./notify.tag'); -require('./notification-preview.tag'); -require('./search.tag'); -require('./search-posts.tag'); -require('./post-detail.tag'); -require('./user.tag'); -require('./user-timeline.tag'); -require('./follow-button.tag'); -require('./user-preview.tag'); -require('./users-list.tag'); -require('./user-following.tag'); -require('./user-followers.tag'); -require('./init-following.tag'); -require('./user-card.tag'); diff --git a/src/web/app/mobile/tags/index.ts b/src/web/app/mobile/tags/index.ts new file mode 100644 index 0000000000..19952c20cd --- /dev/null +++ b/src/web/app/mobile/tags/index.ts @@ -0,0 +1,51 @@ +require('./ui.tag'); +require('./page/entrance.tag'); +require('./page/entrance/signin.tag'); +require('./page/entrance/signup.tag'); +require('./page/home.tag'); +require('./page/drive.tag'); +require('./page/notifications.tag'); +require('./page/user.tag'); +require('./page/user-followers.tag'); +require('./page/user-following.tag'); +require('./page/post.tag'); +require('./page/new-post.tag'); +require('./page/search.tag'); +require('./page/settings.tag'); +require('./page/settings/profile.tag'); +require('./page/settings/signin.tag'); +require('./page/settings/api.tag'); +require('./page/settings/authorized-apps.tag'); +require('./page/settings/twitter.tag'); +require('./page/messaging.tag'); +require('./page/messaging-room.tag'); +require('./page/selectdrive.tag'); +require('./home.tag'); +require('./home-timeline.tag'); +require('./timeline.tag'); +require('./post-preview.tag'); +require('./sub-post-content.tag'); +require('./images-viewer.tag'); +require('./drive.tag'); +require('./drive-selector.tag'); +require('./drive-folder-selector.tag'); +require('./drive/file.tag'); +require('./drive/folder.tag'); +require('./drive/file-viewer.tag'); +require('./post-form.tag'); +require('./notification.tag'); +require('./notifications.tag'); +require('./notify.tag'); +require('./notification-preview.tag'); +require('./search.tag'); +require('./search-posts.tag'); +require('./post-detail.tag'); +require('./user.tag'); +require('./user-timeline.tag'); +require('./follow-button.tag'); +require('./user-preview.tag'); +require('./users-list.tag'); +require('./user-following.tag'); +require('./user-followers.tag'); +require('./init-following.tag'); +require('./user-card.tag'); diff --git a/src/web/app/mobile/tags/post-detail.tag b/src/web/app/mobile/tags/post-detail.tag index 8a32101036..28071a5cac 100644 --- a/src/web/app/mobile/tags/post-detail.tag +++ b/src/web/app/mobile/tags/post-detail.tag @@ -285,7 +285,7 @@ this.refs.text.innerHTML = compile(tokens); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); diff --git a/src/web/app/mobile/tags/post-form.tag b/src/web/app/mobile/tags/post-form.tag index d7d382c9e2..2912bfdfa2 100644 --- a/src/web/app/mobile/tags/post-form.tag +++ b/src/web/app/mobile/tags/post-form.tag @@ -207,7 +207,7 @@ }; this.onpaste = e => { - e.clipboardData.items.forEach(item => { + Array.from(e.clipboardData.items).forEach(item => { if (item.kind == 'file') { this.upload(item.getAsFile()); } @@ -228,7 +228,7 @@ }; this.changeFile = () => { - this.refs.file.files.forEach(this.upload); + Array.from(this.refs.file.files).forEach(this.upload); }; this.upload = file => { diff --git a/src/web/app/mobile/tags/sub-post-content.tag b/src/web/app/mobile/tags/sub-post-content.tag index e32e245185..c14233d3b7 100644 --- a/src/web/app/mobile/tags/sub-post-content.tag +++ b/src/web/app/mobile/tags/sub-post-content.tag @@ -37,7 +37,7 @@ const tokens = this.post.ast; this.refs.text.innerHTML = compile(tokens, false); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); } diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag index f9ec2cca60..52f6f27ea8 100644 --- a/src/web/app/mobile/tags/timeline.tag +++ b/src/web/app/mobile/tags/timeline.tag @@ -538,7 +538,7 @@ this.refs.text.innerHTML = this.refs.text.innerHTML.replace('

', compile(tokens)); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); diff --git a/src/web/app/stats/script.js b/src/web/app/stats/script.js deleted file mode 100644 index 75063501bb..0000000000 --- a/src/web/app/stats/script.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Stats - */ - -// Style -import './style.styl'; - -import * as riot from 'riot'; -require('./tags'); -import init from '../init'; - -document.title = 'Misskey Statistics'; - -/** - * init - */ -init(me => { - mount(document.createElement('mk-index')); -}); - -function mount(content) { - riot.mount(document.getElementById('app').appendChild(content)); -} diff --git a/src/web/app/stats/script.ts b/src/web/app/stats/script.ts new file mode 100644 index 0000000000..75063501bb --- /dev/null +++ b/src/web/app/stats/script.ts @@ -0,0 +1,23 @@ +/** + * Stats + */ + +// Style +import './style.styl'; + +import * as riot from 'riot'; +require('./tags'); +import init from '../init'; + +document.title = 'Misskey Statistics'; + +/** + * init + */ +init(me => { + mount(document.createElement('mk-index')); +}); + +function mount(content) { + riot.mount(document.getElementById('app').appendChild(content)); +} diff --git a/src/web/app/stats/tags/index.js b/src/web/app/stats/tags/index.js deleted file mode 100644 index f41151949f..0000000000 --- a/src/web/app/stats/tags/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./index.tag'); diff --git a/src/web/app/stats/tags/index.ts b/src/web/app/stats/tags/index.ts new file mode 100644 index 0000000000..f41151949f --- /dev/null +++ b/src/web/app/stats/tags/index.ts @@ -0,0 +1 @@ +require('./index.tag'); diff --git a/src/web/app/status/script.js b/src/web/app/status/script.js deleted file mode 100644 index 06d4d9a7a4..0000000000 --- a/src/web/app/status/script.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Status - */ - -// Style -import './style.styl'; - -import * as riot from 'riot'; -require('./tags'); -import init from '../init'; - -document.title = 'Misskey System Status'; - -/** - * init - */ -init(me => { - mount(document.createElement('mk-index')); -}); - -function mount(content) { - riot.mount(document.getElementById('app').appendChild(content)); -} diff --git a/src/web/app/status/script.ts b/src/web/app/status/script.ts new file mode 100644 index 0000000000..06d4d9a7a4 --- /dev/null +++ b/src/web/app/status/script.ts @@ -0,0 +1,23 @@ +/** + * Status + */ + +// Style +import './style.styl'; + +import * as riot from 'riot'; +require('./tags'); +import init from '../init'; + +document.title = 'Misskey System Status'; + +/** + * init + */ +init(me => { + mount(document.createElement('mk-index')); +}); + +function mount(content) { + riot.mount(document.getElementById('app').appendChild(content)); +} diff --git a/src/web/app/status/tags/index.js b/src/web/app/status/tags/index.js deleted file mode 100644 index f41151949f..0000000000 --- a/src/web/app/status/tags/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./index.tag'); diff --git a/src/web/app/status/tags/index.ts b/src/web/app/status/tags/index.ts new file mode 100644 index 0000000000..f41151949f --- /dev/null +++ b/src/web/app/status/tags/index.ts @@ -0,0 +1 @@ +require('./index.tag'); diff --git a/tslint.json b/tslint.json index 1c44579512..d3f96000b9 100644 --- a/tslint.json +++ b/tslint.json @@ -13,6 +13,7 @@ "object-literal-sort-keys": false, "curly": false, "no-console": [false], + "no-empty":false, "ordered-imports": [false], "arrow-parens": false, "object-literal-shorthand": false, diff --git a/webpack/webpack.config.ts b/webpack/webpack.config.ts index 97782a4102..f2bcf48f31 100644 --- a/webpack/webpack.config.ts +++ b/webpack/webpack.config.ts @@ -14,13 +14,13 @@ module.exports = langs.map(([lang, locale]) => { // Entries const entry = { - desktop: './src/web/app/desktop/script.js', - mobile: './src/web/app/mobile/script.js', - ch: './src/web/app/ch/script.js', - stats: './src/web/app/stats/script.js', - status: './src/web/app/status/script.js', - dev: './src/web/app/dev/script.js', - auth: './src/web/app/auth/script.js' + desktop: './src/web/app/desktop/script.ts', + mobile: './src/web/app/mobile/script.ts', + ch: './src/web/app/ch/script.ts', + stats: './src/web/app/stats/script.ts', + status: './src/web/app/status/script.ts', + dev: './src/web/app/dev/script.ts', + auth: './src/web/app/auth/script.ts' }; const output = { @@ -33,6 +33,11 @@ module.exports = langs.map(([lang, locale]) => { entry, module: module_(lang, locale), plugins: plugins(version, lang), - output + output, + resolve: { + extensions: [ + '.js', '.ts' + ] + } }; }); -- cgit v1.2.3-freya From 0a994e5b9885265873e02b3b3ab9add7ec7e7e6b Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Nov 2017 19:58:29 +0900 Subject: Add access log widget --- locales/en.yml | 3 + locales/ja.yml | 3 + src/api/stream/requests.ts | 19 +++++ src/api/streaming.ts | 6 ++ src/log-request.ts | 21 +++++ src/server.ts | 6 ++ src/web/app/common/mixins/index.ts | 2 + .../app/common/scripts/requests-stream-manager.ts | 12 +++ src/web/app/common/scripts/requests-stream.ts | 14 ++++ .../app/desktop/tags/home-widgets/access-log.tag | 93 ++++++++++++++++++++++ src/web/app/desktop/tags/home.tag | 1 + src/web/app/desktop/tags/index.ts | 1 + 12 files changed, 181 insertions(+) create mode 100644 src/api/stream/requests.ts create mode 100644 src/log-request.ts create mode 100644 src/web/app/common/scripts/requests-stream-manager.ts create mode 100644 src/web/app/common/scripts/requests-stream.ts create mode 100644 src/web/app/desktop/tags/home-widgets/access-log.tag (limited to 'src') diff --git a/locales/en.yml b/locales/en.yml index 574af26a68..d464b2fe2f 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -390,6 +390,9 @@ desktop: post: "Post" placeholder: "What's happening?" + mk-access-log-home-widget: + title: "Access log" + mk-repost-form: quote: "Quote..." cancel: "Cancel" diff --git a/locales/ja.yml b/locales/ja.yml index 9e6251d0d7..5c6f8e38e1 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -390,6 +390,9 @@ desktop: post: "投稿" placeholder: "いまどうしてる?" + mk-access-log-home-widget: + title: "アクセスログ" + mk-repost-form: quote: "引用する..." cancel: "キャンセル" diff --git a/src/api/stream/requests.ts b/src/api/stream/requests.ts new file mode 100644 index 0000000000..2c36e58b6e --- /dev/null +++ b/src/api/stream/requests.ts @@ -0,0 +1,19 @@ +import * as websocket from 'websocket'; +import Xev from 'xev'; + +const ev = new Xev(); + +export default function homeStream(request: websocket.request, connection: websocket.connection): void { + const onRequest = request => { + connection.send(JSON.stringify({ + type: 'request', + body: request + })); + }; + + ev.addListener('request', onRequest); + + connection.on('close', () => { + ev.removeListener('request', onRequest); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 0e512fb210..6caf7db3e8 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -9,6 +9,7 @@ import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; import messagingStream from './stream/messaging'; import serverStream from './stream/server'; +import requestsStream from './stream/requests'; import channelStream from './stream/channel'; module.exports = (server: http.Server) => { @@ -27,6 +28,11 @@ module.exports = (server: http.Server) => { return; } + if (request.resourceURL.pathname === '/requests') { + requestsStream(request, connection); + return; + } + // Connect to Redis const subscriber = redis.createClient( config.redis.port, config.redis.host); diff --git a/src/log-request.ts b/src/log-request.ts new file mode 100644 index 0000000000..e431aa271d --- /dev/null +++ b/src/log-request.ts @@ -0,0 +1,21 @@ +import * as crypto from 'crypto'; +import * as express from 'express'; +import * as proxyAddr from 'proxy-addr'; +import Xev from 'xev'; + +const ev = new Xev(); + +export default function(req: express.Request) { + const ip = proxyAddr(req, () => true); + + const md5 = crypto.createHash('md5'); + md5.update(ip); + const hashedIp = md5.digest('hex').substr(0, 3); + + ev.emit('request', { + ip: hashedIp, + method: req.method, + hostname: req.hostname, + path: req.originalUrl + }); +} diff --git a/src/server.ts b/src/server.ts index 3e9bd44eef..9cf44eb0d0 100644 --- a/src/server.ts +++ b/src/server.ts @@ -11,6 +11,7 @@ import * as morgan from 'morgan'; import Accesses from 'accesses'; import vhost = require('vhost'); +import log from './log-request'; import config from './conf'; /** @@ -35,6 +36,11 @@ app.use(morgan(process.env.NODE_ENV == 'production' ? 'combined' : 'dev', { stream: config.accesslog ? fs.createWriteStream(config.accesslog) : null })); +app.use((req, res, next) => { + log(req); + next(); +}); + // Drop request when without 'Host' header app.use((req, res, next) => { if (!req.headers['host']) { diff --git a/src/web/app/common/mixins/index.ts b/src/web/app/common/mixins/index.ts index 45427fb9d3..a11bfa7b64 100644 --- a/src/web/app/common/mixins/index.ts +++ b/src/web/app/common/mixins/index.ts @@ -3,6 +3,7 @@ import * as riot from 'riot'; import activateMe from './i'; import activateApi from './api'; import ServerStreamManager from '../scripts/server-stream-manager'; +import RequestsStreamManager from '../scripts/requests-stream-manager'; export default (me, stream) => { activateMe(me); @@ -11,4 +12,5 @@ export default (me, stream) => { (riot as any).mixin('stream', { stream }); (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); + (riot as any).mixin('requests-stream', { requestsStream: new RequestsStreamManager() }); }; diff --git a/src/web/app/common/scripts/requests-stream-manager.ts b/src/web/app/common/scripts/requests-stream-manager.ts new file mode 100644 index 0000000000..44db913e78 --- /dev/null +++ b/src/web/app/common/scripts/requests-stream-manager.ts @@ -0,0 +1,12 @@ +import StreamManager from './stream-manager'; +import Connection from './requests-stream'; + +export default class RequestsStreamManager extends StreamManager { + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/requests-stream.ts b/src/web/app/common/scripts/requests-stream.ts new file mode 100644 index 0000000000..325224587a --- /dev/null +++ b/src/web/app/common/scripts/requests-stream.ts @@ -0,0 +1,14 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Requests stream connection + */ +class Connection extends Stream { + constructor() { + super('requests'); + } +} + +export default Connection; diff --git a/src/web/app/desktop/tags/home-widgets/access-log.tag b/src/web/app/desktop/tags/home-widgets/access-log.tag new file mode 100644 index 0000000000..a148577563 --- /dev/null +++ b/src/web/app/desktop/tags/home-widgets/access-log.tag @@ -0,0 +1,93 @@ + + +

%i18n:desktop.tags.mk-access-log-home-widget.title%

+
+
+

+ { ip } + { method } + { path } +

+
+ + +
diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index fd286851d9..88d06d2baa 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -20,6 +20,7 @@ + diff --git a/src/web/app/desktop/tags/index.ts b/src/web/app/desktop/tags/index.ts index 15677471c3..8b5a52d670 100644 --- a/src/web/app/desktop/tags/index.ts +++ b/src/web/app/desktop/tags/index.ts @@ -43,6 +43,7 @@ require('./home-widgets/slideshow.tag'); require('./home-widgets/channel.tag'); require('./home-widgets/timemachine.tag'); require('./home-widgets/post-form.tag'); +require('./home-widgets/access-log.tag'); require('./timeline.tag'); require('./messaging/window.tag'); require('./messaging/room-window.tag'); -- cgit v1.2.3-freya From ab2293aa4c0832f9e57d64aa22d2fce319fbfcb1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 14 Nov 2017 00:54:16 +0900 Subject: Add messaging widget --- locales/en.yml | 3 + locales/ja.yml | 3 + src/api/common/read-messaging-message.ts | 2 + src/api/endpoints/messaging/messages/create.ts | 3 + src/api/event.ts | 6 ++ src/api/stream/messaging-index.ts | 10 +++ src/api/streaming.ts | 2 + src/web/app/common/mixins/index.ts | 2 + .../scripts/messaging-index-stream-manager.ts | 20 ++++++ .../app/common/scripts/messaging-index-stream.ts | 14 ++++ src/web/app/common/tags/messaging/index.tag | 76 ++++++++++++++++++++-- .../app/desktop/tags/home-widgets/messaging.tag | 50 ++++++++++++++ src/web/app/desktop/tags/home.tag | 1 + src/web/app/desktop/tags/index.ts | 1 + 14 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 src/api/stream/messaging-index.ts create mode 100644 src/web/app/common/scripts/messaging-index-stream-manager.ts create mode 100644 src/web/app/common/scripts/messaging-index-stream.ts create mode 100644 src/web/app/desktop/tags/home-widgets/messaging.tag (limited to 'src') diff --git a/locales/en.yml b/locales/en.yml index d464b2fe2f..d6fcd1e6d4 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -393,6 +393,9 @@ desktop: mk-access-log-home-widget: title: "Access log" + mk-messaging-home-widget: + title: "Messaging" + mk-repost-form: quote: "Quote..." cancel: "Cancel" diff --git a/locales/ja.yml b/locales/ja.yml index 5c6f8e38e1..478afac132 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -393,6 +393,9 @@ desktop: mk-access-log-home-widget: title: "アクセスログ" + mk-messaging-home-widget: + title: "メッセージ" + mk-repost-form: quote: "引用する..." cancel: "キャンセル" diff --git a/src/api/common/read-messaging-message.ts b/src/api/common/read-messaging-message.ts index 3257ec8b07..8e5e5b2b68 100644 --- a/src/api/common/read-messaging-message.ts +++ b/src/api/common/read-messaging-message.ts @@ -3,6 +3,7 @@ import Message from '../models/messaging-message'; import { IMessagingMessage as IMessage } from '../models/messaging-message'; import publishUserStream from '../event'; import { publishMessagingStream } from '../event'; +import { publishMessagingIndexStream } from '../event'; /** * Mark as read message(s) @@ -49,6 +50,7 @@ export default ( // Publish event publishMessagingStream(otherpartyId, userId, 'read', ids.map(id => id.toString())); + publishMessagingIndexStream(userId, 'read', ids.map(id => id.toString())); // Calc count of my unread messages const count = await Message diff --git a/src/api/endpoints/messaging/messages/create.ts b/src/api/endpoints/messaging/messages/create.ts index 149852c093..29a4671f84 100644 --- a/src/api/endpoints/messaging/messages/create.ts +++ b/src/api/endpoints/messaging/messages/create.ts @@ -10,6 +10,7 @@ import DriveFile from '../../../models/drive-file'; import serialize from '../../../serializers/messaging-message'; import publishUserStream from '../../../event'; import { publishMessagingStream } from '../../../event'; +import { publishMessagingIndexStream } from '../../../event'; import config from '../../../../conf'; /** @@ -85,10 +86,12 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // 自分のストリーム publishMessagingStream(message.user_id, message.recipient_id, 'message', messageObj); + publishMessagingIndexStream(message.user_id, 'message', messageObj); publishUserStream(message.user_id, 'messaging_message', messageObj); // 相手のストリーム publishMessagingStream(message.recipient_id, message.user_id, 'message', messageObj); + publishMessagingIndexStream(message.recipient_id, 'message', messageObj); publishUserStream(message.recipient_id, 'messaging_message', messageObj); // 3秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する diff --git a/src/api/event.ts b/src/api/event.ts index 909b0d2556..927883737e 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -25,6 +25,10 @@ class MisskeyEvent { this.publish(`messaging-stream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value); } + public publishMessagingIndexStream(userId: ID, type: string, value?: any): void { + this.publish(`messaging-index-stream:${userId}`, type, typeof value === 'undefined' ? null : value); + } + public publishChannelStream(channelId: ID, type: string, value?: any): void { this.publish(`channel-stream:${channelId}`, type, typeof value === 'undefined' ? null : value); } @@ -46,4 +50,6 @@ export const publishPostStream = ev.publishPostStream.bind(ev); export const publishMessagingStream = ev.publishMessagingStream.bind(ev); +export const publishMessagingIndexStream = ev.publishMessagingIndexStream.bind(ev); + export const publishChannelStream = ev.publishChannelStream.bind(ev); diff --git a/src/api/stream/messaging-index.ts b/src/api/stream/messaging-index.ts new file mode 100644 index 0000000000..c1b2fbc806 --- /dev/null +++ b/src/api/stream/messaging-index.ts @@ -0,0 +1,10 @@ +import * as websocket from 'websocket'; +import * as redis from 'redis'; + +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { + // Subscribe messaging index stream + subscriber.subscribe(`misskey:messaging-index-stream:${user._id}`); + subscriber.on('message', (_, data) => { + connection.send(data); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 6caf7db3e8..1f0ba848c1 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -8,6 +8,7 @@ import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; import messagingStream from './stream/messaging'; +import messagingIndexStream from './stream/messaging-index'; import serverStream from './stream/server'; import requestsStream from './stream/requests'; import channelStream from './stream/channel'; @@ -58,6 +59,7 @@ module.exports = (server: http.Server) => { const channel = request.resourceURL.pathname === '/' ? homeStream : request.resourceURL.pathname === '/messaging' ? messagingStream : + request.resourceURL.pathname === '/messaging-index' ? messagingIndexStream : null; if (channel !== null) { diff --git a/src/web/app/common/mixins/index.ts b/src/web/app/common/mixins/index.ts index a11bfa7b64..c0c1c0555f 100644 --- a/src/web/app/common/mixins/index.ts +++ b/src/web/app/common/mixins/index.ts @@ -4,6 +4,7 @@ import activateMe from './i'; import activateApi from './api'; import ServerStreamManager from '../scripts/server-stream-manager'; import RequestsStreamManager from '../scripts/requests-stream-manager'; +import MessagingIndexStream from '../scripts/messaging-index-stream-manager'; export default (me, stream) => { activateMe(me); @@ -13,4 +14,5 @@ export default (me, stream) => { (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); (riot as any).mixin('requests-stream', { requestsStream: new RequestsStreamManager() }); + (riot as any).mixin('messaging-index-stream', { messagingIndexStream: new MessagingIndexStream(me) }); }; diff --git a/src/web/app/common/scripts/messaging-index-stream-manager.ts b/src/web/app/common/scripts/messaging-index-stream-manager.ts new file mode 100644 index 0000000000..dc386204ca --- /dev/null +++ b/src/web/app/common/scripts/messaging-index-stream-manager.ts @@ -0,0 +1,20 @@ +import StreamManager from './stream-manager'; +import Connection from './messaging-index-stream'; + +export default class ServerStreamManager extends StreamManager { + private me; + + constructor(me) { + super(); + + this.me = me; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(this.me); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/messaging-index-stream.ts b/src/web/app/common/scripts/messaging-index-stream.ts new file mode 100644 index 0000000000..c194e663c2 --- /dev/null +++ b/src/web/app/common/scripts/messaging-index-stream.ts @@ -0,0 +1,14 @@ +import Stream from './stream'; + +/** + * Messaging index stream connection + */ +class Connection extends Stream { + constructor(me) { + super('messaging-index', { + i: me.token + }); + } +} + +export default Connection; diff --git a/src/web/app/common/tags/messaging/index.tag b/src/web/app/common/tags/messaging/index.tag index 731c9da2c7..4c1bf0c6e4 100644 --- a/src/web/app/common/tags/messaging/index.tag +++ b/src/web/app/common/tags/messaging/index.tag @@ -1,5 +1,5 @@ - - diff --git a/src/web/app/desktop/tags/home-widgets/broadcast.tag b/src/web/app/desktop/tags/home-widgets/broadcast.tag index 7caf4dcddd..00fef83742 100644 --- a/src/web/app/desktop/tags/home-widgets/broadcast.tag +++ b/src/web/app/desktop/tags/home-widgets/broadcast.tag @@ -1,4 +1,4 @@ - +
@@ -8,22 +8,35 @@
-

開発者募集中!

-

Misskeyはオープンソースで開発されています。リポジトリはこちら。

+

%i18n:desktop.tags.mk-broadcast-home-widget.fetching%

+

{ + broadcasts.length == 0 ? '%i18n:desktop.tags.mk-broadcast-home-widget.no-broadcasts%' : broadcasts[i].title + }

+

%i18n:desktop.tags.mk-broadcast-home-widget.have-a-nice-day%

+ 1 } onclick={ next }>%i18n:desktop.tags.mk-broadcast-home-widget.next% >>
-- cgit v1.2.3-freya From 598500223a762ada9abe084f81248432731792e4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 16 Nov 2017 22:49:58 +0900 Subject: Fix #924 and some readability improvements --- src/api/common/add-file-to-drive.ts | 120 ++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index 9ed5e88744..f96f58cb66 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -1,18 +1,20 @@ +import { Buffer } from 'buffer'; +import * as fs from 'fs'; +import * as tmp from 'tmp'; +import * as stream from 'stream'; + import * as mongodb from 'mongodb'; import * as crypto from 'crypto'; import * as gm from 'gm'; import * as debug from 'debug'; import fileType = require('file-type'); import prominence = require('prominence'); + import DriveFile, { getGridFSBucket } from '../models/drive-file'; import DriveFolder from '../models/drive-folder'; import serialize from '../serializers/drive-file'; import event from '../event'; import config from '../../conf'; -import { Buffer } from 'buffer'; -import * as fs from 'fs'; -import * as tmp from 'tmp'; -import * as stream from 'stream'; const log = debug('misskey:register-drive-file'); @@ -67,10 +69,12 @@ const addFile = async ( .once('data', (buffer: Buffer) => { readable.destroy(); const type = fileType(buffer); - if (!type) { + if (type) { + return res([type.mime, type.ext]); + } else { + // 種類が同定できなかったら application/octet-stream にする return res(['application/octet-stream', null]); } - return res([type.mime, type.ext]); }); }))(), // size @@ -105,9 +109,18 @@ const addFile = async ( const [properties, folder] = await Promise.all([ // properties (async () => { + // 画像かどうか if (!/^image\/.*$/.test(mime)) { return null; } + + const imageType = mime.split('/')[1]; + + // 画像でもPNGかJPEGでないならスキップ + if (imageType != 'png' && imageType != 'jpeg') { + return null; + } + // If the file is an image, calculate width and height to save in property const g = gm(fs.createReadStream(path), name); const size = await prominence(g).size(); @@ -115,7 +128,9 @@ const addFile = async ( width: size.width, height: size.height }; + log('image width and height is calculated'); + return properties; })(), // folder @@ -136,20 +151,18 @@ const addFile = async ( (async () => { // Calculate drive usage const usage = await DriveFile - .aggregate([ - { $match: { 'metadata.user_id': user._id } }, - { - $project: { - length: true - } - }, - { - $group: { - _id: null, - usage: { $sum: '$length' } - } + .aggregate([{ + $match: { 'metadata.user_id': user._id } + }, { + $project: { + length: true } - ]) + }, { + $group: { + _id: null, + usage: { $sum: '$length' } + } + }]) .then((aggregates: any[]) => { if (aggregates.length > 0) { return aggregates[0].usage; @@ -211,41 +224,40 @@ export default (user: any, file: string | stream.Readable, ...args) => new Promi } rej(new Error('un-compatible file.')); }) - .then(([path, remove]): Promise => new Promise((res, rej) => { - addFile(user, path, ...args) - .then(file => { - res(file); - if (remove) { - fs.unlink(path, (e) => { - if (e) log(e.stack); - }); - } - }) - .catch(rej); - })) - .then(file => { - log(`drive file has been created ${file._id}`); - resolve(file); - - serialize(file) - .then(serializedFile => { - // Publish drive_file_created event - event(user._id, 'drive_file_created', serializedFile); - - // Register to search database - if (config.elasticsearch.enable) { - const es = require('../../db/elasticsearch'); - es.index({ - index: 'misskey', - type: 'drive_file', - id: file._id.toString(), - body: { - name: file.name, - user_id: user._id.toString() - } - }); + .then(([path, remove]): Promise => new Promise((res, rej) => { + addFile(user, path, ...args) + .then(file => { + res(file); + if (remove) { + fs.unlink(path, (e) => { + if (e) log(e.stack); + }); + } + }) + .catch(rej); + })) + .then(file => { + log(`drive file has been created ${file._id}`); + resolve(file); + + serialize(file).then(serializedFile => { + // Publish drive_file_created event + event(user._id, 'drive_file_created', serializedFile); + + // Register to search database + if (config.elasticsearch.enable) { + const es = require('../../db/elasticsearch'); + es.index({ + index: 'misskey', + type: 'drive_file', + id: file._id.toString(), + body: { + name: file.name, + user_id: user._id.toString() } }); - }) - .catch(reject); + } + }); + }) + .catch(reject); }); -- cgit v1.2.3-freya From 16d4861ff67c057737c9253bcb37fac4fe40eeab Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 16 Nov 2017 22:51:28 +0900 Subject: Fix bug --- src/web/app/mobile/tags/drive/file-viewer.tag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/web/app/mobile/tags/drive/file-viewer.tag b/src/web/app/mobile/tags/drive/file-viewer.tag index 8dc49a0865..2cec4f329e 100644 --- a/src/web/app/mobile/tags/drive/file-viewer.tag +++ b/src/web/app/mobile/tags/drive/file-viewer.tag @@ -2,7 +2,7 @@
{ -
+
{ file.properties.width } × -- cgit v1.2.3-freya From d81bc3cd212dbea309ce1ff2e5c9083ba943334d Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 16 Nov 2017 23:05:12 +0900 Subject: Fix thumbnail --- src/file/assets/thumbnail-not-available.png | Bin 0 -> 8822 bytes src/file/server.ts | 11 +++++++++++ 2 files changed, 11 insertions(+) create mode 100644 src/file/assets/thumbnail-not-available.png (limited to 'src') diff --git a/src/file/assets/thumbnail-not-available.png b/src/file/assets/thumbnail-not-available.png new file mode 100644 index 0000000000..f960ce4d00 Binary files /dev/null and b/src/file/assets/thumbnail-not-available.png differ diff --git a/src/file/server.ts b/src/file/server.ts index fa03fb7772..844b3d7369 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -50,11 +50,22 @@ interface ISend { function thumbnail(data: stream.Readable, type: string, resize: number): ISend { const readable: stream.Readable = (() => { + // 画像ではない場合 if (!/^image\/.*$/.test(type)) { // 使わないことにしたストリームはしっかり取り壊しておく data.destroy(); return fs.createReadStream(`${__dirname}/assets/not-an-image.png`); } + + const imageType = type.split('/')[1]; + + // 画像でもPNGかJPEGでないならダメ + if (imageType != 'png' && imageType != 'jpeg') { + // 使わないことにしたストリームはしっかり取り壊しておく + data.destroy(); + return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`); + } + return data; })(); -- cgit v1.2.3-freya From 3d3309282e3954004b95296260efa8999e893861 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 16 Nov 2017 23:14:19 +0900 Subject: Fix indentation --- src/file/server.ts | 64 +++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/file/server.ts b/src/file/server.ts index 844b3d7369..1f8d21b80d 100644 --- a/src/file/server.ts +++ b/src/file/server.ts @@ -49,41 +49,41 @@ interface ISend { } function thumbnail(data: stream.Readable, type: string, resize: number): ISend { - const readable: stream.Readable = (() => { - // 画像ではない場合 - if (!/^image\/.*$/.test(type)) { - // 使わないことにしたストリームはしっかり取り壊しておく - data.destroy(); - return fs.createReadStream(`${__dirname}/assets/not-an-image.png`); - } - - const imageType = type.split('/')[1]; - - // 画像でもPNGかJPEGでないならダメ - if (imageType != 'png' && imageType != 'jpeg') { - // 使わないことにしたストリームはしっかり取り壊しておく - data.destroy(); - return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`); - } - - return data; - })(); - - let g = gm(readable); - - if (resize) { - g = g.resize(resize, resize); + const readable: stream.Readable = (() => { + // 画像ではない場合 + if (!/^image\/.*$/.test(type)) { + // 使わないことにしたストリームはしっかり取り壊しておく + data.destroy(); + return fs.createReadStream(`${__dirname}/assets/not-an-image.png`); } - const stream = g - .compress('jpeg') - .quality(80) - .stream(); + const imageType = type.split('/')[1]; - return { - contentType: 'image/jpeg', - stream - }; + // 画像でもPNGかJPEGでないならダメ + if (imageType != 'png' && imageType != 'jpeg') { + // 使わないことにしたストリームはしっかり取り壊しておく + data.destroy(); + return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`); + } + + return data; + })(); + + let g = gm(readable); + + if (resize) { + g = g.resize(resize, resize); + } + + const stream = g + .compress('jpeg') + .quality(80) + .stream(); + + return { + contentType: 'image/jpeg', + stream + }; } const commonReadableHandlerGenerator = (req: express.Request, res: express.Response) => (e: Error): void => { -- cgit v1.2.3-freya From a8c6d0ed9023f7e0699cfe5c519532231e49cc3b Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 16 Nov 2017 23:46:36 +0900 Subject: #465 --- src/api/common/add-file-to-drive.ts | 3 ++- src/api/endpoints/drive/files/update.ts | 6 +++--- src/api/endpoints/drive/folders/create.ts | 6 +++--- src/api/endpoints/drive/folders/update.ts | 6 +++--- src/api/event.ts | 6 ++++++ src/api/stream/drive.ts | 10 ++++++++++ src/api/streaming.ts | 2 ++ src/web/app/common/mixins.ts | 3 ++- src/web/app/common/scripts/drive-stream-manager.ts | 20 ++++++++++++++++++++ src/web/app/common/scripts/drive-stream.ts | 14 ++++++++++++++ src/web/app/desktop/tags/drive/browser.tag | 22 +++++++++++++--------- src/web/app/mobile/tags/drive.tag | 22 +++++++++++++--------- 12 files changed, 91 insertions(+), 29 deletions(-) create mode 100644 src/api/stream/drive.ts create mode 100644 src/web/app/common/scripts/drive-stream-manager.ts create mode 100644 src/web/app/common/scripts/drive-stream.ts (limited to 'src') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index f96f58cb66..2a649788af 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -13,7 +13,7 @@ import prominence = require('prominence'); import DriveFile, { getGridFSBucket } from '../models/drive-file'; import DriveFolder from '../models/drive-folder'; import serialize from '../serializers/drive-file'; -import event from '../event'; +import event, { publishDriveStream } from '../event'; import config from '../../conf'; const log = debug('misskey:register-drive-file'); @@ -243,6 +243,7 @@ export default (user: any, file: string | stream.Readable, ...args) => new Promi serialize(file).then(serializedFile => { // Publish drive_file_created event event(user._id, 'drive_file_created', serializedFile); + publishDriveStream(user._id, 'file_created', serializedFile); // Register to search database if (config.elasticsearch.enable) { diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index f265142c4d..f39a420d6e 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -6,7 +6,7 @@ import DriveFolder from '../../../models/drive-folder'; import DriveFile from '../../../models/drive-file'; import { validateFileName } from '../../../models/drive-file'; import serialize from '../../../serializers/drive-file'; -import event from '../../../event'; +import { publishDriveStream } from '../../../event'; /** * Update a file @@ -72,6 +72,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Response res(fileObj); - // Publish drive_file_updated event - event(user._id, 'drive_file_updated', fileObj); + // Publish file_updated event + publishDriveStream(user._id, 'file_updated', fileObj); }); diff --git a/src/api/endpoints/drive/folders/create.ts b/src/api/endpoints/drive/folders/create.ts index 8c875db164..be847b2153 100644 --- a/src/api/endpoints/drive/folders/create.ts +++ b/src/api/endpoints/drive/folders/create.ts @@ -5,7 +5,7 @@ import $ from 'cafy'; import DriveFolder from '../../../models/drive-folder'; import { isValidFolderName } from '../../../models/drive-folder'; import serialize from '../../../serializers/drive-folder'; -import event from '../../../event'; +import { publishDriveStream } from '../../../event'; /** * Create drive folder @@ -52,6 +52,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Response res(folderObj); - // Publish drive_folder_created event - event(user._id, 'drive_folder_created', folderObj); + // Publish folder_created event + publishDriveStream(user._id, 'folder_created', folderObj); }); diff --git a/src/api/endpoints/drive/folders/update.ts b/src/api/endpoints/drive/folders/update.ts index 4f2e3d2a7a..ff673402ab 100644 --- a/src/api/endpoints/drive/folders/update.ts +++ b/src/api/endpoints/drive/folders/update.ts @@ -5,7 +5,7 @@ import $ from 'cafy'; import DriveFolder from '../../../models/drive-folder'; import { isValidFolderName } from '../../../models/drive-folder'; import serialize from '../../../serializers/drive-folder'; -import event from '../../../event'; +import { publishDriveStream } from '../../../event'; /** * Update a folder @@ -96,6 +96,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Response res(folderObj); - // Publish drive_folder_updated event - event(user._id, 'drive_folder_updated', folderObj); + // Publish folder_updated event + publishDriveStream(user._id, 'folder_updated', folderObj); }); diff --git a/src/api/event.ts b/src/api/event.ts index 927883737e..8605a0f1e4 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -17,6 +17,10 @@ class MisskeyEvent { this.publish(`user-stream:${userId}`, type, typeof value === 'undefined' ? null : value); } + public publishDriveStream(userId: ID, type: string, value?: any): void { + this.publish(`drive-stream:${userId}`, type, typeof value === 'undefined' ? null : value); + } + public publishPostStream(postId: ID, type: string, value?: any): void { this.publish(`post-stream:${postId}`, type, typeof value === 'undefined' ? null : value); } @@ -46,6 +50,8 @@ const ev = new MisskeyEvent(); export default ev.publishUserStream.bind(ev); +export const publishDriveStream = ev.publishDriveStream.bind(ev); + export const publishPostStream = ev.publishPostStream.bind(ev); export const publishMessagingStream = ev.publishMessagingStream.bind(ev); diff --git a/src/api/stream/drive.ts b/src/api/stream/drive.ts new file mode 100644 index 0000000000..c97ab80dcc --- /dev/null +++ b/src/api/stream/drive.ts @@ -0,0 +1,10 @@ +import * as websocket from 'websocket'; +import * as redis from 'redis'; + +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { + // Subscribe drive stream + subscriber.subscribe(`misskey:drive-stream:${user._id}`); + subscriber.on('message', (_, data) => { + connection.send(data); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 1f0ba848c1..c06d64c245 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -7,6 +7,7 @@ import AccessToken from './models/access-token'; import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; +import driveStream from './stream/drive'; import messagingStream from './stream/messaging'; import messagingIndexStream from './stream/messaging-index'; import serverStream from './stream/server'; @@ -58,6 +59,7 @@ module.exports = (server: http.Server) => { const channel = request.resourceURL.pathname === '/' ? homeStream : + request.resourceURL.pathname === '/drive' ? driveStream : request.resourceURL.pathname === '/messaging' ? messagingStream : request.resourceURL.pathname === '/messaging-index' ? messagingIndexStream : null; diff --git a/src/web/app/common/mixins.ts b/src/web/app/common/mixins.ts index b5eb1acc78..5949069624 100644 --- a/src/web/app/common/mixins.ts +++ b/src/web/app/common/mixins.ts @@ -4,6 +4,7 @@ import MiOS from './mios'; import ServerStreamManager from './scripts/server-stream-manager'; import RequestsStreamManager from './scripts/requests-stream-manager'; import MessagingIndexStream from './scripts/messaging-index-stream-manager'; +import DriveStreamManager from './scripts/drive-stream-manager'; export default (mios: MiOS) => { (riot as any).mixin('os', { @@ -30,7 +31,7 @@ export default (mios: MiOS) => { (riot as any).mixin('api', { api: mios.api }); - + (riot as any).mixin('drive-stream', { driveStream: new DriveStreamManager(mios.i) }); (riot as any).mixin('stream', { stream: mios.stream }); (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); diff --git a/src/web/app/common/scripts/drive-stream-manager.ts b/src/web/app/common/scripts/drive-stream-manager.ts new file mode 100644 index 0000000000..8acdd7cbba --- /dev/null +++ b/src/web/app/common/scripts/drive-stream-manager.ts @@ -0,0 +1,20 @@ +import StreamManager from './stream-manager'; +import Connection from './drive-stream'; + +export default class DriveStreamManager extends StreamManager { + private me; + + constructor(me) { + super(); + + this.me = me; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(this.me); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/drive-stream.ts b/src/web/app/common/scripts/drive-stream.ts new file mode 100644 index 0000000000..1b33435578 --- /dev/null +++ b/src/web/app/common/scripts/drive-stream.ts @@ -0,0 +1,14 @@ +import Stream from './stream'; + +/** + * Drive stream connection + */ +class Connection extends Stream { + constructor(me) { + super('drive', { + i: me.token + }); + } +} + +export default Connection; diff --git a/src/web/app/desktop/tags/drive/browser.tag b/src/web/app/desktop/tags/drive/browser.tag index 18e27f24bc..311209fcb6 100644 --- a/src/web/app/desktop/tags/drive/browser.tag +++ b/src/web/app/desktop/tags/drive/browser.tag @@ -247,7 +247,10 @@ this.mixin('i'); this.mixin('api'); - this.mixin('stream'); + + this.mixin('drive-stream'); + this.connection = this.driveStream.getConnection(); + this.connectionId = this.driveStream.use(); this.files = []; this.folders = []; @@ -280,10 +283,10 @@ }); }); - this.stream.on('drive_file_created', this.onStreamDriveFileCreated); - this.stream.on('drive_file_updated', this.onStreamDriveFileUpdated); - this.stream.on('drive_folder_created', this.onStreamDriveFolderCreated); - this.stream.on('drive_folder_updated', this.onStreamDriveFolderUpdated); + this.connection.on('file_created', this.onStreamDriveFileCreated); + this.connection.on('file_updated', this.onStreamDriveFileUpdated); + this.connection.on('folder_created', this.onStreamDriveFolderCreated); + this.connection.on('folder_updated', this.onStreamDriveFolderUpdated); if (this.opts.folder) { this.move(this.opts.folder); @@ -293,10 +296,11 @@ }); this.on('unmount', () => { - this.stream.off('drive_file_created', this.onStreamDriveFileCreated); - this.stream.off('drive_file_updated', this.onStreamDriveFileUpdated); - this.stream.off('drive_folder_created', this.onStreamDriveFolderCreated); - this.stream.off('drive_folder_updated', this.onStreamDriveFolderUpdated); + this.connection.off('file_created', this.onStreamDriveFileCreated); + this.connection.off('file_updated', this.onStreamDriveFileUpdated); + this.connection.off('folder_created', this.onStreamDriveFolderCreated); + this.connection.off('folder_updated', this.onStreamDriveFolderUpdated); + this.driveStream.dispose(this.connectionId); }); this.onStreamDriveFileCreated = file => { diff --git a/src/web/app/mobile/tags/drive.tag b/src/web/app/mobile/tags/drive.tag index 870a451acb..2c36c43ac5 100644 --- a/src/web/app/mobile/tags/drive.tag +++ b/src/web/app/mobile/tags/drive.tag @@ -172,7 +172,10 @@ diff --git a/src/web/app/desktop/script.ts b/src/web/app/desktop/script.ts index b4a8d829d6..bc0fc8dfe3 100644 --- a/src/web/app/desktop/script.ts +++ b/src/web/app/desktop/script.ts @@ -13,6 +13,7 @@ import route from './router'; import fuckAdBlock from './scripts/fuck-ad-block'; import getPostSummary from '../../../common/get-post-summary'; import MiOS from '../common/mios'; +import HomeStreamManager from '../common/scripts/streaming/home-stream-manager'; /** * init @@ -41,52 +42,62 @@ init(async (mios: MiOS) => { route(mios); }); -function registerNotifications(stream) { +function registerNotifications(stream: HomeStreamManager) { if (stream == null) return; - stream.on('drive_file_created', file => { - const n = new Notification('ファイルがアップロードされました', { - body: file.name, - icon: file.url + '?thumbnail&size=64' - }); - setTimeout(n.close.bind(n), 5000); + if (stream.hasConnection) { + attach(stream.borrow()); + } + + stream.on('connected', connection => { + attach(connection); }); - stream.on('mention', post => { - const n = new Notification(`${post.user.name}さんから:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + function attach(connection) { + connection.on('drive_file_created', file => { + const n = new Notification('ファイルがアップロードされました', { + body: file.name, + icon: file.url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 5000); }); - setTimeout(n.close.bind(n), 6000); - }); - stream.on('reply', post => { - const n = new Notification(`${post.user.name}さんから返信:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + connection.on('mention', post => { + const n = new Notification(`${post.user.name}さんから:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); }); - setTimeout(n.close.bind(n), 6000); - }); - stream.on('quote', post => { - const n = new Notification(`${post.user.name}さんが引用:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + connection.on('reply', post => { + const n = new Notification(`${post.user.name}さんから返信:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); }); - setTimeout(n.close.bind(n), 6000); - }); - stream.on('unread_messaging_message', message => { - const n = new Notification(`${message.user.name}さんからメッセージ:`, { - body: message.text, // TODO: getMessagingMessageSummary(message), - icon: message.user.avatar_url + '?thumbnail&size=64' + connection.on('quote', post => { + const n = new Notification(`${post.user.name}さんが引用:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); }); - n.onclick = () => { - n.close(); - (riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { - user: message.user + + connection.on('unread_messaging_message', message => { + const n = new Notification(`${message.user.name}さんからメッセージ:`, { + body: message.text, // TODO: getMessagingMessageSummary(message), + icon: message.user.avatar_url + '?thumbnail&size=64' }); - }; - setTimeout(n.close.bind(n), 7000); - }); + n.onclick = () => { + n.close(); + (riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { + user: message.user + }); + }; + setTimeout(n.close.bind(n), 7000); + }); + } } diff --git a/src/web/app/desktop/tags/big-follow-button.tag b/src/web/app/desktop/tags/big-follow-button.tag index 86df2d4924..8897748ae1 100644 --- a/src/web/app/desktop/tags/big-follow-button.tag +++ b/src/web/app/desktop/tags/big-follow-button.tag @@ -74,7 +74,10 @@ this.mixin('i'); this.mixin('api'); + this.mixin('stream'); + this.connection = this.stream.getConnection(); + this.connectionId = this.stream.use(); this.user = null; this.userPromise = isPromise(this.opts.user) @@ -89,14 +92,15 @@ init: false, user: user }); - this.stream.on('follow', this.onStreamFollow); - this.stream.on('unfollow', this.onStreamUnfollow); + this.connection.on('follow', this.onStreamFollow); + this.connection.on('unfollow', this.onStreamUnfollow); }); }); this.on('unmount', () => { - this.stream.off('follow', this.onStreamFollow); - this.stream.off('unfollow', this.onStreamUnfollow); + this.connection.off('follow', this.onStreamFollow); + this.connection.off('unfollow', this.onStreamUnfollow); + this.stream.dispose(this.connectionId); }); this.onStreamFollow = user => { diff --git a/src/web/app/desktop/tags/follow-button.tag b/src/web/app/desktop/tags/follow-button.tag index 00ff686f69..a1cbc191d8 100644 --- a/src/web/app/desktop/tags/follow-button.tag +++ b/src/web/app/desktop/tags/follow-button.tag @@ -71,7 +71,10 @@ this.mixin('i'); this.mixin('api'); + this.mixin('stream'); + this.connection = this.stream.getConnection(); + this.connectionId = this.stream.use(); this.user = null; this.userPromise = isPromise(this.opts.user) @@ -86,14 +89,15 @@ init: false, user: user }); - this.stream.on('follow', this.onStreamFollow); - this.stream.on('unfollow', this.onStreamUnfollow); + this.connection.on('follow', this.onStreamFollow); + this.connection.on('unfollow', this.onStreamUnfollow); }); }); this.on('unmount', () => { - this.stream.off('follow', this.onStreamFollow); - this.stream.off('unfollow', this.onStreamUnfollow); + this.connection.off('follow', this.onStreamFollow); + this.connection.off('unfollow', this.onStreamUnfollow); + this.stream.dispose(this.connectionId); }); this.onStreamFollow = user => { diff --git a/src/web/app/desktop/tags/home-widgets/channel.tag b/src/web/app/desktop/tags/home-widgets/channel.tag index 28c66df5c0..fc4a27e4f4 100644 --- a/src/web/app/desktop/tags/home-widgets/channel.tag +++ b/src/web/app/desktop/tags/home-widgets/channel.tag @@ -138,7 +138,7 @@ + + + + + + + + + +

直近1年間分の統計です。一番右が現在で、一番左が1年前です。青は通常の投稿、赤は返信、緑はRepostをそれぞれ表しています。

+

+ だいたい*1日に{ averageOfAllTypePostsEachDays }回投稿(返信、Repost含む)しています。
+ だいたい*1日に{ averageOfPostsEachDays }回投稿(通常の)しています。
+ だいたい*1日に{ averageOfRepliesEachDays }回返信しています。
+ だいたい*1日に{ averageOfRepostsEachDays }回Repostしています。
+

+

* 中央値

+ + + +
-- cgit v1.2.3-freya From 5f040ac85d0e608bd38ff73afdb82217740f1808 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 Nov 2017 04:30:24 +0900 Subject: Check Edge --- src/web/app/safe.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/web/app/safe.js b/src/web/app/safe.js index 327a034d1e..b37b89024c 100644 --- a/src/web/app/safe.js +++ b/src/web/app/safe.js @@ -1,6 +1,5 @@ /** - * 古いブラウザの検知を行う - * ブートローダーとは隔離されているため互いに影響を及ぼすことはない + * ブラウザの検証 */ // Detect an old browser @@ -12,3 +11,13 @@ if (!('fetch' in window)) { 'Your browser seems outdated. ' + 'To run Misskey, please update your browser to latest version or try other browsers.'); } + +// Detect Edge +if (navigator.userAgent.indexOf('Edge')) { + alert( + '現在、お使いのブラウザ(Microsoft Edge)ではMisskeyは正しく動作しません。' + + 'サポートしているブラウザ: Google Chrome, Mozilla Firefox, Apple Safari など' + + '\n\n' + + 'Currently, Misskey cannot run correctly on your browser (Microsoft Edge).' + + 'Supported browsers: Google Chrome, Mozilla Firefox, Apple Safari, etc'); +} -- cgit v1.2.3-freya From 163d53b229a54ebe28e1b5de7bf7194c5a9171e2 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 Nov 2017 04:32:49 +0900 Subject: Insert missing whitespace --- src/web/app/safe.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/web/app/safe.js b/src/web/app/safe.js index b37b89024c..a29ba4d87f 100644 --- a/src/web/app/safe.js +++ b/src/web/app/safe.js @@ -18,6 +18,6 @@ if (navigator.userAgent.indexOf('Edge')) { '現在、お使いのブラウザ(Microsoft Edge)ではMisskeyは正しく動作しません。' + 'サポートしているブラウザ: Google Chrome, Mozilla Firefox, Apple Safari など' + '\n\n' + - 'Currently, Misskey cannot run correctly on your browser (Microsoft Edge).' + + 'Currently, Misskey cannot run correctly on your browser (Microsoft Edge). ' + 'Supported browsers: Google Chrome, Mozilla Firefox, Apple Safari, etc'); } -- cgit v1.2.3-freya From 39778c8458c46c847671e927cc31efd4bea5c1c6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 Nov 2017 04:42:42 +0900 Subject: :v: --- src/web/app/safe.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/web/app/safe.js b/src/web/app/safe.js index a29ba4d87f..6a0f22fe6c 100644 --- a/src/web/app/safe.js +++ b/src/web/app/safe.js @@ -13,7 +13,7 @@ if (!('fetch' in window)) { } // Detect Edge -if (navigator.userAgent.indexOf('Edge')) { +if (navigator.userAgent.indexOf('Edge') != -1) { alert( '現在、お使いのブラウザ(Microsoft Edge)ではMisskeyは正しく動作しません。' + 'サポートしているブラウザ: Google Chrome, Mozilla Firefox, Apple Safari など' + -- cgit v1.2.3-freya From a8f51e8e8624ecff4171c7af3d210a0f2ec0f337 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 Nov 2017 05:47:09 +0900 Subject: Check Cookie --- src/web/app/safe.js | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/web/app/safe.js b/src/web/app/safe.js index 6a0f22fe6c..e8482b0573 100644 --- a/src/web/app/safe.js +++ b/src/web/app/safe.js @@ -21,3 +21,11 @@ if (navigator.userAgent.indexOf('Edge') != -1) { 'Currently, Misskey cannot run correctly on your browser (Microsoft Edge). ' + 'Supported browsers: Google Chrome, Mozilla Firefox, Apple Safari, etc'); } + +// Check whether cookie enabled +if (!navigator.cookieEnabled) { + alert( + 'Misskeyを利用するにはCookieを有効にしてください。' + + '\n\n' + + 'To use Misskey, please enable Cookie.'); +} -- cgit v1.2.3-freya From fd18359178bd06c9247282071f85b0a049faefbc Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 Nov 2017 05:47:34 +0900 Subject: Better detection --- src/web/app/safe.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/web/app/safe.js b/src/web/app/safe.js index e8482b0573..2fd5361725 100644 --- a/src/web/app/safe.js +++ b/src/web/app/safe.js @@ -13,7 +13,7 @@ if (!('fetch' in window)) { } // Detect Edge -if (navigator.userAgent.indexOf('Edge') != -1) { +if (navigator.userAgent.toLowerCase().indexOf('edge') != -1) { alert( '現在、お使いのブラウザ(Microsoft Edge)ではMisskeyは正しく動作しません。' + 'サポートしているブラウザ: Google Chrome, Mozilla Firefox, Apple Safari など' + -- cgit v1.2.3-freya From 88804731d0499f6e1c53cc9baf4f90919f8804bd Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 Nov 2017 08:47:03 +0900 Subject: :art: --- src/web/app/desktop/tags/drive/browser.tag | 26 +++++++++++++------------- src/web/app/desktop/tags/drive/file.tag | 4 +--- src/web/app/desktop/tags/drive/folder.tag | 2 -- 3 files changed, 14 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/web/app/desktop/tags/drive/browser.tag b/src/web/app/desktop/tags/drive/browser.tag index 311209fcb6..6b756b9952 100644 --- a/src/web/app/desktop/tags/drive/browser.tag +++ b/src/web/app/desktop/tags/drive/browser.tag @@ -18,12 +18,14 @@ +
0 }> +
@@ -161,22 +163,20 @@ > .contents > .folders - &:after - content "" - display block - clear both - - > .folder - float left - > .files - &:after - content "" - display block - clear both + display flex + flex-wrap wrap + > .folder > .file - float left + flex-grow 1 + width 144px + margin 4px + + > .padding + flex-grow 1 + pointer-events none + width 144px + 8px // 8px is margin > .empty padding 16px diff --git a/src/web/app/desktop/tags/drive/file.tag b/src/web/app/desktop/tags/drive/file.tag index bf9d38bd2f..0f019d95bf 100644 --- a/src/web/app/desktop/tags/drive/file.tag +++ b/src/web/app/desktop/tags/drive/file.tag @@ -10,9 +10,7 @@ diff --git a/src/web/app/desktop/tags/messaging/room-window.tag b/src/web/app/desktop/tags/messaging/room-window.tag index dca0172be3..1c6ff7c4bc 100644 --- a/src/web/app/desktop/tags/messaging/room-window.tag +++ b/src/web/app/desktop/tags/messaging/room-window.tag @@ -19,11 +19,9 @@ diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag index 1d6ce23598..074422a20e 100644 --- a/src/web/app/mobile/tags/timeline.tag +++ b/src/web/app/mobile/tags/timeline.tag @@ -164,7 +164,7 @@
-

{ p.channel.title }:

+

{ p.channel.title }:

diff --git a/src/web/app/mobile/tags/ui.tag b/src/web/app/mobile/tags/ui.tag index 0c969d3902..bad6bf73fe 100644 --- a/src/web/app/mobile/tags/ui.tag +++ b/src/web/app/mobile/tags/ui.tag @@ -239,7 +239,7 @@
  • %i18n:mobile.tags.mk-ui-nav.messaging%
  • -

    %i18n:mobile.tags.mk-ui-nav.about%

    +

    %i18n:mobile.tags.mk-ui-nav.about%