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

@@ -95,6 +95,8 @@ import PoliticalOfficeHistory from './falukant/log/political_office_history.js';
import ElectionHistory from './falukant/log/election_history.js';
import Underground from './falukant/data/underground.js';
import UndergroundType from './falukant/type/underground.js';
import Blog from './community/blog.js';
import BlogPost from './community/blog_post.js';
export default function setupAssociations() {
// RoomType 1:n Room
@@ -758,4 +760,12 @@ export default function setupAssociations() {
foreignKey: 'victimId',
as: 'victimUndergrounds'
});
// Blog associations
Blog.belongsTo(User, { foreignKey: 'user_id', as: 'owner' });
User.hasMany(Blog, { foreignKey: 'user_id', as: 'blogs' });
BlogPost.belongsTo(Blog, { foreignKey: 'blog_id', as: 'blog' });
Blog.hasMany(BlogPost, { foreignKey: 'blog_id', as: 'posts' });
BlogPost.belongsTo(User, { foreignKey: 'user_id', as: 'author' });
User.hasMany(BlogPost, { foreignKey: 'user_id', as: 'blogPosts' });
}

View File

@@ -0,0 +1,60 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../utils/sequelize.js';
class Blog extends Model {}
Blog.init({
userId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'user_id'
},
title: {
type: DataTypes.STRING(255),
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
// 'public' or 'logged_in'
visibility: {
type: DataTypes.STRING(20),
allowNull: false,
defaultValue: 'public',
},
ageMin: {
type: DataTypes.INTEGER,
allowNull: true,
field: 'age_min'
},
ageMax: {
type: DataTypes.INTEGER,
allowNull: true,
field: 'age_max'
},
// 'm' | 'f' | null; comma-separated for future-proofing (e.g., 'm,f')
genders: {
type: DataTypes.STRING(10),
allowNull: true,
},
createdAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
field: 'updated_at'
}
}, {
sequelize,
modelName: 'Blog',
tableName: 'blog',
schema: 'community',
timestamps: true,
underscored: true,
});
export default Blog;

View File

@@ -0,0 +1,44 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../utils/sequelize.js';
class BlogPost extends Model {}
BlogPost.init({
blogId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'blog_id'
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'user_id'
},
title: {
type: DataTypes.STRING(255),
allowNull: false,
},
content: {
type: DataTypes.TEXT,
allowNull: false,
},
createdAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
field: 'updated_at'
}
}, {
sequelize,
modelName: 'BlogPost',
tableName: 'blog_post',
schema: 'community',
timestamps: true,
underscored: true,
});
export default BlogPost;

View File

@@ -34,6 +34,8 @@ import MessageHistory from './forum/message_history.js';
import MessageImage from './forum/message_image.js';
import ForumForumPermission from './forum/forum_forum_permission.js';
import Friendship from './community/friendship.js';
import Blog from './community/blog.js';
import BlogPost from './community/blog_post.js';
import FalukantUser from './falukant/data/user.js';
import RegionType from './falukant/type/region.js';
@@ -140,6 +142,8 @@ const models = {
MessageHistory,
MessageImage,
Friendship,
Blog,
BlogPost,
// Falukant core
RegionType,