Implement age validation for political applications in FalukantService: Added MIN_AGE_POLITICS_DAYS constant and logic to check user age before allowing applications. Updated PoliticsView to reflect age eligibility and display appropriate hints. Enhanced error handling for age-related restrictions.
This commit is contained in:
@@ -4408,9 +4408,15 @@ class FalukantService extends BaseService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Mindestalter für Bewerbung auf politische Ämter (in Tagen; 16 Tage Realzeit = 16 Spieljahre) */
|
||||||
|
static MIN_AGE_POLITICS_DAYS = 16;
|
||||||
|
|
||||||
async getOpenPolitics(hashedUserId) {
|
async getOpenPolitics(hashedUserId) {
|
||||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||||
const characterId = user.character.id;
|
const character = user.character;
|
||||||
|
const characterId = character.id;
|
||||||
|
const ageDays = character.birthdate ? calcAge(character.birthdate) : 0;
|
||||||
|
const canApplyByAge = ageDays >= FalukantService.MIN_AGE_POLITICS_DAYS;
|
||||||
const rows = await sequelize.query(
|
const rows = await sequelize.query(
|
||||||
FalukantService.RECURSIVE_REGION_SEARCH,
|
FalukantService.RECURSIVE_REGION_SEARCH,
|
||||||
{
|
{
|
||||||
@@ -4481,7 +4487,8 @@ class FalukantService extends BaseService {
|
|||||||
return {
|
return {
|
||||||
...e,
|
...e,
|
||||||
history: matchingHistory,
|
history: matchingHistory,
|
||||||
alreadyApplied
|
alreadyApplied,
|
||||||
|
canApplyByAge
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter(election => !election.alreadyApplied); // Nur Positionen ohne bestehende Bewerbung
|
.filter(election => !election.alreadyApplied); // Nur Positionen ohne bestehende Bewerbung
|
||||||
@@ -4499,24 +4506,30 @@ class FalukantService extends BaseService {
|
|||||||
throw new Error('Kein Charakter zum User gefunden');
|
throw new Error('Kein Charakter zum User gefunden');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Noncivil‐Titel aussperren
|
// 2) Mindestalter 16 (Spieljahre = 16 Tage Realzeit)
|
||||||
|
const ageDays = character.birthdate ? calcAge(character.birthdate) : 0;
|
||||||
|
if (ageDays < FalukantService.MIN_AGE_POLITICS_DAYS) {
|
||||||
|
throw new Error('too_young');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Noncivil‐Titel aussperren
|
||||||
if (character.nobleTitle.labelTr === 'noncivil') {
|
if (character.nobleTitle.labelTr === 'noncivil') {
|
||||||
return { applied: [], skipped: electionIds };
|
return { applied: [], skipped: electionIds };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Ermittle die offenen Wahlen, auf die er zugreifen darf
|
// 4) Ermittle die offenen Wahlen, auf die er zugreifen darf
|
||||||
// Verwende getOpenPolitics statt getElections, da getOpenPolitics die gleichen Wahlen
|
// Verwende getOpenPolitics statt getElections, da getOpenPolitics die gleichen Wahlen
|
||||||
// zurückgibt, die im Frontend angezeigt werden
|
// zurückgibt, die im Frontend angezeigt werden
|
||||||
const openPolitics = await this.getOpenPolitics(hashedUserId);
|
const openPolitics = await this.getOpenPolitics(hashedUserId);
|
||||||
const allowedIds = new Set(openPolitics.map(e => e.id));
|
const allowedIds = new Set(openPolitics.map(e => e.id));
|
||||||
|
|
||||||
// 4) Filter alle electionIds auf gültige/erlaubte
|
// 5) Filter alle electionIds auf gültige/erlaubte
|
||||||
const toTry = electionIds.filter(id => allowedIds.has(id));
|
const toTry = electionIds.filter(id => allowedIds.has(id));
|
||||||
if (toTry.length === 0) {
|
if (toTry.length === 0) {
|
||||||
return { applied: [], skipped: electionIds };
|
return { applied: [], skipped: electionIds };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5) Prüfe, auf welche dieser Wahlen der Character bereits als Candidate eingetragen ist
|
// 6) Prüfe, auf welche dieser Wahlen der Character bereits als Candidate eingetragen ist
|
||||||
const existing = await Candidate.findAll({
|
const existing = await Candidate.findAll({
|
||||||
where: {
|
where: {
|
||||||
electionId: { [Op.in]: toTry },
|
electionId: { [Op.in]: toTry },
|
||||||
@@ -4526,13 +4539,11 @@ class FalukantService extends BaseService {
|
|||||||
});
|
});
|
||||||
const alreadyIds = new Set(existing.map(c => c.electionId));
|
const alreadyIds = new Set(existing.map(c => c.electionId));
|
||||||
|
|
||||||
// 6) Erstelle Liste der Wahlen, für die er sich noch nicht beworben hat
|
// 7) Erstelle Liste der Wahlen, für die er sich noch nicht beworben hat
|
||||||
const newApplications = toTry.filter(id => !alreadyIds.has(id));
|
const newApplications = toTry.filter(id => !alreadyIds.has(id));
|
||||||
const skipped = electionIds.filter(id => !newApplications.includes(id));
|
const skipped = electionIds.filter(id => !newApplications.includes(id));
|
||||||
|
|
||||||
console.log(newApplications, skipped);
|
// 8) Bulk-Insert aller neuen Bewerbungen
|
||||||
|
|
||||||
// 7) Bulk-Insert aller neuen Bewerbungen
|
|
||||||
if (newApplications.length > 0) {
|
if (newApplications.length > 0) {
|
||||||
const toInsert = newApplications.map(eid => ({
|
const toInsert = newApplications.map(eid => ({
|
||||||
electionId: eid,
|
electionId: eid,
|
||||||
|
|||||||
@@ -1030,8 +1030,10 @@
|
|||||||
"date": "Datum",
|
"date": "Datum",
|
||||||
"candidacy": "Kandidatur",
|
"candidacy": "Kandidatur",
|
||||||
"none": "Keine offenen Positionen.",
|
"none": "Keine offenen Positionen.",
|
||||||
"apply": "Für ausgewählte Positionen kandidieren"
|
"apply": "Für ausgewählte Positionen kandidieren",
|
||||||
|
"minAgeHint": "Kandidatur erst ab 16 Jahren möglich."
|
||||||
},
|
},
|
||||||
|
"too_young": "Dein Charakter ist noch zu jung. Eine Bewerbung ist erst ab 16 Jahren möglich.",
|
||||||
"upcoming": {
|
"upcoming": {
|
||||||
"office": "Amt",
|
"office": "Amt",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
|
|||||||
@@ -364,8 +364,10 @@
|
|||||||
"date": "Date",
|
"date": "Date",
|
||||||
"candidacy": "Candidacy",
|
"candidacy": "Candidacy",
|
||||||
"none": "No open positions.",
|
"none": "No open positions.",
|
||||||
"apply": "Apply for selected positions"
|
"apply": "Apply for selected positions",
|
||||||
|
"minAgeHint": "Candidacy is only possible from age 16."
|
||||||
},
|
},
|
||||||
|
"too_young": "Your character is too young. Applications are only possible from age 16.",
|
||||||
"upcoming": {
|
"upcoming": {
|
||||||
"office": "Office",
|
"office": "Office",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
|
|||||||
@@ -74,13 +74,13 @@
|
|||||||
<td>{{ e.region.name }}</td>
|
<td>{{ e.region.name }}</td>
|
||||||
<td>{{ formatDate(e.date) }}</td>
|
<td>{{ formatDate(e.date) }}</td>
|
||||||
<!-- Checkbox ganz am Ende -->
|
<!-- Checkbox ganz am Ende -->
|
||||||
<td>
|
<td :title="e.canApplyByAge === false ? $t('falukant.politics.open.minAgeHint') : null">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:id="`apply-${e.id}`"
|
:id="`apply-${e.id}`"
|
||||||
v-model="selectedApplications"
|
v-model="selectedApplications"
|
||||||
:value="e.id"
|
:value="e.id"
|
||||||
:disabled="e.alreadyApplied"
|
:disabled="e.alreadyApplied || e.canApplyByAge === false"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -389,6 +389,10 @@ export default {
|
|||||||
.map(e => e.id);
|
.map(e => e.id);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error submitting applications', err);
|
console.error('Error submitting applications', err);
|
||||||
|
const msg = err?.response?.data?.error === 'too_young'
|
||||||
|
? this.$t('falukant.politics.too_young')
|
||||||
|
: (err?.response?.data?.error || err?.message || this.$t('falukant.politics.applyError'));
|
||||||
|
this.$root.$refs?.messageDialog?.open?.(msg, this.$t('falukant.politics.title'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user