mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-18 10:36:22 +08:00
feat(server): add image resize support (#14588)
fix #13842 #### PR Dependency Tree * **PR #14588** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Images are now processed natively and converted to WebP for smaller, optimized files; Copilot and avatar attachments use the processed WebP output. * Avatar uploads accept BMP, GIF, JPEG, PNG, WebP (5MB max) and are downscaled to a standard edge. * **Error Messages / i18n** * Added localized error "Image format not supported: {format}". * **Tests** * Added end-to-end and unit tests for conversion, EXIF preservation, and upload limits. * **Chores** * Added native image-processing dependencies. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -17,6 +17,8 @@ import { isNil, omitBy } from 'lodash-es';
|
||||
import {
|
||||
CannotDeleteOwnAccount,
|
||||
type FileUpload,
|
||||
ImageFormatNotSupported,
|
||||
OneMB,
|
||||
readBufferWithLimit,
|
||||
sniffMime,
|
||||
Throttle,
|
||||
@@ -28,6 +30,7 @@ import {
|
||||
UserFeatureName,
|
||||
UserSettingsSchema,
|
||||
} from '../../models';
|
||||
import { processImage } from '../../native';
|
||||
import { Public } from '../auth/guard';
|
||||
import { sessionUser } from '../auth/service';
|
||||
import { CurrentUser } from '../auth/session';
|
||||
@@ -115,16 +118,26 @@ export class UserResolver {
|
||||
throw new UserNotFound();
|
||||
}
|
||||
|
||||
const avatarBuffer = await readBufferWithLimit(avatar.createReadStream());
|
||||
const contentType = sniffMime(avatarBuffer, avatar.mimetype);
|
||||
const avatarBuffer = await readBufferWithLimit(
|
||||
avatar.createReadStream(),
|
||||
5 * OneMB
|
||||
);
|
||||
const contentType = sniffMime(avatarBuffer, avatar.mimetype)?.toLowerCase();
|
||||
if (!contentType || !contentType.startsWith('image/')) {
|
||||
throw new Error(`Invalid file type: ${contentType || 'unknown'}`);
|
||||
throw new ImageFormatNotSupported({ format: contentType || 'unknown' });
|
||||
}
|
||||
|
||||
let processedAvatarBuffer: Buffer;
|
||||
try {
|
||||
processedAvatarBuffer = await processImage(avatarBuffer, 512, false);
|
||||
} catch {
|
||||
throw new ImageFormatNotSupported({ format: contentType });
|
||||
}
|
||||
|
||||
const avatarUrl = await this.storage.put(
|
||||
`${user.id}-avatar-${Date.now()}`,
|
||||
avatarBuffer,
|
||||
{ contentType }
|
||||
processedAvatarBuffer,
|
||||
{ contentType: 'image/webp' }
|
||||
);
|
||||
|
||||
if (user.avatarUrl) {
|
||||
|
||||
Reference in New Issue
Block a user