feat: Implement blog and blog post models, routes, and services

- Added Blog and BlogPost models with necessary fields and relationships.
- Created blogRouter for handling blog-related API endpoints including CRUD operations.
- Developed BlogService for business logic related to blogs and posts, including sharing functionality.
- Implemented API client methods for frontend to interact with blog-related endpoints.
- Added internationalization support for blog-related text in English and German.
- Created Vue components for blog editing, listing, and viewing, including a rich text editor for post content.
- Enhanced user experience with form validations and dynamic visibility settings based on user input.
This commit is contained in:
Torsten Schulz (local)
2025-08-18 13:41:37 +02:00
parent 19ee6ba0a1
commit 53c748a074
27 changed files with 1342 additions and 19 deletions

View File

@@ -467,6 +467,33 @@ class SocialNetworkService extends BaseService {
return imagePath;
}
// Public variant used by blog: allow access if the image's folder is visible to 'everyone'.
async getImageFilePathPublicByHash(hash) {
const image = await Image.findOne({ where: { hash } });
if (!image) {
throw new Error('Image not found');
}
const folder = await Folder.findOne({ where: { id: image.folderId } });
if (!folder) {
throw new Error('Folder not found');
}
const everyone = await ImageVisibilityType.findOne({ where: { description: 'everyone' } });
if (!everyone) {
throw new Error('Visibility type not found');
}
const hasEveryone = await FolderImageVisibility.findOne({ where: { folderId: folder.id, visibilityTypeId: everyone.id } });
if (!hasEveryone) {
const err = new Error('Access denied');
err.status = 403;
throw err;
}
const imagePath = this.buildFilePath(image.hash, 'user');
if (!fs.existsSync(imagePath)) {
throw new Error(`File "${imagePath}" not found`);
}
return imagePath;
}
async checkUserImageAccess(userId, imageId) {
const image = await Image.findByPk(imageId);
if (image.userId === userId) {