fix ogp rendering and refactor
This commit is contained in:
		
							parent
							
								
									ce51ef5df5
								
							
						
					
					
						commit
						d338ea2591
					
				
					 10 changed files with 51 additions and 37 deletions
				
			
		|  | @ -1,6 +1,6 @@ | |||
| import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm'; | ||||
| import { DriveFile } from './drive-file.js'; | ||||
| import { id } from '../id.js'; | ||||
| import { DriveFile } from './drive-file.js'; | ||||
| 
 | ||||
| @Entity() | ||||
| @Index(['usernameLower', 'host'], { unique: true }) | ||||
|  | @ -207,7 +207,7 @@ export class User { | |||
| 
 | ||||
| 	@Column('boolean', { | ||||
| 		default: false, | ||||
| 		comment: 'Whether to show users replying to other users in the timeline' | ||||
| 		comment: 'Whether to show users replying to other users in the timeline', | ||||
| 	}) | ||||
| 	public showTimelineReplies: boolean; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| import { EntityRepository, Repository, In, Not } from 'typeorm'; | ||||
| import Ajv from 'ajv'; | ||||
| import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; | ||||
| import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js'; | ||||
| import config from '@/config/index.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { awaitAll, Promiseable } from '@/prelude/await-all.js'; | ||||
|  | @ -9,8 +8,9 @@ import { populateEmojis } from '@/misc/populate-emojis.js'; | |||
| import { getAntennas } from '@/misc/antenna-cache.js'; | ||||
| import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; | ||||
| import { Cache } from '@/misc/cache.js'; | ||||
| import { Instance } from '../entities/instance.js'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Instance } from '../entities/instance.js'; | ||||
| import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js'; | ||||
| 
 | ||||
| const userInstanceCache = new Cache<Instance | null>(1000 * 60 * 60 * 3); | ||||
| 
 | ||||
