Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
50e917d232 | |||
ccd14e0462 | |||
d0c0104546 | |||
cd34ade638 | |||
3f91e33a8c | |||
17cc996288 | |||
385776dc0f | |||
e52278c371 | |||
7ffc8c1eda | |||
1359615c82 | |||
7a7a56940c |
@ -15,7 +15,8 @@ jobs:
|
|||||||
executor: docker
|
executor: docker
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- setup_remote_docker
|
- setup_remote_docker:
|
||||||
|
version: 19.03.13
|
||||||
- run:
|
- run:
|
||||||
name: Build
|
name: Build
|
||||||
command: |
|
command: |
|
||||||
|
@ -609,6 +609,8 @@ desktop: "デスクトップ"
|
|||||||
clip: "クリップ"
|
clip: "クリップ"
|
||||||
createNew: "新規作成"
|
createNew: "新規作成"
|
||||||
optional: "任意"
|
optional: "任意"
|
||||||
|
createNewClip: "新しいクリップを作成"
|
||||||
|
public: "パブリック"
|
||||||
|
|
||||||
_mfm:
|
_mfm:
|
||||||
cheatSheet: "MFMチートシート"
|
cheatSheet: "MFMチートシート"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||||
"version": "12.57.0",
|
"version": "12.57.4",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -786,7 +786,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
isPublic: {
|
isPublic: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
label: this.$t('public')
|
label: this.$t('public'),
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
@ -60,7 +60,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
isPublic: {
|
isPublic: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
label: this.$t('public')
|
label: this.$t('public'),
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
@ -10,7 +10,7 @@ import { ApiError } from '../../error';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['account', 'notes', 'clips'],
|
tags: ['account', 'notes', 'clips'],
|
||||||
|
|
||||||
requireCredential: true as const,
|
requireCredential: false as const,
|
||||||
|
|
||||||
kind: 'read:account',
|
kind: 'read:account',
|
||||||
|
|
||||||
@ -45,13 +45,16 @@ export const meta = {
|
|||||||
export default define(meta, async (ps, user) => {
|
export default define(meta, async (ps, user) => {
|
||||||
const clip = await Clips.findOne({
|
const clip = await Clips.findOne({
|
||||||
id: ps.clipId,
|
id: ps.clipId,
|
||||||
userId: user.id
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (clip == null) {
|
if (clip == null) {
|
||||||
throw new ApiError(meta.errors.noSuchClip);
|
throw new ApiError(meta.errors.noSuchClip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!clip.isPublic && (user == null || (clip.userId !== user.id))) {
|
||||||
|
throw new ApiError(meta.errors.noSuchClip);
|
||||||
|
}
|
||||||
|
|
||||||
const clipQuery = ClipNotes.createQueryBuilder('joining')
|
const clipQuery = ClipNotes.createQueryBuilder('joining')
|
||||||
.select('joining.noteId')
|
.select('joining.noteId')
|
||||||
.where('joining.clipId = :clipId', { clipId: clip.id });
|
.where('joining.clipId = :clipId', { clipId: clip.id });
|
||||||
@ -61,8 +64,10 @@ export default define(meta, async (ps, user) => {
|
|||||||
.leftJoinAndSelect('note.user', 'user')
|
.leftJoinAndSelect('note.user', 'user')
|
||||||
.setParameters(clipQuery.getParameters());
|
.setParameters(clipQuery.getParameters());
|
||||||
|
|
||||||
|
if (user) {
|
||||||
generateVisibilityQuery(query, user);
|
generateVisibilityQuery(query, user);
|
||||||
generateMutedUserQuery(query, user);
|
generateMutedUserQuery(query, user);
|
||||||
|
}
|
||||||
|
|
||||||
const notes = await query
|
const notes = await query
|
||||||
.take(ps.limit!)
|
.take(ps.limit!)
|
||||||
|
@ -7,7 +7,7 @@ import { Clips } from '../../../../models';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['clips', 'account'],
|
tags: ['clips', 'account'],
|
||||||
|
|
||||||
requireCredential: true as const,
|
requireCredential: false as const,
|
||||||
|
|
||||||
kind: 'read:account',
|
kind: 'read:account',
|
||||||
|
|
||||||
@ -30,12 +30,15 @@ export default define(meta, async (ps, me) => {
|
|||||||
// Fetch the clip
|
// Fetch the clip
|
||||||
const clip = await Clips.findOne({
|
const clip = await Clips.findOne({
|
||||||
id: ps.clipId,
|
id: ps.clipId,
|
||||||
userId: me.id,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (clip == null) {
|
if (clip == null) {
|
||||||
throw new ApiError(meta.errors.noSuchClip);
|
throw new ApiError(meta.errors.noSuchClip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!clip.isPublic && (me == null || (clip.userId !== me.id))) {
|
||||||
|
throw new ApiError(meta.errors.noSuchClip);
|
||||||
|
}
|
||||||
|
|
||||||
return await Clips.pack(clip);
|
return await Clips.pack(clip);
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,7 @@ import packFeed from './feed';
|
|||||||
import { fetchMeta } from '../../misc/fetch-meta';
|
import { fetchMeta } from '../../misc/fetch-meta';
|
||||||
import { genOpenapiSpec } from '../api/openapi/gen-spec';
|
import { genOpenapiSpec } from '../api/openapi/gen-spec';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import { Users, Notes, Emojis, UserProfiles, Pages, Channels } from '../../models';
|
import { Users, Notes, Emojis, UserProfiles, Pages, Channels, Clips } from '../../models';
|
||||||
import parseAcct from '../../misc/acct/parse';
|
import parseAcct from '../../misc/acct/parse';
|
||||||
import getNoteSummary from '../../misc/get-note-summary';
|
import getNoteSummary from '../../misc/get-note-summary';
|
||||||
import { ensure } from '../../prelude/ensure';
|
import { ensure } from '../../prelude/ensure';
|
||||||
@ -298,6 +298,28 @@ router.get('/@:user/pages/:page', async ctx => {
|
|||||||
ctx.status = 404;
|
ctx.status = 404;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Clip
|
||||||
|
router.get('/clips/:clip', async ctx => {
|
||||||
|
const clip = await Clips.findOne({
|
||||||
|
id: ctx.params.clip,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (clip) {
|
||||||
|
const _clip = await Clips.pack(clip);
|
||||||
|
const meta = await fetchMeta();
|
||||||
|
await ctx.render('clip', {
|
||||||
|
clip: _clip,
|
||||||
|
instanceName: meta.name || 'Misskey'
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.set('Cache-Control', 'public, max-age=180');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.status = 404;
|
||||||
|
});
|
||||||
|
|
||||||
// Channel
|
// Channel
|
||||||
router.get('/channels/:channel', async ctx => {
|
router.get('/channels/:channel', async ctx => {
|
||||||
const channel = await Channels.findOne({
|
const channel = await Channels.findOne({
|
||||||
|
30
src/server/web/views/clip.pug
Normal file
30
src/server/web/views/clip.pug
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
extends ./base
|
||||||
|
|
||||||
|
block vars
|
||||||
|
- const user = clip.user;
|
||||||
|
- const title = clip.name;
|
||||||
|
- const url = `${config.url}/clips/${clip.id}`;
|
||||||
|
|
||||||
|
block title
|
||||||
|
= `${title} | ${instanceName}`
|
||||||
|
|
||||||
|
block desc
|
||||||
|
meta(name='description' content= clip.description)
|
||||||
|
|
||||||
|
block og
|
||||||
|
meta(property='og:type' content='article')
|
||||||
|
meta(property='og:title' content= title)
|
||||||
|
meta(property='og:description' content= clip.description)
|
||||||
|
meta(property='og:url' content= url)
|
||||||
|
meta(property='og:image' content= user.avatarUrl)
|
||||||
|
|
||||||
|
block meta
|
||||||
|
meta(name='misskey:user-username' content=user.username)
|
||||||
|
meta(name='misskey:user-id' content=user.id)
|
||||||
|
meta(name='misskey:clip-id' content=clip.id)
|
||||||
|
|
||||||
|
meta(name='twitter:card' content='summary')
|
||||||
|
|
||||||
|
// todo
|
||||||
|
if user.twitter
|
||||||
|
meta(name='twitter:creator' content=`@${user.twitter.screenName}`)
|
Reference in New Issue
Block a user