Falukant production, family and administration enhancements
This commit is contained in:
@@ -89,6 +89,43 @@ class AdminController {
|
||||
res.status(error.status || 500).json({ error: error.message || 'Internal Server Error' });
|
||||
}
|
||||
}
|
||||
|
||||
async searchUser(req, res) {
|
||||
try {
|
||||
const { userid: userId } = req.headers;
|
||||
const { userName, characterName } = req.body;
|
||||
const response = await AdminService.getFalukantUser(userId, userName, characterName);
|
||||
res.status(200).json(response);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(403).json({ error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
async getFalukantUserById(req, res) {
|
||||
try {
|
||||
const { userid: userId } = req.headers;
|
||||
const { id: hashedId } = req.params;
|
||||
const response = await AdminService.getFalukantUserById(userId, hashedId);
|
||||
res.status(200).json(response);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(403).json({ error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
async changeFalukantUser(req, res) {
|
||||
try {
|
||||
const { userid: userId } = req.headers;
|
||||
const data = req.body;
|
||||
const { id: falukantUserId, } = req.body;
|
||||
const response = await AdminService.changeFalukantUser(userId, falukantUserId, data);
|
||||
res.status(200).json(response);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(403).json({ error: error.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminController;
|
||||
|
||||
@@ -21,7 +21,10 @@ class FalukantController {
|
||||
this.convertProposalToDirector = this.convertProposalToDirector.bind(this);
|
||||
this.getDirectorForBranch = this.getDirectorForBranch.bind(this);
|
||||
this.setSetting = this.setSetting.bind(this);
|
||||
this.getMarriageProposals = this.getMarriageProposals.bind(this);
|
||||
this.getFamily = this.getFamily.bind(this);
|
||||
this.acceptMarriageProposal = this.acceptMarriageProposal.bind(this);
|
||||
this.getGifts = this.getGifts.bind(this);
|
||||
this.sendGift = this.sendGift.bind(this);
|
||||
}
|
||||
|
||||
async getUser(req, res) {
|
||||
@@ -308,9 +311,6 @@ class FalukantController {
|
||||
const { userid: hashedUserId } = req.headers;
|
||||
const { branchId } = req.params;
|
||||
const result = await FalukantService.getDirectorForBranch(hashedUserId, branchId);
|
||||
if (!result) {
|
||||
return res.status(404).json({ message: 'No director found for this branch' });
|
||||
}
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
@@ -329,13 +329,74 @@ class FalukantController {
|
||||
}
|
||||
}
|
||||
|
||||
async getMarriageProposals(req, res) {
|
||||
async getFamily(req, res) {
|
||||
try {
|
||||
const { userid: hashedUserId } = req.headers;
|
||||
const result = await FalukantService.getMarriageProposals(hashedUserId);
|
||||
const result = await FalukantService.getFamily(hashedUserId);
|
||||
if (!result) {
|
||||
res.status(404).json({ error: 'No family data found' });
|
||||
}
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async acceptMarriageProposal(req, res) {
|
||||
try {
|
||||
const { userid: hashedUserId } = req.headers;
|
||||
const { proposalId } = req.body;
|
||||
const result = await FalukantService.acceptMarriageProposal(hashedUserId, proposalId);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async getGifts(req, res) {
|
||||
try {
|
||||
const { userid: hashedUserId } = req.headers;
|
||||
const result = await FalukantService.getGifts(hashedUserId);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async sendGift(req, res) {
|
||||
try {
|
||||
const { userid: hashedUserId } = req.headers;
|
||||
const { giftId} = req.body;
|
||||
const result = await FalukantService.sendGift(hashedUserId, giftId);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async getTitelsOfNobility(req, res) {
|
||||
try {
|
||||
const { userid: hashedUserId } = req.headers;
|
||||
const result = await FalukantService.getTitlesOfNobility(hashedUserId);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async getHouseTypes(req, res) {
|
||||
try {
|
||||
const { userid: hashedUserId } = req.headers;
|
||||
const result = await FalukantService.getHouseTypes(hashedUserId);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,10 +93,6 @@ const menuStructure = {
|
||||
visible: ["hasfalukantaccount"],
|
||||
path: "/falukant/directors"
|
||||
},
|
||||
factory: {
|
||||
visible: ["hasfalukantaccount"],
|
||||
path: "/falukant/factory"
|
||||
},
|
||||
family: {
|
||||
visible: ["hasfalukantaccount"],
|
||||
path: "/falukant/family"
|
||||
|
||||
@@ -52,13 +52,16 @@ import TownProductWorth from './falukant/data/town_product_worth.js';
|
||||
import DayProduction from './falukant/log/dayproduction.js';
|
||||
import DaySell from './falukant/log/daysell.js';
|
||||
import MarriageProposal from './falukant/data/marriage_proposal.js';
|
||||
import Notification from './falukant/log/notification';
|
||||
import Notification from './falukant/log/notification.js';
|
||||
import CharacterTrait from './falukant/type/character_trait.js';
|
||||
import FalukantCharacterTrait from './falukant/data/falukant_character_trait.js';
|
||||
import Mood from './falukant/type/mood.js';
|
||||
import PromotionalGift from './falukant/type/promotional_gift.js';
|
||||
import PromotionalGiftCharacterTrait from './falukant/predefine/promotional_gift_character_trait.js';
|
||||
import PromotionalGiftMood from './falukant/predefine/promotional_gift_mood.js';
|
||||
import RelationshipType from './falukant/type/relationship.js';
|
||||
import Relationship from './falukant/data/relationship.js';
|
||||
import PromotionalGiftLog from './falukant/log/promotional_gift.js';
|
||||
|
||||
export default function setupAssociations() {
|
||||
// UserParam related associations
|
||||
@@ -326,4 +329,27 @@ export default function setupAssociations() {
|
||||
|
||||
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(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(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' });
|
||||
|
||||
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' });
|
||||
}
|
||||
|
||||
@@ -5,19 +5,19 @@ class FalukantCharacter extends Model {}
|
||||
|
||||
FalukantCharacter.init(
|
||||
{
|
||||
user_id: {
|
||||
userId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
},
|
||||
region_id: {
|
||||
regionId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
first_name: {
|
||||
firstName: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
last_name: {
|
||||
lastName: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
|
||||
@@ -35,6 +35,11 @@ Director.init({
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true,
|
||||
},
|
||||
lastSalaryPayout: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: new Date(0)
|
||||
}
|
||||
}, {
|
||||
sequelize,
|
||||
|
||||
56
backend/models/falukant/data/relationship.js
Normal file
56
backend/models/falukant/data/relationship.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Model, DataTypes } from 'sequelize';
|
||||
import { sequelize } from '../../../utils/sequelize.js';
|
||||
import FalukantCharacter from './character.js';
|
||||
|
||||
class Relationship extends Model {}
|
||||
|
||||
Relationship.init(
|
||||
{
|
||||
character1Id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: FalukantCharacter,
|
||||
key: 'id',
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
character2Id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
references: {
|
||||
model: FalukantCharacter,
|
||||
key: 'id',
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
relationshipTypeId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
widowFirstName1: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
widowFirstName2: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
nextStepProgress: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
modelName: 'Relationship',
|
||||
tableName: 'relationship',
|
||||
schema: 'falukant_data',
|
||||
timestamps: true,
|
||||
underscored: true,
|
||||
}
|
||||
);
|
||||
|
||||
export default Relationship;
|
||||
@@ -24,6 +24,11 @@ DayProduction.init({
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: sequelize.literal('CURRENT_TIMESTAMP'),
|
||||
},
|
||||
productionDate: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false,
|
||||
defaultValue: sequelize.literal('CURRENT_DATE'),
|
||||
}
|
||||
}, {
|
||||
sequelize,
|
||||
@@ -35,10 +40,9 @@ DayProduction.init({
|
||||
indexes: [
|
||||
{
|
||||
unique: true,
|
||||
fields: ['producer_id', 'product_id', 'region_id']
|
||||
fields: ['producer_id', 'product_id', 'region_id', 'production_date']
|
||||
}
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
export default DayProduction;
|
||||
|
||||
32
backend/models/falukant/log/promotional_gift.js
Normal file
32
backend/models/falukant/log/promotional_gift.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Model, DataTypes } from 'sequelize';
|
||||
import { sequelize } from '../../../utils/sequelize.js';
|
||||
|
||||
class PromotionalGiftLog extends Model { };
|
||||
|
||||
PromotionalGiftLog.init({
|
||||
senderCharacterId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
recipientCharacterId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
giftId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
changeValue: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
},
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'PromotionalGiftLog',
|
||||
tableName: 'promotional_gift',
|
||||
schema: 'falukant_log',
|
||||
timestamps: true,
|
||||
underscored: true,
|
||||
});
|
||||
|
||||
export default PromotionalGiftLog;
|
||||
@@ -16,7 +16,7 @@ PromotionalGift.init(
|
||||
value: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0, // Wert des Geschenks
|
||||
defaultValue: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Model, DataTypes } from 'sequelize';
|
||||
import { sequelize } from '../../../utils/sequelize.js';
|
||||
|
||||
class Relationship extends Model {}
|
||||
class RelationshipType extends Model {}
|
||||
|
||||
Relationship.init(
|
||||
RelationshipType.init(
|
||||
{
|
||||
tr: {
|
||||
type: DataTypes.STRING,
|
||||
@@ -12,7 +12,7 @@ Relationship.init(
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
modelName: 'Relationship',
|
||||
modelName: 'RelationshipType',
|
||||
tableName: 'relationship',
|
||||
schema: 'falukant_type',
|
||||
timestamps: false,
|
||||
@@ -20,4 +20,4 @@ Relationship.init(
|
||||
}
|
||||
);
|
||||
|
||||
export default Relationship;
|
||||
export default RelationshipType;
|
||||
|
||||
@@ -7,6 +7,7 @@ FalukantStockType.init({
|
||||
labelTr: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
},
|
||||
cost: {
|
||||
type: DataTypes.INTEGER,
|
||||
|
||||
@@ -55,15 +55,17 @@ import DirectorProposal from './falukant/data/director_proposal.js';
|
||||
import TownProductWorth from './falukant/data/town_product_worth.js';
|
||||
import DayProduction from './falukant/log/dayproduction.js';
|
||||
import DaySell from './falukant/log/daysell.js';
|
||||
import Notification from './falukant/log/notification';
|
||||
import Notification from './falukant/log/notification.js';
|
||||
import MarriageProposal from './falukant/data/marriage_proposal.js';
|
||||
import Relationship from './falukant/type/relationship.js';
|
||||
import RelationshipType from './falukant/type/relationship.js';
|
||||
import CharacterTrait from './falukant/type/character_trait.js';
|
||||
import FalukantCharacterTrait from './falukant/data/falukant_character_trait.js';
|
||||
import Mood from './falukant/type/mood.js';
|
||||
import PromotionalGift from './falukant/type/promotional_gift.js';
|
||||
import PromotionalGiftCharacterTrait from './falukant/predefine/promotional_gift_character_trait.js';
|
||||
import PromotionalGiftMood from './falukant/predefine/promotional_gift_mood.js';
|
||||
import Relationship from './falukant/data/relationship.js';
|
||||
import PromotionalGiftLog from './falukant/log/promotional_gift.js';
|
||||
|
||||
const models = {
|
||||
SettingsType,
|
||||
@@ -125,6 +127,7 @@ const models = {
|
||||
DaySell,
|
||||
Notification,
|
||||
MarriageProposal,
|
||||
RelationshipType,
|
||||
Relationship,
|
||||
CharacterTrait,
|
||||
FalukantCharacterTrait,
|
||||
@@ -132,6 +135,7 @@ const models = {
|
||||
PromotionalGift,
|
||||
PromotionalGiftCharacterTrait,
|
||||
PromotionalGiftMood,
|
||||
PromotionalGiftLog,
|
||||
};
|
||||
|
||||
export default models;
|
||||
|
||||
@@ -193,6 +193,7 @@ export async function createTriggers() {
|
||||
await sequelize.query(createKnowledgeTriggerMethod);
|
||||
await sequelize.query(createKnowledgeTrigger);
|
||||
await sequelize.query(updateMoney);
|
||||
await initializeCharacterTraitTrigger();
|
||||
|
||||
console.log('Triggers created successfully');
|
||||
} catch (error) {
|
||||
@@ -200,3 +201,53 @@ export async function createTriggers() {
|
||||
}
|
||||
}
|
||||
|
||||
export const initializeCharacterTraitTrigger = async () => {
|
||||
try {
|
||||
const triggerCheckQuery = `
|
||||
SELECT tgname
|
||||
FROM pg_trigger
|
||||
WHERE tgname = 'trigger_assign_traits';
|
||||
`;
|
||||
const [existingTrigger] = await sequelize.query(triggerCheckQuery, { type: sequelize.QueryTypes.SELECT });
|
||||
if (!existingTrigger) {
|
||||
console.log('⚡ Erstelle den Trigger für zufällige Traits...');
|
||||
const createTriggerFunctionQuery = `
|
||||
CREATE OR REPLACE FUNCTION falukant_data.assign_random_traits()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
trait_ids INTEGER[];
|
||||
i INTEGER;
|
||||
BEGIN
|
||||
-- Zufällig 5 Trait-IDs auswählen
|
||||
SELECT ARRAY(
|
||||
SELECT id FROM falukant_type.character_trait
|
||||
ORDER BY RANDOM()
|
||||
LIMIT 5
|
||||
) INTO trait_ids;
|
||||
|
||||
-- Die 5 Traits dem neuen Charakter zuweisen
|
||||
FOR i IN 1..array_length(trait_ids, 1) LOOP
|
||||
INSERT INTO falukant_data.falukant_character_trait (character_id, trait_id)
|
||||
VALUES (NEW.id, trait_ids[i]);
|
||||
END LOOP;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
`;
|
||||
const createTriggerQuery = `
|
||||
CREATE TRIGGER trigger_assign_traits
|
||||
AFTER INSERT ON falukant_data.character
|
||||
FOR EACH ROW EXECUTE FUNCTION falukant_data.assign_random_traits();
|
||||
`;
|
||||
await sequelize.query(createTriggerFunctionQuery);
|
||||
await sequelize.query(createTriggerQuery);
|
||||
console.log('✅ Trigger erfolgreich erstellt.');
|
||||
} else {
|
||||
console.log('🔹 Trigger existiert bereits. Keine Aktion erforderlich.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler beim Erstellen des Triggers:', error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,5 +11,8 @@ router.post('/interest/translation', authenticate, adminController.changeTransla
|
||||
router.delete('/interest/:id', authenticate, adminController.deleteInterest);
|
||||
router.get('/opencontacts', authenticate, adminController.getOpenContacts);
|
||||
router.post('/contacts/answer', authenticate, adminController.answerContact);
|
||||
router.post('/falukant/searchuser', authenticate, adminController.searchUser);
|
||||
router.get('/falukant/getuser/:id', authenticate, adminController.getFalukantUserById);
|
||||
router.post('/falukant/edituser', authenticate, adminController.changeFalukantUser);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -30,5 +30,11 @@ router.post('/director/proposal', falukantController.getDirectorProposals);
|
||||
router.post('/director/convertproposal', falukantController.convertProposalToDirector);
|
||||
router.post('/director/settings', falukantController.setSetting);
|
||||
router.get('/director/:branchId', falukantController.getDirectorForBranch);
|
||||
router.get('/marriage/proposals', falukantController.getMarriageProposals);
|
||||
router.post('/family/acceptmarriageproposal', falukantController.acceptMarriageProposal);
|
||||
router.get('/family/gifts', falukantController.getGifts);
|
||||
router.post('/family/gift', falukantController.sendGift);
|
||||
router.get('/family', falukantController.getFamily);
|
||||
router.get('/nobility/titels', falukantController.getTitelsOfNobility);
|
||||
router.get('/houses/types', falukantController.getHouseTypes);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -7,6 +7,11 @@ import UserParamValue from "../models/type/user_param_value.js";
|
||||
import ContactMessage from "../models/service/contactmessage.js";
|
||||
import ContactService from "./ContactService.js";
|
||||
import { sendAnswerEmail } from './emailService.js';
|
||||
import { Op } from 'sequelize';
|
||||
import FalukantUser from "../models/falukant/data/user.js";
|
||||
import FalukantCharacter from "../models/falukant/data/character.js";
|
||||
import FalukantPredefineFirstname from "../models/falukant/predefine/firstname.js";
|
||||
import FalukantPredefineLastname from "../models/falukant/predefine/lastname.js";
|
||||
|
||||
class AdminService {
|
||||
async hasUserAccess(userId, section) {
|
||||
@@ -18,7 +23,7 @@ class AdminService {
|
||||
title: [section, 'mainadmin'],
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
model: User,
|
||||
as: 'user_with_rights',
|
||||
where: {
|
||||
@@ -26,9 +31,9 @@ class AdminService {
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
});
|
||||
return userRights.length > 0;
|
||||
return userRights.length > 0;
|
||||
}
|
||||
|
||||
async getOpenInterests(userId) {
|
||||
@@ -55,7 +60,7 @@ class AdminService {
|
||||
where: {
|
||||
id: interestId
|
||||
}
|
||||
});
|
||||
});
|
||||
if (interest) {
|
||||
interest.allowed = active;
|
||||
interest.adultOnly = adultOnly;
|
||||
@@ -69,7 +74,7 @@ class AdminService {
|
||||
}
|
||||
const interest = await InterestType.findOne({
|
||||
where: {
|
||||
id: interestId
|
||||
id: interestId
|
||||
}
|
||||
});
|
||||
if (interest) {
|
||||
@@ -114,10 +119,10 @@ class AdminService {
|
||||
interestsId: interestId,
|
||||
language: languageObject.id,
|
||||
translation: translations[languageId]
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getOpenContacts(userId) {
|
||||
@@ -138,6 +143,149 @@ class AdminService {
|
||||
await sendAnswerEmail(contact.email, answer, contact.language || 'en');
|
||||
}
|
||||
|
||||
async getFalukantUser(userId, userName, characterName) {
|
||||
if (!(await this.hasUserAccess(userId, 'falukantusers'))) {
|
||||
throw new Error('noaccess');
|
||||
}
|
||||
let users;
|
||||
if (userName) {
|
||||
users = await User.findAll({
|
||||
where: {
|
||||
username: {
|
||||
[Op.like]: '%' + userName + '%'
|
||||
}
|
||||
},
|
||||
include: [{
|
||||
model: FalukantUser,
|
||||
as: 'falukantData',
|
||||
required: true,
|
||||
include: [{
|
||||
model: FalukantCharacter,
|
||||
as: 'character',
|
||||
required: true,
|
||||
include: [{
|
||||
model: FalukantPredefineFirstname,
|
||||
as: 'definedFirstName',
|
||||
required: true
|
||||
}, {
|
||||
model: FalukantPredefineLastname,
|
||||
as: 'definedLastName',
|
||||
required: true
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
} else if (characterName) {
|
||||
const [firstname, lastname] = characterName.split(' ');
|
||||
users = await User.findAll({
|
||||
include: [{
|
||||
model: FalukantUser,
|
||||
as: 'falukantData',
|
||||
required: true,
|
||||
include: [{
|
||||
model: FalukantCharacter,
|
||||
as: 'character',
|
||||
required: true,
|
||||
include: [{
|
||||
model: FalukantPredefineFirstname,
|
||||
as: 'definedFirstName',
|
||||
required: true,
|
||||
where: {
|
||||
name: firstname
|
||||
}
|
||||
}, {
|
||||
model: FalukantPredefineLastname,
|
||||
as: 'definedLastName',
|
||||
required: true,
|
||||
where: {
|
||||
name: lastname
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
} else {
|
||||
throw new Error('no search parameter');
|
||||
}
|
||||
return users.map(user => {
|
||||
return {
|
||||
id: user.hashedId,
|
||||
username: user.username,
|
||||
falukantUser: user.falukantData
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async getFalukantUserById(userId, hashedId) {
|
||||
if (!(await this.hasUserAccess(userId, 'falukantusers'))) {
|
||||
throw new Error('noaccess');
|
||||
}
|
||||
const user = await User.findOne({
|
||||
where: {
|
||||
hashedId: hashedId
|
||||
},
|
||||
attributes: ['hashedId', 'username'],
|
||||
include: [{
|
||||
model: FalukantUser,
|
||||
as: 'falukantData',
|
||||
required: true,
|
||||
attributes: ['money', 'certificate', 'id'],
|
||||
include: [{
|
||||
model: FalukantCharacter,
|
||||
as: 'character',
|
||||
attributes: ['birthdate', 'health', 'title_of_nobility'],
|
||||
include: [{
|
||||
model: FalukantPredefineFirstname,
|
||||
as: 'definedFirstName',
|
||||
}, {
|
||||
model: FalukantPredefineLastname,
|
||||
as: 'definedLastName',
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
});
|
||||
return user;
|
||||
}
|
||||
|
||||
async changeFalukantUser(userId, falukantUserId, falukantData) {
|
||||
if (!(await this.hasUserAccess(userId, 'falukantusers'))) {
|
||||
throw new Error('noaccess');
|
||||
}
|
||||
const falukantUser = await FalukantUser.findOne({
|
||||
where: {
|
||||
id: falukantUserId
|
||||
}
|
||||
});
|
||||
if (!falukantUser) {
|
||||
throw new Error('notfound');
|
||||
}
|
||||
const character = await FalukantCharacter.findOne({
|
||||
where: {
|
||||
userId: falukantUserId
|
||||
}
|
||||
});
|
||||
if (!character) {
|
||||
throw new Error('notfound');
|
||||
}
|
||||
if (Object.keys(falukantData).indexOf('age') >= 0) {
|
||||
const birthDate = (new Date()) - (falukantData.age * 24 * 3600000);
|
||||
await character.update({
|
||||
birthdate: birthDate
|
||||
});
|
||||
}
|
||||
if (Object.keys(falukantData).indexOf('money') >= 0) {
|
||||
await falukantUser.update({
|
||||
money: falukantData.money
|
||||
});
|
||||
}
|
||||
if (Object.keys(falukantData).indexOf('title_of_nobility') >= 0) {
|
||||
await character.update({
|
||||
titleOfNobility: falukantData.title_of_nobility
|
||||
});
|
||||
}
|
||||
await falukantUser.save();
|
||||
await character.save();
|
||||
}
|
||||
}
|
||||
|
||||
export default new AdminService();
|
||||
@@ -104,7 +104,6 @@ export const loginUser = async ({ username, password }) => {
|
||||
user.authCode = authCode;
|
||||
await user.save();
|
||||
const friends = await getFriends(user.id);
|
||||
console.log('send login to friends');
|
||||
for (const friend of friends) {
|
||||
await notifyUser(friend.hashedId, 'friendloginchanged', {
|
||||
userId: user.hashedId,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import BaseService from './BaseService.js';
|
||||
import { Sequelize, Op } from 'sequelize';
|
||||
import { Sequelize, Op, where } from 'sequelize';
|
||||
|
||||
import FalukantPredefineFirstname from '../models/falukant/predefine/firstname.js';
|
||||
import FalukantPredefineLastname from '../models/falukant/predefine/lastname.js';
|
||||
@@ -25,7 +25,14 @@ import BuyableStock from '../models/falukant/data/buyable_stock.js';
|
||||
import DirectorProposal from '../models/falukant/data/director_proposal.js';
|
||||
import Director from '../models/falukant/data/director.js';
|
||||
import DaySell from '../models/falukant/log/daysell.js';
|
||||
|
||||
import MarriageProposal from '../models/falukant/data/marriage_proposal.js';
|
||||
import RelationshipType from '../models/falukant/type/relationship.js';
|
||||
import Relationship from '../models/falukant/data/relationship.js';
|
||||
import PromotionalGift from '../models/falukant/type/promotional_gift.js';
|
||||
import PromotionalGiftCharacterTrait from '../models/falukant/predefine/promotional_gift_character_trait.js';
|
||||
import PromotionalGiftMood from '../models/falukant/predefine/promotional_gift_mood.js';
|
||||
import PromotionalGiftLog from '../models/falukant/log/promotional_gift.js';
|
||||
import CharacterTrait from '../models/falukant/type/character_trait.js';
|
||||
|
||||
function calcAge(birthdate) {
|
||||
const b = new Date(birthdate); b.setHours(0, 0);
|
||||
@@ -53,11 +60,33 @@ function calcSellPrice(product, knowledgeFactor = 0) {
|
||||
return min + (max - min) * (knowledgeFactor / 100);
|
||||
}
|
||||
|
||||
function calculateMarriageCost(titleOfNobility, age) {
|
||||
const minTitle = 1;
|
||||
const adjustedTitle = titleOfNobility - minTitle + 1;
|
||||
const baseCost = 500;
|
||||
return baseCost * Math.pow(adjustedTitle, 1.3) - (age - 12) * 20;
|
||||
}
|
||||
|
||||
class FalukantService extends BaseService {
|
||||
async getFalukantUserByHashedId(hashedId) {
|
||||
return FalukantUser.findOne({
|
||||
include: [{ model: User, as: 'user', attributes: ['username', 'hashedId'], where: { hashedId } }]
|
||||
const user = await FalukantUser.findOne({
|
||||
include: [
|
||||
{ model: User, as: 'user', attributes: ['username', 'hashedId'], where: { hashedId } },
|
||||
{
|
||||
model: FalukantCharacter,
|
||||
as: 'character',
|
||||
include: [
|
||||
{ model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'] },
|
||||
{ model: FalukantPredefineLastname, as: 'definedLastName', attributes: ['name'] },
|
||||
{ model: TitleOfNobility, as: 'nobleTitle', attributes: ['labelTr'] },
|
||||
{ model: CharacterTrait, as: 'traits', attributes: ['id', 'tr'] }
|
||||
],
|
||||
attributes: ['id', 'birthdate', 'gender']
|
||||
},
|
||||
]
|
||||
});
|
||||
if (!user) throw new Error('User not found');
|
||||
return user;
|
||||
}
|
||||
|
||||
async getUser(hashedUserId) {
|
||||
@@ -137,7 +166,7 @@ class FalukantService extends BaseService {
|
||||
await FalukantStock.create({ userId: falukantUser.id, regionId: region.id, stockTypeId: stType.id, quantity: 10 });
|
||||
falukantUser.character = ch;
|
||||
const bType = await BranchType.findOne({ where: { labelTr: 'fullstack' } });
|
||||
await Branch.create({ userId: falukantUser.id, regionId: region.id, branchTypeId: bType.id });
|
||||
await Branch.create({ falukantUserId: falukantUser.id, regionId: region.id, branchTypeId: bType.id });
|
||||
notifyUser(user.hashedId, 'reloadmenu', {});
|
||||
return falukantUser;
|
||||
}
|
||||
@@ -209,7 +238,12 @@ class FalukantService extends BaseService {
|
||||
const u = await getFalukantUserOrFail(hashedUserId);
|
||||
const b = await getBranchOrFail(u.id, branchId);
|
||||
const p = await ProductType.findOne({ where: { id: productId } });
|
||||
const runningProductions = await Production.findAll({ where: { branchId: b.id } });
|
||||
if (runningProductions.length >= 2) {
|
||||
throw new Error('Too many productions');
|
||||
}
|
||||
if (!p) throw new Error('Product not found');
|
||||
quantity = Math.min(100, quantity);
|
||||
const cost = quantity * p.category * 6;
|
||||
if (u.money < cost) throw new Error('notenoughmoney');
|
||||
const r = await updateFalukantUserMoney(u.id, -cost, 'Production cost', u.id);
|
||||
@@ -293,7 +327,7 @@ class FalukantService extends BaseService {
|
||||
const stock = await FalukantStock.findOne({ where: { branchId: branch.id } });
|
||||
if (!stock) throw new Error('Stock not found');
|
||||
const inventory = await Inventory.findAll({
|
||||
where: { stockId: stock.id, quality },
|
||||
where: { quality },
|
||||
include: [
|
||||
{
|
||||
model: ProductType,
|
||||
@@ -311,8 +345,12 @@ class FalukantService extends BaseService {
|
||||
}
|
||||
]
|
||||
});
|
||||
if (!inventory.length) throw new Error('No inventory found');
|
||||
if (!inventory.length) {
|
||||
throw new Error('No inventory found');
|
||||
}
|
||||
console.log(inventory);
|
||||
const available = inventory.reduce((sum, i) => sum + i.quantity, 0);
|
||||
console.log(available);
|
||||
if (available < quantity) throw new Error('Not enough inventory available');
|
||||
const item = inventory[0].productType;
|
||||
const knowledgeVal = item.knowledges?.[0]?.knowledge || 0;
|
||||
@@ -330,7 +368,7 @@ class FalukantService extends BaseService {
|
||||
break;
|
||||
}
|
||||
}
|
||||
await this.addSellItem(branchId, falukantUser.id, productId, quantity);
|
||||
await this.addSellItem(branchId, user.id, productId, quantity);
|
||||
notifyUser(user.user.hashedId, 'falukantUpdateStatus', {});
|
||||
notifyUser(user.user.hashedId, 'falukantBranchUpdate', { branchId: branch.id });
|
||||
return { success: true };
|
||||
@@ -384,7 +422,7 @@ class FalukantService extends BaseService {
|
||||
for (const item of inventory) {
|
||||
const knowledgeVal = item.productType.knowledges[0]?.knowledge || 0;
|
||||
total += item.quantity * calcSellPrice(item.productType, knowledgeVal);
|
||||
await this.addSellItem(item.stock[0].branch[0].id, falukantUser.id, item.productType.id, item.quantity);
|
||||
await this.addSellItem(item.stock.branch.id, falukantUser.id, item.productType.id, item.quantity);
|
||||
}
|
||||
const moneyResult = await updateFalukantUserMoney(
|
||||
falukantUser.id,
|
||||
@@ -397,7 +435,7 @@ class FalukantService extends BaseService {
|
||||
await Inventory.destroy({ where: { id: item.id } });
|
||||
}
|
||||
notifyUser(falukantUser.user.hashedId, 'falukantUpdateStatus', {});
|
||||
notifyUser(falukantUser.user.hashedId, 'falukantBranchUpdate', {});
|
||||
notifyUser(falukantUser.user.hashedId, 'falukantBranchUpdate', { branchId });
|
||||
return { success: true, revenue: total };
|
||||
}
|
||||
|
||||
@@ -408,7 +446,7 @@ class FalukantService extends BaseService {
|
||||
;
|
||||
const daySell = await DaySell.findOne({
|
||||
where: {
|
||||
regionId: regionId,
|
||||
regionId: branch.regionId,
|
||||
productId: productId,
|
||||
sellerId: userId,
|
||||
}
|
||||
@@ -418,7 +456,7 @@ class FalukantService extends BaseService {
|
||||
await daySell.save();
|
||||
} else {
|
||||
await DaySell.create({
|
||||
regionId: regionId,
|
||||
regionId: branch.regionId,
|
||||
productId: productId,
|
||||
sellerId: userId,
|
||||
quantity: quantity,
|
||||
@@ -528,13 +566,22 @@ class FalukantService extends BaseService {
|
||||
if (!moneyResult.success) throw new Error('Failed to update money');
|
||||
buyable.quantity -= amount;
|
||||
await buyable.save();
|
||||
const stock = await FalukantStock.findOne({
|
||||
let stock = await FalukantStock.findOne({
|
||||
where: { branchId: branch.id, stockTypeId },
|
||||
include: [{ model: FalukantStockType, as: 'stockType' }]
|
||||
});
|
||||
if (!stock) throw new Error('No stock record found for this branch and stockType');
|
||||
if (!stock) {
|
||||
stock = await FalukantStock.create({
|
||||
branchId: branch.id,
|
||||
stockTypeId,
|
||||
quantity: amount,
|
||||
});
|
||||
return { success: true, bought: amount, totalCost, stockType: buyable.stockType.labelTr };
|
||||
}
|
||||
stock.quantity += amount;
|
||||
await stock.save();
|
||||
notifyUser(user.user.hashedId, 'falukantUpdateStatus', {});
|
||||
notifyUser(user.user.hashedId, 'falukantBranchUpdate', { branchId });
|
||||
return { success: true, bought: amount, totalCost, stockType: buyable.stockType.labelTr };
|
||||
}
|
||||
|
||||
@@ -775,10 +822,13 @@ class FalukantService extends BaseService {
|
||||
}
|
||||
|
||||
async convertProposalToDirector(hashedUserId, proposalId) {
|
||||
console.log('convert proposal to director - start');
|
||||
const user = await getFalukantUserOrFail(hashedUserId);
|
||||
console.log('convert proposal to director - check user');
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
console.log('convert proposal to director - find proposal', proposalId);
|
||||
const proposal = await DirectorProposal.findOne(
|
||||
{
|
||||
where: { id: proposalId },
|
||||
@@ -787,10 +837,12 @@ class FalukantService extends BaseService {
|
||||
]
|
||||
}
|
||||
);
|
||||
console.log('convert proposal to director - check proposal');
|
||||
if (!proposal || proposal.employerUserId !== user.id) {
|
||||
throw new Error('Proposal does not belong to the user');
|
||||
}
|
||||
|
||||
console.log('convert proposal to director - check existing director', user, proposal);
|
||||
const existingDirector = await Director.findOne({
|
||||
where: {
|
||||
employerUserId: user.id
|
||||
@@ -808,6 +860,7 @@ class FalukantService extends BaseService {
|
||||
if (existingDirector) {
|
||||
throw new Error('A director already exists for this region');
|
||||
}
|
||||
console.log('convert proposal to director - create new director');
|
||||
const newDirector = await Director.create({
|
||||
directorCharacterId: proposal.directorCharacterId,
|
||||
employerUserId: proposal.employerUserId,
|
||||
@@ -827,11 +880,13 @@ class FalukantService extends BaseService {
|
||||
},
|
||||
]
|
||||
});
|
||||
console.log('convert proposal to director - remove propsals');
|
||||
if (regionUserDirectorProposals.length > 0) {
|
||||
for (const proposal of regionUserDirectorProposals) {
|
||||
await DirectorProposal.destroy();
|
||||
}
|
||||
}
|
||||
console.log('convert proposal to director - notify user');
|
||||
notifyUser(hashedUserId, 'directorchanged');
|
||||
return newDirector;
|
||||
}
|
||||
@@ -932,59 +987,268 @@ class FalukantService extends BaseService {
|
||||
return { result: 'ok' };
|
||||
}
|
||||
|
||||
async getMarriageProposals(hashedUserId) {
|
||||
async getFamily(hashedUserId) {
|
||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
const character = await FalukantCharacter.findOne({ where: { userId: user.id } });
|
||||
if (!character) {
|
||||
throw new Error('Character not found for this user');
|
||||
}
|
||||
const midnight = new Date();
|
||||
midnight.setHours(0, 0, 0, 0);
|
||||
await MarriageProposal.destroy({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ requesterCharacterId: character.id },
|
||||
{ proposedCharacterId: character.id },
|
||||
],
|
||||
createdAt: {
|
||||
[Op.lt]: midnight,
|
||||
},
|
||||
},
|
||||
});
|
||||
let proposals = await MarriageProposal.findAll({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ requesterCharacterId: character.id },
|
||||
{ proposedCharacterId: character.id },
|
||||
],
|
||||
},
|
||||
});
|
||||
if (proposals.length === 0) {
|
||||
const proposalCount = Math.floor(Math.random() * 4) + 3; // 3–6
|
||||
const thirteenDaysAgo = new Date(Date.now() - 13 * 24 * 60 * 60 * 1000);
|
||||
const possiblePartners = await FalukantCharacter.findAll({
|
||||
const family = {
|
||||
relationships: [],
|
||||
deathPartners: [],
|
||||
children: [],
|
||||
lovers: [],
|
||||
possiblePartners: [],
|
||||
};
|
||||
let relationships = await Relationship.findAll(
|
||||
{
|
||||
where: {
|
||||
id: { [Op.ne]: character.id },
|
||||
createdAt: { [Op.lt]: thirteenDaysAgo },
|
||||
character1Id: character.id,
|
||||
},
|
||||
order: [sequelize.fn('RANDOM')],
|
||||
});
|
||||
if (possiblePartners.length === 0) {
|
||||
return [];
|
||||
attributes: ['createdAt', 'widowFirstName2'],
|
||||
include: [
|
||||
{
|
||||
model: FalukantCharacter,
|
||||
as: 'character2',
|
||||
attributes: ['id', 'birthdate', 'gender'],
|
||||
include: [
|
||||
{ model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'] },
|
||||
{ model: TitleOfNobility, as: 'nobleTitle', attributes: ['labelTr'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
model: RelationshipType,
|
||||
as: 'relationshipType',
|
||||
attributes: ['tr'],
|
||||
},
|
||||
],
|
||||
}
|
||||
const newProposals = [];
|
||||
for (let i = 0; i < proposalCount; i++) {
|
||||
const partner = possiblePartners[i % possiblePartners.length];
|
||||
const createdProposal = await MarriageProposal.create({
|
||||
requesterCharacterId: character.id,
|
||||
proposedCharacterId: partner.id,
|
||||
courtingProgress: 0,
|
||||
});
|
||||
newProposals.push(createdProposal);
|
||||
);
|
||||
relationships = relationships.map((relationship) => ({
|
||||
createdAt: relationship.createdAt,
|
||||
widowFirstName2: relationship.widowFirstName2,
|
||||
character2: {
|
||||
id: relationship.character2.id,
|
||||
age: calcAge(relationship.character2.birthdate),
|
||||
gender: relationship.character2.gender,
|
||||
firstName: relationship.character2.definedFirstName?.name || 'Unknown',
|
||||
nobleTitle: relationship.character2.nobleTitle?.labelTr || '',
|
||||
},
|
||||
relationshipType: relationship.relationshipType.tr,
|
||||
}));
|
||||
family.relationships = relationships.filter((relationship) => ['wooing', 'engaged', 'married'].includes(relationship.relationshipType));
|
||||
family.lovers = relationships.filter((relationship) => ['lover'].includes(relationship.relationshipType.tr));
|
||||
family.deathPartners = relationships.filter((relationship) => ['widowed'].includes(relationship.relationshipType.tr));
|
||||
if (family.relationships.length === 0 ) {
|
||||
family.possiblePartners = await this.getPossiblePartners(character.id);
|
||||
if (family.possiblePartners.length === 0) {
|
||||
await this.createPossiblePartners(character.id, character.gender, character.regionId, character.titleOfNobility);
|
||||
family.possiblePartners = await this.getPossiblePartners(character.id);
|
||||
}
|
||||
proposals = newProposals;
|
||||
}
|
||||
return proposals;
|
||||
return family;
|
||||
}
|
||||
|
||||
async getPossiblePartners(requestingCharacterId) {
|
||||
const proposals = await MarriageProposal.findAll({
|
||||
where: {
|
||||
requesterCharacterId: requestingCharacterId,
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: FalukantCharacter,
|
||||
as: 'proposedCharacter',
|
||||
attributes: ['id', 'firstName', 'lastName', 'gender', 'regionId', 'birthdate'],
|
||||
include: [
|
||||
{ model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'] },
|
||||
{ model: FalukantPredefineLastname, as: 'definedLastName', attributes: ['name'] },
|
||||
{ model: TitleOfNobility, as: 'nobleTitle', attributes: ['labelTr'] },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
return proposals.map(proposal => {
|
||||
const birthdate = new Date(proposal.proposedCharacter.birthdate);
|
||||
const age = calcAge(birthdate);
|
||||
console.log(proposal.proposedCharacter);
|
||||
return {
|
||||
id: proposal.id,
|
||||
requesterCharacterId: proposal.requesterCharacterId,
|
||||
proposedCharacterId: proposal.proposedCharacter.id,
|
||||
proposedCharacterName: `${proposal.proposedCharacter.definedFirstName?.name} ${proposal.proposedCharacter.definedLastName?.name}`,
|
||||
proposedCharacterGender: proposal.proposedCharacter.gender,
|
||||
proposedCharacterRegionId: proposal.proposedCharacter.regionId,
|
||||
proposedCharacterAge: age,
|
||||
proposedCharacterNobleTitle: proposal.proposedCharacter.nobleTitle.labelTr,
|
||||
cost: proposal.cost,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async createPossiblePartners(requestingCharacterId, requestingCharacterGender, requestingRegionId, requestingCharacterTitleOfNobility) {
|
||||
try {
|
||||
const minTitleResult = await TitleOfNobility.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
attributes: ['id'],
|
||||
});
|
||||
if (!minTitleResult) {
|
||||
throw new Error('No title of nobility found');
|
||||
}
|
||||
const minTitle = minTitleResult.id;
|
||||
const potentialPartners = await FalukantCharacter.findAll({
|
||||
where: {
|
||||
id: { [Op.ne]: requestingCharacterId },
|
||||
gender: { [Op.ne]: requestingCharacterGender },
|
||||
regionId: requestingRegionId,
|
||||
createdAt: { [Op.lt]: new Date(new Date() - 12 * 24 * 60 * 60 * 1000) },
|
||||
titleOfNobility: { [Op.between]: [requestingCharacterTitleOfNobility - 1, requestingCharacterTitleOfNobility + 1] }
|
||||
},
|
||||
limit: 5,
|
||||
});
|
||||
const proposals = potentialPartners.map(partner => {
|
||||
const age = calcAge(partner.birthdate);
|
||||
return {
|
||||
requesterCharacterId: requestingCharacterId,
|
||||
proposedCharacterId: partner.id,
|
||||
cost: calculateMarriageCost(partner.titleOfNobility, age, minTitle),
|
||||
};
|
||||
});
|
||||
await MarriageProposal.bulkCreate(proposals);
|
||||
} catch (error) {
|
||||
console.error('Error creating possible partners:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async acceptMarriageProposal(hashedUserId, proposedCharacterId) {
|
||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||
const character = await FalukantCharacter.findOne({ where: { userId: user.id } });
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
const proposal = await MarriageProposal.findOne({
|
||||
where: {
|
||||
requesterCharacterId: character.id,
|
||||
proposedCharacterId: proposedCharacterId,
|
||||
},
|
||||
});
|
||||
if (!proposal) {
|
||||
throw new Error('Proposal not found');
|
||||
}
|
||||
if (user.money < proposal.cost) {
|
||||
console.log(user, proposal);
|
||||
throw new Error('Not enough money to accept the proposal');
|
||||
}
|
||||
const moneyResult = await updateFalukantUserMoney(user.id, -proposal.cost, 'Marriage cost', user.id);
|
||||
if (!moneyResult.success) {
|
||||
throw new Error('Failed to update money');
|
||||
}
|
||||
const marriedType = await RelationshipType.findOne({
|
||||
where: { tr: 'wooing' },
|
||||
});
|
||||
if (!marriedType) {
|
||||
throw new Error('Relationship type "married" not found');
|
||||
}
|
||||
await Relationship.create({
|
||||
character1Id: proposal.requesterCharacterId,
|
||||
character2Id: proposal.proposedCharacterId,
|
||||
relationshipTypeId: marriedType.id,
|
||||
});
|
||||
await MarriageProposal.destroy({
|
||||
where: { character1Id: character.id },
|
||||
})
|
||||
;
|
||||
return { success: true, message: 'Marriage proposal accepted' };
|
||||
}
|
||||
|
||||
async getGifts(hashedUserId) {
|
||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||
const character = await FalukantCharacter.findOne({
|
||||
where: { userId: user.id },
|
||||
});
|
||||
if (!character) {
|
||||
throw new Error('Character not found');
|
||||
}
|
||||
let gifts = await PromotionalGift.findAll();
|
||||
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),
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
async sendGift(hashedUserId, giftId) {
|
||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||
const lowestTitleOfNobility = await TitleOfNobility.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
});
|
||||
const relation = Relationship.findOne({
|
||||
where: {
|
||||
character1Id: user.character.id,
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: RelationshipType,
|
||||
as: 'relationshipType',
|
||||
where: { tr: 'wooing' },
|
||||
}
|
||||
],
|
||||
});
|
||||
if (!relation) {
|
||||
throw new Error('User and character are not related');
|
||||
}
|
||||
console.log(user);
|
||||
const gift = await PromotionalGift.findOne({
|
||||
where: { id: giftId },
|
||||
include: [
|
||||
{
|
||||
model: PromotionalGiftCharacterTrait,
|
||||
as: 'characterTraits',
|
||||
where: { trait_id: { [Op.in]: user.character.characterTraits.map(trait => trait.id) }, },
|
||||
},
|
||||
{
|
||||
model: PromotionalGiftMood,
|
||||
as: 'promotionalgiftmoods',
|
||||
},
|
||||
]
|
||||
});
|
||||
const cost = await this.getGiftCost(gift.value, user.character.titleOfNobility, lowestTitleOfNobility.id);
|
||||
if (user.money < cost) {
|
||||
console.log(user, user.money, cost);
|
||||
throw new Error('Not enough money to send the gift');
|
||||
}
|
||||
console.log(JSON.stringify(gift));
|
||||
const changeValue = gift.characterTraits.suitability + gift.promotionalgiftmoods.suitability - 4;
|
||||
this.updateFalukantUserMoney(user.id, -cost, 'Gift cost', user.id);
|
||||
await relation.update({ value: relation.value + changeValue });
|
||||
await PromotionalGiftLog.create({
|
||||
senderCharacterId: user.character.id,
|
||||
recipientCharacterId: relation.character2Id,
|
||||
giftId: giftId,
|
||||
changeValue: changeValue,
|
||||
});
|
||||
return { success: true, message: 'Gift sent' };
|
||||
}
|
||||
|
||||
async getGiftCost(value, titleOfNobility, lowestTitleOfNobility) {
|
||||
const titleLevel = titleOfNobility - lowestTitleOfNobility + 1;
|
||||
return Math.round(value * Math.pow(1 + titleLevel * 0.3, 1.3) * 100) / 100;
|
||||
}
|
||||
|
||||
async getTitlesOfNobility() {
|
||||
return TitleOfNobility.findAll();
|
||||
}
|
||||
|
||||
async getHouseTypes() {
|
||||
// return House
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -231,16 +231,16 @@ async function initializeFalukantProducts() {
|
||||
await ProductType.bulkCreate([
|
||||
{ labelTr: 'wheat', category: 1, productionTime: 2, sellCost: 7 },
|
||||
{ labelTr: 'grain', category: 1, productionTime: 2, sellCost: 7 },
|
||||
{ labelTr: 'carrot', category: 1, productionTime: 1, sellCost: 4 },
|
||||
{ labelTr: 'carrot', category: 1, productionTime: 1, sellCost: 46},
|
||||
{ labelTr: 'fish', category: 1, productionTime: 2, sellCost: 7 },
|
||||
{ labelTr: 'meat', category: 1, productionTime: 2, sellCost: 7 },
|
||||
{ labelTr: 'leather', category: 1, productionTime: 2, sellCost: 7 },
|
||||
{ labelTr: 'wood', category: 1, productionTime: 2, sellCost: 7 },
|
||||
{ labelTr: 'stone', category: 1, productionTime: 2, sellCost: 7 },
|
||||
{ labelTr: 'milk', category: 1, productionTime: 1, sellCost: 4 },
|
||||
{ labelTr: 'cheese', category: 1, productionTime: 1, sellCost: 4 },
|
||||
{ labelTr: 'bread', category: 1, productionTime: 1, sellCost: 4 },
|
||||
{ labelTr: 'beer', category: 2, productionTime: 3, sellCost: 4 },
|
||||
{ labelTr: 'milk', category: 1, productionTime: 1, sellCost: 6 },
|
||||
{ labelTr: 'cheese', category: 1, productionTime: 1, sellCost: 6 },
|
||||
{ labelTr: 'bread', category: 1, productionTime: 1, sellCost: 6 },
|
||||
{ labelTr: 'beer', category: 2, productionTime: 3, sellCost: 6 },
|
||||
{ labelTr: 'iron', category: 2, productionTime: 4, sellCost: 15 },
|
||||
{ labelTr: 'copper', category: 2, productionTime: 4, sellCost: 15 },
|
||||
{ labelTr: 'spices', category: 2, productionTime: 8, sellCost: 30 },
|
||||
|
||||
@@ -7,6 +7,15 @@ import PromotionalGift from "../../models/falukant/type/promotional_gift.js";
|
||||
import PromotionalGiftCharacterTrait from "../../models/falukant/predefine/promotional_gift_character_trait.js";
|
||||
import PromotionalGiftMood from "../../models/falukant/predefine/promotional_gift_mood.js";
|
||||
|
||||
export const initializeFalukantTypes = async () => {
|
||||
await initializeFalukantTypeRegions();
|
||||
await initializeFalukantRelationships();
|
||||
await initializeFalukantMoods();
|
||||
await initializeFalukantCharacterTraits();
|
||||
await initializeFalukantPromotionalGifts();
|
||||
await initializePromotionalGiftMoodLinks();
|
||||
};
|
||||
|
||||
const regionTypes = [];
|
||||
const regionTypeTrs = [
|
||||
"country",
|
||||
@@ -33,7 +42,8 @@ const relationships = [
|
||||
{ tr: "wooing" },
|
||||
{ tr: "engaged" },
|
||||
{ tr: "married" },
|
||||
{ tr: "widowed" }
|
||||
{ tr: "widowed" },
|
||||
{ tr: "lover" },
|
||||
];
|
||||
|
||||
const moods = [
|
||||
@@ -194,15 +204,6 @@ const promotionalGiftMoodLinks = [
|
||||
{ gift: "Horse", mood: "nervous", suitability: 4 },
|
||||
];
|
||||
|
||||
export const initializeFalukantTypes = async () => {
|
||||
await initializeFalukantTypeRegions();
|
||||
await initializeFalukantRelationships();
|
||||
await initializeFalukantMoods();
|
||||
await initializeFalukantCharacterTraits();
|
||||
await initializeFalukantPromotionalGifts();
|
||||
await initializePromotionalGiftMoodLinks();
|
||||
};
|
||||
|
||||
const initializeFalukantTypeRegions = async () => {
|
||||
for (const regionType of regionTypeTrs) {
|
||||
const [regionTypeRecord] = await RegionType.findOrCreate({
|
||||
@@ -326,3 +327,4 @@ export const initializePromotionalGiftMoodLinks = async () => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@ const syncDatabase = async () => {
|
||||
console.log("Setting up associations...");
|
||||
setupAssociations();
|
||||
|
||||
console.log("Creating triggers...");
|
||||
await createTriggers();
|
||||
|
||||
console.log("Initializing settings...");
|
||||
await initializeSettings();
|
||||
|
||||
@@ -43,6 +40,9 @@ const syncDatabase = async () => {
|
||||
console.log("Initializing Falukant...");
|
||||
await initializeFalukant();
|
||||
|
||||
console.log("Creating triggers...");
|
||||
await createTriggers();
|
||||
|
||||
console.log('Database synchronization complete.');
|
||||
} catch (error) {
|
||||
console.error('Unable to synchronize the database:', error);
|
||||
|
||||
Reference in New Issue
Block a user