|  | @ -112,7 +112,7 @@ export const UserRepository = db.getRepository(User).extend({ | |||
| 		const joinings = await UserGroupJoinings.findBy({ userId: userId }); | ||||
| 
 | ||||
| 		const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message') | ||||
| 			.where(`message.groupId = :groupId`, { groupId: j.userGroupId }) | ||||
| 			.where('message.groupId = :groupId', { groupId: j.userGroupId }) | ||||
| 			.andWhere('message.userId != :userId', { userId: userId }) | ||||
| 			.andWhere('NOT (:userId = ANY(message.reads))', { userId: userId }) | ||||
| 			.andWhere('message.createdAt > :joinedAt', { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない
 | ||||
|  | @ -204,8 +204,18 @@ export const UserRepository = db.getRepository(User).extend({ | |||
| 		); | ||||
| 	}, | ||||
| 
 | ||||
| 	getAvatarUrl(user: User): string { | ||||
| 		// TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング
 | ||||
| 	async getAvatarUrl(user: User): Promise<string> { | ||||
| 		if (user.avatar) { | ||||
| 			return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); | ||||
| 		} else if (user.avatarId) { | ||||
| 			const avatar = await DriveFiles.findOneByOrFail({ id: user.avatarId }); | ||||
| 			return DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id); | ||||
| 		} else { | ||||
| 			return this.getIdenticonUrl(user.id); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	getAvatarUrlSync(user: User): string { | ||||
| 		if (user.avatar) { | ||||
| 			return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); | ||||
| 		} else { | ||||
|  | @ -223,7 +233,7 @@ export const UserRepository = db.getRepository(User).extend({ | |||
| 		options?: { | ||||
| 			detail?: D, | ||||
| 			includeSecrets?: boolean, | ||||
| 		} | ||||
| 		}, | ||||
| 	): Promise<IsMeAndIsUserDetailed<ExpectsMe, D>> { | ||||
| 		const opts = Object.assign({ | ||||
| 			detail: false, | ||||
|  | @ -274,7 +284,7 @@ export const UserRepository = db.getRepository(User).extend({ | |||
| 			name: user.name, | ||||
| 			username: user.username, | ||||
| 			host: user.host, | ||||
| 			avatarUrl: this.getAvatarUrl(user), | ||||
| 			avatarUrl: this.getAvatarUrlSync(user), | ||||
| 			avatarBlurhash: user.avatar?.blurhash || null, | ||||
| 			avatarColor: null, // 後方互換性のため
 | ||||
| 			isAdmin: user.isAdmin || falsy, | ||||
|  | @ -283,7 +293,7 @@ export const UserRepository = db.getRepository(User).extend({ | |||
| 			isCat: user.isCat || falsy, | ||||
| 			instance: user.host ? userInstanceCache.fetch(user.host, | ||||
| 				() => Instances.findOneBy({ host: user.host! }), | ||||
| 				v => v != null | ||||
| 				v => v != null, | ||||
| 			).then(instance => instance ? { | ||||
| 				name: instance.name, | ||||
| 				softwareName: instance.softwareName, | ||||
|  | @ -403,7 +413,7 @@ export const UserRepository = db.getRepository(User).extend({ | |||
| 		options?: { | ||||
| 			detail?: D, | ||||
| 			includeSecrets?: boolean, | ||||
| 		} | ||||
| 		}, | ||||
| 	): Promise<IsUserDetailed<D>[]> { | ||||
| 		return Promise.all(users.map(u => this.pack(u, me, options))); | ||||
| 	}, | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ import { publishMainStream } from '@/services/stream.js'; | |||
| export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) { | ||||
| 	if (redirect) { | ||||
| 		//#region Cookie
 | ||||
| 		ctx.cookies.set('igi', user.token, { | ||||
| 		ctx.cookies.set('igi', user.token!, { | ||||
| 			path: '/', | ||||
| 			// SEE: https://github.com/koajs/koa/issues/974
 | ||||
| 			// When using a SSL proxy it should be configured to add the "X-Forwarded-Proto: https" header
 | ||||
|  |  | |||
|  | @ -10,23 +10,23 @@ import mount from 'koa-mount'; | |||
| import koaLogger from 'koa-logger'; | ||||
| import * as slow from 'koa-slow'; | ||||
| 
 | ||||
| import activityPub from './activitypub.js'; | ||||
| import nodeinfo from './nodeinfo.js'; | ||||
| import wellKnown from './well-known.js'; | ||||
| import { IsNull } from 'typeorm'; | ||||
| import config from '@/config/index.js'; | ||||
| import apiServer from './api/index.js'; | ||||
| import fileServer from './file/index.js'; | ||||
| import proxyServer from './proxy/index.js'; | ||||
| import webServer from './web/index.js'; | ||||
| import Logger from '@/services/logger.js'; | ||||
| import { envOption } from '../env.js'; | ||||
| import { UserProfiles, Users } from '@/models/index.js'; | ||||
| import { genIdenticon } from '@/misc/gen-identicon.js'; | ||||
| import { createTemp } from '@/misc/create-temp.js'; | ||||
| import { publishMainStream } from '@/services/stream.js'; | ||||
| import * as Acct from '@/misc/acct.js'; | ||||
| import { envOption } from '../env.js'; | ||||
| import activityPub from './activitypub.js'; | ||||
| import nodeinfo from './nodeinfo.js'; | ||||
| import wellKnown from './well-known.js'; | ||||
| import apiServer from './api/index.js'; | ||||
| import fileServer from './file/index.js'; | ||||
| import proxyServer from './proxy/index.js'; | ||||
| import webServer from './web/index.js'; | ||||
| import { initializeStreamingServer } from './api/streaming.js'; | ||||
| import { IsNull } from 'typeorm'; | ||||
| 
 | ||||
| export const serverLogger = new Logger('server', 'gray', false); | ||||
| 
 | ||||
|  | @ -81,7 +81,7 @@ router.get('/avatar/@:acct', async ctx => { | |||
| 	}); | ||||
| 
 | ||||
| 	if (user) { | ||||
| 		ctx.redirect(Users.getAvatarUrl(user)); | ||||
| 		ctx.redirect(Users.getAvatarUrlSync(user)); | ||||
| 	} else { | ||||
| 		ctx.redirect('/static-assets/user-unknown.png'); | ||||
| 	} | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| import { Feed } from 'feed'; | ||||
| import { In, IsNull } from 'typeorm'; | ||||
| import config from '@/config/index.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
| import { Notes, DriveFiles, UserProfiles } from '@/models/index.js'; | ||||
| import { In, IsNull } from 'typeorm'; | ||||
| import { Notes, DriveFiles, UserProfiles, Users } from '@/models/index.js'; | ||||
| 
 | ||||
| export default async function(user: User) { | ||||
| 	const author = { | ||||
|  | @ -29,7 +29,7 @@ export default async function(user: User) { | |||
| 		generator: 'Misskey', | ||||
| 		description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, | ||||
| 		link: author.link, | ||||
| 		image: user.avatarUrl ? user.avatarUrl : undefined, | ||||
| 		image: await Users.getAvatarUrl(user), | ||||
| 		feedLinks: { | ||||
| 			json: `${author.link}.json`, | ||||
| 			atom: `${author.link}.atom`, | ||||
|  |  | |||
|  | @ -11,20 +11,20 @@ import send from 'koa-send'; | |||
| import favicon from 'koa-favicon'; | ||||
| import views from 'koa-views'; | ||||
| import { createBullBoard } from '@bull-board/api'; | ||||
| import { BullAdapter  } from '@bull-board/api/bullAdapter.js'; | ||||
| import { BullAdapter } from '@bull-board/api/bullAdapter.js'; | ||||
| import { KoaAdapter } from '@bull-board/koa'; | ||||
| 
 | ||||
| import packFeed from './feed.js'; | ||||
| import { IsNull } from 'typeorm'; | ||||
| import { fetchMeta } from '@/misc/fetch-meta.js'; | ||||
| import { genOpenapiSpec } from '../api/openapi/gen-spec.js'; | ||||
| import config from '@/config/index.js'; | ||||
| import { Users, Notes, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '@/models/index.js'; | ||||
| import * as Acct from '@/misc/acct.js'; | ||||
| import { getNoteSummary } from '@/misc/get-note-summary.js'; | ||||
| import { queues } from '@/queue/queues.js'; | ||||
| import { genOpenapiSpec } from '../api/openapi/gen-spec.js'; | ||||
| import { urlPreviewHandler } from './url-preview.js'; | ||||
| import { manifestHandler } from './manifest.js'; | ||||
| import { queues } from '@/queue/queues.js'; | ||||
| import { IsNull } from 'typeorm'; | ||||
| import packFeed from './feed.js'; | ||||
| 
 | ||||
| const _filename = fileURLToPath(import.meta.url); | ||||
| const _dirname = dirname(_filename); | ||||
|  | @ -127,7 +127,7 @@ router.get('/twemoji/(.*)', async ctx => { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`); | ||||
| 	ctx.set('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\''); | ||||
| 
 | ||||
| 	await send(ctx as any, path, { | ||||
| 		root: `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/`, | ||||
|  | @ -235,6 +235,7 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => { | |||
| 
 | ||||
| 		await ctx.render('user', { | ||||
| 			user, profile, me, | ||||
| 			avatarUrl: await Users.getAvatarUrl(user), | ||||
| 			sub: ctx.params.sub, | ||||
| 			instanceName: meta.name || 'Misskey', | ||||
| 			icon: meta.iconUrl, | ||||
|  | @ -274,6 +275,7 @@ router.get('/notes/:note', async (ctx, next) => { | |||
| 		await ctx.render('note', { | ||||
| 			note: _note, | ||||
| 			profile, | ||||
| 			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: note.userId })), | ||||
| 			// TODO: Let locale changeable by instance setting
 | ||||
| 			summary: getNoteSummary(_note), | ||||
| 			instanceName: meta.name || 'Misskey', | ||||
|  | @ -315,6 +317,7 @@ router.get('/@:user/pages/:page', async (ctx, next) => { | |||
| 		await ctx.render('page', { | ||||
| 			page: _page, | ||||
| 			profile, | ||||
| 			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: page.userId })), | ||||
| 			instanceName: meta.name || 'Misskey', | ||||
| 			icon: meta.iconUrl, | ||||
| 			themeColor: meta.themeColor, | ||||
|  | @ -346,6 +349,7 @@ router.get('/clips/:clip', async (ctx, next) => { | |||
| 		await ctx.render('clip', { | ||||
| 			clip: _clip, | ||||
| 			profile, | ||||
| 			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: clip.userId })), | ||||
| 			instanceName: meta.name || 'Misskey', | ||||
| 			icon: meta.iconUrl, | ||||
| 			themeColor: meta.themeColor, | ||||
|  | @ -370,6 +374,7 @@ router.get('/gallery/:post', async (ctx, next) => { | |||
| 		await ctx.render('gallery-post', { | ||||
| 			post: _post, | ||||
| 			profile, | ||||
| 			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: post.userId })), | ||||
| 			instanceName: meta.name || 'Misskey', | ||||
| 			icon: meta.iconUrl, | ||||
| 			themeColor: meta.themeColor, | ||||
|  | @ -434,7 +439,7 @@ router.get('/cli', async ctx => { | |||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| const override = (source: string, target: string, depth: number = 0) => | ||||
| const override = (source: string, target: string, depth = 0) => | ||||
| 	[, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/'); | ||||
| 
 | ||||
| router.get('/flush', async ctx => { | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ block og | |||
| 	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) | ||||
| 	meta(property='og:image'       content= avatarUrl) | ||||
| 
 | ||||
| block meta | ||||
| 	if profile.noCrawle | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ block og | |||
| 	meta(property='og:title'       content= title) | ||||
| 	meta(property='og:description' content= summary) | ||||
| 	meta(property='og:url'         content= url) | ||||
| 	meta(property='og:image'       content= user.avatarUrl) | ||||
| 	meta(property='og:image'       content= avatarUrl) | ||||
| 
 | ||||
| block meta | ||||
| 	if user.host || isRenote || profile.noCrawle | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ block og | |||
| 	meta(property='og:title'       content= title) | ||||
| 	meta(property='og:description' content= page.summary) | ||||
| 	meta(property='og:url'         content= url) | ||||
| 	meta(property='og:image'       content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : user.avatarUrl) | ||||
| 	meta(property='og:image'       content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : avatarUrl) | ||||
| 
 | ||||
| block meta | ||||
| 	if profile.noCrawle | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ extends ./base | |||
| block vars | ||||
| 	- const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`; | ||||
| 	- const url = `${config.url}/@${(user.host ? `${user.username}@${user.host}` : user.username)}`; | ||||
| 	- const img = user.avatarUrl || null; | ||||
| 
 | ||||
| block title | ||||
| 	= `${title} | ${instanceName}` | ||||
|  | @ -16,7 +15,7 @@ block og | |||
| 	meta(property='og:title'       content= title) | ||||
| 	meta(property='og:description' content= profile.description) | ||||
| 	meta(property='og:url'         content= url) | ||||
| 	meta(property='og:image'       content= img) | ||||
| 	meta(property='og:image'       content= avatarUrl) | ||||
| 
 | ||||
| block meta | ||||
| 	if user.host || profile.noCrawle | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue