Start implementation of branches, new form element tabledropdown, model improvements

This commit is contained in:
Torsten Schulz
2024-12-06 23:35:28 +01:00
parent 8c15fb7f2b
commit 1bb2bd49d5
57 changed files with 2176 additions and 170 deletions

View File

@@ -1,13 +1,69 @@
import * as falukantService from '../services/falukantService.js';
import FalukantService from '../services/falukantService.js';
class FalukantController {
constructor() {
this.exampleMethod = this.exampleMethod.bind(this);
this.getUser = this.getUser.bind(this);
this.createUser = this.createUser.bind(this);
this.randomFirstName = this.randomFirstName.bind(this);
this.randomLastName = this.randomLastName.bind(this);
this.getInfo = this.getInfo.bind(this);
}
async exampleMethod(req, res) {
async getUser(req, res) {
try {
const result = await falukantService.exampleMethod();
const { userid: hashedUserId } = req.headers;
const result = await FalukantService.getUser(hashedUserId);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async createUser(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { gender, firstname: firstName, lastname: lastName } = req.body;
console.log(req.body);
const result = await FalukantService.createUser(hashedUserId, gender, firstName, lastName);
res.status(201).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async randomFirstName(req, res) {
try {
const { gender } = req.params;
const result = await FalukantService.randomFirstName(gender);
res.status(200).json({ name: result });
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async randomLastName(req, res) {
try {
const result = await FalukantService.randomLastName();
res.status(200).json({ name: result });
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getInfo(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const result = await FalukantService.getInfo(hashedUserId);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getBranches(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const result = await FalukantService.getBranches(hashedUserId);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });

View File

@@ -87,7 +87,7 @@ const menuStructure = {
},
towns: {
visible: ["hasfalukantaccount"],
path: "/falukant/towns"
path: "/falukant/branch"
},
directors: {
visible: ["hasfalukantaccount"],
@@ -117,6 +117,10 @@ const menuStructure = {
visible: ["hasfalukantaccount"],
path: "/falukant/education"
},
health: {
visible: ["hasfalukantaccount"],
path: "/falukant/health"
},
bank: {
visible: ["hasfalukantaccount"],
path: "/falukant/bank"
@@ -238,7 +242,6 @@ class NavigationController {
}
async filterMenu(menu, rights, age, userId) {
console.log(userId);
const filteredMenu = {};
const hasFalukantAccount = await this.hasFalukantAccount(userId);
for (const [key, value] of Object.entries(menu)) {

View File

@@ -31,6 +31,18 @@ import Friendship from './community/friendship.js';
import FalukantUser from './falukant/data/user.js';
import RegionType from './falukant/type/region.js';
import RegionData from './falukant/data/region.js';
import FalukantCharacter from './falukant/data/character.js';
import FalukantPredefineFirstname from './falukant/predefine/firstname.js';
import FalukantPredefineLastname from './falukant/predefine/lastname.js';
import FalukantStock from './falukant/data/stock.js';
import FalukantStockType from './falukant/type/stock.js';
import Knowledge from './falukant/data/product_knowledge.js';
import ProductType from './falukant/type/product.js';
import TitleOfNobility from './falukant/type/title_of_nobility.js';
import TitleRequirement from './falukant/type/title_requirement.js';
import Branch from './falukant/data/branch.js';
import BranchType from './falukant/type/branch.js';
export default function setupAssociations() {
// UserParam related associations
@@ -181,4 +193,46 @@ export default function setupAssociations() {
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(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(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' });
FalukantStock.belongsTo(FalukantStockType, { foreignKey: 'stockTypeId', as: 'stockType' });
FalukantStockType.hasMany(FalukantStock, { foreignKey: 'stockTypeId', as: 'stocks' });
FalukantStock.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' });
FalukantUser.hasMany(FalukantStock, { foreignKey: 'userId', as: 'stocks' });
FalukantStock.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' });
RegionData.hasMany(FalukantStock, { foreignKey: 'regionId', as: 'stocksInRegion' });
Knowledge.belongsTo(ProductType, { foreignKey: 'productTypeId', as: 'productType' });
ProductType.hasMany(Knowledge, { foreignKey: 'productTypeId', 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' });
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(BranchType, { foreignKey: 'branchTypeId', as: 'branchType' });
BranchType.hasMany(Branch, { foreignKey: 'branchTypeId', as: 'branches' });
}

View File

@@ -0,0 +1,34 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class Branch extends Model { }
Branch.init({
branchTypeId: {
type: DataTypes.INTEGER,
allowNull: false,
},
regionId: {
type: DataTypes.INTEGER,
allowNull: false,
},
falukantUserId: {
type: DataTypes.INTEGER,
allowNull: false,
},
}, {
sequelize,
modelName: 'BranchType',
tableName: 'branch',
schema: 'falukant_data',
timestamps: false,
underscored: true,
indexes: [
{
unique: true,
fields: ['region_id', 'falukant_user_id']
}
],
});
export default Branch;

View File

@@ -0,0 +1,49 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class FalukantCharacter extends Model {};
FalukantCharacter.init({
userId: {
type: DataTypes.INTEGER,
allowNull: true,
},
regionId: {
type: DataTypes.INTEGER,
allowNull: false,
},
firstName: {
type: DataTypes.INTEGER,
allowNull: false,
},
lastName: {
type: DataTypes.INTEGER,
allowNull: false,
},
birthdate: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
},
gender: {
type: DataTypes.STRING
},
health: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 100
},
titleOfNobility: {
type: DataTypes.INTEGER,
allowNull: false,
}
}, {
sequelize,
modelName: 'FalukantCharacter',
tableName: 'character',
schema: 'falukant_data',
timestamps: true,
underscored: true,
});
export default FalukantCharacter;

View File

@@ -0,0 +1,34 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class Knowledge extends Model { }
Knowledge.init({
productId: {
type: DataTypes.INTEGER,
allowNull: false,
},
characterId: {
type: DataTypes.INTEGER,
allowNull: false,
},
knowledge: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
}
}, {
sequelize,
modelName: 'Knowledge',
tableName: 'knowledge',
schema: 'falukant_data',
timestamps: false,
underscored: true,
hooks: {
beforeCreate: (knowledge) => {
knowledge.knowledge = Math.floor(Math.random() * 61) + 20;
}
}
});
export default Knowledge;

View File

@@ -0,0 +1,32 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class FalukantStock extends Model { }
FalukantStock.init({
userId: {
type: DataTypes.INTEGER,
allowNull: false,
},
regionId: {
type: DataTypes.INTEGER,
allowNull: false,
},
stockTypeId: {
type: DataTypes.INTEGER,
allowNull: false,
},
quantity: {
type: DataTypes.INTEGER,
allowNull: false,
},
}, {
sequelize,
modelName: 'StockType',
tableName: 'stock',
schema: 'falukant_data',
timestamps: false,
underscored: true,
});
export default FalukantStock;

View File

@@ -14,7 +14,8 @@ FalukantUser.init({
schema: 'community'
},
key: 'id'
}
},
unique: true,
},
money: {
type: DataTypes.DECIMAL(10, 2),

View File

@@ -0,0 +1,26 @@
import { sequelize } from '../../../utils/sequelize.js';
import { DataTypes } from 'sequelize';
const FalukantPredefineFirstname = sequelize.define('firstname', {
name: {
type: DataTypes.STRING,
allowNull: false
},
gender: {
type: DataTypes.STRING,
allowNull: false
}
}, {
tableName: 'firstname',
schema: 'falukant_predefine',
underscored: true,
timestamps: false,
indexes: [
{
unique: true,
fields: ['name', 'gender']
}
],
});
export default FalukantPredefineFirstname;

View File

@@ -0,0 +1,23 @@
import { sequelize } from '../../../utils/sequelize.js';
import { DataTypes } from 'sequelize';
const FalukantPredefineLastname = sequelize.define('lastname', {
name: {
type: DataTypes.STRING,
length: 1,
allowNull: false
},
}, {
tableName: 'lastname',
schema: 'falukant_predefine',
underscored: true,
timestamps: false,
indexes: [
{
unique: true,
fields: ['name']
}
],
});
export default FalukantPredefineLastname;

View File

@@ -0,0 +1,30 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class BranchType extends Model { }
BranchType.init({
labelTr: {
type: DataTypes.STRING,
allowNull: false,
},
baseCost: {
type: DataTypes.INTEGER,
allowNull: false,
}
}, {
sequelize,
modelName: 'BranchType',
tableName: 'branch',
schema: 'falukant_type',
timestamps: false,
underscored: true,
indexes: [
{
unique: true,
fields: ['label_tr']
}
],
});
export default BranchType;

View File

@@ -0,0 +1,38 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class ProductType extends Model { }
ProductType.init({
labelTr: {
type: DataTypes.STRING,
allowNull: false,
},
category: {
type: DataTypes.INTEGER,
allowNull: false,
},
productionTime: {
type: DataTypes.INTEGER,
allowNull: false,
},
sellCost: {
type: DataTypes.INTEGER,
allowNull: false,
}
}, {
sequelize,
modelName: 'ProductType',
tableName: 'product',
schema: 'falukant_type',
timestamps: false,
underscored: true,
indexes: [
{
unique: true,
fields: ['label_tr']
}
],
});
export default ProductType;

View File

@@ -0,0 +1,24 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class FalukantStockType extends Model { }
FalukantStockType.init({
labelTr: {
type: DataTypes.STRING,
allowNull: false,
},
cost: {
type: DataTypes.INTEGER,
allowNull: false,
}
}, {
sequelize,
modelName: 'StockType',
tableName: 'stock',
schema: 'falukant_type',
timestamps: false,
underscored: true,
});
export default FalukantStockType;

View File

@@ -0,0 +1,20 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class TitleOfNobility extends Model { }
TitleOfNobility.init({
labelTr: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
sequelize,
modelName: 'Title',
tableName: 'title',
schema: 'falukant_type',
timestamps: false,
underscored: true,
});
export default TitleOfNobility;

View File

@@ -0,0 +1,30 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class TitleRequirement extends Model { }
TitleRequirement.init({
titleId: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
requirementType: {
type: DataTypes.STRING,
allowNull: false,
},
requirementValue: {
type: DataTypes.DECIMAL(14, 2),
allowNull: false,
},
}, {
sequelize,
modelName: 'TitleRequirement',
tableName: 'title_requirement',
schema: 'falukant_type',
timestamps: false,
underscored: true,
});
export default TitleRequirement;

View File

@@ -35,6 +35,17 @@ import Friendship from './community/friendship.js';
import FalukantUser from './falukant/data/user.js';
import RegionType from './falukant/type/region.js';
import RegionData from './falukant/data/region.js';
import FalukantPredefineFirstname from './falukant/predefine/firstname.js';
import FalukantPredefineLastname from './falukant/predefine/lastname.js';
import FalukantCharacter from './falukant/data/character.js';
import FalukantStock from './falukant/data/stock.js';
import FalukantStockType from './falukant/type/stock.js';
import ProductType from './falukant/type/product.js';
import Knowledge from './falukant/data/product_knowledge.js';
import TitleRequirement from './falukant/type/title_requirement.js';
import TitleOfNobility from './falukant/type/title_of_nobility.js';
import BranchType from './falukant/type/branch.js';
import Branch from './falukant/data/branch.js';
const models = {
SettingsType,
@@ -74,6 +85,17 @@ const models = {
RegionType,
RegionData,
FalukantUser,
FalukantPredefineFirstname,
FalukantPredefineLastname,
FalukantCharacter,
FalukantStock,
FalukantStockType,
ProductType,
Knowledge,
TitleOfNobility,
TitleRequirement,
BranchType,
Branch,
};
export default models;

View File

@@ -2,7 +2,7 @@ import { sequelize } from '../utils/sequelize.js';
export async function createTriggers() {
const createTriggerFunction = `
CREATE OR REPLACE FUNCTION create_user_param_visibility_trigger()
CREATE OR REPLACE FUNCTION community.create_user_param_visibility_trigger()
RETURNS TRIGGER AS $$
BEGIN
-- Check if UserParamVisibility already exists for this UserParam
@@ -32,7 +32,7 @@ export async function createTriggers() {
AFTER INSERT ON community.user_param
FOR EACH ROW
WHEN (NEW.id IS NOT NULL)
EXECUTE FUNCTION create_user_param_visibility_trigger();
EXECUTE FUNCTION community.create_user_param_visibility_trigger();
`;
const createUpdateTrigger = `
@@ -40,11 +40,11 @@ export async function createTriggers() {
AFTER UPDATE ON community.user_param
FOR EACH ROW
WHEN (NEW.id IS NOT NULL)
EXECUTE FUNCTION create_user_param_visibility_trigger();
EXECUTE FUNCTION community.create_user_param_visibility_trigger();
`;
const createDiaryHistoryTriggerFunction = `
CREATE OR REPLACE FUNCTION insert_diary_history()
CREATE OR REPLACE FUNCTION community.insert_diary_history()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO community.diary_history (diary_id, user_id, old_text, old_created_at, old_updated_at)
@@ -65,11 +65,11 @@ export async function createTriggers() {
BEFORE UPDATE ON community.diary
FOR EACH ROW
WHEN (OLD.id IS NOT NULL)
EXECUTE FUNCTION insert_diary_history();
EXECUTE FUNCTION community.insert_diary_history();
`;
const createTitleHistoryTriggerFunction = `
CREATE OR REPLACE FUNCTION insert_title_history()
CREATE OR REPLACE FUNCTION forum.insert_title_history()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO forum.title_history (title_id, old_title, changed_by, old_updated_at)
@@ -84,7 +84,44 @@ export async function createTriggers() {
BEFORE UPDATE ON forum.title
FOR EACH ROW
WHEN (OLD.id IS NOT NULL)
EXECUTE FUNCTION insert_title_history();
EXECUTE FUNCTION forum.insert_title_history();
`;
const createCharacterCreationTriggerMethod = `
CREATE OR REPLACE FUNCTION falukant_data.create_character_creation_trigger()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO falukant_data.knowledge (product_id, character_id)
SELECT id, NEW.id FROM falukant_type.product;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
`;
const createCharacterCreationTrigger = `
CREATE OR REPLACE TRIGGER character_creation_trigger
AFTER INSERT ON falukant_data.character
FOR EACH ROW
WHEN (NEW.id IS NOT NULL)
EXECUTE FUNCTION falukant_data.create_character_creation_trigger();
`;
const createKnowledgeTriggerMethod = `
CREATE OR REPLACE FUNCTION falukant_data.create_knowledge_trigger()
RETURNS TRIGGER AS $$
BEGIN
NEW.knowledge = random() * 61 + 20;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
`;
const createKnowledgeTrigger = `
CREATE OR REPLACE TRIGGER knowledge_trigger
BEFORE INSERT ON falukant_data.knowledge
FOR EACH ROW
WHEN (NEW.id IS NOT NULL)
EXECUTE FUNCTION falukant_data.create_knowledge_trigger();
`;
try {
@@ -95,10 +132,14 @@ export async function createTriggers() {
await sequelize.query(createDiaryHistoryTrigger);
await sequelize.query(createTitleHistoryTriggerFunction);
await sequelize.query(createTitleHistoryTrigger);
await sequelize.query(createCharacterCreationTriggerMethod);
await sequelize.query(createCharacterCreationTrigger);
await sequelize.query(createKnowledgeTriggerMethod);
await sequelize.query(createKnowledgeTrigger);
console.log('Triggers created successfully');
} catch (error) {
console.error('Error creating triggers:', error);
}
}

View File

@@ -13,6 +13,7 @@
"bcrypt": "^5.1.1",
"connect-redis": "^7.1.1",
"cors": "^2.8.5",
"date-fns": "^4.1.0",
"dompurify": "^3.1.7",
"dotenv": "^16.4.5",
"express": "^4.19.2",
@@ -1231,9 +1232,9 @@
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"dependencies": {
"path-key": "^3.1.0",
@@ -1311,6 +1312,15 @@
"node": ">=18"
}
},
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/debug": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",

View File

@@ -15,6 +15,7 @@
"bcrypt": "^5.1.1",
"connect-redis": "^7.1.1",
"cors": "^2.8.5",
"date-fns": "^4.1.0",
"dompurify": "^3.1.7",
"dotenv": "^16.4.5",
"express": "^4.19.2",

View File

@@ -4,6 +4,10 @@ import FalukantController from '../controllers/falukantController.js';
const router = express.Router();
const falukantController = new FalukantController();
router.get('/example', falukantController.exampleMethod);
router.get('/user', falukantController.getUser);
router.post('/user', falukantController.createUser);
router.get('/name/randomfirstname/:gender', falukantController.randomFirstName);
router.get('/name/randomlastname', falukantController.randomLastName);
router.get('/info', falukantController.getInfo);
router.get('/branches', falukantController.getBranches);
export default router;

View File

@@ -1,7 +1,284 @@
class FalukantService {
async exampleMethod() {
// Logik für die Methode
import BaseService from './BaseService.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';
import User from '../models/community/user.js';
import FalukantCharacter from '../models/falukant/data/character.js';
import RegionData from '../models/falukant/data/region.js';
import RegionType from '../models/falukant/type/region.js';
import { Sequelize } from 'sequelize';
import FalukantStock from '../models/falukant/data/stock.js';
import FalukantStockType from '../models/falukant/type/stock.js';
import { notifyUser } from '../utils/socket.js';
import { differenceInDays } from 'date-fns';
import TitleOfNobility from '../models/falukant/type/title_of_nobility.js';
import Branch from '../models/falukant/data/branch.js';
import BranchType from '../models/falukant/type/branch.js';
class FalukantService extends BaseService {
async getFalukantUserByHashedId(hashedId) {
const falukantUser = await FalukantUser.findOne({
include: [{
model: User,
as: 'user',
attributes: ['username', 'hashedId'],
where: {
hashedId: hashedId
},
}
],
});
return falukantUser;
}
async getUser(hashedUserId) {
const falukantUser = await FalukantUser.findOne({
include: [{
model: User,
as: 'user',
attributes: ['username', 'hashedId'],
where: {
hashedId: hashedUserId
},
},
{
model: FalukantCharacter,
as: 'character',
include: [
{
model: FalukantPredefineFirstname,
as: 'definedFirstName',
attributes: ['name']
},
{
model: FalukantPredefineLastname,
as: 'definedLastName',
attributes: ['name']
},
{
model: TitleOfNobility,
as: 'nobleTitle',
attributes: ['labelTr']
}
],
attributes: ['birthdate', 'gender'],
},
{
model: RegionData,
as: 'mainBranchRegion',
include: [
{
model: RegionType,
as: 'regionType',
}
],
attributes: ['name'],
},
{
model: Branch,
as: 'branches',
include: [
{
model: BranchType,
as: 'branchType',
attributes: ['labelTr']
},
{
model: RegionData,
as: 'region',
include: [
{
model: RegionType,
as: 'regionType',
}
],
attributes: ['name'],
}
]
}
],
attributes: ['money', 'creditAmount', 'todayCreditTaken'],
});
if (!falukantUser) {
throw new Error('User not found');
}
const character = falukantUser.character;
if (character && character.birthdate) {
const birthdate = new Date(character.birthdate);
birthdate.setHours(0);
birthdate.setMinutes(0);
const currentDate = new Date();
currentDate.setHours(0);
currentDate.setMinutes(0);
const ageInDays = differenceInDays(currentDate, birthdate);
character.setDataValue('age', ageInDays);
}
return falukantUser;
}
async randomFirstName(gender) {
const names = await FalukantPredefineFirstname.findAll({ where: { gender: gender } });
return names[Math.floor(Math.random() * names.length)].name;
}
async randomLastName() {
const names = await FalukantPredefineLastname.findAll();
return names[Math.floor(Math.random() * names.length)].name;
}
async createUser(hashedUserId, gender, firstName, lastName) {
try {
const user = await this.getUserByHashedId(hashedUserId);
const userExistsCheck = await FalukantUser.findOne({ where: { userId: user.id } });
if (userExistsCheck) {
throw new Error('User already exists in Falukant.');
}
let firstNameObject = await FalukantPredefineFirstname.findOne({ where: { name: firstName } });
let lastNameObject = await FalukantPredefineLastname.findOne({ where: { name: lastName } });
if (!firstNameObject) {
firstNameObject = await FalukantPredefineFirstname.create({ name: firstName, gender: gender });
}
if (!lastNameObject) {
lastNameObject = await FalukantPredefineLastname.create({ name: lastName });
}
const randomRegion = await RegionData.findOne({
order: Sequelize.fn('RANDOM'),
limit: 1,
include: [
{
model: RegionType,
as: 'regionType',
where: {
labelTr: 'city'
}
}
]
});
if (!randomRegion) {
throw new Error('No region found with the label "city".');
}
const titleOfNobility = await TitleOfNobility.findOne({ where: { labelTr: 'noncivil' } });
if (!titleOfNobility) {
throw new Error('No title of nobility found with the label "noncivil".');
}
const falukantUser = await FalukantUser.create({
userId: user.id,
money: 50.00,
creditAmount: 0.00,
todayCreditTaken: 0.00,
creditInterestRate: 0.00,
mainBranchRegionId: randomRegion.id,
});
const fourteenDaysAgo = new Date();
fourteenDaysAgo.setDate(fourteenDaysAgo.getDate() - 14);
const character = await FalukantCharacter.create({
userId: falukantUser.id,
regionId: randomRegion.id,
firstName: firstNameObject.id,
lastName: lastNameObject.id,
gender: gender,
birthdate: fourteenDaysAgo,
titleOfNobility: titleOfNobility.id,
});
await FalukantStock.create({
userId: falukantUser.id,
regionId: randomRegion.id,
stockTypeId: (await FalukantStockType.findOne({ where: [{ label_tr: 'wood' }] })).id,
quantity: 10,
});
falukantUser['character'] = character;
const branchType = await BranchType.findOne({ where: { labelTr: 'fullstack' } });
await Branch.create({
userId: falukantUser.id,
regionId: randomRegion.id,
branchTypeId: branchType.id,
})
notifyUser(user.hashedId, 'reloadmenu', {});
return falukantUser;
} catch (error) {
console.error('Error creating character');
console.log(error);
}
}
async getInfo(hashedUserId) {
try {
const user = await User.findOne({ where: { hashedId: hashedUserId } });
if (!user) {
throw new Error('User not found');
}
const falukantUser = await FalukantUser.findOne({
include: [{
model: User,
as: 'user',
attributes: ['hashedId'],
where: {
hashedId: hashedUserId
},
},
{
model: FalukantCharacter,
as: 'character',
attributes: ['birthdate', 'health'],
},
],
attributes: ['money']
});
if (!falukantUser) {
throw new Error('User not found');
}
const character = falukantUser.character;
if (character && character.birthdate) {
const birthdate = new Date(character.birthdate);
birthdate.setHours(0);
birthdate.setMinutes(0);
const currentDate = new Date();
currentDate.setHours(0);
currentDate.setMinutes(0);
const ageInDays = differenceInDays(currentDate, birthdate);
character.setDataValue('age', ageInDays);
}
return falukantUser;
} catch (error) {
console.error('Error getting character info');
console.log(error);
}
}
async getBranches(hashedUserId) {
try {
const falukantUser = await this.getFalukantUserByHashedId(hashedUserId);
if (!falukantUser) {
throw new Error('User not found');
}
const branches = await Branch.findAll({
where: { falukantUserId: falukantUser.id },
include: [
{
model: BranchType,
as: 'branchType',
attributes: ['labelTr'],
},
{
model: RegionData,
as: 'region',
attributes: ['name'],
}
],
attributes: ['id', 'regionId'],
order: [['branchTypeId', 'ASC']],
});
const enrichedBranches = branches.map(branch => ({
...branch.toJSON(),
isMainBranch: falukantUser.mainBranchRegionId === branch.regionId,
}));
return enrichedBranches;
} catch (error) {
console.error('Error in getBranches:', error);
throw new Error('Failed to retrieve branches');
}
}
}
export default new FalukantService();

View File

@@ -0,0 +1,341 @@
import FalukantPredefineFirstname from "../../models/falukant/predefine/firstname.js";
import FalukantPredefineLastname from "../../models/falukant/predefine/lastname.js";
import BranchType from "../../models/falukant/type/branch.js";
import ProductType from "../../models/falukant/type/product.js";
import FalukantStockType from "../../models/falukant/type/stock.js";
import TitleOfNobility from "../../models/falukant/type/title_of_nobility.js";
import TitleRequirement from "../../models/falukant/type/title_requirement.js";
export const initializeFalukantPredefines = async () => {
await initializeFalukantFirstnames();
await initializeFalukantLastnames();
await initializeFalukantStockTypes();
await initializeFalukantProducts();
await initializeFalukantTitles();
await initializeFalukantTitleRequirements();
await initializeFalukantBranchTypes();
}
const initializeFalukantFirstnames = async () => {
await FalukantPredefineFirstname.bulkCreate([
{ name: "Alexander", gender: "male" },
{ name: "Ben", gender: "male" },
{ name: "Christian", gender: "male" },
{ name: "Daniel", gender: "male" },
{ name: "Elias", gender: "male" },
{ name: "Felix", gender: "male" },
{ name: "Gabriel", gender: "male" },
{ name: "Hans", gender: "male" },
{ name: "Ismail", gender: "male" },
{ name: "Jakob", gender: "male" },
{ name: "Kai", gender: "male" },
{ name: "Lukas", gender: "male" },
{ name: "Maximilian", gender: "male" },
{ name: "Niklas", gender: "male" },
{ name: "Oliver", gender: "male" },
{ name: "Paul", gender: "male" },
{ name: "Quentin", gender: "male" },
{ name: "Robert", gender: "male" },
{ name: "Sebastian", gender: "male" },
{ name: "Thomas", gender: "male" },
{ name: "Ulf", gender: "male" },
{ name: "Vincent", gender: "male" },
{ name: "Thorsten", gender: "male" },
{ name: "Ulrich", gender: "male" },
{ name: "Torben", gender: "male" },
{ name: "Torsten", gender: "male" },
{ name: "Uwe", gender: "male" },
{ name: "Viktor", gender: "male" },
{ name: "Wolfgang", gender: "male" },
{ name: "Xaver", gender: "male" },
{ name: "Yannik", gender: "male" },
{ name: "Zacharias", gender: "male" },
{ name: "Aaron", gender: "male" },
{ name: "Bruno", gender: "male" },
{ name: "Carl", gender: "male" },
{ name: "David", gender: "male" },
{ name: "Emil", gender: "male" },
{ name: "Fabian", gender: "male" },
{ name: "Georg", gender: "male" },
{ name: "Heinrich", gender: "male" },
{ name: "Ian", gender: "male" },
{ name: "Jonas", gender: "male" },
{ name: "Karl", gender: "male" },
{ name: "Leon", gender: "male" },
{ name: "Matthias", gender: "male" },
{ name: "Nils", gender: "male" },
{ name: "Oskar", gender: "male" },
{ name: "Peter", gender: "male" },
{ name: "Ralf", gender: "male" },
{ name: "Simon", gender: "male" },
{ name: "Tobias", gender: "male" },
{ name: "Ulrich", gender: "male" },
{ name: "Vince", gender: "male" },
{ name: "Walter", gender: "male" },
{ name: "Xeno", gender: "male" },
{ name: "Yves", gender: "male" },
{ name: "Zeno", gender: "male" },
{ name: "Anna", gender: "female" },
{ name: "Berit", gender: "female" },
{ name: "Charlotte", gender: "female" },
{ name: "Diana", gender: "female" },
{ name: "Emilia", gender: "female" },
{ name: "Fiona", gender: "female" },
{ name: "Greta", gender: "female" },
{ name: "Hanna", gender: "female" },
{ name: "Isabelle", gender: "female" },
{ name: "Johanna", gender: "female" },
{ name: "Katharina", gender: "female" },
{ name: "Lena", gender: "female" },
{ name: "Marie", gender: "female" },
{ name: "Nina", gender: "female" },
{ name: "Olivia", gender: "female" },
{ name: "Paula", gender: "female" },
{ name: "Quirina", gender: "female" },
{ name: "Rebecca", gender: "female" },
{ name: "Sophia", gender: "female" },
{ name: "Theresa", gender: "female" },
{ name: "Ulrike", gender: "female" },
{ name: "Valeria", gender: "female" },
{ name: "Wilma", gender: "female" },
{ name: "Xenia", gender: "female" },
{ name: "Yara", gender: "female" },
{ name: "Zoe", gender: "female" },
{ name: "Antonia", gender: "female" },
{ name: "Beate", gender: "female" },
{ name: "Carla", gender: "female" },
{ name: "Dorothea", gender: "female" },
{ name: "Elisabeth", gender: "female" },
{ name: "Franziska", gender: "female" },
{ name: "Gerda", gender: "female" },
{ name: "Helena", gender: "female" },
{ name: "Irene", gender: "female" },
{ name: "Julia", gender: "female" },
{ name: "Klara", gender: "female" },
{ name: "Leonie", gender: "female" },
{ name: "Marlene", gender: "female" },
{ name: "Nele", gender: "female" },
{ name: "Petra", gender: "female" },
{ name: "Renate", gender: "female" },
{ name: "Sandra", gender: "female" },
{ name: "Tanja", gender: "female" },
{ name: "Ursula", gender: "female" },
{ name: "Vanessa", gender: "female" },
{ name: "Waltraud", gender: "female" },
{ name: "Xaveria", gender: "female" },
{ name: "Yvonne", gender: "female" },
{ name: "Zora", gender: "female" },
], {
ignoreDuplicates: true,
});
}
const initializeFalukantLastnames = async () => {
await FalukantPredefineLastname.bulkCreate([
{ name: "Adler" },
{ name: "Bauer" },
{ name: "Becker" },
{ name: "Bergmann" },
{ name: "Braun" },
{ name: "Busch" },
{ name: "Dreyer" },
{ name: "Eberhardt" },
{ name: "Fischer" },
{ name: "Franke" },
{ name: "Friedrich" },
{ name: "Geiger" },
{ name: "Gärtner" },
{ name: "Hartmann" },
{ name: "Hoffmann" },
{ name: "Hofmann" },
{ name: "Horn" },
{ name: "Huber" },
{ name: "Jäger" },
{ name: "Jung" },
{ name: "Kaiser" },
{ name: "Keller" },
{ name: "Klein" },
{ name: "Koch" },
{ name: "König" },
{ name: "Krüger" },
{ name: "Lang" },
{ name: "Lehmann" },
{ name: "Ludwig" },
{ name: "Maier" },
{ name: "Meyer" },
{ name: "Müller" },
{ name: "Neumann" },
{ name: "Neff" },
{ name: "Obermeier" },
{ name: "Otto" },
{ name: "Peters" },
{ name: "Ritter" },
{ name: "Richter" },
{ name: "Rosen" },
{ name: "Schäfer" },
{ name: "Schmidt" },
{ name: "Schneider" },
{ name: "Schulz" },
{ name: "Schulze" },
{ name: "Schwarz" },
{ name: "Schuster" },
{ name: "Sommer" },
{ name: "Stein" },
{ name: "Tanner" },
{ name: "Thiel" },
{ name: "Ullmann" },
{ name: "Ullrich" },
{ name: "Vogel" },
{ name: "Voigt" },
{ name: "Wagner" },
{ name: "Walter" },
{ name: "Weber" },
{ name: "Weiß" },
{ name: "Winter" },
{ name: "Wolf" },
{ name: "Xaver" },
{ name: "Xavier" },
{ name: "Zimmer" },
{ name: "Zimmermann" },
{ name: "Albrecht" },
{ name: "Arnold" },
{ name: "Baumann" },
{ name: "Dietrich" },
{ name: "Engel" },
{ name: "Graf" },
{ name: "Kirsch" },
{ name: "Lenz" },
{ name: "Schirmer" },
{ name: "Vogt" },
{ name: "Ziegler" },
], {
ignoreDuplicates: true,
});
}
async function initializeFalukantStockTypes() {
await FalukantStockType.bulkCreate([
{ labelTr: 'wood', cost: 15 },
{ labelTr: 'stone', cost: 25 },
{ labelTr: 'iron', cost: 100 },
{ labelTr: 'field', cost: 5 },
]);
}
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: '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: 1, productionTime: 1, sellCost: 4 },
{ labelTr: 'iron', category: 2, productionTime: 4, sellCost: 15 },
{ labelTr: 'copper', category: 2, productionTime: 4, sellCost: 15 },
{ labelTr: 'spices', category: 2, productionTime: 8, sellCost: 30 },
{ labelTr: 'salt', category: 2, productionTime: 4, sellCost: 15 },
{ labelTr: 'sugar', category: 2, productionTime: 4, sellCost: 15 },
{ labelTr: 'vinegar', category: 2, productionTime: 4, sellCost: 15 },
{ labelTr: 'cotton', category: 2, productionTime: 4, sellCost: 15 },
{ labelTr: 'wine', category: 2, productionTime: 4, sellCost: 15 },
{ labelTr: 'gold', category: 3, productionTime: 4, sellCost: 30 },
{ labelTr: 'diamond', category: 3, productionTime: 4, sellCost: 30 },
{ labelTr: 'furniture', category: 3, productionTime: 4, sellCost: 30 },
{ labelTr: 'clothing', category: 3, productionTime: 4, sellCost: 30 },
{ labelTr: 'jewelry', category: 4, productionTime: 5, sellCost: 60 },
{ labelTr: 'painting', category: 4, productionTime: 5, sellCost: 60 },
{ labelTr: 'book', category: 4, productionTime: 5, sellCost: 60 },
{ labelTr: 'weapon', category: 4, productionTime: 5, sellCost: 60 },
{ labelTr: 'armor', category: 4, productionTime: 5, sellCost: 60 },
{ labelTr: 'shield', category: 4, productionTime: 5, sellCost: 60 },
{ labelTr: 'horse', category: 5, productionTime: 5, sellCost: 60 },
{ labelTr: 'ox', category: 5, productionTime: 5, sellCost: 60 },
], {
ignoreDuplicates: true,
});
}
async function initializeFalukantTitles() {
await TitleOfNobility.bulkCreate([
{ labelTr: "noncivil" },
{ labelTr: "civil" },
{ labelTr: "sir" },
{ labelTr: "townlord" },
{ labelTr: "by" },
{ labelTr: "landlord" },
{ labelTr: "knight" },
{ labelTr: "baron" },
{ labelTr: "count" },
{ labelTr: "palsgrave" },
{ labelTr: "margrave" },
{ labelTr: "landgrave" },
{ labelTr: "ruler" },
{ labelTr: "elector" },
{ labelTr: "imperial-prince" },
{ labelTr: "duke" },
{ labelTr: "grand-duke" },
{ labelTr: "prince-regent" },
{ labelTr: "king" },
], {
updateOnDuplicate: ['labelTr'],
});
}
async function initializeFalukantTitleRequirements() {
const titleRequirements = [
{ labelTr: "civil", requirements: [{ type: "money", value: 500 }] },
{ labelTr: "sir", requirements: [{ type: "branches", value: 2 }] },
{ labelTr: "townlord", requirements: [] },
{ labelTr: "by", requirements: [] },
{ labelTr: "landlord", requirements: [] },
{ labelTr: "knight", requirements: [] },
{ labelTr: "baron", requirements: [{ type: "branches", value: 4 }] },
{ labelTr: "count", requirements: [] },
{ labelTr: "palsgrave", requirements: [] },
{ labelTr: "margrave", requirements: [] },
{ labelTr: "landgrave", requirements: [] },
{ labelTr: "ruler", requirements: [] },
{ labelTr: "elector", requirements: [] },
{ labelTr: "imperial-prince", requirements: [] },
{ labelTr: "duke", requirements: [] },
{ labelTr: "grand-duke", requirements: [] },
{ labelTr: "prince-regent", requirements: [] },
{ labelTr: "king", requirements: [] },
];
const titles = await TitleOfNobility.findAll();
const requirementsToInsert = [];
for (let i = 0; i < titleRequirements.length; i++) {
const titleRequirement = titleRequirements[i];
const title = titles.find(t => t.labelTr === titleRequirement.labelTr);
if (!title) continue;
if (i > 1) {
const moneyRequirement = {
type: "money",
value: 5000 * Math.pow(3, i - 1),
};
titleRequirement.requirements.push(moneyRequirement);
}
for (const requirement of titleRequirement.requirements) {
requirementsToInsert.push({
titleId: title.id,
requirementType: requirement.type,
requirementValue: requirement.value,
});
}
}
await TitleRequirement.bulkCreate(requirementsToInsert, { ignoreDuplicates: true });
}
async function initializeFalukantBranchTypes() {
await BranchType.bulkCreate([
{ labelTr: 'production', baseCost: 3000 },
{ labelTr: 'store', baseCost: 2000 },
{ labelTr: 'fullstack', baseCost: 4500},
], { ignoreDuplicates: true });
}

View File

@@ -1,8 +1,10 @@
import { initializeFalukantTypes, initializeFalukantRegions } from './falukant/initializeFalukantTypes.js';
import { initializeFalukantPredefines } from './falukant/initializeFalukantPredefines.js';
const initializeFalukant = async () => {
await initializeFalukantTypes();
await initializeFalukantRegions();
await initializeFalukantPredefines();
}
export default initializeFalukant;

View File

@@ -19,6 +19,7 @@ const createSchemas = async () => {
await sequelize.query('CREATE SCHEMA IF NOT EXISTS forum');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_data');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_type');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_predefine');
};
const initializeDatabase = async () => {