Director hiring added

This commit is contained in:
Torsten Schulz
2025-01-09 15:31:55 +01:00
parent 6f7d97672e
commit 2f60741116
30 changed files with 2368 additions and 751 deletions

View File

@@ -9,6 +9,18 @@ class FalukantController {
this.getInfo = this.getInfo.bind(this);
this.getInventory = this.getInventory.bind(this);
this.sellProduct = this.sellProduct.bind(this);
this.sellAllProducts = this.sellAllProducts.bind(this);
this.moneyHistory = this.moneyHistory.bind(this);
this.getStorage = this.getStorage.bind(this);
this.buyStorage = this.buyStorage.bind(this);
this.sellStorage = this.sellStorage.bind(this);
this.getStockTypes = this.getStockTypes.bind(this);
this.getStockOverview = this.getStockOverview.bind(this);
this.getAllProductions = this.getAllProductions.bind(this);
this.getDirectorProposals = this.getDirectorProposals.bind(this);
this.convertProposalToDirector = this.convertProposalToDirector.bind(this);
this.getDirectorForBranch = this.getDirectorForBranch.bind(this);
this.setSetting = this.setSetting.bind(this);
}
async getUser(req, res) {
@@ -118,6 +130,7 @@ class FalukantController {
}
async createStock(req, res) {
console.log('build stock');
try {
const { userid: hashedUserId } = req.headers;
const { branchId, stockTypeId, stockSize } = req.body;
@@ -159,6 +172,146 @@ class FalukantController {
res.status(500).json({ error: error.message });
}
}
async sellAllProducts(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { branchId } = req.body;
const result = await FalukantService.sellAllProducts(hashedUserId, branchId);
res.status(201).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async moneyHistory(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { page, filter } = req.body;
if (!page) {
page = 1;
}
const result = await FalukantService.moneyHistory(hashedUserId, page, filter);
res.status(201).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getStorage(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { branchId } = req.params;
const result = await FalukantService.getStorage(hashedUserId, branchId);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message});
console.log(error);
}
}
async buyStorage(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { branchId, amount, stockTypeId } = req.body;
const result = await FalukantService.buyStorage(hashedUserId, branchId, amount, stockTypeId);
res.status(201).json(result);
} catch (error) {
res.status(500).json({ error: error.message});
console.log(error);
}
}
async sellStorage(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { branchId, amount, stockTypeId } = req.body;
const result = await FalukantService.sellStorage(hashedUserId, branchId, amount, stockTypeId);
res.status(202).json(result);
} catch (error) {
res.status(500).json({ error: error.message});
console.log(error);
}
}
async getStockTypes(req, res) {
console.log('load stock');
try {
const result = await FalukantService.getStockTypes();
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
console.log(error);
}
}
async getStockOverview(req, res) {
try {
const result = await FalukantService.getStockOverview();
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getAllProductions(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const result = await FalukantService.getAllProductions(hashedUserId);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getDirectorProposals(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { branchId } = req.body;
const result = await FalukantService.getDirectorProposals(hashedUserId, branchId);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async convertProposalToDirector(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { proposalId } = req.body;
const result = await FalukantService.convertProposalToDirector(hashedUserId, proposalId);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
async getDirectorForBranch(req, res) {
try {
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 });
}
}
async setSetting(req, res) {
try {
const { userid: hashedUserId } = req.headers;
const { branchId, directorId, settingKey, value } = req.body;
const result = await FalukantService.setSetting(hashedUserId, branchId, directorId, settingKey, value);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
console.log(error);
}
}
}
export default FalukantController;

View File

@@ -44,8 +44,10 @@ import Branch from './falukant/data/branch.js';
import BranchType from './falukant/type/branch.js';
import Production from './falukant/data/production.js';
import Inventory from './falukant/data/inventory.js';
import BuyableStock from './falukant/data/buayble_stock.js';
import BuyableStock from './falukant/data/buyable_stock.js';
import MoneyFlow from './falukant/log/moneyflow.js';
import Director from './falukant/data/director.js';
import DirectorProposal from './falukant/data/director_proposal.js';
export default function setupAssociations() {
// UserParam related associations
@@ -251,4 +253,21 @@ export default function setupAssociations() {
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' });
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(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(FalukantCharacter, { foreignKey: 'directorCharacterId', as: 'character' });
FalukantCharacter.hasMany(DirectorProposal, { foreignKey: 'directorCharacterId', as: 'directorProposals' });
}

View File

@@ -18,7 +18,7 @@ Branch.init({
},
}, {
sequelize,
modelName: 'BranchType',
modelName: 'Branch',
tableName: 'branch',
schema: 'falukant_data',
timestamps: false,

View File

@@ -0,0 +1,48 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class Director extends Model { }
Director.init({
directorCharacterId: {
type: DataTypes.INTEGER,
allowNull: false,
},
employerUserId: {
type: DataTypes.INTEGER,
allowNull: false,
},
income: {
type: DataTypes.INTEGER,
allowNull: false,
},
satisfaction: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 100,
},
mayProduce: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
},
maySell: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
},
mayStartTransport: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
}
}, {
sequelize,
modelName: 'Director',
tableName: 'director',
schema: 'falukant_data',
timestamps: false,
underscored: true,
});
export default Director;

View File

@@ -0,0 +1,28 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class DirectorProposal extends Model { }
DirectorProposal.init({
directorCharacterId: {
type: DataTypes.INTEGER,
allowNull: false,
},
employerUserId: {
type: DataTypes.INTEGER,
allowNull: false,
},
proposedIncome: {
type: DataTypes.INTEGER,
allowNull: false,
},
}, {
sequelize,
modelName: 'DirectorProposal',
tableName: 'director_proposal',
schema: 'falukant_data',
timestamps: true,
underscored: true,
});
export default DirectorProposal;

View File

@@ -19,7 +19,7 @@ FalukantStock.init({
},
}, {
sequelize,
modelName: 'StockType',
modelName: 'StockData',
tableName: 'stock',
schema: 'falukant_data',
timestamps: false,

View File

@@ -0,0 +1,45 @@
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../../../utils/sequelize.js';
class MoneyFlow extends Model { }
MoneyFlow.init({
falukantUserId: {
type: DataTypes.INTEGER,
allowNull: false,
},
activity: {
type: DataTypes.STRING,
allowNull: false,
},
moneyBefore: {
type: DataTypes.DOUBLE,
allowNull: false,
},
moneyAfter: {
type: DataTypes.DOUBLE,
allowNull: true,
},
time: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
},
changeValue: {
type: DataTypes.DOUBLE,
allowNull: false,
},
changedBy: {
type: DataTypes.INTEGER,
allowNull: true,
},
}, {
sequelize,
modelName: 'MoneyFlow',
tableName: 'moneyflow',
schema: 'falukant_log',
timestamps: false,
underscored: true,
});
export default MoneyFlow;

View File

@@ -48,7 +48,10 @@ import BranchType from './falukant/type/branch.js';
import Branch from './falukant/data/branch.js';
import Production from './falukant/data/production.js';
import Inventory from './falukant/data/inventory.js';
import BuyableStock from './falukant/data/buayble_stock.js';
import BuyableStock from './falukant/data/buyable_stock.js';
import MoneyFlow from './falukant/log/moneyflow.js';
import Director from './falukant/data/director.js';
import DirectorProposal from './falukant/data/director_proposal.js';
const models = {
SettingsType,
@@ -102,6 +105,9 @@ const models = {
Production,
Inventory,
BuyableStock,
MoneyFlow,
Director,
DirectorProposal,
};
export default models;

View File

@@ -124,6 +124,62 @@ export async function createTriggers() {
EXECUTE FUNCTION falukant_data.create_knowledge_trigger();
`;
const updateMoney = `
CREATE OR REPLACE FUNCTION falukant_data.update_money(
p_falukant_user_id integer,
p_money_change numeric,
p_activity text,
p_changed_by integer DEFAULT NULL
)
RETURNS void
LANGUAGE plpgsql
AS $function$
DECLARE
v_money_before numeric(10,2);
v_money_after numeric(10,2);
v_moneyflow_id bigint;
BEGIN
SELECT money
INTO v_money_before
FROM falukant_data.falukant_user
WHERE id = p_falukant_user_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'FalukantUser mit ID % nicht gefunden', p_falukant_user_id;
END IF;
v_money_after := v_money_before + p_money_change;
INSERT INTO falukant_log.moneyflow (
falukant_user_id,
activity,
money_before,
money_after,
change_value,
changed_by,
time
)
VALUES (
p_falukant_user_id,
p_activity,
v_money_before,
NULL, -- Wird gleich aktualisiert
p_money_change,
p_changed_by,
NOW()
)
RETURNING id INTO v_moneyflow_id;
UPDATE falukant_data.falukant_user
SET money = v_money_after
WHERE id = p_falukant_user_id;
UPDATE falukant_log.moneyflow
SET money_after = (
SELECT money
FROM falukant_data.falukant_user
WHERE id = p_falukant_user_id
)
WHERE id = v_moneyflow_id;
END;
$function$;
`;
try {
await sequelize.query(createTriggerFunction);
await sequelize.query(createInsertTrigger);
@@ -136,6 +192,7 @@ export async function createTriggers() {
await sequelize.query(createCharacterCreationTrigger);
await sequelize.query(createKnowledgeTriggerMethod);
await sequelize.query(createKnowledgeTrigger);
await sequelize.query(updateMoney);
console.log('Triggers created successfully');
} catch (error) {

View File

@@ -11,11 +11,24 @@ router.get('/name/randomlastname', falukantController.randomLastName);
router.get('/info', falukantController.getInfo);
router.get('/branches/:branch', falukantController.getBranch);
router.get('/branches', falukantController.getBranches);
router.get('/productions', falukantController.getAllProductions);
router.post('/production', falukantController.createProduction);
router.get('/production/:branchId', falukantController.getProduction);
router.get('/stocktypes', falukantController.getStockTypes);
router.get('/stockoverview', falukantController.getStockOverview);
router.get('/stock/?:branchId', falukantController.getStock);
router.post('/stock', falukantController.createStock);
router.get('/products', falukantController.getProducts);
router.get('/inventory/?:branchId', falukantController.getInventory);
router.post('/sell/all', falukantController.sellAllProducts);
router.post('/sell', falukantController.sellProduct);
router.post('/moneyhistory', falukantController.moneyHistory);
router.get('/storage/:branchId', falukantController.getStorage);
router.post('/storage', falukantController.buyStorage);
router.delete('/storage', falukantController.sellStorage);
router.post('/director/proposal', falukantController.getDirectorProposals);
router.post('/director/convertproposal', falukantController.convertProposalToDirector);
router.post('/director/settings', falukantController.setSetting);
router.get('/director/:branchId', falukantController.getDirectorForBranch);
export default router;

View File

@@ -33,7 +33,7 @@ const getFriends = async (userId) => {
},
{
model: User,
as: 'friendReceiver',
as: 'friendReceiver',
attributes: ['hashedId', 'username'],
},
],
@@ -104,12 +104,14 @@ 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,
status: 'online',
});
}
console.log('set user session');
const sessionData = {
id: user.hashedId,
username: user.username,
@@ -118,6 +120,7 @@ export const loginUser = async ({ username, password }) => {
timestamp: Date.now()
};
await setUserSession(user.id, sessionData);
console.log('get user params');
const params = await UserParam.findAll({
where: {
userId: user.id
@@ -133,11 +136,12 @@ export const loginUser = async ({ username, password }) => {
const mappedParams = params.map(param => {
return { 'name': param.paramType.description, 'value': param.value };
});
console.log('return user');
return {
id: user.hashedId,
username: user.username,
active: user.active,
param: mappedParams,
param: mappedParams,
authCode
};
};

File diff suppressed because it is too large Load Diff

View File

@@ -214,12 +214,15 @@ const initializeFalukantLastnames = async () => {
}
async function initializeFalukantStockTypes() {
await FalukantStockType.bulkCreate([
{ labelTr: 'wood', cost: 15 },
{ labelTr: 'stone', cost: 25 },
{ labelTr: 'iron', cost: 100 },
{ labelTr: 'field', cost: 5 },
]);
try {
await FalukantStockType.bulkCreate([
{ labelTr: 'wood', cost: 15 },
{ labelTr: 'stone', cost: 25 },
{ labelTr: 'iron', cost: 100 },
{ labelTr: 'field', cost: 5 },
]);
} catch (error) {
}
}
async function initializeFalukantProducts() {
@@ -338,4 +341,4 @@ async function initializeFalukantBranchTypes() {
{ labelTr: 'store', baseCost: 2000 },
{ labelTr: 'fullstack', baseCost: 4500},
], { ignoreDuplicates: true });
}
}

View File

@@ -9,7 +9,7 @@ const EXPIRATION_TIME = 30 * 60 * 1000;
const redisClient = createClient({
url: `redis://${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`,
password: process.env.REDIS_PASSWORD,
legacyMode: false,
legacyMode: false,
});
redisClient.connect().catch(console.error);
@@ -23,7 +23,7 @@ const setUserSession = async (userId, sessionData) => {
} catch (error) {
console.error('Fehler beim Setzen der Benutzersitzung:', error);
}
};
};
const deleteUserSession = async (userId) => {
try {
@@ -41,8 +41,8 @@ const deleteUserSession = async (userId) => {
const convertToOriginalType = (value) => {
if (value === 'true') return true;
if (value === 'false') return false;
if (!isNaN(value) && value.trim() !== '') return Number(value);
return value;
if (!isNaN(value) && value.trim() !== '') return Number(value);
return value;
};
const getUserSession = async (userId) => {

View File

@@ -20,6 +20,7 @@ const createSchemas = async () => {
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');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_log');
};
const initializeDatabase = async () => {
@@ -34,4 +35,37 @@ const syncModels = async (models) => {
}
};
export { sequelize, initializeDatabase, syncModels };
async function updateFalukantUserMoney(falukantUserId, moneyChange, activity, changedBy = null) {
try {
const result = await sequelize.query(
`SELECT falukant_data.update_money(
:falukantUserId,
:moneyChange,
:activity,
:changedBy
)`,
{
replacements: {
falukantUserId,
moneyChange,
activity,
changedBy,
},
type: sequelize.QueryTypes.SELECT,
}
);
return {
success: true,
message: 'Money updated successfully',
result
};
} catch (error) {
console.error('Error updating money:', error);
return {
success: false,
message: error.message
};
}
}
export { sequelize, initializeDatabase, syncModels, updateFalukantUserMoney };

View File

@@ -4,12 +4,12 @@ import BaseService from '../services/BaseService.js';
const baseService = new BaseService();
let io;
const userSockets = {};
const userSockets = {};
export function setupWebSocket(server) {
io = new Server(server, {
cors: {
origin: '*',
origin: '*',
},
});
@@ -48,7 +48,9 @@ export async function notifyUser(recipientHashedUserId, event, data) {
if (recipientUser) {
const socketId = userSockets[recipientUser.hashedId];
if (socketId) {
io.to(socketId).emit(event, data);
setTimeout(() => {
io.to(socketId).emit(event, data);
}, 250);
}
} else {
console.log(`Benutzer mit gehashter ID ${recipientHashedUserId} nicht gefunden.`);
@@ -56,6 +58,7 @@ export async function notifyUser(recipientHashedUserId, event, data) {
} catch (err) {
console.error('Fehler beim Senden der Benachrichtigung:', err);
}
console.log('done sending socket');
}
export async function notifyAllUsers(event, data) {