Implement outbox
This commit is contained in:
		
							parent
							
								
									0cb6fbea8c
								
							
						
					
					
						commit
						1f1417a0f7
					
				|  | @ -0,0 +1,7 @@ | |||
| import config from '../../../../conf'; | ||||
| 
 | ||||
| export default ({ _id, contentType }) => ({ | ||||
| 	type: 'Document', | ||||
| 	mediaType: contentType, | ||||
| 	url: `${config.drive_url}/${_id}` | ||||
| }); | ||||
|  | @ -0,0 +1,7 @@ | |||
| import config from '../../../../conf'; | ||||
| 
 | ||||
| export default tag => ({ | ||||
| 	type: 'Hashtag', | ||||
| 	href: `${config.url}/search?q=#${encodeURIComponent(tag)}`, | ||||
| 	name: '#' + tag | ||||
| }); | ||||
|  | @ -0,0 +1,6 @@ | |||
| import config from '../../../../conf'; | ||||
| 
 | ||||
| export default ({ _id }) => ({ | ||||
| 	type: 'Image', | ||||
| 	url: `${config.drive_url}/${_id}` | ||||
| }); | ||||
|  | @ -0,0 +1,9 @@ | |||
| import config from '../../../../conf'; | ||||
| import { extractPublic } from '../../../../crypto_key'; | ||||
| import { ILocalAccount } from '../../../../models/user'; | ||||
| 
 | ||||
| export default ({ username, account }) => ({ | ||||
| 	type: 'Key', | ||||
| 	owner: `${config.url}/@${username}`, | ||||
| 	publicKeyPem: extractPublic((account as ILocalAccount).keypair) | ||||
| }); | ||||
|  | @ -0,0 +1,44 @@ | |||
| import renderDocument from './document'; | ||||
| import renderHashtag from './hashtag'; | ||||
| import config from '../../../../conf'; | ||||
| import DriveFile from '../../../../models/drive-file'; | ||||
| import Post from '../../../../models/post'; | ||||
| import User from '../../../../models/user'; | ||||
| 
 | ||||
