diff --git a/backend/controllers/falukantController.js b/backend/controllers/falukantController.js index d9cebe3..c609f21 100644 --- a/backend/controllers/falukantController.js +++ b/backend/controllers/falukantController.js @@ -48,6 +48,16 @@ class FalukantController { this.advanceNobility = this.advanceNobility.bind(this); this.getHealth = this.getHealth.bind(this); this.healthActivity = this.healthActivity.bind(this); + this.getPoliticsOverview = this.getPoliticsOverview.bind(this); + this.getOpenPolitics = this.getOpenPolitics.bind(this); + this.getElections = this.getElections.bind(this); + this.vote = this.vote.bind(this); + this.getOpenPolitics = this.getOpenPolitics.bind(this); + this.applyForElections = this.applyForElections.bind(this); + this.getRegions = this.getRegions.bind(this); + this.renovate = this.renovate.bind(this); + this.renovateAll = this.renovateAll.bind(this); + this.createBranch = this.createBranch.bind(this); } async getUser(req, res) { @@ -117,6 +127,29 @@ class FalukantController { } } + async createBranch(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const { cityId, branchTypeId } = req.body; + const result = await FalukantService.createBranch(hashedUserId, cityId, branchTypeId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async getBranchTypes(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const result = await FalukantService.getBranchTypes(hashedUserId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + async getBranch(req, res) { try { const { userid: hashedUserId } = req.headers; @@ -325,6 +358,7 @@ class FalukantController { const result = await FalukantService.convertProposalToDirector(hashedUserId, proposalId); res.status(200).json(result); } catch (error) { + console.log(error.message, error.stack); res.status(500).json({ error: error.message }); } } @@ -482,7 +516,6 @@ class FalukantController { try { const { userid: hashedUserId } = req.headers; const result = await FalukantService.getUserHouse(hashedUserId); - console.log(result); res.status(200).json(result); } catch (error) { res.status(500).json({ error: error.message }); @@ -671,6 +704,108 @@ class FalukantController { console.log(error); } } + + async getPoliticsOverview(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const result = await FalukantService.getPoliticsOverview(hashedUserId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async getOpenPolitics(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const result = await FalukantService.getOpenPolitics(hashedUserId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async getElections(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const result = await FalukantService.getElections(hashedUserId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async vote(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const { votes } = req.body; + const result = await FalukantService.vote(hashedUserId, votes); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async getOpenPolitics(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const result = await FalukantService.getOpenPolitics(hashedUserId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async applyForElections(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const { electionIds } = req.body; + const result = await FalukantService.applyForElections(hashedUserId, electionIds); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async getRegions(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const result = await FalukantService.getRegions(hashedUserId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async renovate(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const { element } = req.body; + const result = await FalukantService.renovate(hashedUserId, element); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } + + async renovateAll(req, res) { + try { + const { userid: hashedUserId } = req.headers; + const result = await FalukantService.renovateAll(hashedUserId); + res.status(200).json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + console.log(error); + } + } } export default FalukantController; diff --git a/backend/models/associations.js b/backend/models/associations.js index 18275c7..c58ff41 100644 --- a/backend/models/associations.js +++ b/backend/models/associations.js @@ -85,434 +85,437 @@ import PoliticalOffice from './falukant/data/political_office.js'; import PoliticalOfficeBenefit from './falukant/predefine/political_office_benefit.js'; import PoliticalOfficeBenefitType from './falukant/type/political_office_benefit_type.js'; import PoliticalOfficeRequirement from './falukant/predefine/political_office_prerequisite.js'; +import PoliticalOfficePrerequisite from './falukant/predefine/political_office_prerequisite.js'; +import PoliticalOfficeHistory from './falukant/log/political_office_history.js'; +import ElectionHistory from './falukant/log/election_history.js'; export default function setupAssociations() { - // UserParam related associations - SettingsType.hasMany(UserParamType, { foreignKey: 'settingsId', as: 'user_param_types' }); - UserParamType.belongsTo(SettingsType, { foreignKey: 'settingsId', as: 'settings_type' }); - - UserParamType.hasMany(UserParam, { foreignKey: 'paramTypeId', as: 'user_params' }); - UserParam.belongsTo(UserParamType, { foreignKey: 'paramTypeId', as: 'paramType' }); - - User.hasMany(UserParam, { foreignKey: 'userId', as: 'user_params' }); - UserParam.belongsTo(User, { foreignKey: 'userId', as: 'user' }); - - UserParamValue.belongsTo(UserParamType, { foreignKey: 'userParamTypeId', as: 'user_param_value_type' }); - UserParamType.hasMany(UserParamValue, { foreignKey: 'userParamTypeId', as: 'user_param_type_value' }); - - UserRight.belongsTo(User, { foreignKey: 'userId', as: 'user_with_rights' }); - UserRight.belongsTo(UserRightType, { foreignKey: 'rightTypeId', as: 'rightType' }); - UserRightType.hasMany(UserRight, { foreignKey: 'rightTypeId', as: 'user_rights' }); - - UserParam.hasMany(UserParamVisibility, { foreignKey: 'param_id', as: 'param_visibilities' }); - UserParamVisibility.belongsTo(UserParam, { foreignKey: 'param_id', as: 'param' }); - - UserParamVisibility.belongsTo(UserParamVisibilityType, { foreignKey: 'visibility', as: 'visibility_type' }); - UserParamVisibilityType.hasMany(UserParamVisibility, { foreignKey: 'visibility', as: 'user_param_visibilities' }); - - // Interest related associations - InterestType.hasMany(InterestTranslationType, { foreignKey: 'interestsId', as: 'interest_translations' }); - InterestTranslationType.belongsTo(InterestType, { foreignKey: 'interestsId', as: 'interest_translations' }); - - InterestType.hasMany(Interest, { foreignKey: 'userinterestId', as: 'user_interest_type' }); - User.hasMany(Interest, { foreignKey: 'userId', as: 'user_interests' }); - Interest.belongsTo(InterestType, { foreignKey: 'userinterestId', as: 'interest_type' }); - Interest.belongsTo(User, { foreignKey: 'userId', as: 'interest_owner' }); - - // Folder and Image related associations - Folder.belongsTo(User, { foreignKey: 'userId' }); - User.hasMany(Folder, { foreignKey: 'userId' }); - - Folder.belongsTo(Folder, { foreignKey: 'parentId', as: 'parent' }); - Folder.hasMany(Folder, { foreignKey: 'parentId', as: 'children' }); - - Image.belongsTo(Folder, { foreignKey: 'folderId' }); - Folder.hasMany(Image, { foreignKey: 'folderId' }); - - Image.belongsTo(User, { foreignKey: 'userId' }); - User.hasMany(Image, { foreignKey: 'userId' }); - - // Image visibility associations - Folder.belongsToMany(ImageVisibilityType, { - through: FolderImageVisibility, - foreignKey: 'folderId', - otherKey: 'visibilityTypeId' - }); - ImageVisibilityType.belongsToMany(Folder, { - through: FolderImageVisibility, - foreignKey: 'visibilityTypeId', - otherKey: 'folderId' - }); - - Image.belongsToMany(ImageVisibilityType, { - through: ImageImageVisibility, - foreignKey: 'imageId', - otherKey: 'visibilityTypeId' - }); - ImageVisibilityType.belongsToMany(Image, { - through: ImageImageVisibility, - foreignKey: 'visibilityTypeId', - otherKey: 'imageId' - }); - - Folder.belongsToMany(ImageVisibilityUser, { - through: FolderVisibilityUser, - foreignKey: 'folderId', - otherKey: 'visibilityUserId' - }); - ImageVisibilityUser.belongsToMany(Folder, { - through: FolderVisibilityUser, - foreignKey: 'visibilityUserId', - otherKey: 'folderId' - }); + // UserParam related associations + SettingsType.hasMany(UserParamType, { foreignKey: 'settingsId', as: 'user_param_types' }); + UserParamType.belongsTo(SettingsType, { foreignKey: 'settingsId', as: 'settings_type' }); + + UserParamType.hasMany(UserParam, { foreignKey: 'paramTypeId', as: 'user_params' }); + UserParam.belongsTo(UserParamType, { foreignKey: 'paramTypeId', as: 'paramType' }); + + User.hasMany(UserParam, { foreignKey: 'userId', as: 'user_params' }); + UserParam.belongsTo(User, { foreignKey: 'userId', as: 'user' }); + + UserParamValue.belongsTo(UserParamType, { foreignKey: 'userParamTypeId', as: 'user_param_value_type' }); + UserParamType.hasMany(UserParamValue, { foreignKey: 'userParamTypeId', as: 'user_param_type_value' }); + + UserRight.belongsTo(User, { foreignKey: 'userId', as: 'user_with_rights' }); + UserRight.belongsTo(UserRightType, { foreignKey: 'rightTypeId', as: 'rightType' }); + UserRightType.hasMany(UserRight, { foreignKey: 'rightTypeId', as: 'user_rights' }); + + UserParam.hasMany(UserParamVisibility, { foreignKey: 'param_id', as: 'param_visibilities' }); + UserParamVisibility.belongsTo(UserParam, { foreignKey: 'param_id', as: 'param' }); + + UserParamVisibility.belongsTo(UserParamVisibilityType, { foreignKey: 'visibility', as: 'visibility_type' }); + UserParamVisibilityType.hasMany(UserParamVisibility, { foreignKey: 'visibility', as: 'user_param_visibilities' }); + + // Interest related associations + InterestType.hasMany(InterestTranslationType, { foreignKey: 'interestsId', as: 'interest_translations' }); + InterestTranslationType.belongsTo(InterestType, { foreignKey: 'interestsId', as: 'interest_translations' }); + + InterestType.hasMany(Interest, { foreignKey: 'userinterestId', as: 'user_interest_type' }); + User.hasMany(Interest, { foreignKey: 'userId', as: 'user_interests' }); + Interest.belongsTo(InterestType, { foreignKey: 'userinterestId', as: 'interest_type' }); + Interest.belongsTo(User, { foreignKey: 'userId', as: 'interest_owner' }); + + // Folder and Image related associations + Folder.belongsTo(User, { foreignKey: 'userId' }); + User.hasMany(Folder, { foreignKey: 'userId' }); + + Folder.belongsTo(Folder, { foreignKey: 'parentId', as: 'parent' }); + Folder.hasMany(Folder, { foreignKey: 'parentId', as: 'children' }); + + Image.belongsTo(Folder, { foreignKey: 'folderId' }); + Folder.hasMany(Image, { foreignKey: 'folderId' }); + + Image.belongsTo(User, { foreignKey: 'userId' }); + User.hasMany(Image, { foreignKey: 'userId' }); + + // Image visibility associations + Folder.belongsToMany(ImageVisibilityType, { + through: FolderImageVisibility, + foreignKey: 'folderId', + otherKey: 'visibilityTypeId' + }); + ImageVisibilityType.belongsToMany(Folder, { + through: FolderImageVisibility, + foreignKey: 'visibilityTypeId', + otherKey: 'folderId' + }); + + Image.belongsToMany(ImageVisibilityType, { + through: ImageImageVisibility, + foreignKey: 'imageId', + otherKey: 'visibilityTypeId' + }); + ImageVisibilityType.belongsToMany(Image, { + through: ImageImageVisibility, + foreignKey: 'visibilityTypeId', + otherKey: 'imageId' + }); + + Folder.belongsToMany(ImageVisibilityUser, { + through: FolderVisibilityUser, + foreignKey: 'folderId', + otherKey: 'visibilityUserId' + }); + ImageVisibilityUser.belongsToMany(Folder, { + through: FolderVisibilityUser, + foreignKey: 'visibilityUserId', + otherKey: 'folderId' + }); - // Guestbook related associations - User.hasMany(GuestbookEntry, { foreignKey: 'recipientId', as: 'receivedEntries' }); - User.hasMany(GuestbookEntry, { foreignKey: 'senderId', as: 'sentEntries' }); - GuestbookEntry.belongsTo(User, { foreignKey: 'recipientId', as: 'recipient' }); - GuestbookEntry.belongsTo(User, { foreignKey: 'senderId', as: 'sender' }); + // Guestbook related associations + User.hasMany(GuestbookEntry, { foreignKey: 'recipientId', as: 'receivedEntries' }); + User.hasMany(GuestbookEntry, { foreignKey: 'senderId', as: 'sentEntries' }); + GuestbookEntry.belongsTo(User, { foreignKey: 'recipientId', as: 'recipient' }); + GuestbookEntry.belongsTo(User, { foreignKey: 'senderId', as: 'sender' }); - // Forum related associations - Forum.hasMany(Title, { foreignKey: 'forumId' }); - Title.belongsTo(Forum, { foreignKey: 'forumId' }); + // Forum related associations + Forum.hasMany(Title, { foreignKey: 'forumId' }); + Title.belongsTo(Forum, { foreignKey: 'forumId' }); - Title.belongsTo(User, { foreignKey: 'createdBy', as: 'createdByUser' }); - User.hasMany(Title, { foreignKey: 'createdBy', as: 'titles' }); + Title.belongsTo(User, { foreignKey: 'createdBy', as: 'createdByUser' }); + User.hasMany(Title, { foreignKey: 'createdBy', as: 'titles' }); - Title.hasMany(Message, { foreignKey: 'titleId', as: 'messages' }); - Message.belongsTo(Title, { foreignKey: 'titleId', as: 'title' }); + Title.hasMany(Message, { foreignKey: 'titleId', as: 'messages' }); + Message.belongsTo(Title, { foreignKey: 'titleId', as: 'title' }); - Message.belongsTo(User, { foreignKey: 'createdBy', as: 'lastMessageUser' }); - User.hasMany(Message, { foreignKey: 'createdBy', as: 'userMessages' }); + Message.belongsTo(User, { foreignKey: 'createdBy', as: 'lastMessageUser' }); + User.hasMany(Message, { foreignKey: 'createdBy', as: 'userMessages' }); - Message.hasMany(MessageImage, { foreignKey: 'messageId' }); - MessageImage.belongsTo(Message, { foreignKey: 'messageId' }); + Message.hasMany(MessageImage, { foreignKey: 'messageId' }); + MessageImage.belongsTo(Message, { foreignKey: 'messageId' }); - Message.hasMany(MessageHistory, { foreignKey: 'messageId' }); - MessageHistory.belongsTo(Message, { foreignKey: 'messageId' }); + Message.hasMany(MessageHistory, { foreignKey: 'messageId' }); + MessageHistory.belongsTo(Message, { foreignKey: 'messageId' }); - Title.hasMany(TitleHistory, { foreignKey: 'titleId' }); - TitleHistory.belongsTo(Title, { foreignKey: 'titleId' }); + Title.hasMany(TitleHistory, { foreignKey: 'titleId' }); + TitleHistory.belongsTo(Title, { foreignKey: 'titleId' }); - // Forum permissions associations - Forum.hasMany(ForumUserPermission, { foreignKey: 'forumId', as: 'userPermissions' }); - ForumUserPermission.belongsTo(Forum, { foreignKey: 'forumId' }); + // Forum permissions associations + Forum.hasMany(ForumUserPermission, { foreignKey: 'forumId', as: 'userPermissions' }); + ForumUserPermission.belongsTo(Forum, { foreignKey: 'forumId' }); - User.hasMany(ForumUserPermission, { foreignKey: 'userId', as: 'userPermissions' }); - ForumUserPermission.belongsTo(User, { foreignKey: 'userId' }); + User.hasMany(ForumUserPermission, { foreignKey: 'userId', as: 'userPermissions' }); + ForumUserPermission.belongsTo(User, { foreignKey: 'userId' }); - Forum.belongsToMany(ForumPermission, { - through: ForumForumPermission, - foreignKey: 'forumId', - as: 'associatedPermissions' - }); + Forum.belongsToMany(ForumPermission, { + through: ForumForumPermission, + foreignKey: 'forumId', + as: 'associatedPermissions' + }); - ForumPermission.belongsToMany(Forum, { - through: ForumForumPermission, - foreignKey: 'permissionId', - as: 'forums' - }); + ForumPermission.belongsToMany(Forum, { + through: ForumForumPermission, + foreignKey: 'permissionId', + as: 'forums' + }); - ForumPermission.hasMany(ForumUserPermission, { foreignKey: 'permissionId' }); - ForumUserPermission.belongsTo(ForumPermission, { foreignKey: 'permissionId' }); + ForumPermission.hasMany(ForumUserPermission, { foreignKey: 'permissionId' }); + ForumUserPermission.belongsTo(ForumPermission, { foreignKey: 'permissionId' }); - Friendship.belongsTo(User, { foreignKey: 'user1Id', as: 'friendSender' }); - Friendship.belongsTo(User, { foreignKey: 'user2Id', as: 'friendReceiver' }); - User.hasMany(Friendship, { foreignKey: 'user1Id', as: 'friendSender' }); - User.hasMany(Friendship, { foreignKey: 'user2Id', as: 'friendReceiver' }); + Friendship.belongsTo(User, { foreignKey: 'user1Id', as: 'friendSender' }); + Friendship.belongsTo(User, { foreignKey: 'user2Id', as: 'friendReceiver' }); + User.hasMany(Friendship, { foreignKey: 'user1Id', as: 'friendSender' }); + User.hasMany(Friendship, { foreignKey: 'user2Id', as: 'friendReceiver' }); - User.hasMany(FalukantUser, { foreignKey: 'userId', as: 'falukantData' }); - FalukantUser.belongsTo(User, { foreignKey: 'userId', as: 'user' }); + User.hasMany(FalukantUser, { foreignKey: 'userId', as: 'falukantData' }); + FalukantUser.belongsTo(User, { foreignKey: 'userId', as: 'user' }); - RegionType.hasMany(RegionType, { foreignKey: 'parentId', as: 'children' }); - RegionType.belongsTo(RegionType, { foreignKey: 'parentId', as: 'parent' }); + RegionType.hasMany(RegionType, { foreignKey: 'parentId', as: 'children' }); + RegionType.belongsTo(RegionType, { foreignKey: 'parentId', as: 'parent' }); - RegionData.hasMany(RegionData, { foreignKey: 'parentId', as: 'children' }); - RegionData.belongsTo(RegionData, { foreignKey: 'parentId', as: 'parent' }); + RegionData.hasMany(RegionData, { foreignKey: 'parentId', as: 'children' }); + RegionData.belongsTo(RegionData, { foreignKey: 'parentId', as: 'parent' }); - RegionData.belongsTo(RegionType, { foreignKey: 'regionTypeId', as: 'regionType' }); - RegionType.hasMany(RegionData, { foreignKey: 'regionTypeId', as: 'regions' }); + RegionData.belongsTo(RegionType, { foreignKey: 'regionTypeId', as: 'regionType' }); + RegionType.hasMany(RegionData, { foreignKey: 'regionTypeId', as: 'regions' }); - FalukantUser.belongsTo(RegionData, { foreignKey: 'mainBranchRegionId', as: 'mainBranchRegion' }); - RegionData.hasMany(FalukantUser, { foreignKey: 'mainBranchRegionId', as: 'users' }); + FalukantUser.belongsTo(RegionData, { foreignKey: 'mainBranchRegionId', as: 'mainBranchRegion' }); + RegionData.hasMany(FalukantUser, { foreignKey: 'mainBranchRegionId', as: 'users' }); - FalukantCharacter.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' }); - FalukantUser.hasOne(FalukantCharacter, { foreignKey: 'userId', as: 'character' }); + FalukantCharacter.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' }); + FalukantUser.hasOne(FalukantCharacter, { foreignKey: 'userId', as: 'character' }); - FalukantCharacter.belongsTo(FalukantPredefineFirstname, { foreignKey: 'firstName', as: 'definedFirstName' }); - FalukantPredefineFirstname.hasMany(FalukantCharacter, { foreignKey: 'firstName', as: 'charactersWithFirstName' }); + FalukantCharacter.belongsTo(FalukantPredefineFirstname, { foreignKey: 'firstName', as: 'definedFirstName' }); + FalukantPredefineFirstname.hasMany(FalukantCharacter, { foreignKey: 'firstName', as: 'charactersWithFirstName' }); - FalukantCharacter.belongsTo(FalukantPredefineLastname, { foreignKey: 'lastName', as: 'definedLastName' }); - FalukantPredefineLastname.hasMany(FalukantCharacter, { foreignKey: 'lastName', as: 'charactersWithLastName' }); + FalukantCharacter.belongsTo(FalukantPredefineLastname, { foreignKey: 'lastName', as: 'definedLastName' }); + FalukantPredefineLastname.hasMany(FalukantCharacter, { foreignKey: 'lastName', as: 'charactersWithLastName' }); - FalukantCharacter.belongsTo(TitleOfNobility, { foreignKey: 'titleOfNobility', as: 'nobleTitle' }); - TitleOfNobility.hasMany(FalukantCharacter, { foreignKey: 'titleOfNobility', as: 'charactersWithNobleTitle' }); + FalukantCharacter.belongsTo(TitleOfNobility, { foreignKey: 'titleOfNobility', as: 'nobleTitle' }); + TitleOfNobility.hasMany(FalukantCharacter, { foreignKey: 'titleOfNobility', as: 'charactersWithNobleTitle' }); - FalukantCharacter.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); - RegionData.hasMany(FalukantCharacter, { foreignKey: 'regionId', as: 'charactersInRegion' }); + FalukantCharacter.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); + RegionData.hasMany(FalukantCharacter, { foreignKey: 'regionId', as: 'charactersInRegion' }); - FalukantStock.belongsTo(FalukantStockType, { foreignKey: 'stockTypeId', as: 'stockType' }); - FalukantStockType.hasMany(FalukantStock, { foreignKey: 'stockTypeId', as: 'stocks' }); + FalukantStock.belongsTo(FalukantStockType, { foreignKey: 'stockTypeId', as: 'stockType' }); + FalukantStockType.hasMany(FalukantStock, { foreignKey: 'stockTypeId', as: 'stocks' }); - Knowledge.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); - ProductType.hasMany(Knowledge, { foreignKey: 'productId', as: 'knowledges' }); + Knowledge.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); + ProductType.hasMany(Knowledge, { foreignKey: 'productId', as: 'knowledges' }); - Knowledge.belongsTo(FalukantCharacter, { foreignKey: 'characterId', as: 'character' }); - FalukantCharacter.hasMany(Knowledge, { foreignKey: 'characterId', as: 'knowledges' }); + Knowledge.belongsTo(FalukantCharacter, { foreignKey: 'characterId', as: 'character' }); + FalukantCharacter.hasMany(Knowledge, { foreignKey: 'characterId', as: 'knowledges' }); - TitleRequirement.belongsTo(TitleOfNobility, { foreignKey: 'titleId', as: 'title' }); - TitleOfNobility.hasMany(TitleRequirement, { foreignKey: 'titleId', as: 'requirements' }); + TitleRequirement.belongsTo(TitleOfNobility, { foreignKey: 'titleId', as: 'title' }); + TitleOfNobility.hasMany(TitleRequirement, { foreignKey: 'titleId', as: 'requirements' }); - Branch.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); - RegionData.hasMany(Branch, { foreignKey: 'regionId', as: 'branches' }); + Branch.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); + RegionData.hasMany(Branch, { foreignKey: 'regionId', as: 'branches' }); - Branch.belongsTo(FalukantUser, { foreignKey: 'falukantUserId', as: 'user' }); - FalukantUser.hasMany(Branch, { foreignKey: 'falukantUserId', as: 'branches' }); + Branch.belongsTo(FalukantUser, { foreignKey: 'falukantUserId', as: 'user' }); + FalukantUser.hasMany(Branch, { foreignKey: 'falukantUserId', as: 'branches' }); - Branch.belongsTo(BranchType, { foreignKey: 'branchTypeId', as: 'branchType' }); - BranchType.hasMany(Branch, { foreignKey: 'branchTypeId', as: 'branches' }); + Branch.belongsTo(BranchType, { foreignKey: 'branchTypeId', as: 'branchType' }); + BranchType.hasMany(Branch, { foreignKey: 'branchTypeId', as: 'branches' }); - Production.belongsTo(Branch, { foreignKey: 'branchId', as: 'branch' }); - Branch.hasMany(Production, { foreignKey: 'branchId', as: 'productions' }); + Production.belongsTo(Branch, { foreignKey: 'branchId', as: 'branch' }); + Branch.hasMany(Production, { foreignKey: 'branchId', as: 'productions' }); - Production.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); - ProductType.hasMany(Production, { foreignKey: 'productId', as: 'productions' }); + Production.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); + ProductType.hasMany(Production, { foreignKey: 'productId', as: 'productions' }); - Inventory.belongsTo(FalukantStock, { foreignKey: 'stockId', as: 'stock' }); - FalukantStock.hasMany(Inventory, { foreignKey: 'stockId', as: 'inventories' }); + Inventory.belongsTo(FalukantStock, { foreignKey: 'stockId', as: 'stock' }); + FalukantStock.hasMany(Inventory, { foreignKey: 'stockId', as: 'inventories' }); - Inventory.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); - ProductType.hasMany(Inventory, { foreignKey: 'productId', as: 'inventories' }); + Inventory.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); + ProductType.hasMany(Inventory, { foreignKey: 'productId', as: 'inventories' }); - BuyableStock.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); - RegionData.hasMany(BuyableStock, { foreignKey: 'regionId', as: 'buyableStocks' }); + BuyableStock.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); + RegionData.hasMany(BuyableStock, { foreignKey: 'regionId', as: 'buyableStocks' }); - Branch.hasMany(FalukantStock, { foreignKey: 'branchId', as: 'stocks' }); - FalukantStock.belongsTo(Branch, { foreignKey: 'branchId', as: 'branch' }); + Branch.hasMany(FalukantStock, { foreignKey: 'branchId', as: 'stocks' }); + FalukantStock.belongsTo(Branch, { foreignKey: 'branchId', as: 'branch' }); - MoneyFlow.belongsTo(FalukantUser, { foreignKey: 'falukantUserId', as: 'user' }); - FalukantUser.hasMany(MoneyFlow, { foreignKey: 'falukantUserId', as: 'flows' }); + MoneyFlow.belongsTo(FalukantUser, { foreignKey: 'falukantUserId', as: 'user' }); + FalukantUser.hasMany(MoneyFlow, { foreignKey: 'falukantUserId', as: 'flows' }); - BuyableStock.belongsTo(FalukantStockType, { foreignKey: 'stockTypeId', as: 'stockType' }); - FalukantStockType.hasMany(BuyableStock, { foreignKey: 'stockTypeId', as: 'buyableStocks' }); + BuyableStock.belongsTo(FalukantStockType, { foreignKey: 'stockTypeId', as: 'stockType' }); + FalukantStockType.hasMany(BuyableStock, { foreignKey: 'stockTypeId', as: 'buyableStocks' }); - Director.belongsTo(FalukantUser, { foreignKey: 'employerUserId', as: 'user' }); - FalukantUser.hasMany(Director, { foreignKey: 'employerUserId', as: 'directors' }); + Director.belongsTo(FalukantUser, { foreignKey: 'employerUserId', as: 'user' }); + FalukantUser.hasMany(Director, { foreignKey: 'employerUserId', as: 'directors' }); - Director.belongsTo(FalukantCharacter, { foreignKey: 'directorCharacterId', as: 'character' }); - FalukantCharacter.hasMany(Director, { foreignKey: 'directorCharacterId', as: 'directors' }); + Director.belongsTo(FalukantCharacter, { foreignKey: 'directorCharacterId', as: 'character' }); + FalukantCharacter.hasMany(Director, { foreignKey: 'directorCharacterId', as: 'directors' }); - DirectorProposal.belongsTo(FalukantUser, { foreignKey: 'employerUserId', as: 'user' }); - FalukantUser.hasMany(DirectorProposal, { foreignKey: 'employerUserId', as: 'directorProposals' }); + DirectorProposal.belongsTo(FalukantUser, { foreignKey: 'employerUserId', as: 'user' }); + FalukantUser.hasMany(DirectorProposal, { foreignKey: 'employerUserId', as: 'directorProposals' }); - DirectorProposal.belongsTo(FalukantCharacter, { foreignKey: 'directorCharacterId', as: 'character' }); - FalukantCharacter.hasMany(DirectorProposal, { foreignKey: 'directorCharacterId', as: 'directorProposals' }); + DirectorProposal.belongsTo(FalukantCharacter, { foreignKey: 'directorCharacterId', as: 'character' }); + FalukantCharacter.hasMany(DirectorProposal, { foreignKey: 'directorCharacterId', as: 'directorProposals' }); - TownProductWorth.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); - ProductType.hasMany(TownProductWorth, { foreignKey: 'productId', as: 'townProductWorths' }); + TownProductWorth.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); + ProductType.hasMany(TownProductWorth, { foreignKey: 'productId', as: 'townProductWorths' }); - TownProductWorth.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); - RegionData.hasMany(TownProductWorth, { foreignKey: 'regionId', as: 'townProductWorths' }); + TownProductWorth.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); + RegionData.hasMany(TownProductWorth, { foreignKey: 'regionId', as: 'townProductWorths' }); - DayProduction.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); - ProductType.hasMany(DayProduction, { foreignKey: 'productId', as: 'dayProductions' }); + DayProduction.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); + ProductType.hasMany(DayProduction, { foreignKey: 'productId', as: 'dayProductions' }); - DayProduction.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); - RegionData.hasMany(DayProduction, { foreignKey: 'regionId', as: 'dayProductions' }); + DayProduction.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); + RegionData.hasMany(DayProduction, { foreignKey: 'regionId', as: 'dayProductions' }); - DayProduction.belongsTo(FalukantUser, { foreignKey: 'producerId', as: 'user' }); - FalukantUser.hasMany(DayProduction, { foreignKey: 'producerId', as: 'dayProductions' }); + DayProduction.belongsTo(FalukantUser, { foreignKey: 'producerId', as: 'user' }); + FalukantUser.hasMany(DayProduction, { foreignKey: 'producerId', as: 'dayProductions' }); - DaySell.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); - ProductType.hasMany(DaySell, { foreignKey: 'productId', as: 'daySells' }); + DaySell.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' }); + ProductType.hasMany(DaySell, { foreignKey: 'productId', as: 'daySells' }); - DaySell.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); - RegionData.hasMany(DaySell, { foreignKey: 'regionId', as: 'daySells' }); + DaySell.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' }); + RegionData.hasMany(DaySell, { foreignKey: 'regionId', as: 'daySells' }); - DaySell.belongsTo(FalukantUser, { foreignKey: 'sellerId', as: 'user' }); - FalukantUser.hasMany(DaySell, { foreignKey: 'sellerId', as: 'daySells' }); + DaySell.belongsTo(FalukantUser, { foreignKey: 'sellerId', as: 'user' }); + FalukantUser.hasMany(DaySell, { foreignKey: 'sellerId', as: 'daySells' }); - Notification.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' }); - FalukantUser.hasMany(Notification, { foreignKey: 'userId', as: 'notifications' }); + Notification.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' }); + FalukantUser.hasMany(Notification, { foreignKey: 'userId', as: 'notifications' }); - MarriageProposal.belongsTo(FalukantCharacter, { foreignKey: 'requesterCharacterId', as: 'requesterCharacter', }); - FalukantCharacter.hasMany(MarriageProposal, { foreignKey: 'requesterCharacterId', as: 'initiatedProposals' }); + MarriageProposal.belongsTo(FalukantCharacter, { foreignKey: 'requesterCharacterId', as: 'requesterCharacter', }); + FalukantCharacter.hasMany(MarriageProposal, { foreignKey: 'requesterCharacterId', as: 'initiatedProposals' }); - MarriageProposal.belongsTo(FalukantCharacter, { foreignKey: 'proposedCharacterId', as: 'proposedCharacter', }); - FalukantCharacter.hasMany(MarriageProposal, { foreignKey: 'proposedCharacterId', as: 'receivedProposals' }); + MarriageProposal.belongsTo(FalukantCharacter, { foreignKey: 'proposedCharacterId', as: 'proposedCharacter', }); + FalukantCharacter.hasMany(MarriageProposal, { foreignKey: 'proposedCharacterId', as: 'receivedProposals' }); - FalukantCharacter.belongsToMany(CharacterTrait, { through: FalukantCharacterTrait, foreignKey: 'character_id', as: 'traits', }); - CharacterTrait.belongsToMany(FalukantCharacter, { through: FalukantCharacterTrait, foreignKey: 'trait_id', as: 'characters', }); + FalukantCharacter.belongsToMany(CharacterTrait, { through: FalukantCharacterTrait, foreignKey: 'character_id', as: 'traits', }); + CharacterTrait.belongsToMany(FalukantCharacter, { through: FalukantCharacterTrait, foreignKey: 'trait_id', as: 'characters', }); - Mood.hasMany(FalukantCharacter, { foreignKey: 'mood_id', as: 'moods' }); - FalukantCharacter.belongsTo(Mood, { foreignKey: 'mood_id', as: 'mood' }); + Mood.hasMany(FalukantCharacter, { foreignKey: 'mood_id', as: 'moods' }); + FalukantCharacter.belongsTo(Mood, { foreignKey: 'mood_id', as: 'mood' }); - PromotionalGift.belongsToMany(CharacterTrait, { through: PromotionalGiftCharacterTrait, foreignKey: 'gift_id', as: 'traits', }); - CharacterTrait.belongsToMany(PromotionalGift, { through: PromotionalGiftCharacterTrait, foreignKey: 'trait_id', as: 'gifts', }); + PromotionalGift.belongsToMany(CharacterTrait, { through: PromotionalGiftCharacterTrait, foreignKey: 'gift_id', as: 'traits', }); + CharacterTrait.belongsToMany(PromotionalGift, { through: PromotionalGiftCharacterTrait, foreignKey: 'trait_id', as: 'gifts', }); - PromotionalGift.belongsToMany(Mood, { through: PromotionalGiftMood, foreignKey: 'gift_id', as: 'moods', }); - Mood.belongsToMany(PromotionalGift, { through: PromotionalGiftMood, foreignKey: 'mood_id', as: 'gifts', }); + PromotionalGift.belongsToMany(Mood, { through: PromotionalGiftMood, foreignKey: 'gift_id', as: 'moods', }); + Mood.belongsToMany(PromotionalGift, { through: PromotionalGiftMood, foreignKey: 'mood_id', as: 'gifts', }); - Relationship.belongsTo(RelationshipType, { foreignKey: 'relationshipTypeId', as: 'relationshipType' }); - RelationshipType.hasMany(Relationship, { foreignKey: 'relationshipTypeId', as: 'relationships' }); + Relationship.belongsTo(RelationshipType, { foreignKey: 'relationshipTypeId', as: 'relationshipType' }); + RelationshipType.hasMany(Relationship, { foreignKey: 'relationshipTypeId', as: 'relationships' }); - Relationship.belongsTo(FalukantCharacter, { foreignKey: 'character1Id', as: 'character1', }); - Relationship.belongsTo(FalukantCharacter, { foreignKey: 'character2Id', as: 'character2', }); - FalukantCharacter.hasMany(Relationship, { foreignKey: 'character1Id', as: 'relationshipsAsCharacter1', }); - FalukantCharacter.hasMany(Relationship, { foreignKey: 'character2Id', as: 'relationshipsAsCharacter2', }); + Relationship.belongsTo(FalukantCharacter, { foreignKey: 'character1Id', as: 'character1', }); + Relationship.belongsTo(FalukantCharacter, { foreignKey: 'character2Id', as: 'character2', }); + FalukantCharacter.hasMany(Relationship, { foreignKey: 'character1Id', as: 'relationshipsAsCharacter1', }); + FalukantCharacter.hasMany(Relationship, { foreignKey: 'character2Id', as: 'relationshipsAsCharacter2', }); - PromotionalGiftLog.belongsTo(PromotionalGift, { foreignKey: 'giftId', as: 'gift' }); - PromotionalGift.hasMany(PromotionalGiftLog, { foreignKey: 'giftId', as: 'logs' }); + PromotionalGiftLog.belongsTo(PromotionalGift, { foreignKey: 'giftId', as: 'gift' }); + PromotionalGift.hasMany(PromotionalGiftLog, { foreignKey: 'giftId', as: 'logs' }); - PromotionalGiftLog.belongsTo(FalukantCharacter, { foreignKey: 'senderCharacterId', as: 'character' }); - FalukantCharacter.hasMany(PromotionalGiftLog, { foreignKey: 'senderCharacterId', as: 'logs' }); + PromotionalGiftLog.belongsTo(FalukantCharacter, { foreignKey: 'senderCharacterId', as: 'character' }); + FalukantCharacter.hasMany(PromotionalGiftLog, { foreignKey: 'senderCharacterId', as: 'logs' }); - PromotionalGiftLog.belongsTo(FalukantCharacter, { foreignKey: 'recipientCharacterId', as: 'recipient' }); - FalukantCharacter.hasMany(PromotionalGiftLog, { foreignKey: 'recipientCharacterId', as: 'giftlogs' }); + PromotionalGiftLog.belongsTo(FalukantCharacter, { foreignKey: 'recipientCharacterId', as: 'recipient' }); + FalukantCharacter.hasMany(PromotionalGiftLog, { foreignKey: 'recipientCharacterId', as: 'giftlogs' }); - PromotionalGift.hasMany(PromotionalGiftCharacterTrait, { foreignKey: 'gift_id', as: 'characterTraits' }); - PromotionalGift.hasMany(PromotionalGiftMood, { foreignKey: 'gift_id', as: 'promotionalgiftmoods' }); + PromotionalGift.hasMany(PromotionalGiftCharacterTrait, { foreignKey: 'gift_id', as: 'characterTraits' }); + PromotionalGift.hasMany(PromotionalGiftMood, { foreignKey: 'gift_id', as: 'promotionalgiftmoods' }); - PromotionalGiftCharacterTrait.belongsTo(PromotionalGift, { foreignKey: 'gift_id', as: 'promotionalgiftcharactertrait' }); - PromotionalGiftMood.belongsTo(PromotionalGift, { foreignKey: 'gift_id', as: 'promotionalgiftcharactermood' }); + PromotionalGiftCharacterTrait.belongsTo(PromotionalGift, { foreignKey: 'gift_id', as: 'promotionalgiftcharactertrait' }); + PromotionalGiftMood.belongsTo(PromotionalGift, { foreignKey: 'gift_id', as: 'promotionalgiftcharactermood' }); - HouseType.hasMany(BuyableHouse, { foreignKey: 'houseTypeId', as: 'buyableHouses' }); - BuyableHouse.belongsTo(HouseType, { foreignKey: 'houseTypeId', as: 'houseType' }); + HouseType.hasMany(BuyableHouse, { foreignKey: 'houseTypeId', as: 'buyableHouses' }); + BuyableHouse.belongsTo(HouseType, { foreignKey: 'houseTypeId', as: 'houseType' }); - HouseType.hasMany(UserHouse, { foreignKey: 'houseTypeId', as: 'userHouses' }); - UserHouse.belongsTo(HouseType, { foreignKey: 'houseTypeId', as: 'houseType' }); + HouseType.hasMany(UserHouse, { foreignKey: 'houseTypeId', as: 'userHouses' }); + UserHouse.belongsTo(HouseType, { foreignKey: 'houseTypeId', as: 'houseType' }); - FalukantUser.hasOne(UserHouse, { foreignKey: 'userId', as: 'userHouse' }); - UserHouse.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'houseUser' }); + FalukantUser.hasOne(UserHouse, { foreignKey: 'userId', as: 'userHouse' }); + UserHouse.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'houseUser' }); - TitleOfNobility.hasMany(HouseType, { foreignKey: 'minimumNobleTitle', as: 'houseTypes' }); - HouseType.belongsTo(TitleOfNobility, { foreignKey: 'minimumNobleTitle', as: 'titleOfNobility' }); - - PartyType.hasMany(Party, { foreignKey: 'partyTypeId', as: 'parties' }); - Party.belongsTo(PartyType, { foreignKey: 'partyTypeId', as: 'partyType' }); - - MusicType.hasMany(Party, { foreignKey: 'musicTypeId', as: 'parties' }); - Party.belongsTo(MusicType, { foreignKey: 'musicTypeId', as: 'musicType' }); - - BanquetteType.hasMany(Party, { foreignKey: 'banquetteTypeId', as: 'parties' }); - Party.belongsTo(BanquetteType, { foreignKey: 'banquetteTypeId', as: 'banquetteType' }); - - FalukantUser.hasMany(Party, { foreignKey: 'falukantUserId', as: 'parties' }); - Party.belongsTo(FalukantUser, { foreignKey: 'falukantUserId', as: 'partyUser' }); - - Party.belongsToMany(TitleOfNobility, { - through: PartyInvitedNobility, - foreignKey: 'party_id', - otherKey: 'title_of_nobility_id', - as: 'invitedNobilities', - }); - TitleOfNobility.belongsToMany(Party, { - through: PartyInvitedNobility, - foreignKey: 'title_of_nobility_id', - otherKey: 'party_id', - as: 'partiesInvitedTo', - }); - - ChildRelation.belongsTo(FalukantCharacter, { - foreignKey: 'fatherCharacterId', - as: 'father' - }); - FalukantCharacter.hasMany(ChildRelation, { - foreignKey: 'fatherCharacterId', - as: 'childrenFather' - }); - - ChildRelation.belongsTo(FalukantCharacter, { - foreignKey: 'motherCharacterId', - as: 'mother' - }); - FalukantCharacter.hasMany(ChildRelation, { - foreignKey: 'motherCharacterId', - as: 'childrenMother' - }); - - ChildRelation.belongsTo(FalukantCharacter, { - foreignKey: 'childCharacterId', - as: 'child' - }); - FalukantCharacter.hasMany(ChildRelation, { - foreignKey: 'childCharacterId', - as: 'parentRelations' - }); - - Learning.belongsTo(LearnRecipient, { - foreignKey: 'learningRecipientId', - as: 'recipient' - } - ); - - LearnRecipient.hasMany(Learning, { - foreignKey: 'learningRecipientId', - as: 'learnings' - }); - - Learning.belongsTo(FalukantUser, { - foreignKey: 'associatedFalukantUserId', - as: 'learner' - } - ); - - FalukantUser.hasMany(Learning, { - foreignKey: 'associatedFalukantUserId', - as: 'learnings' - }); - - Learning.belongsTo(ProductType, { - foreignKey: 'productId', - as: 'productType' - }); - - ProductType.hasMany(Learning, { - foreignKey: 'productId', - as: 'learnings' - }); - - Learning.belongsTo(FalukantCharacter, { - foreignKey: 'associatedLearningCharacterId', - as: 'learningCharacter' - }); - - FalukantCharacter.hasMany(Learning, { - foreignKey: 'associatedLearningCharacterId', - as: 'learningsCharacter' - }); - - FalukantUser.hasMany(Credit, { - foreignKey: 'falukantUserId', - as: 'credits' - }); - Credit.belongsTo(FalukantUser, { - foreignKey: 'falukantUserId', - as: 'user' - }); - - FalukantCharacter.hasMany(DebtorsPrism, { - foreignKey: 'character_id', - as: 'debtorsPrisms' - }); - DebtorsPrism.belongsTo(FalukantCharacter, { - foreignKey: 'character_id', - as: 'character' - }); - - HealthActivity.belongsTo(FalukantCharacter, { - foreignKey: 'character_id', - as: 'character' - }); - FalukantCharacter.hasMany(HealthActivity, { - foreignKey: 'character_id', - as: 'healthActivities' - }); - - // — Political Offices — - -// predefine requirements for office -PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { + TitleOfNobility.hasMany(HouseType, { foreignKey: 'minimumNobleTitle', as: 'houseTypes' }); + HouseType.belongsTo(TitleOfNobility, { foreignKey: 'minimumNobleTitle', as: 'titleOfNobility' }); + + PartyType.hasMany(Party, { foreignKey: 'partyTypeId', as: 'parties' }); + Party.belongsTo(PartyType, { foreignKey: 'partyTypeId', as: 'partyType' }); + + MusicType.hasMany(Party, { foreignKey: 'musicTypeId', as: 'parties' }); + Party.belongsTo(MusicType, { foreignKey: 'musicTypeId', as: 'musicType' }); + + BanquetteType.hasMany(Party, { foreignKey: 'banquetteTypeId', as: 'parties' }); + Party.belongsTo(BanquetteType, { foreignKey: 'banquetteTypeId', as: 'banquetteType' }); + + FalukantUser.hasMany(Party, { foreignKey: 'falukantUserId', as: 'parties' }); + Party.belongsTo(FalukantUser, { foreignKey: 'falukantUserId', as: 'partyUser' }); + + Party.belongsToMany(TitleOfNobility, { + through: PartyInvitedNobility, + foreignKey: 'party_id', + otherKey: 'title_of_nobility_id', + as: 'invitedNobilities', + }); + TitleOfNobility.belongsToMany(Party, { + through: PartyInvitedNobility, + foreignKey: 'title_of_nobility_id', + otherKey: 'party_id', + as: 'partiesInvitedTo', + }); + + ChildRelation.belongsTo(FalukantCharacter, { + foreignKey: 'fatherCharacterId', + as: 'father' + }); + FalukantCharacter.hasMany(ChildRelation, { + foreignKey: 'fatherCharacterId', + as: 'childrenFather' + }); + + ChildRelation.belongsTo(FalukantCharacter, { + foreignKey: 'motherCharacterId', + as: 'mother' + }); + FalukantCharacter.hasMany(ChildRelation, { + foreignKey: 'motherCharacterId', + as: 'childrenMother' + }); + + ChildRelation.belongsTo(FalukantCharacter, { + foreignKey: 'childCharacterId', + as: 'child' + }); + FalukantCharacter.hasMany(ChildRelation, { + foreignKey: 'childCharacterId', + as: 'parentRelations' + }); + + Learning.belongsTo(LearnRecipient, { + foreignKey: 'learningRecipientId', + as: 'recipient' + } + ); + + LearnRecipient.hasMany(Learning, { + foreignKey: 'learningRecipientId', + as: 'learnings' + }); + + Learning.belongsTo(FalukantUser, { + foreignKey: 'associatedFalukantUserId', + as: 'learner' + } + ); + + FalukantUser.hasMany(Learning, { + foreignKey: 'associatedFalukantUserId', + as: 'learnings' + }); + + Learning.belongsTo(ProductType, { + foreignKey: 'productId', + as: 'productType' + }); + + ProductType.hasMany(Learning, { + foreignKey: 'productId', + as: 'learnings' + }); + + Learning.belongsTo(FalukantCharacter, { + foreignKey: 'associatedLearningCharacterId', + as: 'learningCharacter' + }); + + FalukantCharacter.hasMany(Learning, { + foreignKey: 'associatedLearningCharacterId', + as: 'learningsCharacter' + }); + + FalukantUser.hasMany(Credit, { + foreignKey: 'falukantUserId', + as: 'credits' + }); + Credit.belongsTo(FalukantUser, { + foreignKey: 'falukantUserId', + as: 'user' + }); + + FalukantCharacter.hasMany(DebtorsPrism, { + foreignKey: 'character_id', + as: 'debtorsPrisms' + }); + DebtorsPrism.belongsTo(FalukantCharacter, { + foreignKey: 'character_id', + as: 'character' + }); + + HealthActivity.belongsTo(FalukantCharacter, { + foreignKey: 'character_id', + as: 'character' + }); + FalukantCharacter.hasMany(HealthActivity, { + foreignKey: 'character_id', + as: 'healthActivities' + }); + + // — Political Offices — + + // predefine requirements for office + PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', as: 'officeType' }); @@ -520,9 +523,9 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', as: 'requirements' }); - + // predefine benefits for office - PoliticalOfficeBenefit.belongsTo( + PoliticalOfficeBenefit.belongsTo( PoliticalOfficeBenefitType, { foreignKey: 'benefitTypeId', as: 'benefitDefinition' } ); @@ -530,7 +533,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { PoliticalOfficeBenefit, { foreignKey: 'benefitTypeId', as: 'benefitDefinitions' } ); - + // tie benefits back to office type PoliticalOfficeBenefit.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', @@ -540,7 +543,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', as: 'benefits' }); - + // actual office holdings PoliticalOffice.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', @@ -550,16 +553,16 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', as: 'offices' }); - + PoliticalOffice.belongsTo(FalukantCharacter, { foreignKey: 'characterId', as: 'holder' }); - FalukantCharacter.hasMany(PoliticalOffice, { + FalukantCharacter.hasOne(PoliticalOffice, { foreignKey: 'characterId', - as: 'heldOffices' + as: 'heldOffice' }); - + // elections Election.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', @@ -569,7 +572,17 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'officeTypeId', as: 'elections' }); - + + Election.belongsTo(RegionData, { + foreignKey: 'regionId', + as: 'region' + }); + + RegionData.hasMany(Election, { + foreignKey: 'regionId', + as: 'elections' + }); + // candidates in an election Candidate.belongsTo(Election, { foreignKey: 'electionId', @@ -579,7 +592,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'electionId', as: 'candidates' }); - + Candidate.belongsTo(FalukantCharacter, { foreignKey: 'characterId', as: 'character' @@ -588,7 +601,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'characterId', as: 'candidacies' }); - + // votes cast Vote.belongsTo(Election, { foreignKey: 'electionId', @@ -598,7 +611,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'electionId', as: 'votes' }); - + Vote.belongsTo(Candidate, { foreignKey: 'candidateId', as: 'candidate' @@ -607,7 +620,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'candidateId', as: 'votes' }); - + Vote.belongsTo(FalukantCharacter, { foreignKey: 'voterCharacterId', as: 'voter' @@ -616,7 +629,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'voterCharacterId', as: 'votesCast' }); - + // election results ElectionResult.belongsTo(Election, { foreignKey: 'electionId', @@ -626,7 +639,7 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { foreignKey: 'electionId', as: 'results' }); - + ElectionResult.belongsTo(Candidate, { foreignKey: 'candidateId', as: 'candidate' @@ -645,4 +658,43 @@ PoliticalOfficeRequirement.belongsTo(PoliticalOfficeType, { as: 'offices' }); + PoliticalOfficePrerequisite.belongsTo(PoliticalOfficeType, { + foreignKey: 'office_type_id', + as: 'officeTypePrerequisite', + }); + + PoliticalOfficeType.hasMany(PoliticalOfficePrerequisite, { + foreignKey: 'office_type_id', + as: 'prerequisites', + }); + + PoliticalOfficeHistory.belongsTo(PoliticalOfficeType, { + foreignKey: 'officeTypeId', + as: 'officeTypeHistory', + }); + + PoliticalOfficeType.hasMany(PoliticalOfficeHistory, { + foreignKey: 'officeTypeId', + as: 'history', + }); + + FalukantCharacter.hasMany(PoliticalOfficeHistory, { + foreignKey: 'characterId', + as: 'officeHistories', + }); + PoliticalOfficeHistory.belongsTo(FalukantCharacter, { + foreignKey: 'characterId', + as: 'character', + }); + + ElectionHistory.belongsTo(PoliticalOfficeType, { + foreignKey: 'officeTypeId', + as: 'officeTypeHistory', + }); + + PoliticalOfficeType.hasMany(ElectionHistory, { + foreignKey: 'officeTypeId', + as: 'electionHistory', + } + ) } diff --git a/backend/models/falukant/data/child_relation.js b/backend/models/falukant/data/child_relation.js index dc5eec2..ddbf5a9 100644 --- a/backend/models/falukant/data/child_relation.js +++ b/backend/models/falukant/data/child_relation.js @@ -30,6 +30,11 @@ ChildRelation.init( allowNull: false, default: false, }, + isHeir: { + type: DataTypes.BOOLEAN, + allowNull: true, + default: false, + } }, { sequelize, diff --git a/backend/models/falukant/data/election.js b/backend/models/falukant/data/election.js index 18086a1..785f911 100644 --- a/backend/models/falukant/data/election.js +++ b/backend/models/falukant/data/election.js @@ -10,15 +10,19 @@ Election.init({ primaryKey: true, autoIncrement: true, }, - political_office_id: { + officeTypeId: { type: DataTypes.INTEGER, - allowNull: false, + allowNull: true, }, - date: { + regionId: { + type: DataTypes.INTEGER, + allowNull: false + }, + date: { type: DataTypes.DATE, allowNull: false, }, - posts_to_fill: { + postsToFill: { type: DataTypes.INTEGER, allowNull: false, }, diff --git a/backend/models/falukant/data/region.js b/backend/models/falukant/data/region.js index c321558..5da6c84 100644 --- a/backend/models/falukant/data/region.js +++ b/backend/models/falukant/data/region.js @@ -26,6 +26,11 @@ RegionData.init({ key: 'id', schema: 'falukant_data', } + }, + map: { + type: DataTypes.JSONB, + allowNull: true, + defaultValue: {} } }, { sequelize, diff --git a/backend/models/falukant/data/vote.js b/backend/models/falukant/data/vote.js index 2b0e528..993a37b 100644 --- a/backend/models/falukant/data/vote.js +++ b/backend/models/falukant/data/vote.js @@ -4,36 +4,45 @@ import { sequelize } from '../../../utils/sequelize.js'; class Vote extends Model {} -Vote.init({ - id: { - type: DataTypes.INTEGER, - primaryKey: true, - autoIncrement: true, +Vote.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + }, + electionId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + candidateId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + timestamp: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + }, + falukantUserId: { + type: DataTypes.INTEGER, + allowNull: false, + }, }, - election_id: { - type: DataTypes.INTEGER, - allowNull: false, - }, - voter_character_id: { - type: DataTypes.INTEGER, - allowNull: false, - }, - candidate_id: { - type: DataTypes.INTEGER, - allowNull: false, - }, - timestamp: { - type: DataTypes.DATE, - allowNull: false, - defaultValue: DataTypes.NOW, - }, -}, { - sequelize, - modelName: 'Vote', - tableName: 'vote', - schema: 'falukant_data', - timestamps: false, - underscored: true, -}); + { + sequelize, + modelName: 'Vote', + tableName: 'vote', + schema: 'falukant_data', + timestamps: true, + underscored: true, + indexes: [ + { + unique: true, + fields: ['election_id', 'candidate_id'], + }, + ], + } +); export default Vote; diff --git a/backend/models/falukant/log/election_history.js b/backend/models/falukant/log/election_history.js new file mode 100644 index 0000000..4e8c71e --- /dev/null +++ b/backend/models/falukant/log/election_history.js @@ -0,0 +1,32 @@ +import { Model, DataTypes } from 'sequelize'; +import { sequelize } from '../../../utils/sequelize.js'; + +class ElectionHistory extends Model { } + +ElectionHistory.init({ + electionId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + politicalOfficeTypeId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + electionDate: { + type: DataTypes.DATE, + allowNull: false, + }, + electionResult: { + type: DataTypes.JSON, + allowNull: false, + } +}, { + sequelize, + modelName: 'ElectionHistory', + tableName: 'election_history', + schema: 'falukant_log', + timestamps: true, + underscored: true, +}); + +export default ElectionHistory; diff --git a/backend/models/falukant/log/political_office_history.js b/backend/models/falukant/log/political_office_history.js new file mode 100644 index 0000000..378c61d --- /dev/null +++ b/backend/models/falukant/log/political_office_history.js @@ -0,0 +1,35 @@ +import { Model, DataTypes } from 'sequelize'; +import { sequelize } from '../../../utils/sequelize.js'; + +class PoliticalOfficeHistory extends Model { } + +PoliticalOfficeHistory.init( + { + characterId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + officeTypeId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + startDate: { + type: DataTypes.DATE, + allowNull: false, + }, + endDate: { + type: DataTypes.DATE, + allowNull: false, + } + }, + { + sequelize, + modelName: 'PoliticalOfficeHistory', + tableName: 'political_office_history', + schema: 'falukant_log', + timestamps: true, + underscored: true, + } +); + +export default PoliticalOfficeHistory; diff --git a/backend/models/falukant/predefine/political_office_prerequisite.js b/backend/models/falukant/predefine/political_office_prerequisite.js index d04ea55..d8178b4 100644 --- a/backend/models/falukant/predefine/political_office_prerequisite.js +++ b/backend/models/falukant/predefine/political_office_prerequisite.js @@ -1,4 +1,5 @@ -// falukant/predefine/political_office_prerequisite.js +// models/falukant/predefine/political_office_prerequisite.js + import { Model, DataTypes } from 'sequelize'; import { sequelize } from '../../../utils/sequelize.js'; @@ -10,10 +11,13 @@ PoliticalOfficePrerequisite.init({ primaryKey: true, autoIncrement: true, }, - political_office_id: { + + // Neu: Feld heißt jetzt eindeutig "office_type_id" + office_type_id: { type: DataTypes.INTEGER, allowNull: false, }, + prerequisite: { type: DataTypes.JSONB, allowNull: false, diff --git a/backend/models/index.js b/backend/models/index.js index cdbb100..8e44802 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -94,6 +94,8 @@ import Election from './falukant/data/election.js'; import Candidate from './falukant/data/candidate.js'; import Vote from './falukant/data/vote.js'; import ElectionResult from './falukant/data/election_result.js'; +import PoliticalOfficeHistory from './falukant/log/political_office_history.js'; +import ElectionHistory from './falukant/log/election_history.js'; const models = { SettingsType, @@ -191,6 +193,8 @@ const models = { Candidate, Vote, ElectionResult, + PoliticalOfficeHistory, + ElectionHistory, }; export default models; diff --git a/backend/models/trigger.js b/backend/models/trigger.js index 137594d..cf7e719 100644 --- a/backend/models/trigger.js +++ b/backend/models/trigger.js @@ -241,6 +241,180 @@ export async function createTriggers() { $$ LANGUAGE plpgsql VOLATILE; `; + // process_elections–Stored-Procedure anlegen + const createProcessElectionsFunction = ` + CREATE OR REPLACE FUNCTION falukant_data.process_elections() + RETURNS TABLE ( + office_id INTEGER, + office_type_id INTEGER, + character_id INTEGER, + region_id INTEGER + ) + AS $$ + BEGIN + RETURN QUERY + WITH + -- 1) Alle Wahlen, die vor mindestens 3 Tagen erstellt wurden + to_process AS ( + SELECT + e.id AS election_id, + e.office_type_id AS tp_office_type_id, + e.region_id AS tp_region_id, + e.posts_to_fill AS tp_posts_to_fill, + e.date AS tp_election_date + FROM falukant_data.election e + WHERE (e.created_at::date + INTERVAL '3 days') <= NOW()::date + ), + + -- 2) Stimmen pro Kandidat zählen + votes AS ( + SELECT + tp.election_id, + tp.tp_posts_to_fill AS posts_to_fill, + c.character_id, + COUNT(v.*) AS votes_received + FROM to_process tp + JOIN falukant_data.candidate c + ON c.election_id = tp.election_id + LEFT JOIN falukant_data.vote v + ON v.election_id = c.election_id + AND v.candidate_id = c.id + GROUP BY tp.election_id, tp.tp_posts_to_fill, c.character_id + ), + + -- 3) Ranking nach Stimmen + ranked AS ( + SELECT + v.election_id, + v.character_id, + v.votes_received, + ROW_NUMBER() OVER ( + PARTITION BY v.election_id + ORDER BY v.votes_received DESC, RANDOM() + ) AS rn + FROM votes v + ), + + -- 4) Top-N (posts_to_fill) sind Gewinner + winners AS ( + SELECT + r.election_id, + r.character_id + FROM ranked r + JOIN to_process tp + ON tp.election_id = r.election_id + WHERE r.rn <= tp.tp_posts_to_fill + ), + + -- 5) Verbleibende Kandidaten ohne Gewinner + remaining AS ( + SELECT + tp.election_id, + c.character_id + FROM to_process tp + JOIN falukant_data.candidate c + ON c.election_id = tp.election_id + WHERE c.character_id NOT IN ( + SELECT w.character_id + FROM winners w + WHERE w.election_id = tp.election_id + ) + ), + + -- 6) Zufalls-Nachrücker bis alle Plätze gefüllt sind + random_fill AS ( + SELECT + rp.election_id, + rp.character_id + FROM remaining rp + JOIN to_process tp + ON tp.election_id = rp.election_id + JOIN LATERAL ( + SELECT r2.character_id + FROM remaining r2 + WHERE r2.election_id = rp.election_id + ORDER BY RANDOM() + LIMIT GREATEST( + 0, + tp.tp_posts_to_fill + - (SELECT COUNT(*) FROM winners w2 WHERE w2.election_id = tp.election_id) + ) + ) sub + ON sub.character_id = rp.character_id + ), + + -- 7) Finale Gewinner (Winners ∪ random_fill) + final_winners AS ( + SELECT * FROM winners + UNION ALL + SELECT * FROM random_fill + ), + + -- 8) Neue Ämter anlegen und sofort zurückliefern + created_offices AS ( + INSERT INTO falukant_data.political_office + (office_type_id, character_id, created_at, updated_at, region_id) + SELECT + tp.tp_office_type_id, + fw.character_id, + NOW() AS created_at, + NOW() AS updated_at, + tp.tp_region_id + FROM final_winners fw + JOIN to_process tp + ON tp.election_id = fw.election_id + RETURNING + id AS co_office_id, + falukant_data.political_office.office_type_id AS co_office_type_id, + falukant_data.political_office.character_id AS co_character_id, + falukant_data.political_office.region_id AS co_region_id + ), + + -- 9) election_history befüllen + _hist AS ( + INSERT INTO falukant_log.election_history + (election_id, political_office_type_id, election_date, election_result, created_at, updated_at) + SELECT + tp.election_id, + tp.tp_office_type_id, + tp.tp_election_date, + ( + SELECT json_agg(vr) + FROM votes vr + WHERE vr.election_id = tp.election_id + ), + NOW() AS created_at, + NOW() AS updated_at + FROM to_process tp + ), + + -- 10) Cleanup: Stimmen, Kandidaten und Wahlen löschen + _del_votes AS ( + DELETE FROM falukant_data.vote + WHERE election_id IN (SELECT election_id FROM to_process) + ), + _del_candidates AS ( + DELETE FROM falukant_data.candidate + WHERE election_id IN (SELECT election_id FROM to_process) + ), + _del_elections AS ( + DELETE FROM falukant_data.election + WHERE id IN (SELECT election_id FROM to_process) + ) + + -- 11) Ergebnis wirklich zurückliefern + SELECT + co.co_office_id AS office_id, + co.co_office_type_id, + co.co_character_id, + co.co_region_id + FROM created_offices co + ORDER BY co.co_region_id, co.co_office_id; + + END; + $$ LANGUAGE plpgsql; + `; + try { await sequelize.query(createTriggerFunction); await sequelize.query(createInsertTrigger); @@ -257,6 +431,7 @@ export async function createTriggers() { await sequelize.query(createChildRelationNameFunction); await sequelize.query(createChildRelationNameTrigger); await sequelize.query(createRandomMoodUpdateMethod); + await sequelize.query(createProcessElectionsFunction); await initializeCharacterTraitTrigger(); console.log('Triggers created successfully'); diff --git a/backend/routers/falukantRouter.js b/backend/routers/falukantRouter.js index 119d230..91a94d8 100644 --- a/backend/routers/falukantRouter.js +++ b/backend/routers/falukantRouter.js @@ -11,8 +11,10 @@ router.get('/character/affect', falukantController.getCharacterAffect); router.get('/name/randomfirstname/:gender', falukantController.randomFirstName); router.get('/name/randomlastname', falukantController.randomLastName); router.get('/info', falukantController.getInfo); +router.get('/branches/types', falukantController.getBranchTypes); router.get('/branches/:branch', falukantController.getBranch); router.get('/branches', falukantController.getBranches); +router.post('/branches', falukantController.createBranch); router.get('/productions', falukantController.getAllProductions); router.post('/production', falukantController.createProduction); router.get('/production/:branchId', falukantController.getProduction); @@ -43,6 +45,8 @@ router.get('/nobility/titels', falukantController.getTitelsOfNobility); router.get('/houses/types', falukantController.getHouseTypes); router.get('/houses/buyable', falukantController.getBuyableHouses); router.get('/houses', falukantController.getUserHouse); +router.post('/houses/renovate-all', falukantController.renovateAll); +router.post('/houses/renovate', falukantController.renovate); router.post('/houses', falukantController.buyUserHouse); router.get('/party/types', falukantController.getPartyTypes); router.post('/party', falukantController.createParty); @@ -57,5 +61,13 @@ router.post('/bank/credits', falukantController.takeBankCredits); router.get('/nobility', falukantController.getNobility); router.post('/nobility', falukantController.advanceNobility); router.get('/health', falukantController.getHealth); -router.post('/health', falukantController.healthActivity) +router.post('/health', falukantController.healthActivity); +router.get('/politics/overview', falukantController.getPoliticsOverview); +router.get('/politics/open', falukantController.getOpenPolitics); +router.get('/politics/elections', falukantController.getElections); +router.post('/politics/elections', falukantController.vote); +router.get('/politics/open', falukantController.getOpenPolitics); +router.post('/politics/open', falukantController.applyForElections); +router.get('/cities', falukantController.getRegions); + export default router; diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 867325e..29a7b75 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -1,6 +1,6 @@ import BaseService from './BaseService.js'; -import { Sequelize, Op, where } from 'sequelize'; - +import { Sequelize, Op } from 'sequelize'; +import { sequelize } from '../utils/sequelize.js'; import FalukantPredefineFirstname from '../models/falukant/predefine/firstname.js'; import FalukantPredefineLastname from '../models/falukant/predefine/lastname.js'; import FalukantUser from '../models/falukant/data/user.js'; @@ -47,6 +47,12 @@ import LearnRecipient from '../models/falukant/type/learn_recipient.js'; import Credit from '../models/falukant/data/credit.js'; import TitleRequirement from '../models/falukant/type/title_requirement.js'; import HealthActivity from '../models/falukant/log/health_activity.js'; +import Election from '../models/falukant/data/election.js'; +import PoliticalOfficeType from '../models/falukant/type/political_office_type.js'; +import Candidate from '../models/falukant/data/candidate.js'; +import Vote from '../models/falukant/data/vote.js'; +import PoliticalOfficePrerequisite from '../models/falukant/predefine/political_office_prerequisite.js'; +import PoliticalOfficeHistory from '../models/falukant/log/political_office_history.js'; function calcAge(birthdate) { const b = new Date(birthdate); b.setHours(0, 0); @@ -96,13 +102,33 @@ class FalukantService extends BaseService { all: { min: 400, max: 40000 } }; static HEALTH_ACTIVITIES = [ - { tr: "barber", method: "healthBarber", cost: 10 }, - { tr: "doctor", method: "healthDoctor", cost: 50 }, - { tr: "witch", method: "healthWitch", cost: 500 }, - { tr: "pill", method: "healthPill", cost: 5000 }, - { tr: "drunkOfLife", method: "healthDruckOfLife", cost:5000000 } - ]; - + { tr: "barber", method: "healthBarber", cost: 10 }, + { tr: "doctor", method: "healthDoctor", cost: 50 }, + { tr: "witch", method: "healthWitch", cost: 500 }, + { tr: "pill", method: "healthPill", cost: 5000 }, + { tr: "drunkOfLife", method: "healthDruckOfLife", cost: 5000000 } + ]; + + static RECURSIVE_REGION_SEARCH = ` + WITH RECURSIVE ancestors AS ( + SELECT + r.id, + r.parent_id + FROM falukant_data.region r + join falukant_data."character" c + on c.region_id = r.id + WHERE c.user_id = :user_id + UNION ALL + SELECT + r.id, + r.parent_id + FROM falukant_data.region r + JOIN ancestors a ON r.id = a.parent_id + ) + SELECT id + FROM ancestors; + `; + async getFalukantUserByHashedId(hashedId) { const user = await FalukantUser.findOne({ include: [ @@ -168,9 +194,21 @@ class FalukantService extends BaseService { attributes: ['name'] } ] - } + }, + { + model: UserHouse, + as: 'userHouse', + include: [ + { + model: HouseType, + as: 'houseType', + 'attributes': ['labelTr', 'position'] + }, + ], + attributes: ['roofCondition'], + }, ], - attributes: ['money', 'creditAmount', 'todayCreditTaken'] + attributes: ['money', 'creditAmount', 'todayCreditTaken',] }); if (!u) throw new Error('User not found'); if (u.character?.birthdate) u.character.setDataValue('age', calcAge(u.character.birthdate)); @@ -277,6 +315,38 @@ class FalukantService extends BaseService { return bs.map(b => ({ ...b.toJSON(), isMainBranch: u.mainBranchRegionId === b.regionId })); } + async createBranch(hashedUserId, cityId, branchTypeId) { + const user = await getFalukantUserOrFail(hashedUserId); + const branchType = await BranchType.findByPk(branchTypeId); + if (!branchType) { + throw new Error(`Unknown branchTypeId ${branchTypeId}`); + } + const existingCount = await Branch.count({ + where: { falukantUserId: user.id } + }); + const exponentBase = Math.max(existingCount, 1); + const rawCost = branchType.baseCost * Math.pow(exponentBase, 1.2); + const cost = Math.round(rawCost * 100) / 100; + await updateFalukantUserMoney( + user.id, + -cost, + 'create_branch' + ); + const branch = await Branch.create({ + branchTypeId, + regionId: cityId, + falukantUserId: user.id + }); + return branch; + } + + async getBranchTypes(hashedUserId) { + const user = await getFalukantUserOrFail(hashedUserId); + const branchTypes = await BranchType.findAll(); + return branchTypes; + + } + async getBranch(hashedUserId, branchId) { const u = await getFalukantUserOrFail(hashedUserId); const br = await Branch.findOne({ @@ -318,6 +388,8 @@ class FalukantService extends BaseService { const runningProductions = await Production.findAll({ where: { branchId: b.id } }); if (runningProductions.length >= 2) { throw new Error('Too many productions'); + return; // wird später implementiert, wenn familie implementiert ist. + } if (!p) throw new Error('Product not found'); quantity = Math.min(100, quantity); @@ -822,9 +894,12 @@ class FalukantService extends BaseService { await this.deleteExpiredProposals(); const existingProposals = await this.fetchProposals(falukantUserId, regionId); if (existingProposals.length > 0) { + console.log('Existing proposals:', existingProposals); return this.formatProposals(existingProposals); } + console.log('No existing proposals, generating new ones'); await this.generateProposals(falukantUserId, regionId); + console.log('Fetch new proposals'); const newProposals = await this.fetchProposals(falukantUserId, regionId); return this.formatProposals(newProposals); } @@ -867,13 +942,14 @@ class FalukantService extends BaseService { } async generateProposals(falukantUserId, regionId) { - const proposalCount = Math.floor(Math.random() * 3) + 3; - for (let i = 0; i < proposalCount; i++) { - const directorCharacter = await FalukantCharacter.findOne({ - where: { - regionId, - createdAt: { - [Op.lt]: new Date(Date.now() - 21 * 24 * 60 * 60 * 1000), + try { + const threeWeeksAgo = new Date(Date.now() - 21 * 24 * 60 * 60 * 1000); + const proposalCount = Math.floor(Math.random() * 3) + 3; + for (let i = 0; i < proposalCount; i++) { + const directorCharacter = await FalukantCharacter.findOne({ + where: { + regionId, + createdAt: { [Op.lt]: threeWeeksAgo }, }, include: [ { @@ -881,22 +957,25 @@ class FalukantService extends BaseService { as: 'nobleTitle', attributes: ['level'], }, - ] - }, - order: Sequelize.fn('RANDOM'), - }); - if (!directorCharacter) { - throw new Error('No directors available for the region'); + ], + order: sequelize.literal('RANDOM()'), + }); + if (!directorCharacter) { + throw new Error('No directors available for the region'); + } + const avgKnowledge = await this.calculateAverageKnowledge(directorCharacter.id); + const proposedIncome = Math.round( + directorCharacter.nobleTitle.level * Math.pow(1.231, avgKnowledge / 1.5) + ); + await DirectorProposal.create({ + directorCharacterId: directorCharacter.id, + employerUserId: falukantUserId, + proposedIncome, + }); } - const avgKnowledge = await this.calculateAverageKnowledge(directorCharacter.id); - const proposedIncome = Math.round( - directorCharacter.nobleTitle.level * Math.pow(1.231, avgKnowledge / 1.5) - ); - await DirectorProposal.create({ - directorCharacterId: directorCharacter.id, - employerUserId: falukantUserId, - proposedIncome, - }); + } catch (error) { + console.log(error.message, error.stack); + throw new Error(error.message); } } @@ -1394,39 +1473,65 @@ class FalukantService extends BaseService { } async getGifts(hashedUserId) { + // 1) Mein User & Character const user = await this.getFalukantUserByHashedId(hashedUserId); - const character = await FalukantCharacter.findOne({ - where: { userId: user.id }, + const myChar = await FalukantCharacter.findOne({ where: { userId: user.id } }); + if (!myChar) throw new Error('Character not found'); + + // 2) Beziehung finden und „anderen“ Character bestimmen + const rel = await Relationship.findOne({ + where: { + [Op.or]: [ + { character1Id: myChar.id }, + { character2Id: myChar.id } + ] + }, + include: [ + { model: FalukantCharacter, as: 'character1', include: [{ model: CharacterTrait, as: 'traits' }] }, + { model: FalukantCharacter, as: 'character2', include: [{ model: CharacterTrait, as: 'traits' }] } + ] }); - if (!character) { - throw new Error('Character not found'); - } - let gifts = await PromotionalGift.findAll({ + if (!rel) throw new Error('Beziehung nicht gefunden'); + + const relatedChar = rel.character1.id === myChar.id ? rel.character2 : rel.character1; + + // 3) Trait-IDs und Mood des relatedChar + const relatedTraitIds = relatedChar.traits.map(t => t.id); + const relatedMoodId = relatedChar.moodId; + + // 4) Gifts laden – aber nur die passenden Moods und Traits als Unter-Arrays + const gifts = await PromotionalGift.findAll({ include: [ { model: PromotionalGiftMood, as: 'promotionalgiftmoods', - attributes: ['mood_id', 'suitability'] + attributes: ['mood_id', 'suitability'], + where: { mood_id: relatedMoodId }, + required: false // Gifts ohne Mood-Match bleiben erhalten, haben dann leeres Array }, { model: PromotionalGiftCharacterTrait, as: 'characterTraits', - attributes: ['trait_id', 'suitability'] + attributes: ['trait_id', 'suitability'], + where: { trait_id: relatedTraitIds }, + required: false // Gifts ohne Trait-Match bleiben erhalten } ] }); - const lowestTitleOfNobility = await TitleOfNobility.findOne({ - order: [['id', 'ASC']], - }); - return await Promise.all(gifts.map(async (gift) => { - return { - id: gift.id, - name: gift.name, - cost: await this.getGiftCost(gift.value, character.titleOfNobility, lowestTitleOfNobility.id), - moodsAffects: gift.promotionalgiftmoods, - charactersAffects: gift.characterTraits, - }; - })); + + // 5) Rest wie gehabt: Kosten berechnen und zurückgeben + const lowestTitleOfNobility = await TitleOfNobility.findOne({ order: [['id', 'ASC']] }); + return Promise.all(gifts.map(async gift => ({ + id: gift.id, + name: gift.name, + cost: await this.getGiftCost( + gift.value, + myChar.titleOfNobility, + lowestTitleOfNobility.id + ), + moodsAffects: gift.promotionalgiftmoods, // nur Einträge mit relatedMoodId + charactersAffects: gift.characterTraits // nur Einträge mit relatedTraitIds + }))); } async getChildren(hashedUserId) { @@ -2199,8 +2304,8 @@ class FalukantService extends BaseService { async getHealth(hashedUserId) { const user = await this.getFalukantUserByHashedId(hashedUserId); - const healthActivities = FalukantService.HEALTH_ACTIVITIES.map((activity) => {return { tr: activity.tr, cost: activity.cost }}); - const healthHistory = await HealthActivity.findAll({ + const healthActivities = FalukantService.HEALTH_ACTIVITIES.map((activity) => { return { tr: activity.tr, cost: activity.cost } }); + const healthHistory = await HealthActivity.findAll({ where: { characterId: user.character.id }, order: [['createdAt', 'DESC']], }); @@ -2208,7 +2313,7 @@ class FalukantService extends BaseService { age: calcAge(user.character.birthdate), health: user.character.health, healthActivities: healthActivities, - history: healthHistory.map((activity) => {return { tr: activity.activityTr, cost: activity.cost, createdAt: activity.createdAt, success: activity.successPercentage }}), + history: healthHistory.map((activity) => { return { tr: activity.activityTr, cost: activity.cost, createdAt: activity.createdAt, success: activity.successPercentage } }), }; } @@ -2232,14 +2337,14 @@ class FalukantService extends BaseService { if (!activityObject) { throw new Error('invalid'); } - if (user.money - activityObject.cost < 0) { + if (user.money - activityObject.cost < 0) { throw new Error('no money'); } user.character.health -= activityObject.cost; await HealthActivity.create({ characterId: user.character.id, activityTr: activity, - successPercentage: await this[activityObject.method](user), + successPercentage: await this[activityObject.method](user), cost: activityObject.cost }); updateFalukantUserMoney(user.id, -activityObject.cost, 'health.' + activity); @@ -2256,32 +2361,424 @@ class FalukantService extends BaseService { health: Math.min(FalukantService.HEALTH_MAX || 100, Math.max(0, char.health + delta)) }); return delta; - } - - async healthBarber(user) { - const raw = Math.floor(Math.random() * 11) - 5; - return this.healthChange(user, raw); - } - - async healthDoctor(user) { - const raw = Math.floor(Math.random() * 8) - 2; - return this.healthChange(user, raw); - } - - async healthWitch(user) { - const raw = Math.floor(Math.random() * 7) - 1; - return this.healthChange(user, raw); - } - - async healthPill(user) { - const raw = Math.floor(Math.random() * 8); - return this.healthChange(user, raw); - } - - async healthDrunkOfLife(user) { - const raw = Math.floor(Math.random() * 26); - return this.healthChange(user, raw); - } } + async healthBarber(user) { + const raw = Math.floor(Math.random() * 11) - 5; + return this.healthChange(user, raw); + } + + async healthDoctor(user) { + const raw = Math.floor(Math.random() * 8) - 2; + return this.healthChange(user, raw); + } + + async healthWitch(user) { + const raw = Math.floor(Math.random() * 7) - 1; + return this.healthChange(user, raw); + } + + async healthPill(user) { + const raw = Math.floor(Math.random() * 8); + return this.healthChange(user, raw); + } + + async healthDrunkOfLife(user) { + const raw = Math.floor(Math.random() * 26); + return this.healthChange(user, raw); + } + + async getPoliticsOverview(hashedUserId) { + + } + + async getOpenPolitics(hashedUserId) { + const user = await this.getFalukantUserByHashedId(hashedUserId); + if (!user || user.character.nobleTitle.labelTr === 'noncivil') { + return []; + } + + } + + async getElections(hashedUserId) { + const user = await this.getFalukantUserByHashedId(hashedUserId); + if (!user || user.character.nobleTitle.labelTr === 'noncivil') { + return []; + } + const rows = await sequelize.query( + FalukantService.RECURSIVE_REGION_SEARCH, + { + replacements: { user_id: user.id }, + type: sequelize.QueryTypes.SELECT + } + ); + const regionIds = rows.map(r => r.id); + + // 3) Zeitbereich "heute" + const todayStart = new Date(); + todayStart.setHours(0, 0, 0, 0); + const todayEnd = new Date(); + todayEnd.setHours(23, 59, 59, 999); + + // 4) Wahlen laden (inkl. Kandidaten, Stimmen und Verknüpfungen) + const rawElections = await Election.findAll({ + where: { + regionId: { [Op.in]: regionIds }, + date: { [Op.between]: [todayStart, todayEnd] } + }, + include: [ + { + model: RegionData, + as: 'region', + attributes: ['name'], + include: [{ + model: RegionType, + as: 'regionType', + attributes: ['labelTr'] + }] + }, + { + model: PoliticalOfficeType, + as: 'officeType', + attributes: ['name'] + }, + { + model: Candidate, + as: 'candidates', + attributes: ['id'], + include: [{ + model: FalukantCharacter, + as: 'character', + attributes: ['birthdate', 'gender'], + include: [ + { model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'] }, + { model: FalukantPredefineLastname, as: 'definedLastName', attributes: ['name'] }, + { model: TitleOfNobility, as: 'nobleTitle', attributes: ['labelTr'] } + ] + }] + }, + { + model: Vote, + as: 'votes', + attributes: ['candidateId'], + where: { + falukantUserId: user.id + }, + required: false + } + ] + }); + + return rawElections.map(election => { + const e = election.get({ plain: true }); + + const voted = Array.isArray(e.votes) && e.votes.length > 0; + const reducedCandidates = (e.candidates || []).map(cand => { + const ch = cand.character || {}; + const firstname = ch.definedFirstName?.name || ''; + const lastname = ch.definedLastName?.name || ''; + return { + id: cand.id, + title: ch.nobleTitle?.labelTr || null, + name: `${firstname} ${lastname}`.trim(), + age: calcAge(ch.birthdate), + gender: ch.gender + }; + }); + + return { + id: e.id, + officeType: { name: e.officeType.name }, + region: { + name: e.region.name, + regionType: { labelTr: e.region.regionType.labelTr } + }, + date: e.date, + postsToFill: e.postsToFill, + candidates: reducedCandidates, + voted: voted, + votedFor: voted ? e.votes.map(vote => { return vote.candidateId }) : null, + }; + }); + } + + async vote(hashedUserId, votes) { + const elections = await this.getElections(hashedUserId); + if (!Array.isArray(elections) || elections.length === 0) { + throw new Error('No elections found'); + } + const user = await this.getFalukantUserByHashedId(hashedUserId); + if (!user) { + throw new Error('User not found'); + } + const validElections = votes.filter(voteEntry => { + const e = elections.find(el => el.id === voteEntry.electionId); + return e && !e.voted; + }); + + if (validElections.length === 0) { + throw new Error('No valid elections to vote for (either non‐existent or already voted)'); + } + validElections.forEach(voteEntry => { + const e = elections.find(el => el.id === voteEntry.electionId); + const allowedIds = e.candidates.map(c => c.id); + voteEntry.candidateIds.forEach(cid => { + if (!allowedIds.includes(cid)) { + throw new Error(`Candidate ID ${cid} is not valid for election ${e.id}`); + } + }); + if (voteEntry.candidateIds.length > e.postsToFill) { + throw new Error(`Too many candidates selected for election ${e.id}. Allowed: ${e.postsToFill}`); + } + }); + return await sequelize.transaction(async (tx) => { + const toCreate = []; + validElections.forEach(voteEntry => { + voteEntry.candidateIds.forEach(candidateId => { + toCreate.push({ + electionId: voteEntry.electionId, + candidateId, + falukantUserId: user.id + }); + }); + }); + await Vote.bulkCreate(toCreate, { + transaction: tx, + ignoreDuplicates: true, + returning: false + }); + return { success: true }; + }); + } + + async getOpenPolitics(hashedUserId) { + const user = await this.getFalukantUserByHashedId(hashedUserId); + const characterId = user.character.id; + const rows = await sequelize.query( + FalukantService.RECURSIVE_REGION_SEARCH, + { + replacements: { user_id: user.id }, + type: sequelize.QueryTypes.SELECT + } + ); + const regionIds = rows.map(r => r.id); + const histories = await PoliticalOfficeHistory.findAll({ + where: { characterId }, + attributes: ['officeTypeId', 'startDate', 'endDate'] + }); + const heldOfficeTypeIds = histories.map(h => h.officeTypeId); + const allTypes = await PoliticalOfficeType.findAll({ attributes: ['id', 'name'] }); + const nameToId = Object.fromEntries(allTypes.map(t => [t.name, t.id])); + const openPositions = await Election.findAll({ + where: { + regionId: { [Op.in]: regionIds }, + date: { [Op.lt]: new Date() } + }, + include: [ + { + model: RegionData, + as: 'region', + attributes: ['name'], + include: [ + { model: RegionType, as: 'regionType', attributes: ['labelTr'] } + ] + }, + { model: Candidate, as: 'candidates' }, + { + model: PoliticalOfficeType, as: 'officeType', + include: [{ model: PoliticalOfficePrerequisite, as: 'prerequisites' }] + } + ] + }); + const result = openPositions + .filter(election => { + const prereqs = election.officeType.prerequisites || []; + return prereqs.some(pr => { + const jobs = pr.prerequisite.jobs; + if (!Array.isArray(jobs) || jobs.length === 0) return true; + return jobs.some(jobName => { + const reqId = nameToId[jobName]; + return heldOfficeTypeIds.includes(reqId); + }); + }); + }) + .map(election => { + const e = election.get({ plain: true }); + const jobs = e.officeType.prerequisites[0]?.prerequisite.jobs || []; + const matchingHistory = histories + .filter(h => jobs.includes(allTypes.find(t => t.id === h.officeTypeId)?.name)) + .map(h => ({ + officeTypeId: h.officeTypeId, + startDate: h.startDate, + endDate: h.endDate + })); + + return { + ...e, + history: matchingHistory + }; + }); + return result; + } + + async applyForElections(hashedUserId, electionIds) { + // 1) Hole FalukantUser + Character + const user = await this.getFalukantUserByHashedId(hashedUserId); + if (!user) { + throw new Error('User nicht gefunden'); + } + const character = user.character; + if (!character) { + throw new Error('Kein Charakter zum User gefunden'); + } + + // 2) Noncivil‐Titel aussperren + if (character.nobleTitle.labelTr === 'noncivil') { + return { applied: [], skipped: electionIds }; + } + + // 3) Ermittle die heute offenen Wahlen, auf die er zugreifen darf + // (getElections liefert id, officeType, region, date, postsToFill, candidates, voted…) + const openElections = await this.getElections(hashedUserId); + const allowedIds = new Set(openElections.map(e => e.id)); + + // 4) Filter alle electionIds auf gültige/erlaubte + const toTry = electionIds.filter(id => allowedIds.has(id)); + if (toTry.length === 0) { + return { applied: [], skipped: electionIds }; + } + + // 5) Prüfe, auf welche dieser Wahlen der Character bereits als Candidate eingetragen ist + const existing = await Candidate.findAll({ + where: { + electionId: { [Op.in]: toTry }, + characterId: character.id + }, + attributes: ['electionId'] + }); + const alreadyIds = new Set(existing.map(c => c.electionId)); + + // 6) Erstelle Liste der Wahlen, für die er sich noch nicht beworben hat + const newApplications = toTry.filter(id => !alreadyIds.has(id)); + const skipped = electionIds.filter(id => !newApplications.includes(id)); + + console.log(newApplications, skipped); + + // 7) Bulk-Insert aller neuen Bewerbungen + if (newApplications.length > 0) { + const toInsert = newApplications.map(eid => ({ + electionId: eid, + characterId: character.id + })); + await Candidate.bulkCreate(toInsert); + } + + return { + applied: newApplications, + skipped: skipped + }; + } + + async getRegions(hashedUserId) { + const user = await this.getFalukantUserByHashedId(hashedUserId); + const regions = await RegionData.findAll({ + attributes: ['id', 'name', 'map'], + include: [ + { + model: RegionType, + as: 'regionType', + where: { + labelTr: 'city' + }, + attributes: ['labelTr'] + }, + { + model: Branch, + as: 'branches', + where: { + falukantUserId: user.id + }, + include: [ + { + model: BranchType, + as: 'branchType', + attributes: ['labelTr'], + }, + ], + attributes: ['branchTypeId'], + required: false, + } + ] + }); + return regions; + } + + async renovate(hashedUserId, element) { + const user = await getFalukantUserOrFail(hashedUserId); + const house = await UserHouse.findOne({ + where: { userId: user.id }, + include: [{ model: HouseType, as: 'houseType' }] + }); + if (!house) throw new Error('House not found'); + const oldValue = house[element]; + if (oldValue >= 100) { + return { cost: 0 }; + } + const baseCost = house.houseType?.cost || 0; + const cost = this._calculateRenovationCost(baseCost, element, oldValue); + house[element] = 100; + await house.save(); + await updateFalukantUserMoney( + user.id, + -cost, + `renovation_${element}` + ); + return { cost }; + } + + _calculateRenovationCost(baseCost, key, currentVal) { + const weights = { + roofCondition: 0.25, + wallCondition: 0.25, + floorCondition: 0.25, + windowCondition: 0.25 + }; + const weight = weights[key] || 0; + const missing = 100 - currentVal; + const raw = (missing / 100) * baseCost * weight; + return Math.round(raw * 100) / 100; + } + + async renovateAll(hashedUserId) { + const user = await getFalukantUserOrFail(hashedUserId); + const house = await UserHouse.findOne({ + where: { userId: user.id }, + include: [{ model: HouseType, as: 'houseType' }] + }); + if (!house) throw new Error('House not found'); + const baseCost = house.houseType?.cost || 0; + const keys = ['roofCondition', 'wallCondition', 'floorCondition', 'windowCondition']; + let rawSum = 0; + for (const key of keys) { + const current = house[key]; + if (current < 100) { + rawSum += this._calculateRenovationCost(baseCost, key, current); + } + } + const totalCost = Math.round(rawSum * 0.8 * 100) / 100; + for (const key of keys) { + house[key] = 100; + } + await house.save(); + await updateFalukantUserMoney( + user.id, + -totalCost, + 'renovation_all' + ); + + return { cost: totalCost }; + } + +} + export default new FalukantService(); diff --git a/backend/utils/falukant/initializeFalukantTypes.js b/backend/utils/falukant/initializeFalukantTypes.js index d55c1c6..8374256 100644 --- a/backend/utils/falukant/initializeFalukantTypes.js +++ b/backend/utils/falukant/initializeFalukantTypes.js @@ -12,6 +12,8 @@ import PartyType from "../../models/falukant/type/party.js"; import MusicType from "../../models/falukant/type/music.js"; import BanquetteType from "../../models/falukant/type/banquette.js"; import LearnRecipient from "../../models/falukant/type/learn_recipient.js"; +import PoliticalOfficeType from "../../models/falukant/type/political_office_type.js"; +import PoliticalOfficePrerequisite from "../../models/falukant/predefine/political_office_prerequisite.js"; export const initializeFalukantTypes = async () => { await initializeFalukantTypeRegions(); @@ -25,6 +27,8 @@ export const initializeFalukantTypes = async () => { await initializeFalukantMusicTypes(); await initializeFalukantBanquetteTypes(); await initializeLearnerTypes(); + await initializePoliticalOfficeTypes(); + await initializePoliticalOfficePrerequisites(); }; const regionTypes = []; @@ -39,14 +43,15 @@ const regionTypeTrs = [ const regions = [ { labelTr: "falukant", regionType: "country", parentTr: null }, - { labelTr: "duchy1", regionType: "duchy", parentTr: "falukant" }, - { labelTr: "markgravate", regionType: "markgravate", parentTr: "duchy1" }, - { labelTr: "shire1", regionType: "shire", parentTr: "markgravate" }, - { labelTr: "county1", regionType: "county", parentTr: "shire1" }, - { labelTr: "town1", regionType: "city", parentTr: "county1" }, - { labelTr: "town2", regionType: "city", parentTr: "county1" }, - { labelTr: "town3", regionType: "city", parentTr: "county1" }, - { labelTr: "town4", regionType: "city", parentTr: "county1" }, + { labelTr: "Hessen", regionType: "duchy", parentTr: "falukant" }, + { labelTr: "Groß-Benbach", regionType: "markgravate", parentTr: "Hessen" }, + { labelTr: "Siebenbachen", regionType: "shire", parentTr: "Groß-Benbach" }, + { labelTr: "Bad Homburg", regionType: "county", parentTr: "Siebenbachen" }, + { labelTr: "Maintal", regionType: "county", parentTr: "Siebenbachen" }, + { labelTr: "Frankfurt", regionType: "city", parentTr: "Bad Homburg", map: {x: 187, y: 117, w: 10, h:11} }, + { labelTr: "Oberursel", regionType: "city", parentTr: "Bad Homburg", map: {x: 168, y: 121, w: 10, h:11} }, + { labelTr: "Offenbach", regionType: "city", parentTr: "Bad Homburg", map: {x: 171, y: 142, w: 10, h:11} }, + { labelTr: "Königstein", regionType: "city", parentTr: "Maintal", map: {x: 207, y: 124, w: 24, h:18} }, ]; const relationships = [ @@ -244,8 +249,8 @@ const musicTypes = [ ]; const banquetteTypes = [ - { type: 'bread', cost: 5, reputationGrowth: 0 }, - { type: 'roastWithBeer', cost: 200, reputationGrowth: 5 }, + { type: 'bread', cost: 5, reputationGrowth: 0 }, + { type: 'roastWithBeer', cost: 200, reputationGrowth: 5 }, { type: 'poultryWithVegetablesAndWine', cost: 5000, reputationGrowth: 10 }, { type: 'extensiveBuffet', cost: 100000, reputationGrowth: 20 } ]; @@ -256,6 +261,282 @@ const learnerTypes = [ { tr: 'director', }, ]; +const politicalOffices = [ + { tr: "assessor", seatsPerRegion: 10, regionType: "city", termLength: 5 }, + { tr: "councillor", seatsPerRegion: 7, regionType: "city", termLength: 7 }, + { tr: "council", seatsPerRegion: 5, regionType: "city", termLength: 4 }, + { tr: "beadle", seatsPerRegion: 1, regionType: "city", termLength: 6 }, + { tr: "town-clerk", seatsPerRegion: 3, regionType: "city", termLength: 10 }, + { tr: "mayor", seatsPerRegion: 1, regionType: "city", termLength: 3 }, + { tr: "master-builder", seatsPerRegion: 10, regionType: "county", termLength: 10 }, + { tr: "village-major", seatsPerRegion: 6, regionType: "county", termLength: 5 }, + { tr: "judge", seatsPerRegion: 3, regionType: "county", termLength: 8 }, + { tr: "bailif", seatsPerRegion: 1, regionType: "county", termLength: 4 }, + { tr: "taxman", seatsPerRegion: 8, regionType: "shire", termLength: 5 }, + { tr: "sheriff", seatsPerRegion: 5, regionType: "shire", termLength: 8 }, + { tr: "consultant", seatsPerRegion: 3, regionType: "shire", termLength: 9 }, + { tr: "treasurer", seatsPerRegion: 1, regionType: "shire", termLength: 7 }, + { tr: "hangman", seatsPerRegion: 9, regionType: "markgravate", termLength: 5 }, + { tr: "territorial-council", seatsPerRegion: 6, regionType: "markgravate", termLength: 6 }, + { tr: "territorial-council-speaker", seatsPerRegion: 4, regionType: "markgravate", termLength: 8 }, + { tr: "ruler-consultant", seatsPerRegion: 1, regionType: "markgravate", termLength: 3 }, + { tr: "state-administrator", seatsPerRegion: 7, regionType: "duchy", termLength: 3 }, + { tr: "super-state-administrator", seatsPerRegion: 5, regionType: "duchy", termLength: 6 }, + { tr: "governor", seatsPerRegion: 1, regionType: "duchy", termLength: 5 }, + { tr: "ministry-helper", seatsPerRegion: 12, regionType: "country", termLength: 4 }, + { tr: "minister", seatsPerRegion: 3, regionType: "country", termLength: 4 }, + { tr: "chancellor", seatsPerRegion: 1, regionType: "country", termLength: 4 } +]; + +const politicalOfficePrerequisites = [ + { + officeTr: "assessor", + prerequisite: { + titles: [ + "civil", "sir", "townlord", "by", "landlord", "knight", + "baron", "count", "palsgrave", "margrave", "landgrave", + "ruler", "elector", "imperial-prince", "duke", "grand-duke", + "prince-regent", "king" + ] + } + }, + { + officeTr: "councillor", + prerequisite: { + titles: [ + "civil", "sir", "townlord", "by", "landlord", "knight", + "baron", "count", "palsgrave", "margrave", "landgrave", + "ruler", "elector", "imperial-prince", "duke", "grand-duke", + "prince-regent", "king" + ], + jobs: ["assessor"] + } + }, + { + officeTr: "council", + prerequisite: { + titles: [ + "civil", "sir", "townlord", "by", "landlord", "knight", + "baron", "count", "palsgrave", "margrave", "landgrave", + "ruler", "elector", "imperial-prince", "duke", "grand-duke", + "prince-regent", "king" + ], + jobs: ["councillor"] + } + }, + { + officeTr: "beadle", + prerequisite: { + titles: [ + "sir", "townlord", "by", "landlord", "knight", "baron", + "count", "palsgrave", "margrave", "landgrave", "ruler", + "elector", "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["council"] + } + }, + { + officeTr: "town-clerk", + prerequisite: { + titles: [ + "sir", "townlord", "by", "landlord", "knight", "baron", + "count", "palsgrave", "margrave", "landgrave", "ruler", + "elector", "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["council"] + } + }, + { + officeTr: "mayor", + prerequisite: { + titles: [ + "townlord", "by", "landlord", "knight", "baron", "count", + "palsgrave", "margrave", "landgrave", "ruler", "elector", + "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["beadle", "town-clerk"] + } + }, + { + officeTr: "master-builder", + prerequisite: { + titles: [ + "by", "landlord", "knight", "baron", "count", "palsgrave", + "margrave", "landgrave", "ruler", "elector", "imperial-prince", + "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["mayor"] + } + }, + { + officeTr: "village-major", + prerequisite: { + titles: [ + "by", "landlord", "knight", "baron", "count", "palsgrave", + "margrave", "landgrave", "ruler", "elector", "imperial-prince", + "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["master-builder"] + } + }, + { + officeTr: "judge", + prerequisite: { + titles: [ + "landlord", "knight", "baron", "count", "palsgrave", "margrave", + "landgrave", "ruler", "elector", "imperial-prince", "duke", + "grand-duke", "prince-regent", "king" + ], + jobs: ["village-major"] + } + }, + { + officeTr: "bailif", + prerequisite: { + titles: [ + "landlord", "knight", "baron", "count", "palsgrave", "margrave", + "landgrave", "ruler", "elector", "imperial-prince", "duke", + "grand-duke", "prince-regent", "king" + ], + jobs: ["judge"] + } + }, + { + officeTr: "taxman", + prerequisite: { + titles: [ + "knight", "baron", "count", "palsgrave", "margrave", "landgrave", + "ruler", "elector", "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["bailif"] + } + }, + { + officeTr: "sheriff", + prerequisite: { + titles: [ + "baron", "count", "palsgrave", "margrave", "landgrave", "ruler", + "elector", "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["taxman"] + } + }, + { + officeTr: "consultant", + prerequisite: { + titles: [ + "baron", "count", "palsgrave", "margrave", "landgrave", "ruler", + "elector", "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["sheriff"] + } + }, + { + officeTr: "treasurer", + prerequisite: { + titles: [ + "count", "palsgrave", "margrave", "landgrave", "ruler", "elector", + "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["consultant"] + } + }, + { + officeTr: "hangman", + prerequisite: { + titles: [ + "count", "palsgrave", "margrave", "landgrave", "ruler", "elector", + "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["consultant"] + } + }, + { + officeTr: "territorial-council", + prerequisite: { + titles: [ + "palsgrave", "margrave", "landgrave", "ruler", "elector", "imperial-prince", + "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["treasurer", "hangman"] + } + }, + { + officeTr: "territorial-council-speaker", + prerequisite: { + titles: [ + "margrave", "landgrave", "ruler", "elector", "imperial-prince", "duke", + "grand-duke", "prince-regent", "king" + ], + jobs: ["territorial-council"] + } + }, + { + officeTr: "ruler-consultant", + prerequisite: { + titles: [ + "landgrave", "ruler", "elector", "imperial-prince", "duke", "grand-duke", + "prince-regent", "king" + ], + jobs: ["territorial-council-speaker"] + } + }, + { + officeTr: "state-administrator", + prerequisite: { + titles: [ + "ruler", "elector", "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["ruler-consultant"] + } + }, + { + officeTr: "super-state-administrator", + prerequisite: { + titles: [ + "elector", "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["state-administrator"] + } + }, + { + officeTr: "governor", + prerequisite: { + titles: [ + "imperial-prince", "duke", "grand-duke", "prince-regent", "king" + ], + jobs: ["super-state-administrator"] + } + }, + { + officeTr: "ministry-helper", + prerequisite: { + titles: [ + "grand-duke", "prince-regent", "king" + ], + jobs: ["governor"] + } + }, + { + officeTr: "minister", + prerequisite: { + titles: [ + "prince-regent", "king" + ], + jobs: ["ministry-helper"] + } + }, + { + officeTr: "chancellor", + prerequisite: { + titles: [ + "prince-regent", "king" + ], + jobs: ["minister"] + } + } +]; + { const giftNames = promotionalGifts.map(g => g.name); const traitNames = characterTraits.map(t => t.name); @@ -330,7 +611,8 @@ export const initializeFalukantRegions = async () => { where: { name: region.labelTr }, defaults: { regionTypeId: regionType.id, - parentId: parentRegion?.id || null + parentId: parentRegion?.id || null, + map: parentRegion?.map || {}, } }); } @@ -478,4 +760,37 @@ export const initializeLearnerTypes = async () => { } }); } -} \ No newline at end of file +} + +export const initializePoliticalOfficeTypes = async () => { + for (const po of politicalOffices) { + await PoliticalOfficeType.findOrCreate({ + where: { name: po.tr }, + defaults: { + seatsPerRegion: po.seatsPerRegion, + regionType: po.regionType, + termLength: po.termLength + } + }); + } +}; + +export const initializePoliticalOfficePrerequisites = async () => { + for (const prereq of politicalOfficePrerequisites) { + // zunächst den OfficeType anhand seines Namens (tr) ermitteln + const office = await PoliticalOfficeType.findOne({ + where: { name: prereq.officeTr } + }); + if (!office) continue; + + // Nun findOrCreate mit dem neuen Spaltennamen: + await PoliticalOfficePrerequisite.findOrCreate({ + where: { office_type_id: office.id }, + defaults: { + office_type_id: office.id, + prerequisite: prereq.prerequisite + } + }); + } + }; + \ No newline at end of file diff --git a/dump.rdb b/dump.rdb index 45e19e6..9612a68 100644 Binary files a/dump.rdb and b/dump.rdb differ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4441bac..5c03670 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,13 +8,13 @@ "name": "frontend", "version": "1.0.0", "dependencies": { - "@tinymce/tinymce-vue": "^6.0.1", + "@tiptap/starter-kit": "^2.14.0", + "@tiptap/vue-3": "^2.14.0", "axios": "^1.7.2", "date-fns": "^3.6.0", "dotenv": "^16.4.5", "mitt": "^3.0.1", "socket.io-client": "^4.8.1", - "tinymce": "^7.3.0", "vue": "~3.4.31", "vue-i18n": "^10.0.0-beta.2", "vue-multiselect": "^3.1.0", @@ -30,7 +30,7 @@ "sass": "^1.77.8", "stream-browserify": "^3.0.0", "util": "^0.12.5", - "vite": "^5.4.4" + "vite": "^6.3.5" } }, "node_modules/@babel/helper-string-parser": { @@ -99,380 +99,438 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", "cpu": [ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", "cpu": [ - "x64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@intlify/core-base": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.5.tgz", - "integrity": "sha512-F3snDTQs0MdvnnyzTDTVkOYVAZOE/MHwRvF7mn7Jw1yuih4NrFYLNYIymGlLmq4HU2iIdzYsZ7f47bOcwY73XQ==", + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.7.tgz", + "integrity": "sha512-mE71aUH5baH0me8duB4FY5qevUJizypHsYw3eCvmOx07QvmKppgOONx3dYINxuA89Z2qkAGb/K6Nrpi7aAMwew==", + "license": "MIT", "dependencies": { - "@intlify/message-compiler": "10.0.5", - "@intlify/shared": "10.0.5" + "@intlify/message-compiler": "10.0.7", + "@intlify/shared": "10.0.7" }, "engines": { "node": ">= 16" @@ -482,11 +540,12 @@ } }, "node_modules/@intlify/message-compiler": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.5.tgz", - "integrity": "sha512-6GT1BJ852gZ0gItNZN2krX5QAmea+cmdjMvsWohArAZ3GmHdnNANEcF9JjPXAMRtQ6Ux5E269ymamg/+WU6tQA==", + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.7.tgz", + "integrity": "sha512-nrC4cDL/UHZSUqd8sRbVz+DPukzZ8NnG5OK+EB/nlxsH35deyzyVkXP/QuR8mFZrISJ+4hCd6VtCQCcT+RO+5g==", + "license": "MIT", "dependencies": { - "@intlify/shared": "10.0.5", + "@intlify/shared": "10.0.7", "source-map-js": "^1.0.2" }, "engines": { @@ -497,9 +556,10 @@ } }, "node_modules/@intlify/shared": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.5.tgz", - "integrity": "sha512-bmsP4L2HqBF6i6uaMqJMcFBONVjKt+siGluRq4Ca4C0q7W2eMaVZr8iCgF9dKbcVXutftkC7D6z2SaSMmLiDyA==", + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.7.tgz", + "integrity": "sha512-oeoq0L5+5P4ShXa6jBQcx+BT+USe3MjX0xJexZO1y7rfDJdwZ9+QP3jO4tcS1nxhBYYdjvFTqe4bmnLijV0GxQ==", + "license": "MIT", "engines": { "node": ">= 16" }, @@ -512,10 +572,26 @@ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@remirror/core-constants": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", + "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.26.0.tgz", - "integrity": "sha512-gJNwtPDGEaOEgejbaseY6xMFu+CPltsc8/T+diUTTbOQLqD+bnrJq9ulH6WD69TqwqWmrfRAtUv30cCFZlbGTQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz", + "integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==", "cpu": [ "arm" ], @@ -527,9 +603,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.26.0.tgz", - "integrity": "sha512-YJa5Gy8mEZgz5JquFruhJODMq3lTHWLm1fOy+HIANquLzfIOzE9RA5ie3JjCdVb9r46qfAQY/l947V0zfGJ0OQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz", + "integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==", "cpu": [ "arm64" ], @@ -541,9 +617,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.26.0.tgz", - "integrity": "sha512-ErTASs8YKbqTBoPLp/kA1B1Um5YSom8QAc4rKhg7b9tyyVqDBlQxy7Bf2wW7yIlPGPg2UODDQcbkTlruPzDosw==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz", + "integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==", "cpu": [ "arm64" ], @@ -555,9 +631,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.26.0.tgz", - "integrity": "sha512-wbgkYDHcdWW+NqP2mnf2NOuEbOLzDblalrOWcPyY6+BRbVhliavon15UploG7PpBRQ2bZJnbmh8o3yLoBvDIHA==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz", + "integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==", "cpu": [ "x64" ], @@ -569,9 +645,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.26.0.tgz", - "integrity": "sha512-Y9vpjfp9CDkAG4q/uwuhZk96LP11fBz/bYdyg9oaHYhtGZp7NrbkQrj/66DYMMP2Yo/QPAsVHkV891KyO52fhg==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz", + "integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==", "cpu": [ "arm64" ], @@ -583,9 +659,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.26.0.tgz", - "integrity": "sha512-A/jvfCZ55EYPsqeaAt/yDAG4q5tt1ZboWMHEvKAH9Zl92DWvMIbnZe/f/eOXze65aJaaKbL+YeM0Hz4kLQvdwg==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz", + "integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==", "cpu": [ "x64" ], @@ -597,9 +673,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.26.0.tgz", - "integrity": "sha512-paHF1bMXKDuizaMODm2bBTjRiHxESWiIyIdMugKeLnjuS1TCS54MF5+Y5Dx8Ui/1RBPVRE09i5OUlaLnv8OGnA==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz", + "integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==", "cpu": [ "arm" ], @@ -611,9 +687,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.26.0.tgz", - "integrity": "sha512-cwxiHZU1GAs+TMxvgPfUDtVZjdBdTsQwVnNlzRXC5QzIJ6nhfB4I1ahKoe9yPmoaA/Vhf7m9dB1chGPpDRdGXg==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz", + "integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==", "cpu": [ "arm" ], @@ -625,9 +701,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.26.0.tgz", - "integrity": "sha512-4daeEUQutGRCW/9zEo8JtdAgtJ1q2g5oHaoQaZbMSKaIWKDQwQ3Yx0/3jJNmpzrsScIPtx/V+1AfibLisb3AMQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz", + "integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==", "cpu": [ "arm64" ], @@ -639,9 +715,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.26.0.tgz", - "integrity": "sha512-eGkX7zzkNxvvS05ROzJ/cO/AKqNvR/7t1jA3VZDi2vRniLKwAWxUr85fH3NsvtxU5vnUUKFHKh8flIBdlo2b3Q==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz", + "integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==", "cpu": [ "arm64" ], @@ -652,10 +728,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz", + "integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.26.0.tgz", - "integrity": "sha512-Odp/lgHbW/mAqw/pU21goo5ruWsytP7/HCC/liOt0zcGG0llYWKrd10k9Fj0pdj3prQ63N5yQLCLiE7HTX+MYw==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz", + "integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==", "cpu": [ "ppc64" ], @@ -667,9 +757,23 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.26.0.tgz", - "integrity": "sha512-MBR2ZhCTzUgVD0OJdTzNeF4+zsVogIR1U/FsyuFerwcqjZGvg2nYe24SAHp8O5sN8ZkRVbHwlYeHqcSQ8tcYew==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz", + "integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz", + "integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==", "cpu": [ "riscv64" ], @@ -681,9 +785,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.26.0.tgz", - "integrity": "sha512-YYcg8MkbN17fMbRMZuxwmxWqsmQufh3ZJFxFGoHjrE7bv0X+T6l3glcdzd7IKLiwhT+PZOJCblpnNlz1/C3kGQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz", + "integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==", "cpu": [ "s390x" ], @@ -695,9 +799,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.26.0.tgz", - "integrity": "sha512-ZuwpfjCwjPkAOxpjAEjabg6LRSfL7cAJb6gSQGZYjGhadlzKKywDkCUnJ+KEfrNY1jH5EEoSIKLCb572jSiglA==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz", + "integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==", "cpu": [ "x64" ], @@ -709,9 +813,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.26.0.tgz", - "integrity": "sha512-+HJD2lFS86qkeF8kNu0kALtifMpPCZU80HvwztIKnYwym3KnA1os6nsX4BGSTLtS2QVAGG1P3guRgsYyMA0Yhg==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz", + "integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==", "cpu": [ "x64" ], @@ -723,9 +827,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.26.0.tgz", - "integrity": "sha512-WUQzVFWPSw2uJzX4j6YEbMAiLbs0BUysgysh8s817doAYhR5ybqTI1wtKARQKo6cGop3pHnrUJPFCsXdoFaimQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz", + "integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==", "cpu": [ "arm64" ], @@ -737,9 +841,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.26.0.tgz", - "integrity": "sha512-D4CxkazFKBfN1akAIY6ieyOqzoOoBV1OICxgUblWxff/pSjCA2khXlASUx7mK6W1oP4McqhgcCsu6QaLj3WMWg==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz", + "integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==", "cpu": [ "ia32" ], @@ -751,9 +855,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.26.0.tgz", - "integrity": "sha512-2x8MO1rm4PGEP0xWbubJW5RtbNLk3puzAMaLQd3B3JHVw4KcHlmXcO+Wewx9zCoo7EUFiMlu/aZbCJ7VjMzAag==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz", + "integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==", "cpu": [ "x64" ], @@ -769,34 +873,427 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" }, - "node_modules/@tinymce/tinymce-vue": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-6.0.1.tgz", - "integrity": "sha512-VzjI8AKlNrrsosIk3WuBez6kubqPsPMeaButkRLuts77uo4e2EwPRFX+VyB6fHbMGHwUPK22zNjOUGMvJFZFCw==", - "dependencies": { - "tinymce": "^7.0.0 || ^6.0.0 || ^5.5.1" + "node_modules/@tiptap/core": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.14.0.tgz", + "integrity": "sha512-MBSMzGYRFlwYCocvx3dU7zpCBSDQ0qWByNtStaEzuBUgzCJ6wn2DP/xG0cMcLmE3Ia0VLM4nwbLOAAvBXOtylA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.14.0.tgz", + "integrity": "sha512-AwqPP0jLYNioKxakiVw0vlfH/ceGFbV+SGoqBbPSGFPRdSbHhxHDNBlTtiThmT3N2PiVwXAD9xislJV+WY4GUA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.14.0.tgz", + "integrity": "sha512-8DWwelH55H8KtLECSIv0wh8x/F/6lpagV/pMvT+Azujad0oqK+1iAPKU/kLgjXbFSkisrpV6KSwQts5neCtfRQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.14.0.tgz", + "integrity": "sha512-sN15n0RjPh+2Asvxs7l47hVEvX6c0aPempU8QQWcPUlHoGf1D/XkyHXy6GWVPSxZ5Rj5uAwgKvhHsG/FJ/YGKQ==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.14.0.tgz", + "integrity": "sha512-SWnL4bP8Mm/mWN42AMQNoqYE0V6LgSBTVsHwwAki2wIUQdr9HyoAnohvHy3IME56NMwoyZyo+Mzl45wOqUxziA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.14.0.tgz", + "integrity": "sha512-kyo02mnzqgwXayMcyRA/fHQgb+nMmQQpIt1irZwjtEoFZshA7NnY/6b5SJmRcxQ4/X4r2Y2Ha2sWmOcEkLmt4A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.14.0.tgz", + "integrity": "sha512-LRYYZeh8U2XgfTsJ4houB9s9cVRt7PRfVa4MaCeOYKfowVOKQh67yV5oom8Azk9XrMPkPxDmMmdPAEPxeVYFvw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.14.0.tgz", + "integrity": "sha512-qwEgpPIJ3AgXdEtRTr88hODbXRdt14VAwLj27PTSqexB5V7Ra1Jy7iQDhqRwBCoUomVywBsWYxkSuDisSRG+9w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.14.0.tgz", + "integrity": "sha512-FIh5cdPuoPKvZ0GqSKhzMZGixm05ac3hSgqhMNCBZmXX459qBUI9CvDl/uzSnY9koBDeLVV3HYMthWQQLSXl9A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.14.0.tgz", + "integrity": "sha512-Khx7M7RfZlD1/T/PUlpJmao6FtEBa2L6td2hhaW1USflwGJGk0U/ud4UEqh+aZoJZrkot/EMhEvzmORF3nq+xw==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.14.0.tgz", + "integrity": "sha512-as+SqC39FRshw4Fm1XVlrdSXveiusf5xiC4nuefLmXsUxO7Yx67x8jS0/VQbxWTLHZ6R1YEW8prLtnxGmVLCAQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.14.0.tgz", + "integrity": "sha512-A8c8n8881iBq3AusNqibh6Hloybr+FgYdg4Lg4jNxbbEaL0WhyLFge1bWlGVpbHXFqdv5YldMUAu6Rop3FhNvw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.14.0.tgz", + "integrity": "sha512-vM//6G3Ox3mxPv9eilhrDqylELCc8kEP1aQ4xUuOw7vCidjNtGggOa1ERnnpV2dCa2A9E8y4FHtN4Xh29stXQg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-history": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.14.0.tgz", + "integrity": "sha512-/qnOHQFCEPfkb3caykqd+sqzEC2gx30EQB/mM7+5kIG7CQy7XXaGjFAEaqzE1xJ783Q2E7GVk4JxWM+3NhYSLw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.14.0.tgz", + "integrity": "sha512-OrKWgHOhmJtVHjPYaEJetNLiNEvrI85lTrGxzeQa+a8ACb93h4svyHe9J+LHs5pKkXDQFcpYEXJntu0LVLLiDw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.14.0.tgz", + "integrity": "sha512-yEw2S+smoVR8DMYQMAWckVW2Sstf7z5+GBZ8zm8NMGhMKb1JFCPZUv5KTTIPnq7ZrKuuZHvjN9+Ef1dRYD8T2A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.14.0.tgz", + "integrity": "sha512-t1jXDPEd82sC6vZVE/12/CB52uuiydCIcRfwdh21xNgBMckToKO9S0K6XEp4ROtrKQdlIH2JDVPfpUBvVrYN8Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.14.0.tgz", + "integrity": "sha512-QUZcyuW9AKvSfpFHcGmbyRCqxcpY0VNf0xipEtogxbA+JDDw3ZSPqU1dUgz9wk00RahPTwNDdY5aVjdQ5N4N9Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.14.0.tgz", + "integrity": "sha512-bsQesVpgvDS2e+wr2fp59QO7rWRp2FqcJvBafwXS3Br9U5Mx3eFYryx4wC7cUnhlhUwX5pmaoA7zISgV9dZDgg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.14.0.tgz", + "integrity": "sha512-rD5d/IL3XPfBOrHRHxt+b+0X1jbIbWONGiad/3sX0ZYQD3PandtCWboH40r/J5tFksebuY12dVYyYQKgLpDBOQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.14.0.tgz", + "integrity": "sha512-rHny566nGZHq61zRLwQ9BPG55W/O+eDKwUJl+LhrLiVWwzpvAl9QQYixtoxJKOY48VK41PKwxe3bgDYgNs/Fhg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-text-style": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.14.0.tgz", + "integrity": "sha512-dl0oi2i0rjLpBqTf4wGy6SLidvPpjxLcmX727pwJlCklkFJVDf8wSFeD4ddxJXiD2Rwef0D/lkcwXSY73CoDcA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/pm": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.14.0.tgz", + "integrity": "sha512-cnsfaIlvTFCDtLP/A2Fd3LmpttgY0O/tuTM2fC71vetONz83wUTYT+aD9uvxdX0GkSocoh840b0TsEazbBxhpA==", + "license": "MIT", + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-collab": "^1.3.1", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.23.0", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.4.1", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-trailing-node": "^3.0.0", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.37.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.14.0.tgz", + "integrity": "sha512-Z1bKAfHl14quRI3McmdU+bs675jp6/iexEQTI9M9oHa6l3McFF38g9N3xRpPPX02MX83DghsUPupndUW/yJvEQ==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^2.14.0", + "@tiptap/extension-blockquote": "^2.14.0", + "@tiptap/extension-bold": "^2.14.0", + "@tiptap/extension-bullet-list": "^2.14.0", + "@tiptap/extension-code": "^2.14.0", + "@tiptap/extension-code-block": "^2.14.0", + "@tiptap/extension-document": "^2.14.0", + "@tiptap/extension-dropcursor": "^2.14.0", + "@tiptap/extension-gapcursor": "^2.14.0", + "@tiptap/extension-hard-break": "^2.14.0", + "@tiptap/extension-heading": "^2.14.0", + "@tiptap/extension-history": "^2.14.0", + "@tiptap/extension-horizontal-rule": "^2.14.0", + "@tiptap/extension-italic": "^2.14.0", + "@tiptap/extension-list-item": "^2.14.0", + "@tiptap/extension-ordered-list": "^2.14.0", + "@tiptap/extension-paragraph": "^2.14.0", + "@tiptap/extension-strike": "^2.14.0", + "@tiptap/extension-text": "^2.14.0", + "@tiptap/extension-text-style": "^2.14.0", + "@tiptap/pm": "^2.14.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/vue-3": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-2.14.0.tgz", + "integrity": "sha512-w7jzOYmaNgL/1p4q3wRJf4NdvO23IvOgGR6sUM/3ULtjG0dchn9JMpD3Vm7Y9FLSKBcwAWZim4gR6PFIvIsETA==", + "license": "MIT", + "dependencies": { + "@tiptap/extension-bubble-menu": "^2.14.0", + "@tiptap/extension-floating-menu": "^2.14.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0", "vue": "^3.0.0" } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "dev": true, "license": "MIT" }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-vue": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.3.tgz", - "integrity": "sha512-3xbWsKEKXYlmX82aOHufFQVnkbMC/v8fLpWwh6hWOUrK5fbbtBh9Q/WWse27BFgSy2/e2c0fz5Scgya9h2GLhw==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^5.0.0", + "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, @@ -909,6 +1406,12 @@ "node": ">= 8" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", @@ -943,9 +1446,10 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -1030,6 +1534,12 @@ "node": ">= 0.8" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1166,48 +1676,50 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" } }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -1530,6 +2042,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -1538,6 +2059,29 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1569,15 +2113,16 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -1637,10 +2182,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -1664,9 +2216,9 @@ } }, "node_modules/postcss": { - "version": "8.4.45", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", - "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -1681,20 +2233,225 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, + "node_modules/prosemirror-changeset": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz", + "integrity": "sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-collab": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", + "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz", + "integrity": "sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz", + "integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.0.tgz", + "integrity": "sha512-K0xJRCmt+uSw7xesnHmcn72yBGTbY45vm8gXI4LZXbx2Z0jwh5aF9xrGQgrVPu0WbyFVFF3E/o9VhJYz6SQWnA==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-markdown": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz", + "integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==", + "license": "MIT", + "dependencies": { + "@types/markdown-it": "^14.0.0", + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-menu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.5.tgz", + "integrity": "sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==", + "license": "MIT", + "dependencies": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.1.tgz", + "integrity": "sha512-AUvbm7qqmpZa5d9fPKMvH1Q5bqYQvAZWOGRvxsB6iFLyycvC9MwNemNVjHVrWgjaoxAfY8XVg7DbvQ/qxvI9Eg==", + "license": "MIT", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-basic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", + "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz", + "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.7.1.tgz", + "integrity": "sha512-eRQ97Bf+i9Eby99QbyAiyov43iOKgWa7QCGly+lrDt7efZ1v8NWolhXiB43hSDGIXT1UXgbs4KJN3a06FGpr1Q==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.2", + "prosemirror-model": "^1.25.0", + "prosemirror-state": "^1.4.3", + "prosemirror-transform": "^1.10.3", + "prosemirror-view": "^1.39.1" + } + }, + "node_modules/prosemirror-trailing-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", + "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", + "license": "MIT", + "dependencies": { + "@remirror/core-constants": "3.0.0", + "escape-string-regexp": "^4.0.0" + }, + "peerDependencies": { + "prosemirror-model": "^1.22.1", + "prosemirror-state": "^1.4.2", + "prosemirror-view": "^1.33.8" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.4.tgz", + "integrity": "sha512-pwDy22nAnGqNR1feOQKHxoFkkUtepoFAd3r2hbEDsnf4wp57kKA36hXsB3njA9FtONBEwSDnDeCiJe+ItD+ykw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.40.0.tgz", + "integrity": "sha512-2G3svX0Cr1sJjkD/DYWSe3cfV5VPVTBOxI9XQEGWJDFEpsZb/gh4MV29ctv+OJx2RFX4BLt09i+6zaGM/ldkCw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -1722,13 +2479,13 @@ } }, "node_modules/rollup": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.26.0.tgz", - "integrity": "sha512-ilcl12hnWonG8f+NxU6BlgysVA0gvY2l8N0R84S1HcINbW20bvwuCngJkkInV6LXhwRpucsW5k1ovDwEdBVrNg==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz", + "integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -1738,24 +2495,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.26.0", - "@rollup/rollup-android-arm64": "4.26.0", - "@rollup/rollup-darwin-arm64": "4.26.0", - "@rollup/rollup-darwin-x64": "4.26.0", - "@rollup/rollup-freebsd-arm64": "4.26.0", - "@rollup/rollup-freebsd-x64": "4.26.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.26.0", - "@rollup/rollup-linux-arm-musleabihf": "4.26.0", - "@rollup/rollup-linux-arm64-gnu": "4.26.0", - "@rollup/rollup-linux-arm64-musl": "4.26.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.26.0", - "@rollup/rollup-linux-riscv64-gnu": "4.26.0", - "@rollup/rollup-linux-s390x-gnu": "4.26.0", - "@rollup/rollup-linux-x64-gnu": "4.26.0", - "@rollup/rollup-linux-x64-musl": "4.26.0", - "@rollup/rollup-win32-arm64-msvc": "4.26.0", - "@rollup/rollup-win32-ia32-msvc": "4.26.0", - "@rollup/rollup-win32-x64-msvc": "4.26.0", + "@rollup/rollup-android-arm-eabi": "4.43.0", + "@rollup/rollup-android-arm64": "4.43.0", + "@rollup/rollup-darwin-arm64": "4.43.0", + "@rollup/rollup-darwin-x64": "4.43.0", + "@rollup/rollup-freebsd-arm64": "4.43.0", + "@rollup/rollup-freebsd-x64": "4.43.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", + "@rollup/rollup-linux-arm-musleabihf": "4.43.0", + "@rollup/rollup-linux-arm64-gnu": "4.43.0", + "@rollup/rollup-linux-arm64-musl": "4.43.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", + "@rollup/rollup-linux-riscv64-gnu": "4.43.0", + "@rollup/rollup-linux-riscv64-musl": "4.43.0", + "@rollup/rollup-linux-s390x-gnu": "4.43.0", + "@rollup/rollup-linux-x64-gnu": "4.43.0", + "@rollup/rollup-linux-x64-musl": "4.43.0", + "@rollup/rollup-win32-arm64-msvc": "4.43.0", + "@rollup/rollup-win32-ia32-msvc": "4.43.0", + "@rollup/rollup-win32-x64-msvc": "4.43.0", "fsevents": "~2.3.2" } }, @@ -1810,6 +2569,12 @@ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1924,10 +2689,59 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/tinymce": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-7.3.0.tgz", - "integrity": "sha512-Ls4PgYlpk73XAxBSBqbVmSl8Mb3DuNfgF01GZ0lY6/MOEVRl3IL+VxC1Oe6165e8WqbqVsxO3Qj/PmoYNvQKGQ==" + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.9.0" + } }, "node_modules/to-fast-properties": { "version": "2.0.0", @@ -1949,6 +2763,12 @@ "node": ">=8.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -1969,20 +2789,24 @@ "dev": true }, "node_modules/vite": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", - "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, + "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -1991,19 +2815,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -2024,9 +2854,43 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vue": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.38.tgz", @@ -2048,12 +2912,13 @@ } }, "node_modules/vue-i18n": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.5.tgz", - "integrity": "sha512-9/gmDlCblz3i8ypu/afiIc/SUIfTTE1mr0mZhb9pk70xo2csHAM9mp2gdQ3KD2O0AM3Hz/5ypb+FycTj/lHlPQ==", + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.7.tgz", + "integrity": "sha512-bKsk0PYwP9gdYF4nqSAT0kDpnLu1gZzlxFl885VH4mHVhEnqP16+/mAU05r1U6NIrc0fGDWP89tZ8GzeJZpe+w==", + "license": "MIT", "dependencies": { - "@intlify/core-base": "10.0.5", - "@intlify/shared": "10.0.5", + "@intlify/core-base": "10.0.7", + "@intlify/shared": "10.0.7", "@vue/devtools-api": "^6.5.0" }, "engines": { @@ -2129,6 +2994,12 @@ "vue": "^3.2.0" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/which-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", diff --git a/frontend/package.json b/frontend/package.json index 40b75f0..ff93f8a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,13 +8,13 @@ "preview": "vite preview" }, "dependencies": { - "@tinymce/tinymce-vue": "^6.0.1", + "@tiptap/starter-kit": "^2.14.0", + "@tiptap/vue-3": "^2.14.0", "axios": "^1.7.2", "date-fns": "^3.6.0", "dotenv": "^16.4.5", "mitt": "^3.0.1", "socket.io-client": "^4.8.1", - "tinymce": "^7.3.0", "vue": "~3.4.31", "vue-i18n": "^10.0.0-beta.2", "vue-multiselect": "^3.1.0", @@ -30,6 +30,6 @@ "sass": "^1.77.8", "stream-browserify": "^3.0.0", "util": "^0.12.5", - "vite": "^5.4.4" + "vite": "^6.3.5" } } diff --git a/frontend/public/images/falukant/map.png b/frontend/public/images/falukant/map.png new file mode 100644 index 0000000..5bc792a Binary files /dev/null and b/frontend/public/images/falukant/map.png differ diff --git a/frontend/src/components/SimpleTabs.vue b/frontend/src/components/SimpleTabs.vue index df24dce..2e7a884 100644 --- a/frontend/src/components/SimpleTabs.vue +++ b/frontend/src/components/SimpleTabs.vue @@ -1,56 +1,63 @@ - - - - - \ No newline at end of file +}; + + + diff --git a/frontend/src/components/falukant/BranchSelection.vue b/frontend/src/components/falukant/BranchSelection.vue index 85e33ba..54567e1 100644 --- a/frontend/src/components/falukant/BranchSelection.vue +++ b/frontend/src/components/falukant/BranchSelection.vue @@ -1,64 +1,91 @@ - - - - - \ No newline at end of file + }, +}; + + + diff --git a/frontend/src/dialogues/admin/AnswerContact.vue b/frontend/src/dialogues/admin/AnswerContact.vue index c5f3807..30e2e5f 100644 --- a/frontend/src/dialogues/admin/AnswerContact.vue +++ b/frontend/src/dialogues/admin/AnswerContact.vue @@ -6,7 +6,7 @@

{{ contact.message }}

- +
@@ -19,8 +19,8 @@ @@ -106,5 +100,13 @@ export default { .editor-container { margin-top: 20px; + border: 1px solid #ccc; + padding: 10px; + min-height: 200px; +} + +.editor { + min-height: 150px; + outline: none; } diff --git a/frontend/src/dialogues/falukant/CreateBranchDialog.vue b/frontend/src/dialogues/falukant/CreateBranchDialog.vue new file mode 100644 index 0000000..12678ee --- /dev/null +++ b/frontend/src/dialogues/falukant/CreateBranchDialog.vue @@ -0,0 +1,342 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/dialogues/falukant/NewDirectorDialog.vue b/frontend/src/dialogues/falukant/NewDirectorDialog.vue index 924d0b1..67d2067 100644 --- a/frontend/src/dialogues/falukant/NewDirectorDialog.vue +++ b/frontend/src/dialogues/falukant/NewDirectorDialog.vue @@ -51,8 +51,8 @@ export default { selectedProposal: null, products: [], buttons: [ - { text: 'Einstellen', action: this.hireDirector }, - { text: 'Abbrechen', action: 'close' }, + { text: this.$t('falukant.newdirector.hire'), action: this.hireDirector }, + { text: this.$t('Cancel'), action: 'close' }, ], }; }, diff --git a/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue b/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue index 881fd77..005c00c 100644 --- a/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue +++ b/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue @@ -55,8 +55,7 @@ Image Preview - + @@ -95,14 +94,15 @@ import DialogWidget from '@/components/DialogWidget.vue'; import apiClient from '@/utils/axios.js'; import FolderItem from '../../components/FolderItem.vue'; -import TinyMCEEditor from '@tinymce/tinymce-vue'; +import { Editor, EditorContent } from '@tiptap/vue-3' +import StarterKit from '@tiptap/starter-kit' export default { name: 'UserProfileDialog', components: { DialogWidget, FolderItem, - editor: TinyMCEEditor, + EditorContent, }, data() { return { @@ -126,27 +126,20 @@ export default { { name: 'guestbook', label: this.$t('socialnetwork.profile.tab.guestbook') } ], apiKey: import.meta.env.VITE_TINYMCE_API_KEY, - tinymceInitOptions: { - script_url: '/tinymce/tinymce.min.js', - height: 300, - menubar: true, - plugins: [ - 'lists', 'link', - 'searchreplace', 'visualblocks', 'code', - 'insertdatetime', 'table' - ], - toolbar: - 'undo redo cut copy paste | bold italic forecolor backcolor fontfamily fontsize| \ - alignleft aligncenter alignright alignjustify | \ - bullist numlist outdent indent | removeformat | link visualblocks code', - contextmenu: 'link image table', - menubar: 'edit format table', - promotion: false, - }, + editor: null, hasSendFriendshipRequest: false, friendshipState: 'none', }; }, + mounted: async function () { + this.editor = new Editor({ + extensions: [StarterKit], + content: '', + }); + }, + beforeUnmount: function () { + if (this.editor) this.editor.destroy(); + }, methods: { open() { this.$refs.dialog.open(); diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index 76f04df..7c563fb 100644 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -4,7 +4,8 @@ "age": "Alter", "wealth": "Vermögen", "health": "Gesundheit", - "events": "Ereignisse" + "events": "Ereignisse", + "relationship": "Beziehung" }, "health": { "amazing": "Super", @@ -97,7 +98,8 @@ "selection": { "title": "Niederlassungsauswahl", "selected": "Ausgewählte Niederlassung", - "placeholder": "Noch keine Niederlassung ausgewählt" + "placeholder": "Noch keine Niederlassung ausgewählt", + "selectedcity": "Ausgewählte Stadt" }, "actions": { "create": "Neue Niederlassung erstellen", @@ -223,7 +225,6 @@ "3": "Mittel", "4": "Hoch", "5": "Sehr hoch" - }, "mood": "Stimmung", "progress": "Zuneigung", @@ -353,19 +354,32 @@ "Fine Wine": "Feiner Wein", "Artisan Chocolate": "Kunsthandwerkliche Schokolade", "Pearl Necklace": "Perlenanhänger", - "Rare Painting": "Seltenes Gemälde", + "Rare Painting": "Seltenes Gemälde", "Silver Watch": "Silberuhr", - "Cat": "Katze", - "Dog": "Hund", + "Cat": "Katze", + "Dog": "Hund", "Horse": "Pferd" }, "mood": { "happy": "Glücklich", "sad": "Traurig", "angry": "Wütend", - "scared": "Verängstigt", - "surprised": "Überrascht", - "normal": "Normal" + "nervous": "Nervös", + "excited": "Aufgeregt", + "bored": "Gelangweilt", + "fearful": "Ängstlich", + "confident": "Selbstbewusst", + "curious": "Neugierig", + "hopeful": "Hoffnungsvoll", + "frustrated": "Frustriert", + "lonely": "Einsam", + "grateful": "Dankbar", + "jealous": "Eifersüchtig", + "guilty": "Schuldig", + "apathetic": "Apathisch", + "relieved": "Erleichtert", + "proud": "Stolz", + "ashamed": "Beschämt" }, "character": { "brave": "Mutig", @@ -595,6 +609,72 @@ "barber": "Barbier" }, "choose": "Bitte auswählen" + }, + "politics": { + "title": "Politik", + "tabs": { + "current": "Aktuelle Position", + "upcoming": "Anstehende Neuwahl-Positionen", + "elections": "Wahlen" + }, + "current": { + "office": "Amt", + "region": "Region", + "termEnds": "Läuft ab am", + "income": "Einkommen", + "none": "Keine aktuelle Position vorhanden.", + "holder": "Inhaber" + }, + "open": { + "office": "Amt", + "region": "Region", + "date": "Datum", + "candidacy": "Kandidatur", + "none": "Keine offenen Positionen." + }, + "upcoming": { + "office": "Amt", + "region": "Region", + "postDate": "Datum", + "none": "Keine anstehenden Positionen." + }, + "elections": { + "office": "Amt", + "region": "Region", + "date": "Datum", + "posts": "Zu besetzende Posten", + "none": "Keine Wahlen vorhanden.", + "choose": "Kandidaten", + "vote": "Stimme abgeben", + "voteAll": "Alle Stimmen abgeben", + "candidates": "Kandidaten", + "action": "Aktion" + }, + "offices": { + "chancellor": "Kanzler", + "minister": "Minister", + "ministry-helper": "Ministerhelfer", + "governor": "Gouverneur", + "super-state-administrator": "Oberstaatsverwalter", + "state-administrator": "Staatsverwalter", + "ruler-consultant": "Berater des Herrschers", + "territorial-council-speaker": "Sprecher des Territorialrats", + "territorial-council": "Territorialrat", + "hangman": "Henker", + "treasurer": "Schatzmeister", + "sheriff": "Sheriff", + "taxman": "Steuereintreiber", + "bailif": "Gerichtsdiener", + "judge": "Richter", + "village-major": "Dorfvorsteher", + "master-builder": "Baumeister", + "mayor": "Bürgermeister", + "town-clerk": "Stadtschreiber", + "beadle": "Schulze", + "council": "Ratsherr", + "councillor": "Stadtrat", + "assessor": "Schätzer" + } } } } \ No newline at end of file diff --git a/frontend/src/router/falukantRoutes.js b/frontend/src/router/falukantRoutes.js index c259c75..0a8235b 100644 --- a/frontend/src/router/falukantRoutes.js +++ b/frontend/src/router/falukantRoutes.js @@ -11,6 +11,7 @@ import EducationView from '../views/falukant/EducationView.vue'; import BankView from '../views/falukant/BankView.vue'; import DirectorView from '../views/falukant/DirectorView.vue'; import HealthView from '../views/falukant/HealthView.vue'; +import PoliticsView from '../views/falukant/PoliticsView.vue'; const falukantRoutes = [ { @@ -91,6 +92,12 @@ const falukantRoutes = [ component: HealthView, meta: { requiresAuth: true } }, + { + path: '/falukant/politics', + name: 'PoliticsView', + component: PoliticsView, + meta: { requiresAuth: true } + }, ]; export default falukantRoutes; diff --git a/frontend/src/views/falukant/BranchView.vue b/frontend/src/views/falukant/BranchView.vue index eef5439..56e821a 100644 --- a/frontend/src/views/falukant/BranchView.vue +++ b/frontend/src/views/falukant/BranchView.vue @@ -1,236 +1,291 @@ - - - - \ No newline at end of file + } + + \ No newline at end of file diff --git a/frontend/src/views/falukant/FamilyView.vue b/frontend/src/views/falukant/FamilyView.vue index a0d8102..58da7c0 100644 --- a/frontend/src/views/falukant/FamilyView.vue +++ b/frontend/src/views/falukant/FamilyView.vue @@ -43,12 +43,13 @@ + }}
@@ -64,16 +65,18 @@ - + + + {{ $t(`falukant.gifts.${gift.name}`) }} - {{ $t(`falukant.family.spouse.giftAffect.${getEffect(gift)}`) }} + {{ getEffect(gift) }} {{ formatCost(gift.cost) }}
+ }}
@@ -93,7 +96,7 @@ v-model="selectedProposalId"> {{ $t(`falukant.titles.${proposal.proposedCharacterGender}.${proposal.proposedCharacterNobleTitle}`) - }} {{ proposal.proposedCharacterName }} + }} {{ proposal.proposedCharacterName }} {{ proposal.proposedCharacterAge }} {{ formatCost(proposal.cost) }} @@ -123,7 +126,8 @@ {{ child.name }} - + {{ child.age }} @@ -308,12 +312,38 @@ export default { }); }, - handleDaemonMessage() { + handleDaemonMessage(event) { + if (event.data === 'ping') { + return; + } const message = JSON.parse(event.data); if (message.event === 'children_update') { this.loadFamilyData(); } - } + }, + + getEffect(gift) { + // aktueller Partner + const partner = this.relationships[0].character2; + // seine aktuelle Mood-ID + const moodId = partner.mood?.id ?? partner.mood_id; + + // 1) Mood-Eintrag finden + const moodEntry = gift.moodsAffects.find(ma => ma.mood_id === moodId); + const moodValue = moodEntry ? moodEntry.suitability : 0; + + // 2) Trait-Einträge matchen + let highestTraitValue = 0; + for (const trait of partner.traits) { + const charEntry = gift.charactersAffects.find(ca => ca.trait_id === trait.id); + if (charEntry && charEntry.suitability > highestTraitValue) { + highestTraitValue = charEntry.suitability; + } + } + + // Durchschnitt, gerundet + return Math.round((moodValue + highestTraitValue) / 2); + }, } } diff --git a/frontend/src/views/falukant/OverviewView.vue b/frontend/src/views/falukant/OverviewView.vue index f42d0da..9f9bd97 100644 --- a/frontend/src/views/falukant/OverviewView.vue +++ b/frontend/src/views/falukant/OverviewView.vue @@ -13,14 +13,15 @@ {{ $t('falukant.overview.metadata.nobleTitle') }} - {{ $t('falukant.titles.' + falukantUser?.character.gender + '.' + falukantUser?.character.nobleTitle.labelTr) }} + {{ $t('falukant.titles.' + falukantUser?.character.gender + '.' + + falukantUser?.character.nobleTitle.labelTr) }} {{ $t('falukant.overview.metadata.money') }} {{ moneyValue != null ? moneyValue.toLocaleString(locale, { style: 'currency', currency: 'EUR' }) - : '---' }} + : '---' }} @@ -170,17 +171,24 @@ export default { }; }, getHouseStyle() { - if (!this.falukantUser) return {}; + console.log(this.falukantUser); + if (!this.falukantUser || !this.falukantUser.userHouse?.houseType) return {}; const imageUrl = '/images/falukant/houses.png'; - const housePosition = this.falukantUser.house ? this.falukantUser.house.type.position : 0; - const x = housePosition % 3; - const y = Math.floor(housePosition / 3); + const pos = this.falukantUser.userHouse.houseType.position; + const index = pos - 1; + const columns = 3; + const spriteSize = 300; + const x = (index % columns) * spriteSize; + const y = Math.floor(index / columns) * spriteSize; return { backgroundImage: `url(${imageUrl})`, - backgroundPosition: `-${x * 341}px -${y * 341}px`, - backgroundSize: "341px 341px", - width: "114px", - height: "114px", + backgroundPosition: `-${x}px -${y}px`, + backgroundSize: `${columns * spriteSize}px auto`, + width: `300px`, + height: `300px`, + border: '1px solid #ccc', + borderRadius: '4px', + imageRendering: 'crisp-edges', }; }, getAgeColor(age) { @@ -321,12 +329,10 @@ export default { border: 1px solid #ccc; border-radius: 4px; background-repeat: no-repeat; - background-size: cover; image-rendering: crisp-edges; } h2 { padding-top: 20px; } - diff --git a/frontend/src/views/falukant/PoliticsView.vue b/frontend/src/views/falukant/PoliticsView.vue new file mode 100644 index 0000000..504469d --- /dev/null +++ b/frontend/src/views/falukant/PoliticsView.vue @@ -0,0 +1,405 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/views/social/ForumTopicView.vue b/frontend/src/views/social/ForumTopicView.vue index b878523..d815a9f 100644 --- a/frontend/src/views/social/ForumTopicView.vue +++ b/frontend/src/views/social/ForumTopicView.vue @@ -2,89 +2,84 @@

{{ forumTopic }}

- + +
+ +
- \ No newline at end of file + +.editor-container { + margin-top: 1rem; + border: 1px solid #ccc; + padding: 10px; + min-height: 200px; + background-color: white; +} + +.editor { + min-height: 150px; + outline: none; +} + diff --git a/frontend/src/views/social/ForumView.vue b/frontend/src/views/social/ForumView.vue index 7e8f7dd..fb65620 100644 --- a/frontend/src/views/social/ForumView.vue +++ b/frontend/src/views/social/ForumView.vue @@ -11,71 +11,27 @@ - +
+ +
- - - - - - - - - - - - - - - - - - - - -
{{ $t('socialnetwork.forum.topic') }}{{ $t('socialnetwork.forum.createdBy') }}{{ $t('socialnetwork.forum.createdAt') }}{{ $t('socialnetwork.forum.reactions') }}{{ $t('socialnetwork.forum.lastReaction') }}
{{ title.title }}{{ title.createdBy }}{{ new Date(title.createdAt).toLocaleString() }}{{ title.numberOfItems }}{{ new Date(title.lastMessageDate).toLocaleString() }}
- + +
{{ $t('socialnetwork.forum.noTitles') }}