summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-07-20 02:40:37 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-07-20 02:40:37 +0900
commitec2b1ec3f0035466585d9cc2a7842e519e14e31a (patch)
tree9a8e7c40e7b068d24b362a72552e456b1adddba7 /src
parent4.24.1 (diff)
downloadsharkey-ec2b1ec3f0035466585d9cc2a7842e519e14e31a.tar.gz
sharkey-ec2b1ec3f0035466585d9cc2a7842e519e14e31a.tar.bz2
sharkey-ec2b1ec3f0035466585d9cc2a7842e519e14e31a.zip
#1334
Diffstat (limited to 'src')
-rw-r--r--src/client/app/common/views/components/media-list.vue24
-rw-r--r--src/client/app/desktop/views/components/drive.file.vue12
-rw-r--r--src/client/app/desktop/views/components/media-image.vue30
-rw-r--r--src/client/app/mobile/views/components/media-image.vue30
-rw-r--r--src/docs/api/entities/drive-file.yaml7
-rw-r--r--src/models/drive-file.ts1
-rw-r--r--src/remote/activitypub/models/image.ts4
-rw-r--r--src/remote/activitypub/renderer/image.ts5
-rw-r--r--src/remote/activitypub/renderer/person.ts12
-rw-r--r--src/server/activitypub.ts8
-rw-r--r--src/server/api/endpoints/drive/files/create.ts10
-rw-r--r--src/server/api/endpoints/drive/files/update.ts59
-rw-r--r--src/services/drive/add-file.ts6
-rw-r--r--src/services/drive/upload-from-url.ts4
14 files changed, 168 insertions, 44 deletions
diff --git a/src/client/app/common/views/components/media-list.vue b/src/client/app/common/views/components/media-list.vue
index 2f8a1943ad..cdfc2c8d3c 100644
--- a/src/client/app/common/views/components/media-list.vue
+++ b/src/client/app/common/views/components/media-list.vue
@@ -46,33 +46,45 @@ export default Vue.extend({
display grid
grid-gap 4px
+ > *
+ overflow hidden
+ border-radius 4px
+
&[data-count="1"]
grid-template-rows 1fr
+
&[data-count="2"]
grid-template-columns 1fr 1fr
grid-template-rows 1fr
+
&[data-count="3"]
grid-template-columns 1fr 0.5fr
grid-template-rows 1fr 1fr
- :nth-child(1)
+
+ > *:nth-child(1)
grid-row 1 / 3
- :nth-child(3)
+
+ > *:nth-child(3)
grid-column 2 / 3
grid-row 2 / 3
+
&[data-count="4"]
grid-template-columns 1fr 1fr
grid-template-rows 1fr 1fr
- :nth-child(1)
+ > *:nth-child(1)
grid-column 1 / 2
grid-row 1 / 2
- :nth-child(2)
+
+ > *:nth-child(2)
grid-column 2 / 3
grid-row 1 / 2
- :nth-child(3)
+
+ > *:nth-child(3)
grid-column 1 / 2
grid-row 2 / 3
- :nth-child(4)
+
+ > *:nth-child(4)
grid-column 2 / 3
grid-row 2 / 3
diff --git a/src/client/app/desktop/views/components/drive.file.vue b/src/client/app/desktop/views/components/drive.file.vue
index 86addb1318..11700d4966 100644
--- a/src/client/app/desktop/views/components/drive.file.vue
+++ b/src/client/app/desktop/views/components/drive.file.vue
@@ -69,6 +69,11 @@ export default Vue.extend({
action: this.rename
}, {
type: 'item',
+ text: this.file.isSensitive ? '%i18n:@contextmenu.unmark-as-sensitive%' : '%i18n:@contextmenu.mark-as-sensitive%',
+ icon: this.file.isSensitive ? '%fa:R eye%' : '%fa:R eye-slash%',
+ action: this.toggleSensitive
+ }, null, {
+ type: 'item',
text: '%i18n:@contextmenu.copy-url%',
icon: '%fa:link%',
action: this.copyUrl
@@ -149,6 +154,13 @@ export default Vue.extend({
});
},
+ toggleSensitive() {
+ (this as any).api('drive/files/update', {
+ fileId: this.file.id,
+ isSensitive: !this.file.isSensitive
+ });
+ },
+
copyUrl() {
copyToClipboard(this.file.url);
(this as any).apis.dialog({
diff --git a/src/client/app/desktop/views/components/media-image.vue b/src/client/app/desktop/views/components/media-image.vue
index b98a4707ec..42a31c4c2d 100644
--- a/src/client/app/desktop/views/components/media-image.vue
+++ b/src/client/app/desktop/views/components/media-image.vue
@@ -1,5 +1,11 @@
<template>
-<a class="mk-media-image"
+<div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide" @click="hide = false">
+ <div>
+ <b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
+ <span>%i18n:@click-to-show%</span>
+ </div>
+</div>
+<a class="lcjomzwbohoelkxsnuqjiaccdbdfiazy" v-else
:href="image.url"
@mousemove="onMousemove"
@mouseleave="onMouseleave"
@@ -21,6 +27,10 @@ export default Vue.extend({
},
raw: {
default: false
+ },
+ hide: {
+ type: Boolean,
+ default: true
}
},
computed: {
@@ -56,16 +66,30 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
-.mk-media-image
+.lcjomzwbohoelkxsnuqjiaccdbdfiazy
display block
cursor zoom-in
overflow hidden
width 100%
height 100%
background-position center
- border-radius 4px
&:not(:hover)
background-size cover
+.ldwbgwstjsdgcjruamauqdrffetqudry
+ display flex
+ justify-content center
+ align-items center
+ background #111
+ color #fff
+
+ > div
+ display table-cell
+ text-align center
+ font-size 12px
+
+ > b
+ display block
+
</style>
diff --git a/src/client/app/mobile/views/components/media-image.vue b/src/client/app/mobile/views/components/media-image.vue
index c2f9c66e84..1042404c98 100644
--- a/src/client/app/mobile/views/components/media-image.vue
+++ b/src/client/app/mobile/views/components/media-image.vue
@@ -1,5 +1,11 @@
<template>
-<a class="mk-media-image" :href="image.url" target="_blank" :style="style" :title="image.name"></a>
+<div class="qjewsnkgzzxlxtzncydssfbgjibiehcy" v-if="image.isSensitive && hide" @click="hide = false">
+ <div>
+ <b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
+ <span>%i18n:@click-to-show%</span>
+ </div>
+</div>
+<a class="gqnyydlzavusgskkfvwvjiattxdzsqlf" v-else :href="image.url" target="_blank" :style="style" :title="image.name"></a>
</template>
<script lang="ts">
@@ -13,6 +19,10 @@ export default Vue.extend({
},
raw: {
default: false
+ },
+ hide: {
+ type: Boolean,
+ default: true
}
},
computed: {
@@ -35,13 +45,27 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
-.mk-media-image
+.gqnyydlzavusgskkfvwvjiattxdzsqlf
display block
overflow hidden
width 100%
height 100%
background-position center
background-size cover
- border-radius 4px
+
+.qjewsnkgzzxlxtzncydssfbgjibiehcy
+ display flex
+ justify-content center
+ align-items center
+ background #111
+ color #fff
+
+ > div
+ display table-cell
+ text-align center
+ font-size 12px
+
+ > b
+ display block
</style>
diff --git a/src/docs/api/entities/drive-file.yaml b/src/docs/api/entities/drive-file.yaml
index bb39e90112..2d14c6e1f5 100644
--- a/src/docs/api/entities/drive-file.yaml
+++ b/src/docs/api/entities/drive-file.yaml
@@ -81,3 +81,10 @@ props:
desc:
ja: "フォルダ"
en: "The folder of this file"
+
+ sensitive:
+ type: "boolean"
+ optional: true
+ desc:
+ ja: "このメディアが「閲覧注意」(NSFW)かどうか"
+ en: "Whether this media is NSFW"
diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts
index 2bdf38f484..3a0390f792 100644
--- a/src/models/drive-file.ts
+++ b/src/models/drive-file.ts
@@ -33,6 +33,7 @@ export type IMetadata = {
url?: string;
deletedAt?: Date;
isMetaOnly?: boolean;
+ isSensitive?: boolean;
};
export type IDriveFile = {
diff --git a/src/remote/activitypub/models/image.ts b/src/remote/activitypub/models/image.ts
index fb17a7c9e5..8b33187ef5 100644
--- a/src/remote/activitypub/models/image.ts
+++ b/src/remote/activitypub/models/image.ts
@@ -16,7 +16,7 @@ export async function createImage(actor: IRemoteUser, value: any): Promise<IDriv
return null;
}
- const image = await new Resolver().resolve(value);
+ const image = await new Resolver().resolve(value) as any;
if (image.url == null) {
throw new Error('invalid image: url not privided');
@@ -24,7 +24,7 @@ export async function createImage(actor: IRemoteUser, value: any): Promise<IDriv
log(`Creating the Image: ${image.url}`);
- return await uploadFromUrl(image.url, actor, null, image.url);
+ return await uploadFromUrl(image.url, actor, null, image.url, image.sensitive);
}
/**
diff --git a/src/remote/activitypub/renderer/image.ts b/src/remote/activitypub/renderer/image.ts
index cf91ce3a0c..69bddd9188 100644
--- a/src/remote/activitypub/renderer/image.ts
+++ b/src/remote/activitypub/renderer/image.ts
@@ -1,7 +1,8 @@
import config from '../../../config';
import { IDriveFile } from '../../../models/drive-file';
-export default (fileId: IDriveFile['_id']) => ({
+export default (file: IDriveFile) => ({
type: 'Image',
- url: `${config.drive_url}/${fileId}`
+ url: `${config.drive_url}/${file._id}`,
+ sensitive: file.metadata.isSensitive
});
diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts
index d4b3f40e41..7d828f97ae 100644
--- a/src/remote/activitypub/renderer/person.ts
+++ b/src/remote/activitypub/renderer/person.ts
@@ -4,10 +4,16 @@ import config from '../../../config';
import { ILocalUser } from '../../../models/user';
import toHtml from '../../../mfm/html';
import parse from '../../../mfm/parse';
+import DriveFile from '../../../models/drive-file';
-export default (user: ILocalUser) => {
+export default async (user: ILocalUser) => {
const id = `${config.url}/users/${user._id}`;
+ const [avatar, banner] = await Promise.all([
+ DriveFile.findOne({ _id: user.avatarId }),
+ DriveFile.findOne({ _id: user.bannerId })
+ ]);
+
return {
type: user.isBot ? 'Service' : 'Person',
id,
@@ -18,8 +24,8 @@ export default (user: ILocalUser) => {
preferredUsername: user.username,
name: user.name,
summary: toHtml(parse(user.description)),
- icon: user.avatarId && renderImage(user.avatarId),
- image: user.bannerId && renderImage(user.bannerId),
+ icon: user.avatarId && renderImage(avatar),
+ image: user.bannerId && renderImage(banner),
manuallyApprovesFollowers: user.isLocked,
publicKey: renderKey(user)
};
diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index 0448ae61b8..17cd34ee6f 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -111,13 +111,13 @@ router.get('/users/:user/publickey', async ctx => {
});
// user
-function userInfo(ctx: Router.IRouterContext, user: IUser) {
+async function userInfo(ctx: Router.IRouterContext, user: IUser) {
if (user === null) {
ctx.status = 404;
return;
}
- ctx.body = pack(renderPerson(user as ILocalUser));
+ ctx.body = pack(await renderPerson(user as ILocalUser));
}
router.get('/users/:user', async ctx => {
@@ -128,7 +128,7 @@ router.get('/users/:user', async ctx => {
host: null
});
- userInfo(ctx, user);
+ await userInfo(ctx, user);
});
router.get('/@:user', async (ctx, next) => {
@@ -139,7 +139,7 @@ router.get('/@:user', async (ctx, next) => {
host: null
});
- userInfo(ctx, user);
+ await userInfo(ctx, user);
});
//#endregion
diff --git a/src/server/api/endpoints/drive/files/create.ts b/src/server/api/endpoints/drive/files/create.ts
index ca12be9104..1c5506f6c4 100644
--- a/src/server/api/endpoints/drive/files/create.ts
+++ b/src/server/api/endpoints/drive/files/create.ts
@@ -29,6 +29,14 @@ export const meta = {
desc: {
ja: 'フォルダID'
}
+ }),
+
+ isSensitive: $.bool.optional.note({
+ default: false,
+ desc: {
+ ja: 'このメディアが「閲覧注意」(NSFW)かどうか',
+ en: 'Whether this media is NSFW'
+ }
})
}
};
@@ -68,7 +76,7 @@ export default async (file: any, params: any, user: ILocalUser): Promise<any> =>
try {
// Create file
- const driveFile = await create(user, file.path, name, null, ps.folderId);
+ const driveFile = await create(user, file.path, name, null, ps.folderId, false, false, null, null, ps.isSensitive);
cleanup();
diff --git a/src/server/api/endpoints/drive/files/update.ts b/src/server/api/endpoints/drive/files/update.ts
index 396bc97694..bac04bae78 100644
--- a/src/server/api/endpoints/drive/files/update.ts
+++ b/src/server/api/endpoints/drive/files/update.ts
@@ -3,6 +3,7 @@ import DriveFolder from '../../../../../models/drive-folder';
import DriveFile, { validateFileName, pack } from '../../../../../models/drive-file';
import { publishDriveStream } from '../../../../../stream';
import { ILocalUser } from '../../../../../models/user';
+import getParams from '../../../get-params';
export const meta = {
desc: {
@@ -12,18 +13,48 @@ export const meta = {
requireCredential: true,
- kind: 'drive-write'
+ kind: 'drive-write',
+
+ params: {
+ fileId: $.type(ID).note({
+ desc: {
+ ja: '対象のファイルID'
+ }
+ }),
+
+ folderId: $.type(ID).optional.nullable.note({
+ default: undefined,
+ desc: {
+ ja: 'フォルダID'
+ }
+ }),
+
+ name: $.str.optional.pipe(validateFileName).note({
+ default: undefined,
+ desc: {
+ ja: 'ファイル名',
+ en: 'Name of the file'
+ }
+ }),
+
+ isSensitive: $.bool.optional.note({
+ default: undefined,
+ desc: {
+ ja: 'このメディアが「閲覧注意」(NSFW)かどうか',
+ en: 'Whether this media is NSFW'
+ }
+ })
+ }
};
export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
- // Get 'fileId' parameter
- const [fileId, fileIdErr] = $.type(ID).get(params.fileId);
- if (fileIdErr) return rej('invalid fileId param');
+ const [ps, psErr] = getParams(meta, params);
+ if (psErr) return rej(psErr);
// Fetch file
const file = await DriveFile
.findOne({
- _id: fileId,
+ _id: ps.fileId,
'metadata.userId': user._id
});
@@ -31,23 +62,18 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
return rej('file-not-found');
}
- // Get 'name' parameter
- const [name, nameErr] = $.str.optional.pipe(validateFileName).get(params.name);
- if (nameErr) return rej('invalid name param');
- if (name) file.filename = name;
+ if (ps.name) file.filename = ps.name;
- // Get 'folderId' parameter
- const [folderId, folderIdErr] = $.type(ID).optional.nullable.get(params.folderId);
- if (folderIdErr) return rej('invalid folderId param');
+ if (ps.isSensitive) file.metadata.isSensitive = ps.isSensitive;
- if (folderId !== undefined) {
- if (folderId === null) {
+ if (ps.folderId !== undefined) {
+ if (ps.folderId === null) {
file.metadata.folderId = null;
} else {
// Fetch folder
const folder = await DriveFolder
.findOne({
- _id: folderId,
+ _id: ps.folderId,
userId: user._id
});
@@ -62,7 +88,8 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
await DriveFile.update(file._id, {
$set: {
filename: file.filename,
- 'metadata.folderId': file.metadata.folderId
+ 'metadata.folderId': file.metadata.folderId,
+ 'metadata.isSensitive': file.metadata.isSensitive
}
});
diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts
index 57c6589176..73d5b4962c 100644
--- a/src/services/drive/add-file.ts
+++ b/src/services/drive/add-file.ts
@@ -83,7 +83,8 @@ export default async function(
force: boolean = false,
metaOnly: boolean = false,
url: string = null,
- uri: string = null
+ uri: string = null,
+ sensitive = false
): Promise<IDriveFile> {
// Calc md5 hash
const calcHash = new Promise<string>((res, rej) => {
@@ -258,7 +259,8 @@ export default async function(
folderId: folder !== null ? folder._id : null,
comment: comment,
properties: properties,
- isMetaOnly: metaOnly
+ isMetaOnly: metaOnly,
+ isSensitive: sensitive
} as IMetadata;
if (url !== null) {
diff --git a/src/services/drive/upload-from-url.ts b/src/services/drive/upload-from-url.ts
index 711889ea41..4e297d3bb1 100644
--- a/src/services/drive/upload-from-url.ts
+++ b/src/services/drive/upload-from-url.ts
@@ -13,7 +13,7 @@ import * as mongodb from 'mongodb';
const log = debug('misskey:drive:upload-from-url');
-export default async (url: string, user: IUser, folderId: mongodb.ObjectID = null, uri: string = null): Promise<IDriveFile> => {
+export default async (url: string, user: IUser, folderId: mongodb.ObjectID = null, uri: string = null, sensitive = false): Promise<IDriveFile> => {
log(`REQUESTED: ${url}`);
let name = URL.parse(url).pathname.split('/').pop();
@@ -48,7 +48,7 @@ export default async (url: string, user: IUser, folderId: mongodb.ObjectID = nul
let error;
try {
- driveFile = await create(user, path, name, null, folderId, false, config.preventCacheRemoteFiles, url, uri);
+ driveFile = await create(user, path, name, null, folderId, false, config.preventCacheRemoteFiles, url, uri, sensitive);
log(`got: ${driveFile._id}`);
} catch (e) {
error = e;