| export default async (user, post) => { | ||||
| 	const promisedFiles = DriveFile.find({ _id: { $in: post.mediaIds } }); | ||||
| 	let inReplyTo; | ||||
| 
 | ||||
| 	if (post.replyId) { | ||||
| 		const inReplyToPost = await Post.findOne({ | ||||
| 			_id: post.replyId, | ||||
| 		}); | ||||
| 
 | ||||
| 		if (inReplyToPost !== null) { | ||||
| 			const inReplyToUser = await User.findOne({ | ||||
| 				_id: post.userId, | ||||
| 			}); | ||||
| 
 | ||||
| 			if (inReplyToUser !== null) { | ||||
| 				inReplyTo = `${config.url}@${inReplyToUser.username}/${inReplyToPost._id}`; | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		inReplyTo = null; | ||||
| 	} | ||||
| 
 | ||||
| 	const attributedTo = `${config.url}/@${user.username}`; | ||||
| 
 | ||||
| 	return { | ||||
| 		id: `${attributedTo}/${post._id}`, | ||||
| 		type: 'Note', | ||||
| 		attributedTo, | ||||
| 		content: post.textHtml, | ||||
| 		published: post.createdAt.toISOString(), | ||||
| 		to: 'https://www.w3.org/ns/activitystreams#Public', | ||||
| 		cc: `${attributedTo}/followers`, | ||||
| 		inReplyTo, | ||||
| 		attachment: (await promisedFiles).map(renderDocument), | ||||
| 		tag: post.tags.map(renderHashtag) | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,6 @@ | |||
| export default (id, totalItems, orderedItems) => ({ | ||||
| 	id, | ||||
| 	type: 'OrderedCollection', | ||||
| 	totalItems, | ||||
| 	orderedItems | ||||
| }); | ||||
|  | @ -0,0 +1,20 @@ | |||
| import renderImage from './image'; | ||||
| import renderKey from './key'; | ||||
| import config from '../../../../conf'; | ||||
| 
 | ||||
| export default user => { | ||||
| 	const id = `${config.url}/@${user.username}`; | ||||
| 
 | ||||
| 	return { | ||||
| 		type: 'Person', | ||||
| 		id, | ||||
| 		inbox: `${id}/inbox`, | ||||
| 		outbox: `${id}/outbox`, | ||||
| 		preferredUsername: user.username, | ||||
| 		name: user.name, | ||||
| 		summary: user.description, | ||||
| 		icon: user.avatarId && renderImage({ _id: user.avatarId }), | ||||
| 		image: user.bannerId && renderImage({ _id: user.bannerId }), | ||||
| 		publicKey: renderKey(user) | ||||
| 	}; | ||||
| }; | ||||
|  | @ -1,14 +1,16 @@ | |||
| import * as express from 'express'; | ||||
| 
 | ||||
| import post from './post'; | ||||
| import user from './user'; | ||||
| import inbox from './inbox'; | ||||
| import outbox from './outbox'; | ||||
| import post from './post'; | ||||
| 
 | ||||
| const app = express(); | ||||
| app.disable('x-powered-by'); | ||||
| 
 | ||||
| app.use(post); | ||||
| app.use(user); | ||||
| app.use(inbox); | ||||
| app.use(outbox); | ||||
| app.use(post); | ||||
| 
 | ||||
| export default app; | ||||
|  |  | |||
|  | @ -0,0 +1,45 @@ | |||
| import * as express from 'express'; | ||||
| import context from '../../common/remote/activitypub/renderer/context'; | ||||
| import renderNote from '../../common/remote/activitypub/renderer/note'; | ||||
| import renderOrderedCollection from '../../common/remote/activitypub/renderer/ordered-collection'; | ||||
| import parseAcct from '../../common/user/parse-acct'; | ||||
| import config from '../../conf'; | ||||
| import Post from '../../models/post'; | ||||
| import User from '../../models/user'; | ||||
| 
 | ||||
| const app = express(); | ||||
| app.disable('x-powered-by'); | ||||
| 
 | ||||
| app.get('/@:user/outbox', async (req, res) => { | ||||
| 	const { username, host } = parseAcct(req.params.user); | ||||
| 	if (host !== null) { | ||||
| 		return res.sendStatus(422); | ||||
| 	} | ||||
| 
 | ||||
| 	const user = await User.findOne({ | ||||
| 		usernameLower: username.toLowerCase(), | ||||
| 		host: null | ||||
| 	}); | ||||
| 	if (user === null) { | ||||
| 		return res.sendStatus(404); | ||||
| 	} | ||||
| 
 | ||||
| 	const id = `${config.url}/@${user.username}/inbox`; | ||||
| 
 | ||||
| 	if (username !== user.username) { | ||||
| 		return res.redirect(id); | ||||
| 	} | ||||
| 
 | ||||
| 	const posts = await Post.find({ userId: user._id }, { | ||||
| 		limit: 20, | ||||
| 		sort: { _id: -1 } | ||||
| 	}); | ||||
| 
 | ||||
| 	const renderedPosts = await Promise.all(posts.map(post => renderNote(user, post))); | ||||
| 	const rendered = renderOrderedCollection(id, user.postsCount, renderedPosts); | ||||
| 	rendered['@context'] = context; | ||||
| 
 | ||||
| 	res.json(rendered); | ||||
| }); | ||||
| 
 | ||||
| export default app; | ||||
|  | @ -1,8 +1,7 @@ | |||
| import * as express from 'express'; | ||||
| import context from '../../common/remote/activitypub/context'; | ||||
| import context from '../../common/remote/activitypub/renderer/context'; | ||||
| import render from '../../common/remote/activitypub/renderer/note'; | ||||
| import parseAcct from '../../common/user/parse-acct'; | ||||
| import config from '../../conf'; | ||||
| import DriveFile from '../../models/drive-file'; | ||||
| import Post from '../../models/post'; | ||||
| import User from '../../models/user'; | ||||
| 
 | ||||
|  | @ -36,50 +35,10 @@ app.get('/@:user/:post', async (req, res, next) => { | |||
| 		return res.sendStatus(404); | ||||
| 	} | ||||
| 
 | ||||
| 	const promisedFiles = DriveFile.find({ _id: { $in: post.mediaIds } }); | ||||
| 	let inReplyTo; | ||||
| 	const rendered = await render(user, post); | ||||
| 	rendered['@context'] = context; | ||||
| 
 | ||||
| 	if (post.replyId) { | ||||
| 		const inReplyToPost = await Post.findOne({ | ||||
| 			_id: post.replyId, | ||||
| 		}); | ||||
| 
 | ||||
| 		if (inReplyToPost !== null) { | ||||
| 			const inReplyToUser = await User.findOne({ | ||||
| 				_id: post.userId, | ||||
| 			}); | ||||
| 
 | ||||
| 			if (inReplyToUser !== null) { | ||||
| 				inReplyTo = `${config.url}@${inReplyToUser.username}/${inReplyToPost._id}`; | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		inReplyTo = null; | ||||
| 	} | ||||
| 
 | ||||
| 	const attributedTo = `${config.url}/@${user.username}`; | ||||
| 
 | ||||
| 	res.json({ | ||||
| 		'@context': context, | ||||
| 		id: `${attributedTo}/${post._id}`, | ||||
| 		type: 'Note', | ||||
| 		attributedTo, | ||||
| 		content: post.textHtml, | ||||
| 		published: post.createdAt.toISOString(), | ||||
| 		to: 'https://www.w3.org/ns/activitystreams#Public', | ||||
| 		cc: `${attributedTo}/followers`, | ||||
| 		inReplyTo, | ||||
| 		attachment: (await promisedFiles).map(({ _id, contentType }) => ({ | ||||
| 			type: 'Document', | ||||
| 			mediaType: contentType, | ||||
| 			url: `${config.drive_url}/${_id}` | ||||
| 		})), | ||||
| 		tag: post.tags.map(tag => ({ | ||||
| 			type: 'Hashtag', | ||||
| 			href: `${config.url}/search?q=#${encodeURIComponent(tag)}`, | ||||
| 			name: '#' + tag | ||||
| 		})) | ||||
| 	}); | ||||
| 	res.json(rendered); | ||||
| }); | ||||
| 
 | ||||
| export default app; | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| import * as express from 'express'; | ||||
| import config from '../../conf'; | ||||
| import { extractPublic } from '../../crypto_key'; | ||||
| import context from '../../common/remote/activitypub/context'; | ||||
| import context from '../../common/remote/activitypub/renderer/context'; | ||||
| import render from '../../common/remote/activitypub/renderer/person'; | ||||
| import parseAcct from '../../common/user/parse-acct'; | ||||
| import User, { ILocalAccount } from '../../models/user'; | ||||
| import User from '../../models/user'; | ||||
| 
 | ||||
| const app = express(); | ||||
| app.disable('x-powered-by'); | ||||
|  | @ -27,34 +27,14 @@ app.get('/@:user', async (req, res, next) => { | |||
| 		return res.sendStatus(404); | ||||
| 	} | ||||
| 
 | ||||
| 	const id = `${config.url}/@${user.username}`; | ||||
| 
 | ||||
| 	if (username !== user.username) { | ||||
| 		return res.redirect(id); | ||||
| 		return res.redirect(`${config.url}/@${user.username}`); | ||||
| 	} | ||||
| 
 | ||||
| 	res.json({ | ||||
| 		'@context': context, | ||||
| 		type: 'Person', | ||||
| 		id, | ||||
| 		inbox: `${id}/inbox`, | ||||
| 		preferredUsername: user.username, | ||||
| 		name: user.name, | ||||
| 		summary: user.description, | ||||
| 		icon: user.avatarId && { | ||||
| 			type: 'Image', | ||||
| 			url: `${config.drive_url}/${user.avatarId}` | ||||
| 		}, | ||||
| 		image: user.bannerId && { | ||||
| 			type: 'Image', | ||||
| 			url: `${config.drive_url}/${user.bannerId}` | ||||
| 		}, | ||||
| 		publicKey: { | ||||
| 			type: 'Key', | ||||
| 			owner: id, | ||||
| 			publicKeyPem: extractPublic((user.account as ILocalAccount).keypair) | ||||
| 		} | ||||
| 	}); | ||||
| 	const rendered = render(user); | ||||
| 	rendered['@context'] = context; | ||||
| 
 | ||||
| 	res.json(rendered); | ||||
| }); | ||||
| 
 | ||||
| export default app; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue