feat(political-benefits): implement political powers and benefits system
All checks were successful
Deploy to production / deploy (push) Successful in 3m3s
All checks were successful
Deploy to production / deploy (push) Successful in 3m3s
- Added new political powers and benefits functionalities, including reputation ticks, tax jurisdiction management, and appointment capabilities. - Introduced a new job for periodic reputation updates and created necessary database tables for tracking political benefits. - Enhanced the FalukantController and services to support new endpoints for managing political powers and appointments. - Updated localization files to reflect new features and improve user experience across multiple languages. - Modified the UI to display new political powers and benefits, ensuring accurate representation in the PoliticsView.
This commit is contained in:
94
backend/jobs/politicalBenefitsTick.js
Normal file
94
backend/jobs/politicalBenefitsTick.js
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Periodischer Job: reputation_periodic für politische Amtsinhaber.
|
||||
* Aufruf: systemd-Timer oder FALUKANT_POLITICAL_REPUTATION_JOB=1 (siehe server.js).
|
||||
*/
|
||||
import PoliticalOffice from '../models/falukant/data/political_office.js';
|
||||
import PoliticalOfficeType from '../models/falukant/type/political_office_type.js';
|
||||
import PoliticalOfficeBenefit from '../models/falukant/predefine/political_office_benefit.js';
|
||||
import PoliticalOfficeBenefitType from '../models/falukant/type/political_office_benefit_type.js';
|
||||
import PoliticalBenefitLastTick from '../models/falukant/data/political_benefit_last_tick.js';
|
||||
import FalukantCharacter from '../models/falukant/data/character.js';
|
||||
import FalukantUser from '../models/falukant/data/user.js';
|
||||
import User from '../models/community/user.js';
|
||||
import { sequelize } from '../utils/sequelize.js';
|
||||
import { notifyUser } from '../utils/socket.js';
|
||||
|
||||
export async function runPoliticalReputationTicks() {
|
||||
const offices = await PoliticalOffice.findAll({
|
||||
include: [{ model: PoliticalOfficeType, as: 'type', attributes: ['id', 'name'] }]
|
||||
});
|
||||
const toNotify = new Set();
|
||||
let ticks = 0;
|
||||
|
||||
for (const po of offices) {
|
||||
const characterId = po.characterId;
|
||||
const benefitRows = await PoliticalOfficeBenefit.findAll({
|
||||
where: { officeTypeId: po.officeTypeId },
|
||||
include: [
|
||||
{
|
||||
model: PoliticalOfficeBenefitType,
|
||||
as: 'benefitDefinition',
|
||||
attributes: ['tr'],
|
||||
required: true,
|
||||
where: { tr: 'reputation_periodic' }
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
for (const br of benefitRows) {
|
||||
const v = br.value && typeof br.value === 'object' ? br.value : {};
|
||||
const intervalDays = Math.max(1, Number(v.intervalDays ?? v.everyDays ?? 7));
|
||||
const gain = Math.max(1, Number(v.gain ?? 1));
|
||||
|
||||
const [tickRow, created] = await PoliticalBenefitLastTick.findOrCreate({
|
||||
where: {
|
||||
characterId,
|
||||
politicalOfficeBenefitId: br.id
|
||||
},
|
||||
defaults: {
|
||||
characterId,
|
||||
politicalOfficeBenefitId: br.id,
|
||||
lastTickAt: new Date(po.createdAt),
|
||||
ticksCount: 0
|
||||
}
|
||||
});
|
||||
|
||||
const baseMs = new Date(tickRow.lastTickAt).getTime();
|
||||
const daysSince = Math.floor((Date.now() - baseMs) / 86400000);
|
||||
if (daysSince < intervalDays) continue;
|
||||
|
||||
await sequelize.transaction(async (t) => {
|
||||
const ch = await FalukantCharacter.findByPk(characterId, { transaction: t });
|
||||
if (!ch) return;
|
||||
const nextRep = Math.min(100, (ch.reputation ?? 0) + gain);
|
||||
await ch.update({ reputation: nextRep }, { transaction: t });
|
||||
await PoliticalBenefitLastTick.update(
|
||||
{
|
||||
lastTickAt: new Date(),
|
||||
ticksCount: (tickRow.ticksCount || 0) + 1
|
||||
},
|
||||
{ where: { id: tickRow.id }, transaction: t }
|
||||
);
|
||||
});
|
||||
|
||||
ticks += 1;
|
||||
toNotify.add(characterId);
|
||||
console.info(
|
||||
`[PoliticalBenefits] reputation_tick characterId=${characterId} benefitId=${br.id} gain=${gain}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const characterId of toNotify) {
|
||||
const ch = await FalukantCharacter.findByPk(characterId, { attributes: ['userId'] });
|
||||
if (!ch?.userId) continue;
|
||||
const fu = await FalukantUser.findOne({
|
||||
where: { id: ch.userId },
|
||||
include: [{ model: User, as: 'user', attributes: ['hashedId'] }]
|
||||
});
|
||||
const hid = fu?.user?.hashedId;
|
||||
if (hid) notifyUser(hid, 'falukantUpdateStatus', {});
|
||||
}
|
||||
|
||||
return { processedOffices: offices.length, ticksApplied: ticks };
|
||||
}
|
||||
Reference in New Issue
Block a user