mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-30 09:23:09 +02:00
Introduce account document to user document
An account document is attached to a user document if an account of the user is on the server. It may be missing if the user is on a remote server.
This commit is contained in:
parent
a633f184ab
commit
19b9cb105d
70 changed files with 355 additions and 280 deletions
|
@ -34,7 +34,7 @@ export default (req: express.Request) => new Promise<IAuthContext>(async (resolv
|
||||||
|
|
||||||
if (isNativeToken(token)) {
|
if (isNativeToken(token)) {
|
||||||
const user: IUser = await User
|
const user: IUser = await User
|
||||||
.findOne({ token: token });
|
.findOne({ 'account.token': token });
|
||||||
|
|
||||||
if (user === null) {
|
if (user === null) {
|
||||||
return reject('user not found');
|
return reject('user not found');
|
||||||
|
|
|
@ -225,7 +225,7 @@ class SigninContext extends Context {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Compare password
|
// Compare password
|
||||||
const same = await bcrypt.compare(query, this.temporaryUser.password);
|
const same = await bcrypt.compare(query, this.temporaryUser.account.password);
|
||||||
|
|
||||||
if (same) {
|
if (same) {
|
||||||
this.bot.signin(this.temporaryUser);
|
this.bot.signin(this.temporaryUser);
|
||||||
|
|
|
@ -110,11 +110,11 @@ class LineBot extends BotCore {
|
||||||
data: `showtl|${user.id}`
|
data: `showtl|${user.id}`
|
||||||
});
|
});
|
||||||
|
|
||||||
if (user.twitter) {
|
if (user.account.twitter) {
|
||||||
actions.push({
|
actions.push({
|
||||||
type: 'uri',
|
type: 'uri',
|
||||||
label: 'Twitterアカウントを見る',
|
label: 'Twitterアカウントを見る',
|
||||||
uri: `https://twitter.com/${user.twitter.screen_name}`
|
uri: `https://twitter.com/${user.account.twitter.screen_name}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ module.exports = async (app: express.Application) => {
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
line: {
|
'account.line': {
|
||||||
user_id: sourceId
|
user_id: sourceId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -181,7 +181,7 @@ module.exports = async (app: express.Application) => {
|
||||||
bot.on('signin', user => {
|
bot.on('signin', user => {
|
||||||
User.update(user._id, {
|
User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
line: {
|
'account.line': {
|
||||||
user_id: sourceId
|
user_id: sourceId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ module.exports = async (app: express.Application) => {
|
||||||
bot.on('signout', user => {
|
bot.on('signout', user => {
|
||||||
User.update(user._id, {
|
User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
line: {
|
'account.line': {
|
||||||
user_id: null
|
user_id: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import config from '../../conf';
|
||||||
|
|
||||||
export default function(res, user, redirect: boolean) {
|
export default function(res, user, redirect: boolean) {
|
||||||
const expires = 1000 * 60 * 60 * 24 * 365; // One Year
|
const expires = 1000 * 60 * 60 * 24 * 365; // One Year
|
||||||
res.cookie('i', user.token, {
|
res.cookie('i', user.account.token, {
|
||||||
path: '/',
|
path: '/',
|
||||||
domain: `.${config.host}`,
|
domain: `.${config.host}`,
|
||||||
secure: config.url.substr(0, 5) === 'https',
|
secure: config.url.substr(0, 5) === 'https',
|
||||||
|
|
|
@ -45,7 +45,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
// Fetch token
|
// Fetch token
|
||||||
const session = await AuthSess
|
const session = await AuthSess
|
||||||
.findOne({ token: token });
|
.findOne({ 'account.token': token });
|
||||||
|
|
||||||
if (session === null) {
|
if (session === null) {
|
||||||
return rej('session not found');
|
return rej('session not found');
|
||||||
|
|
|
@ -32,7 +32,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
data: false,
|
data: false,
|
||||||
profile: false
|
'account.profile': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
data: false,
|
data: false,
|
||||||
profile: false
|
'account.profile': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) =>
|
||||||
// Update lastUsedAt
|
// Update lastUsedAt
|
||||||
User.update({ _id: user._id }, {
|
User.update({ _id: user._id }, {
|
||||||
$set: {
|
$set: {
|
||||||
last_used_at: new Date()
|
'account.last_used_at': new Date()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,8 +28,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
two_factor_secret: user.two_factor_temp_secret,
|
'account.two_factor_secret': user.two_factor_temp_secret,
|
||||||
two_factor_enabled: true
|
'account.two_factor_enabled': true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (passwordErr) return rej('invalid password param');
|
if (passwordErr) return rej('invalid password param');
|
||||||
|
|
||||||
// Compare password
|
// Compare password
|
||||||
const same = await bcrypt.compare(password, user.password);
|
const same = await bcrypt.compare(password, user.account.password);
|
||||||
|
|
||||||
if (!same) {
|
if (!same) {
|
||||||
return rej('incorrect password');
|
return rej('incorrect password');
|
||||||
|
|
|
@ -11,7 +11,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (passwordErr) return rej('invalid password param');
|
if (passwordErr) return rej('invalid password param');
|
||||||
|
|
||||||
// Compare password
|
// Compare password
|
||||||
const same = await bcrypt.compare(password, user.password);
|
const same = await bcrypt.compare(password, user.account.password);
|
||||||
|
|
||||||
if (!same) {
|
if (!same) {
|
||||||
return rej('incorrect password');
|
return rej('incorrect password');
|
||||||
|
@ -19,8 +19,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
two_factor_secret: null,
|
'account.two_factor_secret': null,
|
||||||
two_factor_enabled: false
|
'account.two_factor_enabled': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (newPasswordErr) return rej('invalid new_password param');
|
if (newPasswordErr) return rej('invalid new_password param');
|
||||||
|
|
||||||
// Compare password
|
// Compare password
|
||||||
const same = await bcrypt.compare(currentPassword, user.password);
|
const same = await bcrypt.compare(currentPassword, user.account.password);
|
||||||
|
|
||||||
if (!same) {
|
if (!same) {
|
||||||
return rej('incorrect password');
|
return rej('incorrect password');
|
||||||
|
@ -34,7 +34,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
password: hash
|
'account.password': hash
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (passwordErr) return rej('invalid password param');
|
if (passwordErr) return rej('invalid password param');
|
||||||
|
|
||||||
// Compare password
|
// Compare password
|
||||||
const same = await bcrypt.compare(password, user.password);
|
const same = await bcrypt.compare(password, user.account.password);
|
||||||
|
|
||||||
if (!same) {
|
if (!same) {
|
||||||
return rej('incorrect password');
|
return rej('incorrect password');
|
||||||
|
@ -31,7 +31,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
token: secret
|
'account.token': secret
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,12 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re
|
||||||
// Get 'location' parameter
|
// Get 'location' parameter
|
||||||
const [location, locationErr] = $(params.location).optional.nullable.string().pipe(isValidLocation).$;
|
const [location, locationErr] = $(params.location).optional.nullable.string().pipe(isValidLocation).$;
|
||||||
if (locationErr) return rej('invalid location param');
|
if (locationErr) return rej('invalid location param');
|
||||||
if (location !== undefined) user.profile.location = location;
|
if (location !== undefined) user.account.profile.location = location;
|
||||||
|
|
||||||
// Get 'birthday' parameter
|
// Get 'birthday' parameter
|
||||||
const [birthday, birthdayErr] = $(params.birthday).optional.nullable.string().pipe(isValidBirthday).$;
|
const [birthday, birthdayErr] = $(params.birthday).optional.nullable.string().pipe(isValidBirthday).$;
|
||||||
if (birthdayErr) return rej('invalid birthday param');
|
if (birthdayErr) return rej('invalid birthday param');
|
||||||
if (birthday !== undefined) user.profile.birthday = birthday;
|
if (birthday !== undefined) user.account.profile.birthday = birthday;
|
||||||
|
|
||||||
// Get 'avatar_id' parameter
|
// Get 'avatar_id' parameter
|
||||||
const [avatarId, avatarIdErr] = $(params.avatar_id).optional.id().$;
|
const [avatarId, avatarIdErr] = $(params.avatar_id).optional.id().$;
|
||||||
|
@ -49,12 +49,12 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re
|
||||||
// Get 'is_bot' parameter
|
// Get 'is_bot' parameter
|
||||||
const [isBot, isBotErr] = $(params.is_bot).optional.boolean().$;
|
const [isBot, isBotErr] = $(params.is_bot).optional.boolean().$;
|
||||||
if (isBotErr) return rej('invalid is_bot param');
|
if (isBotErr) return rej('invalid is_bot param');
|
||||||
if (isBot != null) user.is_bot = isBot;
|
if (isBot != null) user.account.is_bot = isBot;
|
||||||
|
|
||||||
// Get 'auto_watch' parameter
|
// Get 'auto_watch' parameter
|
||||||
const [autoWatch, autoWatchErr] = $(params.auto_watch).optional.boolean().$;
|
const [autoWatch, autoWatchErr] = $(params.auto_watch).optional.boolean().$;
|
||||||
if (autoWatchErr) return rej('invalid auto_watch param');
|
if (autoWatchErr) return rej('invalid auto_watch param');
|
||||||
if (autoWatch != null) user.settings.auto_watch = autoWatch;
|
if (autoWatch != null) user.account.settings.auto_watch = autoWatch;
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
|
@ -62,9 +62,9 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re
|
||||||
description: user.description,
|
description: user.description,
|
||||||
avatar_id: user.avatar_id,
|
avatar_id: user.avatar_id,
|
||||||
banner_id: user.banner_id,
|
banner_id: user.banner_id,
|
||||||
profile: user.profile,
|
'account.profile': user.account.profile,
|
||||||
is_bot: user.is_bot,
|
'account.is_bot': user.account.is_bot,
|
||||||
settings: user.settings
|
'account.settings': user.account.settings
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -22,14 +22,14 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (valueErr) return rej('invalid value param');
|
if (valueErr) return rej('invalid value param');
|
||||||
|
|
||||||
const x = {};
|
const x = {};
|
||||||
x[`client_settings.${name}`] = value;
|
x[`account.client_settings.${name}`] = value;
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: x
|
$set: x
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
user.client_settings[name] = value;
|
user.account.client_settings[name] = value;
|
||||||
const iObj = await pack(user, user, {
|
const iObj = await pack(user, user, {
|
||||||
detail: true,
|
detail: true,
|
||||||
includeSecrets: true
|
includeSecrets: true
|
||||||
|
|
|
@ -26,7 +26,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (home) {
|
if (home) {
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'client_settings.home': home
|
'account.client_settings.home': home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
} else {
|
} else {
|
||||||
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
||||||
|
|
||||||
const _home = user.client_settings.home;
|
const _home = user.account.client_settings.home;
|
||||||
const widget = _home.find(w => w.id == id);
|
const widget = _home.find(w => w.id == id);
|
||||||
|
|
||||||
if (widget == null) return rej('widget not found');
|
if (widget == null) return rej('widget not found');
|
||||||
|
@ -47,7 +47,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'client_settings.home': _home
|
'account.client_settings.home': _home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
if (home) {
|
if (home) {
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'client_settings.mobile_home': home
|
'account.client_settings.mobile_home': home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
} else {
|
} else {
|
||||||
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
||||||
|
|
||||||
const _home = user.client_settings.mobile_home || [];
|
const _home = user.account.client_settings.mobile_home || [];
|
||||||
const widget = _home.find(w => w.id == id);
|
const widget = _home.find(w => w.id == id);
|
||||||
|
|
||||||
if (widget == null) return rej('widget not found');
|
if (widget == null) return rej('widget not found');
|
||||||
|
@ -46,7 +46,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
|
||||||
await User.update(user._id, {
|
await User.update(user._id, {
|
||||||
$set: {
|
$set: {
|
||||||
'client_settings.mobile_home': _home
|
'account.client_settings.mobile_home': _home
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
data: false,
|
data: false,
|
||||||
profile: false
|
'account.profile': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
data: false,
|
data: false,
|
||||||
profile: false
|
'account.profile': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import Post from '../../models/post';
|
||||||
* @return {Promise<any>}
|
* @return {Promise<any>}
|
||||||
*/
|
*/
|
||||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
if (!user.is_pro) {
|
if (!user.account.is_pro) {
|
||||||
return rej('This endpoint is available only from a Pro account');
|
return rej('This endpoint is available only from a Pro account');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -390,7 +390,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// この投稿をWatchする
|
// この投稿をWatchする
|
||||||
if (user.settings.auto_watch !== false) {
|
if (user.account.settings.auto_watch !== false) {
|
||||||
watch(user._id, reply);
|
watch(user._id, reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// この投稿をWatchする
|
// この投稿をWatchする
|
||||||
if (user.settings.auto_watch !== false) {
|
if (user.account.settings.auto_watch !== false) {
|
||||||
watch(user._id, post);
|
watch(user._id, post);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -116,7 +116,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// この投稿をWatchする
|
// この投稿をWatchする
|
||||||
if (user.settings.auto_watch !== false) {
|
if (user.account.settings.auto_watch !== false) {
|
||||||
watch(user._id, post);
|
watch(user._id, post);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
|
||||||
_id: {
|
_id: {
|
||||||
$nin: followingIds
|
$nin: followingIds
|
||||||
},
|
},
|
||||||
last_used_at: {
|
'account.last_used_at': {
|
||||||
$gte: new Date(Date.now() - ms('7days'))
|
$gte: new Date(Date.now() - ms('7days'))
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import config from '../../conf';
|
||||||
const User = db.get<IUser>('users');
|
const User = db.get<IUser>('users');
|
||||||
|
|
||||||
User.createIndex('username');
|
User.createIndex('username');
|
||||||
User.createIndex('token');
|
User.createIndex('account.token');
|
||||||
|
|
||||||
export default User;
|
export default User;
|
||||||
|
|
||||||
|
@ -43,20 +43,26 @@ export type IUser = {
|
||||||
_id: mongo.ObjectID;
|
_id: mongo.ObjectID;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
deleted_at: Date;
|
deleted_at: Date;
|
||||||
email: string;
|
|
||||||
followers_count: number;
|
followers_count: number;
|
||||||
following_count: number;
|
following_count: number;
|
||||||
links: string[];
|
|
||||||
name: string;
|
name: string;
|
||||||
password: string;
|
|
||||||
posts_count: number;
|
posts_count: number;
|
||||||
drive_capacity: number;
|
drive_capacity: number;
|
||||||
username: string;
|
username: string;
|
||||||
username_lower: string;
|
username_lower: string;
|
||||||
token: string;
|
|
||||||
avatar_id: mongo.ObjectID;
|
avatar_id: mongo.ObjectID;
|
||||||
banner_id: mongo.ObjectID;
|
banner_id: mongo.ObjectID;
|
||||||
data: any;
|
data: any;
|
||||||
|
description: string;
|
||||||
|
latest_post: IPost;
|
||||||
|
pinned_post_id: mongo.ObjectID;
|
||||||
|
is_suspended: boolean;
|
||||||
|
keywords: string[];
|
||||||
|
account: {
|
||||||
|
email: string;
|
||||||
|
links: string[];
|
||||||
|
password: string;
|
||||||
|
token: string;
|
||||||
twitter: {
|
twitter: {
|
||||||
access_token: string;
|
access_token: string;
|
||||||
access_token_secret: string;
|
access_token_secret: string;
|
||||||
|
@ -66,24 +72,20 @@ export type IUser = {
|
||||||
line: {
|
line: {
|
||||||
user_id: string;
|
user_id: string;
|
||||||
};
|
};
|
||||||
description: string;
|
|
||||||
profile: {
|
profile: {
|
||||||
location: string;
|
location: string;
|
||||||
birthday: string; // 'YYYY-MM-DD'
|
birthday: string; // 'YYYY-MM-DD'
|
||||||
tags: string[];
|
tags: string[];
|
||||||
};
|
};
|
||||||
last_used_at: Date;
|
last_used_at: Date;
|
||||||
latest_post: IPost;
|
|
||||||
pinned_post_id: mongo.ObjectID;
|
|
||||||
is_bot: boolean;
|
is_bot: boolean;
|
||||||
is_pro: boolean;
|
is_pro: boolean;
|
||||||
is_suspended: boolean;
|
|
||||||
keywords: string[];
|
|
||||||
two_factor_secret: string;
|
two_factor_secret: string;
|
||||||
two_factor_enabled: boolean;
|
two_factor_enabled: boolean;
|
||||||
client_settings: any;
|
client_settings: any;
|
||||||
settings: any;
|
settings: any;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export function init(user): IUser {
|
export function init(user): IUser {
|
||||||
user._id = new mongo.ObjectID(user._id);
|
user._id = new mongo.ObjectID(user._id);
|
||||||
|
@ -119,11 +121,11 @@ export const pack = (
|
||||||
|
|
||||||
const fields = opts.detail ? {
|
const fields = opts.detail ? {
|
||||||
} : {
|
} : {
|
||||||
settings: false,
|
'account.settings': false,
|
||||||
client_settings: false,
|
'account.client_settings': false,
|
||||||
profile: false,
|
'account.profile': false,
|
||||||
keywords: false,
|
'account.keywords': false,
|
||||||
domains: false
|
'account.domains': false
|
||||||
};
|
};
|
||||||
|
|
||||||
// Populate the user if 'user' is ID
|
// Populate the user if 'user' is ID
|
||||||
|
@ -158,26 +160,26 @@ export const pack = (
|
||||||
delete _user.latest_post;
|
delete _user.latest_post;
|
||||||
|
|
||||||
// Remove private properties
|
// Remove private properties
|
||||||
delete _user.password;
|
delete _user.account.password;
|
||||||
delete _user.token;
|
delete _user.account.token;
|
||||||
delete _user.two_factor_temp_secret;
|
delete _user.account.two_factor_temp_secret;
|
||||||
delete _user.two_factor_secret;
|
delete _user.account.two_factor_secret;
|
||||||
delete _user.username_lower;
|
delete _user.username_lower;
|
||||||
if (_user.twitter) {
|
if (_user.account.twitter) {
|
||||||
delete _user.twitter.access_token;
|
delete _user.account.twitter.access_token;
|
||||||
delete _user.twitter.access_token_secret;
|
delete _user.account.twitter.access_token_secret;
|
||||||
}
|
}
|
||||||
delete _user.line;
|
delete _user.account.line;
|
||||||
|
|
||||||
// Visible via only the official client
|
// Visible via only the official client
|
||||||
if (!opts.includeSecrets) {
|
if (!opts.includeSecrets) {
|
||||||
delete _user.email;
|
delete _user.account.email;
|
||||||
delete _user.settings;
|
delete _user.account.settings;
|
||||||
delete _user.client_settings;
|
delete _user.account.client_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.detail) {
|
if (!opts.detail) {
|
||||||
delete _user.two_factor_enabled;
|
delete _user.account.two_factor_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
_user.avatar_url = _user.avatar_id != null
|
_user.avatar_url = _user.avatar_id != null
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default async (req: express.Request, res: express.Response) => {
|
||||||
}, {
|
}, {
|
||||||
fields: {
|
fields: {
|
||||||
data: false,
|
data: false,
|
||||||
profile: false
|
'account.profile': false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,12 +48,12 @@ export default async (req: express.Request, res: express.Response) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare password
|
// Compare password
|
||||||
const same = await bcrypt.compare(password, user.password);
|
const same = await bcrypt.compare(password, user.account.password);
|
||||||
|
|
||||||
if (same) {
|
if (same) {
|
||||||
if (user.two_factor_enabled) {
|
if (user.account.two_factor_enabled) {
|
||||||
const verified = (speakeasy as any).totp.verify({
|
const verified = (speakeasy as any).totp.verify({
|
||||||
secret: user.two_factor_secret,
|
secret: user.account.two_factor_secret,
|
||||||
encoding: 'base32',
|
encoding: 'base32',
|
||||||
token: token
|
token: token
|
||||||
});
|
});
|
||||||
|
|
|
@ -105,23 +105,24 @@ export default async (req: express.Request, res: express.Response) => {
|
||||||
|
|
||||||
// Create account
|
// Create account
|
||||||
const account: IUser = await User.insert({
|
const account: IUser = await User.insert({
|
||||||
token: secret,
|
|
||||||
avatar_id: null,
|
avatar_id: null,
|
||||||
banner_id: null,
|
banner_id: null,
|
||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
description: null,
|
description: null,
|
||||||
email: null,
|
|
||||||
followers_count: 0,
|
followers_count: 0,
|
||||||
following_count: 0,
|
following_count: 0,
|
||||||
links: null,
|
|
||||||
name: name,
|
name: name,
|
||||||
password: hash,
|
|
||||||
posts_count: 0,
|
posts_count: 0,
|
||||||
likes_count: 0,
|
likes_count: 0,
|
||||||
liked_count: 0,
|
liked_count: 0,
|
||||||
drive_capacity: 1073741824, // 1GB
|
drive_capacity: 1073741824, // 1GB
|
||||||
username: username,
|
username: username,
|
||||||
username_lower: username.toLowerCase(),
|
username_lower: username.toLowerCase(),
|
||||||
|
account: {
|
||||||
|
token: secret,
|
||||||
|
email: null,
|
||||||
|
links: null,
|
||||||
|
password: hash,
|
||||||
profile: {
|
profile: {
|
||||||
bio: null,
|
bio: null,
|
||||||
birthday: null,
|
birthday: null,
|
||||||
|
@ -138,6 +139,7 @@ export default async (req: express.Request, res: express.Response) => {
|
||||||
client_settings: {
|
client_settings: {
|
||||||
home: homeData
|
home: homeData
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Response
|
// Response
|
||||||
|
|
|
@ -39,10 +39,10 @@ module.exports = (app: express.Application) => {
|
||||||
if (userToken == null) return res.send('plz signin');
|
if (userToken == null) return res.send('plz signin');
|
||||||
|
|
||||||
const user = await User.findOneAndUpdate({
|
const user = await User.findOneAndUpdate({
|
||||||
token: userToken
|
'account.token': userToken
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
twitter: null
|
'account.twitter': null
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ module.exports = (app: express.Application) => {
|
||||||
const result = await twAuth.done(JSON.parse(ctx), req.query.oauth_verifier);
|
const result = await twAuth.done(JSON.parse(ctx), req.query.oauth_verifier);
|
||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
'twitter.user_id': result.userId
|
'account.twitter.user_id': result.userId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
@ -148,10 +148,10 @@ module.exports = (app: express.Application) => {
|
||||||
const result = await twAuth.done(JSON.parse(ctx), verifier);
|
const result = await twAuth.done(JSON.parse(ctx), verifier);
|
||||||
|
|
||||||
const user = await User.findOneAndUpdate({
|
const user = await User.findOneAndUpdate({
|
||||||
token: userToken
|
'account.token': userToken
|
||||||
}, {
|
}, {
|
||||||
$set: {
|
$set: {
|
||||||
twitter: {
|
'account.twitter': {
|
||||||
access_token: result.accessToken,
|
access_token: result.accessToken,
|
||||||
access_token_secret: result.accessTokenSecret,
|
access_token_secret: result.accessTokenSecret,
|
||||||
user_id: result.userId,
|
user_id: result.userId,
|
||||||
|
|
|
@ -74,7 +74,7 @@ export default async function(request: websocket.request, connection: websocket.
|
||||||
// Update lastUsedAt
|
// Update lastUsedAt
|
||||||
User.update({ _id: user._id }, {
|
User.update({ _id: user._id }, {
|
||||||
$set: {
|
$set: {
|
||||||
last_used_at: new Date()
|
'account.last_used_at': new Date()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -94,7 +94,7 @@ function authenticate(token: string): Promise<IUser> {
|
||||||
// Fetch user
|
// Fetch user
|
||||||
const user: IUser = await User
|
const user: IUser = await User
|
||||||
.findOne({
|
.findOne({
|
||||||
token: token
|
'account.token': token
|
||||||
});
|
});
|
||||||
|
|
||||||
resolve(user);
|
resolve(user);
|
||||||
|
|
|
@ -7,6 +7,6 @@ import { IUser } from '../api/models/user';
|
||||||
export default function(user: IUser): string {
|
export default function(user: IUser): string {
|
||||||
return `${user.name} (@${user.username})\n` +
|
return `${user.name} (@${user.username})\n` +
|
||||||
`${user.posts_count}投稿、${user.following_count}フォロー、${user.followers_count}フォロワー\n` +
|
`${user.posts_count}投稿、${user.following_count}フォロー、${user.followers_count}フォロワー\n` +
|
||||||
`場所: ${user.profile.location}、誕生日: ${user.profile.birthday}\n` +
|
`場所: ${user.account.profile.location}、誕生日: ${user.account.profile.birthday}\n` +
|
||||||
`「${user.description}」`;
|
`「${user.description}」`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,14 @@ export default function<T extends object>(data: {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
data: newProps
|
data: newProps
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
(this as any).os.i.client_settings.mobile_home.find(w => w.id == this.id).data = newProps;
|
(this as any).os.i.account.client_settings.mobile_home.find(w => w.id == this.id).data = newProps;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
(this as any).api('i/update_home', {
|
(this as any).api('i/update_home', {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
data: newProps
|
data: newProps
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
(this as any).os.i.client_settings.home.find(w => w.id == this.id).data = newProps;
|
(this as any).os.i.account.client_settings.home.find(w => w.id == this.id).data = newProps;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -270,7 +270,7 @@ export default class MiOS extends EventEmitter {
|
||||||
// Parse response
|
// Parse response
|
||||||
res.json().then(i => {
|
res.json().then(i => {
|
||||||
me = i;
|
me = i;
|
||||||
me.token = token;
|
me.account.token = token;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -294,12 +294,12 @@ export default class MiOS extends EventEmitter {
|
||||||
const fetched = me => {
|
const fetched = me => {
|
||||||
if (me) {
|
if (me) {
|
||||||
// デフォルトの設定をマージ
|
// デフォルトの設定をマージ
|
||||||
me.client_settings = Object.assign({
|
me.account.client_settings = Object.assign({
|
||||||
fetchOnScroll: true,
|
fetchOnScroll: true,
|
||||||
showMaps: true,
|
showMaps: true,
|
||||||
showPostFormOnTopOfTl: false,
|
showPostFormOnTopOfTl: false,
|
||||||
gradientWindowHeader: false
|
gradientWindowHeader: false
|
||||||
}, me.client_settings);
|
}, me.account.client_settings);
|
||||||
|
|
||||||
// ローカルストレージにキャッシュ
|
// ローカルストレージにキャッシュ
|
||||||
localStorage.setItem('me', JSON.stringify(me));
|
localStorage.setItem('me', JSON.stringify(me));
|
||||||
|
@ -329,7 +329,7 @@ export default class MiOS extends EventEmitter {
|
||||||
fetched(cachedMe);
|
fetched(cachedMe);
|
||||||
|
|
||||||
// 後から新鮮なデータをフェッチ
|
// 後から新鮮なデータをフェッチ
|
||||||
fetchme(cachedMe.token, freshData => {
|
fetchme(cachedMe.account.token, freshData => {
|
||||||
merge(cachedMe, freshData);
|
merge(cachedMe, freshData);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -437,7 +437,7 @@ export default class MiOS extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append a credential
|
// Append a credential
|
||||||
if (this.isSignedIn) (data as any).i = this.i.token;
|
if (this.isSignedIn) (data as any).i = this.i.account.token;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
//const viaStream = localStorage.getItem('enableExperimental') == 'true';
|
//const viaStream = localStorage.getItem('enableExperimental') == 'true';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import MiOS from '../../mios';
|
||||||
export class DriveStream extends Stream {
|
export class DriveStream extends Stream {
|
||||||
constructor(os: MiOS, me) {
|
constructor(os: MiOS, me) {
|
||||||
super(os, 'drive', {
|
super(os, 'drive', {
|
||||||
i: me.token
|
i: me.account.token
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,13 @@ import MiOS from '../../mios';
|
||||||
export class HomeStream extends Stream {
|
export class HomeStream extends Stream {
|
||||||
constructor(os: MiOS, me) {
|
constructor(os: MiOS, me) {
|
||||||
super(os, '', {
|
super(os, '', {
|
||||||
i: me.token
|
i: me.account.token
|
||||||
});
|
});
|
||||||
|
|
||||||
// 最終利用日時を更新するため定期的にaliveメッセージを送信
|
// 最終利用日時を更新するため定期的にaliveメッセージを送信
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.send({ type: 'alive' });
|
this.send({ type: 'alive' });
|
||||||
me.last_used_at = new Date();
|
me.account.last_used_at = new Date();
|
||||||
}, 1000 * 60);
|
}, 1000 * 60);
|
||||||
|
|
||||||
// 自分の情報が更新されたとき
|
// 自分の情報が更新されたとき
|
||||||
|
|
|
@ -8,7 +8,7 @@ import MiOS from '../../mios';
|
||||||
export class MessagingIndexStream extends Stream {
|
export class MessagingIndexStream extends Stream {
|
||||||
constructor(os: MiOS, me) {
|
constructor(os: MiOS, me) {
|
||||||
super(os, 'messaging-index', {
|
super(os, 'messaging-index', {
|
||||||
i: me.token
|
i: me.account.token
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ import MiOS from '../../mios';
|
||||||
export class MessagingStream extends Stream {
|
export class MessagingStream extends Stream {
|
||||||
constructor(os: MiOS, me, otherparty) {
|
constructor(os: MiOS, me, otherparty) {
|
||||||
super(os, 'messaging', {
|
super(os, 'messaging', {
|
||||||
i: me.token,
|
i: me.account.token,
|
||||||
otherparty
|
otherparty
|
||||||
});
|
});
|
||||||
|
|
||||||
(this as any).on('_connected_', () => {
|
(this as any).on('_connected_', () => {
|
||||||
this.send({
|
this.send({
|
||||||
i: me.token
|
i: me.account.token
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import MiOS from '../../mios';
|
||||||
export class OthelloGameStream extends Stream {
|
export class OthelloGameStream extends Stream {
|
||||||
constructor(os: MiOS, me, game) {
|
constructor(os: MiOS, me, game) {
|
||||||
super(os, 'othello-game', {
|
super(os, 'othello-game', {
|
||||||
i: me ? me.token : null,
|
i: me ? me.account.token : null,
|
||||||
game: game.id
|
game: game.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import MiOS from '../../mios';
|
||||||
export class OthelloStream extends Stream {
|
export class OthelloStream extends Stream {
|
||||||
constructor(os: MiOS, me) {
|
constructor(os: MiOS, me) {
|
||||||
super(os, 'othello', {
|
super(os, 'othello', {
|
||||||
i: me.token
|
i: me.account.token
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<label class="password">
|
<label class="password">
|
||||||
<input v-model="password" type="password" placeholder="%i18n:common.tags.mk-signin.password%" required/>%fa:lock%
|
<input v-model="password" type="password" placeholder="%i18n:common.tags.mk-signin.password%" required/>%fa:lock%
|
||||||
</label>
|
</label>
|
||||||
<label class="token" v-if="user && user.two_factor_enabled">
|
<label class="token" v-if="user && user.account.two_factor_enabled">
|
||||||
<input v-model="token" type="number" placeholder="%i18n:common.tags.mk-signin.token%" required/>%fa:lock%
|
<input v-model="token" type="number" placeholder="%i18n:common.tags.mk-signin.token%" required/>%fa:lock%
|
||||||
</label>
|
</label>
|
||||||
<button type="submit" :disabled="signing">{{ signing ? '%i18n:common.tags.mk-signin.signing-in%' : '%i18n:common.tags.mk-signin.signin%' }}</button>
|
<button type="submit" :disabled="signing">{{ signing ? '%i18n:common.tags.mk-signin.signing-in%' : '%i18n:common.tags.mk-signin.signin%' }}</button>
|
||||||
|
@ -40,7 +40,7 @@ export default Vue.extend({
|
||||||
(this as any).api('signin', {
|
(this as any).api('signin', {
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
token: this.user && this.user.two_factor_enabled ? this.token : undefined
|
token: this.user && this.user.account.two_factor_enabled ? this.token : undefined
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mk-twitter-setting">
|
<div class="mk-twitter-setting">
|
||||||
<p>%i18n:common.tags.mk-twitter-setting.description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:common.tags.mk-twitter-setting.detail%</a></p>
|
<p>%i18n:common.tags.mk-twitter-setting.description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:common.tags.mk-twitter-setting.detail%</a></p>
|
||||||
<p class="account" v-if="os.i.twitter" :title="`Twitter ID: ${os.i.twitter.user_id}`">%i18n:common.tags.mk-twitter-setting.connected-to%: <a :href="`https://twitter.com/${os.i.twitter.screen_name}`" target="_blank">@{{ os.i.twitter.screen_name }}</a></p>
|
<p class="account" v-if="os.i.account.twitter" :title="`Twitter ID: ${os.i.account.twitter.user_id}`">%i18n:common.tags.mk-twitter-setting.connected-to%: <a :href="`https://twitter.com/${os.i.account.twitter.screen_name}`" target="_blank">@{{ os.i.account.twitter.screen_name }}</a></p>
|
||||||
<p>
|
<p>
|
||||||
<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.twitter ? '%i18n:common.tags.mk-twitter-setting.reconnect%' : '%i18n:common.tags.mk-twitter-setting.connect%' }}</a>
|
<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.account.twitter ? '%i18n:common.tags.mk-twitter-setting.reconnect%' : '%i18n:common.tags.mk-twitter-setting.connect%' }}</a>
|
||||||
<span v-if="os.i.twitter"> or </span>
|
<span v-if="os.i.account.twitter"> or </span>
|
||||||
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter" @click.prevent="disconnect">%i18n:common.tags.mk-twitter-setting.disconnect%</a>
|
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.account.twitter" @click.prevent="disconnect">%i18n:common.tags.mk-twitter-setting.disconnect%</a>
|
||||||
</p>
|
</p>
|
||||||
<p class="id" v-if="os.i.twitter">Twitter ID: {{ os.i.twitter.user_id }}</p>
|
<p class="id" v-if="os.i.account.twitter">Twitter ID: {{ os.i.account.twitter.user_id }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$watch('os.i', () => {
|
this.$watch('os.i', () => {
|
||||||
if ((this as any).os.i.twitter) {
|
if ((this as any).os.i.account.twitter) {
|
||||||
if (this.form) this.form.close();
|
if (this.form) this.form.close();
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -50,7 +50,7 @@ export default Vue.extend({
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
|
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append('i', (this as any).os.i.token);
|
data.append('i', (this as any).os.i.account.token);
|
||||||
data.append('file', file);
|
data.append('file', file);
|
||||||
|
|
||||||
if (folder) data.append('folder_id', folder);
|
if (folder) data.append('folder_id', folder);
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default (os: OS) => (cb, file = null) => {
|
||||||
|
|
||||||
w.$once('cropped', blob => {
|
w.$once('cropped', blob => {
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append('i', os.i.token);
|
data.append('i', os.i.account.token);
|
||||||
data.append('file', blob, file.name + '.cropped.png');
|
data.append('file', blob, file.name + '.cropped.png');
|
||||||
|
|
||||||
os.api('drive/folders/find', {
|
os.api('drive/folders/find', {
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default (os: OS) => (cb, file = null) => {
|
||||||
|
|
||||||
w.$once('cropped', blob => {
|
w.$once('cropped', blob => {
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append('i', os.i.token);
|
data.append('i', os.i.account.token);
|
||||||
data.append('file', blob, file.name + '.cropped.png');
|
data.append('file', blob, file.name + '.cropped.png');
|
||||||
|
|
||||||
os.api('drive/folders/find', {
|
os.api('drive/folders/find', {
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<a @click="hint">カスタマイズのヒント</a>
|
<a @click="hint">カスタマイズのヒント</a>
|
||||||
<div>
|
<div>
|
||||||
<mk-post-form v-if="os.i.client_settings.showPostFormOnTopOfTl"/>
|
<mk-post-form v-if="os.i.account.client_settings.showPostFormOnTopOfTl"/>
|
||||||
<mk-timeline ref="tl" @loaded="onTlLoaded"/>
|
<mk-timeline ref="tl" @loaded="onTlLoaded"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/>
|
<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<mk-post-form v-if="os.i.client_settings.showPostFormOnTopOfTl"/>
|
<mk-post-form v-if="os.i.account.client_settings.showPostFormOnTopOfTl"/>
|
||||||
<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
|
<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
|
||||||
<mk-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/>
|
<mk-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,16 +104,16 @@ export default Vue.extend({
|
||||||
home: {
|
home: {
|
||||||
get(): any[] {
|
get(): any[] {
|
||||||
//#region 互換性のため
|
//#region 互換性のため
|
||||||
(this as any).os.i.client_settings.home.forEach(w => {
|
(this as any).os.i.account.client_settings.home.forEach(w => {
|
||||||
if (w.name == 'rss-reader') w.name = 'rss';
|
if (w.name == 'rss-reader') w.name = 'rss';
|
||||||
if (w.name == 'user-recommendation') w.name = 'users';
|
if (w.name == 'user-recommendation') w.name = 'users';
|
||||||
if (w.name == 'recommended-polls') w.name = 'polls';
|
if (w.name == 'recommended-polls') w.name = 'polls';
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
return (this as any).os.i.client_settings.home;
|
return (this as any).os.i.account.client_settings.home;
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
(this as any).os.i.client_settings.home = value;
|
(this as any).os.i.account.client_settings.home = value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
left(): any[] {
|
left(): any[] {
|
||||||
|
@ -126,7 +126,7 @@ export default Vue.extend({
|
||||||
created() {
|
created() {
|
||||||
this.widgets.left = this.left;
|
this.widgets.left = this.left;
|
||||||
this.widgets.right = this.right;
|
this.widgets.right = this.right;
|
||||||
this.$watch('os.i.client_settings', i => {
|
this.$watch('os.i.account.client_settings', i => {
|
||||||
this.widgets.left = this.left;
|
this.widgets.left = this.left;
|
||||||
this.widgets.right = this.right;
|
this.widgets.right = this.right;
|
||||||
}, {
|
}, {
|
||||||
|
@ -161,17 +161,17 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
onHomeUpdated(data) {
|
onHomeUpdated(data) {
|
||||||
if (data.home) {
|
if (data.home) {
|
||||||
(this as any).os.i.client_settings.home = data.home;
|
(this as any).os.i.account.client_settings.home = data.home;
|
||||||
this.widgets.left = data.home.filter(w => w.place == 'left');
|
this.widgets.left = data.home.filter(w => w.place == 'left');
|
||||||
this.widgets.right = data.home.filter(w => w.place == 'right');
|
this.widgets.right = data.home.filter(w => w.place == 'right');
|
||||||
} else {
|
} else {
|
||||||
const w = (this as any).os.i.client_settings.home.find(w => w.id == data.id);
|
const w = (this as any).os.i.account.client_settings.home.find(w => w.id == data.id);
|
||||||
if (w != null) {
|
if (w != null) {
|
||||||
w.data = data.data;
|
w.data = data.data;
|
||||||
this.$refs[w.id][0].preventSave = true;
|
this.$refs[w.id][0].preventSave = true;
|
||||||
this.$refs[w.id][0].props = w.data;
|
this.$refs[w.id][0].props = w.data;
|
||||||
this.widgets.left = (this as any).os.i.client_settings.home.filter(w => w.place == 'left');
|
this.widgets.left = (this as any).os.i.account.client_settings.home.filter(w => w.place == 'left');
|
||||||
this.widgets.right = (this as any).os.i.client_settings.home.filter(w => w.place == 'right');
|
this.widgets.right = (this as any).os.i.account.client_settings.home.filter(w => w.place == 'right');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -148,7 +148,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
// Draw map
|
// Draw map
|
||||||
if (this.p.geo) {
|
if (this.p.geo) {
|
||||||
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.client_settings.showMaps : true;
|
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.client_settings.showMaps : true;
|
||||||
if (shouldShowMap) {
|
if (shouldShowMap) {
|
||||||
(this as any).os.getGoogleMaps().then(maps => {
|
(this as any).os.getGoogleMaps().then(maps => {
|
||||||
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<header>
|
||||||
<router-link class="name" :to="`/${p.user.username}`" v-user-preview="p.user.id">{{ p.user.name }}</router-link>
|
<router-link class="name" :to="`/${p.user.username}`" v-user-preview="p.user.id">{{ p.user.name }}</router-link>
|
||||||
<span class="is-bot" v-if="p.user.is_bot">bot</span>
|
<span class="is-bot" v-if="p.user.account.is_bot">bot</span>
|
||||||
<span class="username">@{{ p.user.username }}</span>
|
<span class="username">@{{ p.user.username }}</span>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
||||||
|
@ -162,7 +162,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
// Draw map
|
// Draw map
|
||||||
if (this.p.geo) {
|
if (this.p.geo) {
|
||||||
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.client_settings.showMaps : true;
|
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.client_settings.showMaps : true;
|
||||||
if (shouldShowMap) {
|
if (shouldShowMap) {
|
||||||
(this as any).os.getGoogleMaps().then(maps => {
|
(this as any).os.getGoogleMaps().then(maps => {
|
||||||
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<div class="2fa">
|
<div class="2fa">
|
||||||
<p>%i18n:desktop.tags.mk-2fa-setting.intro%<a href="%i18n:desktop.tags.mk-2fa-setting.url%" target="_blank">%i18n:desktop.tags.mk-2fa-setting.detail%</a></p>
|
<p>%i18n:desktop.tags.mk-2fa-setting.intro%<a href="%i18n:desktop.tags.mk-2fa-setting.url%" target="_blank">%i18n:desktop.tags.mk-2fa-setting.detail%</a></p>
|
||||||
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:desktop.tags.mk-2fa-setting.caution%</p></div>
|
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:desktop.tags.mk-2fa-setting.caution%</p></div>
|
||||||
<p v-if="!data && !os.i.two_factor_enabled"><button @click="register" class="ui primary">%i18n:desktop.tags.mk-2fa-setting.register%</button></p>
|
<p v-if="!data && !os.i.account.two_factor_enabled"><button @click="register" class="ui primary">%i18n:desktop.tags.mk-2fa-setting.register%</button></p>
|
||||||
<template v-if="os.i.two_factor_enabled">
|
<template v-if="os.i.account.two_factor_enabled">
|
||||||
<p>%i18n:desktop.tags.mk-2fa-setting.already-registered%</p>
|
<p>%i18n:desktop.tags.mk-2fa-setting.already-registered%</p>
|
||||||
<button @click="unregister" class="ui">%i18n:desktop.tags.mk-2fa-setting.unregister%</button>
|
<button @click="unregister" class="ui">%i18n:desktop.tags.mk-2fa-setting.unregister%</button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -54,7 +54,7 @@ export default Vue.extend({
|
||||||
password: password
|
password: password
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.unregistered%');
|
(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.unregistered%');
|
||||||
(this as any).os.i.two_factor_enabled = false;
|
(this as any).os.i.account.two_factor_enabled = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -64,7 +64,7 @@ export default Vue.extend({
|
||||||
token: this.token
|
token: this.token
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.success%');
|
(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.success%');
|
||||||
(this as any).os.i.two_factor_enabled = true;
|
(this as any).os.i.account.two_factor_enabled = true;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.failed%');
|
(this as any).apis.notify('%i18n:desktop.tags.mk-2fa-setting.failed%');
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="root api">
|
<div class="root api">
|
||||||
<p>Token: <code>{{ os.i.token }}</code></p>
|
<p>Token: <code>{{ os.i.account.token }}</code></p>
|
||||||
<p>%i18n:desktop.tags.mk-api-info.intro%</p>
|
<p>%i18n:desktop.tags.mk-api-info.intro%</p>
|
||||||
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:desktop.tags.mk-api-info.caution%</p></div>
|
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:desktop.tags.mk-api-info.caution%</p></div>
|
||||||
<p>%i18n:desktop.tags.mk-api-info.regeneration-of-token%</p>
|
<p>%i18n:desktop.tags.mk-api-info.regeneration-of-token%</p>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<button class="ui primary" @click="save">%i18n:desktop.tags.mk-profile-setting.save%</button>
|
<button class="ui primary" @click="save">%i18n:desktop.tags.mk-profile-setting.save%</button>
|
||||||
<section>
|
<section>
|
||||||
<h2>その他</h2>
|
<h2>その他</h2>
|
||||||
<mk-switch v-model="os.i.is_bot" @change="onChangeIsBot" text="このアカウントはbotです"/>
|
<mk-switch v-model="os.i.account.is_bot" @change="onChangeIsBot" text="このアカウントはbotです"/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -43,9 +43,9 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.name = (this as any).os.i.name;
|
this.name = (this as any).os.i.name;
|
||||||
this.location = (this as any).os.i.profile.location;
|
this.location = (this as any).os.i.account.profile.location;
|
||||||
this.description = (this as any).os.i.description;
|
this.description = (this as any).os.i.description;
|
||||||
this.birthday = (this as any).os.i.profile.birthday;
|
this.birthday = (this as any).os.i.account.profile.birthday;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateAvatar() {
|
updateAvatar() {
|
||||||
|
@ -63,7 +63,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
onChangeIsBot() {
|
onChangeIsBot() {
|
||||||
(this as any).api('i/update', {
|
(this as any).api('i/update', {
|
||||||
is_bot: (this as any).os.i.is_bot
|
is_bot: (this as any).os.i.account.is_bot
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
<section class="web" v-show="page == 'web'">
|
<section class="web" v-show="page == 'web'">
|
||||||
<h1>動作</h1>
|
<h1>動作</h1>
|
||||||
<mk-switch v-model="os.i.client_settings.fetchOnScroll" @change="onChangeFetchOnScroll" text="スクロールで自動読み込み">
|
<mk-switch v-model="os.i.account.client_settings.fetchOnScroll" @change="onChangeFetchOnScroll" text="スクロールで自動読み込み">
|
||||||
<span>ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。</span>
|
<span>ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。</span>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
<mk-switch v-model="autoPopout" text="ウィンドウの自動ポップアウト">
|
<mk-switch v-model="autoPopout" text="ウィンドウの自動ポップアウト">
|
||||||
|
@ -33,11 +33,11 @@
|
||||||
<div class="div">
|
<div class="div">
|
||||||
<button class="ui button" @click="customizeHome">ホームをカスタマイズ</button>
|
<button class="ui button" @click="customizeHome">ホームをカスタマイズ</button>
|
||||||
</div>
|
</div>
|
||||||
<mk-switch v-model="os.i.client_settings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="タイムライン上部に投稿フォームを表示する"/>
|
<mk-switch v-model="os.i.account.client_settings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="タイムライン上部に投稿フォームを表示する"/>
|
||||||
<mk-switch v-model="os.i.client_settings.showMaps" @change="onChangeShowMaps" text="マップの自動展開">
|
<mk-switch v-model="os.i.account.client_settings.showMaps" @change="onChangeShowMaps" text="マップの自動展開">
|
||||||
<span>位置情報が添付された投稿のマップを自動的に展開します。</span>
|
<span>位置情報が添付された投稿のマップを自動的に展開します。</span>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
<mk-switch v-model="os.i.client_settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="ウィンドウのタイトルバーにグラデーションを使用"/>
|
<mk-switch v-model="os.i.account.client_settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="ウィンドウのタイトルバーにグラデーションを使用"/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="web" v-show="page == 'web'">
|
<section class="web" v-show="page == 'web'">
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
|
|
||||||
<section class="web" v-show="page == 'web'">
|
<section class="web" v-show="page == 'web'">
|
||||||
<h1>モバイル</h1>
|
<h1>モバイル</h1>
|
||||||
<mk-switch v-model="os.i.client_settings.disableViaMobile" @change="onChangeDisableViaMobile" text="「モバイルからの投稿」フラグを付けない"/>
|
<mk-switch v-model="os.i.account.client_settings.disableViaMobile" @change="onChangeDisableViaMobile" text="「モバイルからの投稿」フラグを付けない"/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="web" v-show="page == 'web'">
|
<section class="web" v-show="page == 'web'">
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
|
|
||||||
<section class="notification" v-show="page == 'notification'">
|
<section class="notification" v-show="page == 'notification'">
|
||||||
<h1>通知</h1>
|
<h1>通知</h1>
|
||||||
<mk-switch v-model="os.i.settings.auto_watch" @change="onChangeAutoWatch" text="投稿の自動ウォッチ">
|
<mk-switch v-model="os.i.account.settings.auto_watch" @change="onChangeAutoWatch" text="投稿の自動ウォッチ">
|
||||||
<span>リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。</span>
|
<span>リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。</span>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -107,7 +107,7 @@ export default Vue.extend({
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
onScroll() {
|
onScroll() {
|
||||||
if ((this as any).os.i.client_settings.fetchOnScroll !== false) {
|
if ((this as any).os.i.account.client_settings.fetchOnScroll !== false) {
|
||||||
const current = window.scrollY + window.innerHeight;
|
const current = window.scrollY + window.innerHeight;
|
||||||
if (current > document.body.offsetHeight - 8) this.more();
|
if (current > document.body.offsetHeight - 8) this.more();
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,9 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if ((this as any).os.isSignedIn) {
|
if ((this as any).os.isSignedIn) {
|
||||||
const ago = (new Date().getTime() - new Date((this as any).os.i.last_used_at).getTime()) / 1000
|
const ago = (new Date().getTime() - new Date((this as any).os.i.account.last_used_at).getTime()) / 1000
|
||||||
const isHisasiburi = ago >= 3600;
|
const isHisasiburi = ago >= 3600;
|
||||||
(this as any).os.i.last_used_at = new Date();
|
(this as any).os.i.account.last_used_at = new Date();
|
||||||
if (isHisasiburi) {
|
if (isHisasiburi) {
|
||||||
(this.$refs.welcomeback as any).style.display = 'block';
|
(this.$refs.welcomeback as any).style.display = 'block';
|
||||||
(this.$refs.main as any).style.overflow = 'hidden';
|
(this.$refs.main as any).style.overflow = 'hidden';
|
||||||
|
|
|
@ -24,8 +24,8 @@ export default Vue.extend({
|
||||||
computed: {
|
computed: {
|
||||||
withGradient(): boolean {
|
withGradient(): boolean {
|
||||||
return (this as any).os.isSignedIn
|
return (this as any).os.isSignedIn
|
||||||
? (this as any).os.i.client_settings.gradientWindowHeader != null
|
? (this as any).os.i.account.client_settings.gradientWindowHeader != null
|
||||||
? (this as any).os.i.client_settings.gradientWindowHeader
|
? (this as any).os.i.account.client_settings.gradientWindowHeader
|
||||||
: false
|
: false
|
||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,8 +92,8 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
withGradient(): boolean {
|
withGradient(): boolean {
|
||||||
return (this as any).os.isSignedIn
|
return (this as any).os.isSignedIn
|
||||||
? (this as any).os.i.client_settings.gradientWindowHeader != null
|
? (this as any).os.i.account.client_settings.gradientWindowHeader != null
|
||||||
? (this as any).os.i.client_settings.gradientWindowHeader
|
? (this as any).os.i.account.client_settings.gradientWindowHeader
|
||||||
: false
|
: false
|
||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<p class="name">{{ user.name }}</p>
|
<p class="name">{{ user.name }}</p>
|
||||||
<p class="username">@{{ user.username }}</p>
|
<p class="username">@{{ user.username }}</p>
|
||||||
<p class="location" v-if="user.profile.location">%fa:map-marker%{{ user.profile.location }}</p>
|
<p class="location" v-if="user.account.profile.location">%fa:map-marker%{{ user.account.profile.location }}</p>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<router-link :to="`/${user.username}`" :data-active="$parent.page == 'home'">%fa:home%概要</router-link>
|
<router-link :to="`/${user.username}`" :data-active="$parent.page == 'home'">%fa:home%概要</router-link>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<x-profile :user="user"/>
|
<x-profile :user="user"/>
|
||||||
<x-photos :user="user"/>
|
<x-photos :user="user"/>
|
||||||
<x-followers-you-know v-if="os.isSignedIn && os.i.id != user.id" :user="user"/>
|
<x-followers-you-know v-if="os.isSignedIn && os.i.id != user.id" :user="user"/>
|
||||||
<p>%i18n:desktop.tags.mk-user.last-used-at%: <b><mk-time :time="user.last_used_at"/></b></p>
|
<p>%i18n:desktop.tags.mk-user.last-used-at%: <b><mk-time :time="user.account.last_used_at"/></b></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<main>
|
<main>
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
<p v-if="!user.is_muted"><a @click="mute">%i18n:desktop.tags.mk-user.mute%</a></p>
|
<p v-if="!user.is_muted"><a @click="mute">%i18n:desktop.tags.mk-user.mute%</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="description" v-if="user.description">{{ user.description }}</div>
|
<div class="description" v-if="user.description">{{ user.description }}</div>
|
||||||
<div class="birthday" v-if="user.profile.birthday">
|
<div class="birthday" v-if="user.account.profile.birthday">
|
||||||
<p>%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
|
<p>%fa:birthday-cake%{{ user.account.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="twitter" v-if="user.twitter">
|
<div class="twitter" v-if="user.account.twitter">
|
||||||
<p>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screen_name}`" target="_blank">@{{ user.twitter.screen_name }}</a></p>
|
<p>%fa:B twitter%<a :href="`https://twitter.com/${user.account.twitter.screen_name}`" target="_blank">@{{ user.account.twitter.screen_name }}</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<p class="posts-count">%fa:angle-right%<a>{{ user.posts_count }}</a><b>投稿</b></p>
|
<p class="posts-count">%fa:angle-right%<a>{{ user.posts_count }}</a><b>投稿</b></p>
|
||||||
|
@ -31,7 +31,7 @@ export default Vue.extend({
|
||||||
props: ['user'],
|
props: ['user'],
|
||||||
computed: {
|
computed: {
|
||||||
age(): number {
|
age(): number {
|
||||||
return age(this.user.profile.birthday);
|
return age(this.user.account.profile.birthday);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -144,7 +144,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
// Draw map
|
// Draw map
|
||||||
if (this.p.geo) {
|
if (this.p.geo) {
|
||||||
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.client_settings.showMaps : true;
|
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.client_settings.showMaps : true;
|
||||||
if (shouldShowMap) {
|
if (shouldShowMap) {
|
||||||
(this as any).os.getGoogleMaps().then(maps => {
|
(this as any).os.getGoogleMaps().then(maps => {
|
||||||
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
||||||
|
|
|
@ -111,7 +111,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
post() {
|
post() {
|
||||||
this.posting = true;
|
this.posting = true;
|
||||||
const viaMobile = (this as any).os.i.client_settings.disableViaMobile !== true;
|
const viaMobile = (this as any).os.i.account.client_settings.disableViaMobile !== true;
|
||||||
(this as any).api('posts/create', {
|
(this as any).api('posts/create', {
|
||||||
text: this.text == '' ? undefined : this.text,
|
text: this.text == '' ? undefined : this.text,
|
||||||
media_ids: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
media_ids: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<header>
|
||||||
<router-link class="name" :to="`/${p.user.username}`">{{ p.user.name }}</router-link>
|
<router-link class="name" :to="`/${p.user.username}`">{{ p.user.name }}</router-link>
|
||||||
<span class="is-bot" v-if="p.user.is_bot">bot</span>
|
<span class="is-bot" v-if="p.user.account.is_bot">bot</span>
|
||||||
<span class="username">@{{ p.user.username }}</span>
|
<span class="username">@{{ p.user.username }}</span>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="mobile" v-if="p.via_mobile">%fa:mobile-alt%</span>
|
<span class="mobile" v-if="p.via_mobile">%fa:mobile-alt%</span>
|
||||||
|
@ -137,7 +137,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
// Draw map
|
// Draw map
|
||||||
if (this.p.geo) {
|
if (this.p.geo) {
|
||||||
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.client_settings.showMaps : true;
|
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.account.client_settings.showMaps : true;
|
||||||
if (shouldShowMap) {
|
if (shouldShowMap) {
|
||||||
(this as any).os.getGoogleMaps().then(maps => {
|
(this as any).os.getGoogleMaps().then(maps => {
|
||||||
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
const uluru = new maps.LatLng(this.p.geo.latitude, this.p.geo.longitude);
|
||||||
|
|
|
@ -57,9 +57,9 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ago = (new Date().getTime() - new Date((this as any).os.i.last_used_at).getTime()) / 1000
|
const ago = (new Date().getTime() - new Date((this as any).os.i.account.last_used_at).getTime()) / 1000
|
||||||
const isHisasiburi = ago >= 3600;
|
const isHisasiburi = ago >= 3600;
|
||||||
(this as any).os.i.last_used_at = new Date();
|
(this as any).os.i.account.last_used_at = new Date();
|
||||||
if (isHisasiburi) {
|
if (isHisasiburi) {
|
||||||
(this.$refs.welcomeback as any).style.display = 'block';
|
(this.$refs.welcomeback as any).style.display = 'block';
|
||||||
(this.$refs.main as any).style.overflow = 'hidden';
|
(this.$refs.main as any).style.overflow = 'hidden';
|
||||||
|
|
|
@ -82,8 +82,8 @@ export default Vue.extend({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if ((this as any).os.i.client_settings.mobile_home == null) {
|
if ((this as any).os.i.account.client_settings.mobile_home == null) {
|
||||||
Vue.set((this as any).os.i.client_settings, 'mobile_home', [{
|
Vue.set((this as any).os.i.account.client_settings, 'mobile_home', [{
|
||||||
name: 'calendar',
|
name: 'calendar',
|
||||||
id: 'a', data: {}
|
id: 'a', data: {}
|
||||||
}, {
|
}, {
|
||||||
|
@ -105,14 +105,14 @@ export default Vue.extend({
|
||||||
name: 'version',
|
name: 'version',
|
||||||
id: 'g', data: {}
|
id: 'g', data: {}
|
||||||
}]);
|
}]);
|
||||||
this.widgets = (this as any).os.i.client_settings.mobile_home;
|
this.widgets = (this as any).os.i.account.client_settings.mobile_home;
|
||||||
this.saveHome();
|
this.saveHome();
|
||||||
} else {
|
} else {
|
||||||
this.widgets = (this as any).os.i.client_settings.mobile_home;
|
this.widgets = (this as any).os.i.account.client_settings.mobile_home;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$watch('os.i.client_settings', i => {
|
this.$watch('os.i.account.client_settings', i => {
|
||||||
this.widgets = (this as any).os.i.client_settings.mobile_home;
|
this.widgets = (this as any).os.i.account.client_settings.mobile_home;
|
||||||
}, {
|
}, {
|
||||||
deep: true
|
deep: true
|
||||||
});
|
});
|
||||||
|
@ -157,15 +157,15 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
onHomeUpdated(data) {
|
onHomeUpdated(data) {
|
||||||
if (data.home) {
|
if (data.home) {
|
||||||
(this as any).os.i.client_settings.mobile_home = data.home;
|
(this as any).os.i.account.client_settings.mobile_home = data.home;
|
||||||
this.widgets = data.home;
|
this.widgets = data.home;
|
||||||
} else {
|
} else {
|
||||||
const w = (this as any).os.i.client_settings.mobile_home.find(w => w.id == data.id);
|
const w = (this as any).os.i.account.client_settings.mobile_home.find(w => w.id == data.id);
|
||||||
if (w != null) {
|
if (w != null) {
|
||||||
w.data = data.data;
|
w.data = data.data;
|
||||||
this.$refs[w.id][0].preventSave = true;
|
this.$refs[w.id][0].preventSave = true;
|
||||||
this.$refs[w.id][0].props = w.data;
|
this.$refs[w.id][0].props = w.data;
|
||||||
this.widgets = (this as any).os.i.client_settings.mobile_home;
|
this.widgets = (this as any).os.i.account.client_settings.mobile_home;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -194,7 +194,7 @@ export default Vue.extend({
|
||||||
this.saveHome();
|
this.saveHome();
|
||||||
},
|
},
|
||||||
saveHome() {
|
saveHome() {
|
||||||
(this as any).os.i.client_settings.mobile_home = this.widgets;
|
(this as any).os.i.account.client_settings.mobile_home = this.widgets;
|
||||||
(this as any).api('i/update_mobile_home', {
|
(this as any).api('i/update_mobile_home', {
|
||||||
home: this.widgets
|
home: this.widgets
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,9 +53,9 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.name = (this as any).os.i.name;
|
this.name = (this as any).os.i.name;
|
||||||
this.location = (this as any).os.i.profile.location;
|
this.location = (this as any).os.i.account.profile.location;
|
||||||
this.description = (this as any).os.i.description;
|
this.description = (this as any).os.i.description;
|
||||||
this.birthday = (this as any).os.i.profile.birthday;
|
this.birthday = (this as any).os.i.account.profile.birthday;
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
document.title = 'Misskey | %i18n:mobile.tags.mk-profile-setting-page.title%';
|
document.title = 'Misskey | %i18n:mobile.tags.mk-profile-setting-page.title%';
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="description">{{ user.description }}</div>
|
<div class="description">{{ user.description }}</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<p class="location" v-if="user.profile.location">
|
<p class="location" v-if="user.account.profile.location">
|
||||||
%fa:map-marker%{{ user.profile.location }}
|
%fa:map-marker%{{ user.account.profile.location }}
|
||||||
</p>
|
</p>
|
||||||
<p class="birthday" v-if="user.profile.birthday">
|
<p class="birthday" v-if="user.account.profile.birthday">
|
||||||
%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)
|
%fa:birthday-cake%{{ user.account.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
|
@ -74,7 +74,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
age(): number {
|
age(): number {
|
||||||
return age(this.user.profile.birthday);
|
return age(this.user.account.profile.birthday);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<x-followers-you-know :user="user"/>
|
<x-followers-you-know :user="user"/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<p>%i18n:mobile.tags.mk-user-overview.last-used-at%: <b><mk-time :time="user.last_used_at"/></b></p>
|
<p>%i18n:mobile.tags.mk-user-overview.last-used-at%: <b><mk-time :time="user.account.last_used_at"/></b></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<form @submit.prevent="onSubmit">
|
<form @submit.prevent="onSubmit">
|
||||||
<input v-model="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="ユーザー名" autofocus required @change="onUsernameChange"/>
|
<input v-model="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="ユーザー名" autofocus required @change="onUsernameChange"/>
|
||||||
<input v-model="password" type="password" placeholder="パスワード" required/>
|
<input v-model="password" type="password" placeholder="パスワード" required/>
|
||||||
<input v-if="user && user.two_factor_enabled" v-model="token" type="number" placeholder="トークン" required/>
|
<input v-if="user && user.account.two_factor_enabled" v-model="token" type="number" placeholder="トークン" required/>
|
||||||
<button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</button>
|
<button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</button>
|
||||||
</form>
|
</form>
|
||||||
<div>
|
<div>
|
||||||
|
@ -70,7 +70,7 @@ export default Vue.extend({
|
||||||
(this as any).api('signin', {
|
(this as any).api('signin', {
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
token: this.user && this.user.two_factor_enabled ? this.token : undefined
|
token: this.user && this.user.account.two_factor_enabled ? this.token : undefined
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
|
|
@ -81,12 +81,6 @@ props:
|
||||||
desc:
|
desc:
|
||||||
ja: "自分がこのユーザーをミュートしているか"
|
ja: "自分がこのユーザーをミュートしているか"
|
||||||
en: "Whether you muted this user"
|
en: "Whether you muted this user"
|
||||||
- name: "last_used_at"
|
|
||||||
type: "date"
|
|
||||||
optional: false
|
|
||||||
desc:
|
|
||||||
ja: "最終利用日時"
|
|
||||||
en: "The last used date of this user"
|
|
||||||
- name: "posts_count"
|
- name: "posts_count"
|
||||||
type: "number"
|
type: "number"
|
||||||
optional: false
|
optional: false
|
||||||
|
@ -111,6 +105,20 @@ props:
|
||||||
desc:
|
desc:
|
||||||
ja: "ドライブの容量(bytes)"
|
ja: "ドライブの容量(bytes)"
|
||||||
en: "The capacity of drive of this user (bytes)"
|
en: "The capacity of drive of this user (bytes)"
|
||||||
|
- name: "account"
|
||||||
|
type: "object"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "このサーバーにおけるアカウント"
|
||||||
|
en: "The account of this user on this server"
|
||||||
|
defName: "account"
|
||||||
|
def:
|
||||||
|
- name: "last_used_at"
|
||||||
|
type: "date"
|
||||||
|
optional: false
|
||||||
|
desc:
|
||||||
|
ja: "最終利用日時"
|
||||||
|
en: "The last used date of this user"
|
||||||
- name: "is_bot"
|
- name: "is_bot"
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
optional: true
|
optional: true
|
||||||
|
|
50
test/api.js
50
test/api.js
|
@ -30,7 +30,7 @@ const async = fn => (done) => {
|
||||||
|
|
||||||
const request = (endpoint, params, me) => new Promise((ok, ng) => {
|
const request = (endpoint, params, me) => new Promise((ok, ng) => {
|
||||||
const auth = me ? {
|
const auth = me ? {
|
||||||
i: me.token
|
i: me.account.token
|
||||||
} : {};
|
} : {};
|
||||||
|
|
||||||
_chai.request(server)
|
_chai.request(server)
|
||||||
|
@ -136,9 +136,11 @@ describe('API', () => {
|
||||||
describe('i/update', () => {
|
describe('i/update', () => {
|
||||||
it('アカウント設定を更新できる', async(async () => {
|
it('アカウント設定を更新できる', async(async () => {
|
||||||
const me = await insertSakurako({
|
const me = await insertSakurako({
|
||||||
|
account: {
|
||||||
profile: {
|
profile: {
|
||||||
gender: 'female'
|
gender: 'female'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const myName = '大室櫻子';
|
const myName = '大室櫻子';
|
||||||
|
@ -153,10 +155,10 @@ describe('API', () => {
|
||||||
res.should.have.status(200);
|
res.should.have.status(200);
|
||||||
res.body.should.be.a('object');
|
res.body.should.be.a('object');
|
||||||
res.body.should.have.property('name').eql(myName);
|
res.body.should.have.property('name').eql(myName);
|
||||||
res.body.should.have.property('profile').a('object');
|
res.body.should.have.nested.property('account.profile').a('object');
|
||||||
res.body.should.have.nested.property('profile.location').eql(myLocation);
|
res.body.should.have.nested.property('account.profile.location').eql(myLocation);
|
||||||
res.body.should.have.nested.property('profile.birthday').eql(myBirthday);
|
res.body.should.have.nested.property('account.profile.birthday').eql(myBirthday);
|
||||||
res.body.should.have.nested.property('profile.gender').eql('female');
|
res.body.should.have.nested.property('account.profile.gender').eql('female');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('名前を空白にできない', async(async () => {
|
it('名前を空白にできない', async(async () => {
|
||||||
|
@ -176,8 +178,8 @@ describe('API', () => {
|
||||||
}, me);
|
}, me);
|
||||||
res.should.have.status(200);
|
res.should.have.status(200);
|
||||||
res.body.should.be.a('object');
|
res.body.should.be.a('object');
|
||||||
res.body.should.have.property('profile').a('object');
|
res.body.should.have.nested.property('account.profile').a('object');
|
||||||
res.body.should.have.nested.property('profile.birthday').eql(null);
|
res.body.should.have.nested.property('account.profile.birthday').eql(null);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('不正な誕生日の形式で怒られる', async(async () => {
|
it('不正な誕生日の形式で怒られる', async(async () => {
|
||||||
|
@ -764,7 +766,7 @@ describe('API', () => {
|
||||||
const me = await insertSakurako();
|
const me = await insertSakurako();
|
||||||
const res = await _chai.request(server)
|
const res = await _chai.request(server)
|
||||||
.post('/drive/files/create')
|
.post('/drive/files/create')
|
||||||
.field('i', me.token)
|
.field('i', me.account.token)
|
||||||
.attach('file', fs.readFileSync(__dirname + '/resources/Lenna.png'), 'Lenna.png');
|
.attach('file', fs.readFileSync(__dirname + '/resources/Lenna.png'), 'Lenna.png');
|
||||||
res.should.have.status(200);
|
res.should.have.status(200);
|
||||||
res.body.should.be.a('object');
|
res.body.should.be.a('object');
|
||||||
|
@ -1138,27 +1140,47 @@ describe('API', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function deepAssign(destination, ...sources) {
|
||||||
|
for (const source of sources) {
|
||||||
|
for (const key in source) {
|
||||||
|
const destinationChild = destination[key];
|
||||||
|
|
||||||
|
if (typeof destinationChild === 'object' && destinationChild != null) {
|
||||||
|
deepAssign(destinationChild, source[key]);
|
||||||
|
} else {
|
||||||
|
destination[key] = source[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
function insertSakurako(opts) {
|
function insertSakurako(opts) {
|
||||||
return db.get('users').insert(Object.assign({
|
return db.get('users').insert(deepAssign({
|
||||||
token: '!00000000000000000000000000000000',
|
|
||||||
username: 'sakurako',
|
username: 'sakurako',
|
||||||
username_lower: 'sakurako',
|
username_lower: 'sakurako',
|
||||||
|
account: {
|
||||||
|
token: '!00000000000000000000000000000000',
|
||||||
password: '$2a$08$FnHXg3tP.M/kINWgQSXNqeoBsiVrkj.ecXX8mW9rfBzMRkibYfjYy', // HimawariDaisuki06160907
|
password: '$2a$08$FnHXg3tP.M/kINWgQSXNqeoBsiVrkj.ecXX8mW9rfBzMRkibYfjYy', // HimawariDaisuki06160907
|
||||||
profile: {},
|
profile: {},
|
||||||
settings: {},
|
settings: {},
|
||||||
client_settings: {}
|
client_settings: {}
|
||||||
|
}
|
||||||
}, opts));
|
}, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertHimawari(opts) {
|
function insertHimawari(opts) {
|
||||||
return db.get('users').insert(Object.assign({
|
return db.get('users').insert(deepAssign({
|
||||||
token: '!00000000000000000000000000000001',
|
|
||||||
username: 'himawari',
|
username: 'himawari',
|
||||||
username_lower: 'himawari',
|
username_lower: 'himawari',
|
||||||
|
account: {
|
||||||
|
token: '!00000000000000000000000000000001',
|
||||||
password: '$2a$08$OPESxR2RE/ZijjGanNKk6ezSqGFitqsbZqTjWUZPLhORMKxHCbc4O', // ilovesakurako
|
password: '$2a$08$OPESxR2RE/ZijjGanNKk6ezSqGFitqsbZqTjWUZPLhORMKxHCbc4O', // ilovesakurako
|
||||||
profile: {},
|
profile: {},
|
||||||
settings: {},
|
settings: {},
|
||||||
client_settings: {}
|
client_settings: {}
|
||||||
|
}
|
||||||
}, opts));
|
}, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1171,14 +1193,14 @@ function insertDriveFile(opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertDriveFolder(opts) {
|
function insertDriveFolder(opts) {
|
||||||
return db.get('drive_folders').insert(Object.assign({
|
return db.get('drive_folders').insert(deepAssign({
|
||||||
name: 'my folder',
|
name: 'my folder',
|
||||||
parent_id: null
|
parent_id: null
|
||||||
}, opts));
|
}, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertApp(opts) {
|
function insertApp(opts) {
|
||||||
return db.get('apps').insert(Object.assign({
|
return db.get('apps').insert(deepAssign({
|
||||||
name: 'my app',
|
name: 'my app',
|
||||||
secret: 'mysecret'
|
secret: 'mysecret'
|
||||||
}, opts));
|
}, opts));
|
||||||
|
|
41
tools/migration/shell.1522038492.user-account.js
Normal file
41
tools/migration/shell.1522038492.user-account.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
db.users.dropIndex({ token: 1 });
|
||||||
|
|
||||||
|
db.users.find({}).forEach(function(user) {
|
||||||
|
print(user._id);
|
||||||
|
db.users.update({ _id: user._id }, {
|
||||||
|
$unset: {
|
||||||
|
email: '',
|
||||||
|
links: '',
|
||||||
|
password: '',
|
||||||
|
token: '',
|
||||||
|
twitter: '',
|
||||||
|
line: '',
|
||||||
|
profile: '',
|
||||||
|
last_used_at: '',
|
||||||
|
is_bot: '',
|
||||||
|
is_pro: '',
|
||||||
|
two_factor_secret: '',
|
||||||
|
two_factor_enabled: '',
|
||||||
|
client_settings: '',
|
||||||
|
settings: ''
|
||||||
|
},
|
||||||
|
$set: {
|
||||||
|
account: {
|
||||||
|
email: user.email,
|
||||||
|
links: user.links,
|
||||||
|
password: user.password,
|
||||||
|
token: user.token,
|
||||||
|
twitter: user.twitter,
|
||||||
|
line: user.line,
|
||||||
|
profile: user.profile,
|
||||||
|
last_used_at: user.last_used_at,
|
||||||
|
is_bot: user.is_bot,
|
||||||
|
is_pro: user.is_pro,
|
||||||
|
two_factor_secret: user.two_factor_secret,
|
||||||
|
two_factor_enabled: user.two_factor_enabled,
|
||||||
|
client_settings: user.client_settings,
|
||||||
|
settings: user.settings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, false, false);
|
||||||
|
});
|
Loading…
Reference in a new issue