feat: improve user token handling and add club selection clearing button in settings
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 43s

This commit is contained in:
Torsten Schulz (local)
2026-05-15 16:52:26 +02:00
parent d955577d9a
commit 40bd5e0745
3 changed files with 119 additions and 162 deletions

View File

@@ -177,178 +177,88 @@ class DiaryDateActivityService {
async getActivities(userToken, clubId, diaryDateId) {
await checkAccess(userToken, clubId);
// Avoid Sequelize eager-loading includes here to prevent EagerLoadingErrors
// if associations are not initialized in certain environments. Instead,
// load the core DiaryDateActivity rows and fetch related models separately.
const activities = await DiaryDateActivity.findAll({
where: { diaryDateId },
order: [['orderId', 'ASC']],
include: [
{
model: PredefinedActivity,
as: 'predefinedActivity',
include: [
{
model: PredefinedActivityImage,
as: 'images'
}
]
},
{
model: Group,
as: 'planGroup'
},
{
model: GroupActivity,
as: 'groupActivities',
separate: true,
order: [['orderId', 'ASC'], ['id', 'ASC']],
include: [
{
model: Group,
as: 'groupsGroupActivity'
},
{
model: PredefinedActivity,
as: 'groupPredefinedActivity',
include: [
{
model: PredefinedActivityImage,
as: 'images'
}
]
},
],
}
]
});
// Füge imageUrl zu jeder PredefinedActivity hinzu
const activitiesWithImages = await Promise.all(activities.map(async activity => {
// Konvertiere zu JSON und zurück, um alle Eigenschaften zu serialisieren
const activitiesWithImages = [];
for (const activity of activities) {
const activityData = activity.toJSON();
if (activityData.predefinedActivity) {
// Hole alle Images aus der Datenbank
const allImages = await PredefinedActivityImage.findAll({
where: { predefinedActivityId: activityData.predefinedActivity.id },
order: [['createdAt', 'ASC']]
});
// Konvertiere Images zu JSON und parse drawingData falls vorhanden
const imagesWithParsedData = allImages.map(img => {
const imgData = img.toJSON();
if (imgData.drawingData) {
try {
imgData.drawingData = JSON.parse(imgData.drawingData);
} catch (error) {
console.error(`Image ${imgData.id}: Error parsing drawingData:`, error);
// Load predefinedActivity if present
if (activityData.predefinedActivityId) {
const predefined = await PredefinedActivity.findByPk(activityData.predefinedActivityId);
activityData.predefinedActivity = predefined ? predefined.toJSON() : null;
if (activityData.predefinedActivity) {
const allImages = await PredefinedActivityImage.findAll({
where: { predefinedActivityId: activityData.predefinedActivity.id },
order: [['createdAt', 'ASC']]
});
const imagesWithParsedData = allImages.map(img => {
const imgData = img.toJSON();
if (imgData.drawingData) {
try { imgData.drawingData = JSON.parse(imgData.drawingData); } catch (err) { console.error(err); }
}
return imgData;
});
activityData.predefinedActivity.images = imagesWithParsedData;
const firstImage = allImages.length > 0 ? allImages[0] : null;
if (activityData.predefinedActivity.drawingData) {
try { if (typeof activityData.predefinedActivity.drawingData === 'string') activityData.predefinedActivity.drawingData = JSON.parse(activityData.predefinedActivity.drawingData); } catch (err) { console.error(err); }
} else if (firstImage && firstImage.drawingData) {
try { activityData.predefinedActivity.drawingData = JSON.parse(firstImage.drawingData); } catch (err) { console.error(err); }
}
return imgData;
});
// Setze images Array
activityData.predefinedActivity.images = imagesWithParsedData;
const firstImage = allImages.length > 0 ? allImages[0] : null;
// Füge Zeichnungsdaten hinzu, falls vorhanden
// Priorität: 1. drawingData direkt auf PredefinedActivity, 2. drawingData aus firstImage
if (activityData.predefinedActivity.drawingData) {
// drawingData ist bereits vorhanden (aus dem Model)
try {
if (typeof activityData.predefinedActivity.drawingData === 'string') {
activityData.predefinedActivity.drawingData = JSON.parse(activityData.predefinedActivity.drawingData);
}
} catch (error) {
console.error(`Activity ${activityData.predefinedActivity.id}: Error parsing drawingData:`, error);
if (firstImage) {
activityData.predefinedActivity.imageUrl = `/api/predefined-activities/${activityData.predefinedActivity.id}/image/${firstImage.id}`;
activityData.predefinedActivity.imageLink = `/api/predefined-activities/${activityData.predefinedActivity.id}/image/${firstImage.id}`;
} else {
activityData.predefinedActivity.imageUrl = `/api/predefined-activities/${activityData.predefinedActivity.id}/image`;
activityData.predefinedActivity.imageLink = `/api/predefined-activities/${activityData.predefinedActivity.id}/image`;
}
} else if (firstImage && firstImage.drawingData) {
try {
activityData.predefinedActivity.drawingData = JSON.parse(firstImage.drawingData);
} catch (error) {
console.error(`Activity ${activityData.predefinedActivity.id}: Error parsing drawingData from image:`, error);
}
}
if (firstImage) {
// Füge sowohl imageUrl als auch imageLink mit Image-ID hinzu
activityData.predefinedActivity.imageUrl = `/api/predefined-activities/${activityData.predefinedActivity.id}/image/${firstImage.id}`;
activityData.predefinedActivity.imageLink = `/api/predefined-activities/${activityData.predefinedActivity.id}/image/${firstImage.id}`;
} else {
// Fallback: Verwende den Basis-Pfad ohne Image-ID
activityData.predefinedActivity.imageUrl = `/api/predefined-activities/${activityData.predefinedActivity.id}/image`;
activityData.predefinedActivity.imageLink = `/api/predefined-activities/${activityData.predefinedActivity.id}/image`;
}
}
// Auch für GroupActivities
if (activityData.groupActivities && activityData.groupActivities.length > 0) {
const seenGroupActivityIds = new Set();
activityData.groupActivities = activityData.groupActivities.filter(groupActivity => {
if (!groupActivity || groupActivity.id === undefined || groupActivity.id === null) {
return false;
}
if (seenGroupActivityIds.has(groupActivity.id)) {
return false;
}
seenGroupActivityIds.add(groupActivity.id);
return true;
});
for (const groupActivity of activityData.groupActivities) {
if (groupActivity.groupPredefinedActivity) {
// Hole alle Images aus der Datenbank
const allImages = await PredefinedActivityImage.findAll({
where: { predefinedActivityId: groupActivity.groupPredefinedActivity.id },
order: [['createdAt', 'ASC']]
});
// Konvertiere Images zu JSON und parse drawingData falls vorhanden
const imagesWithParsedData = allImages.map(img => {
const imgData = img.toJSON();
if (imgData.drawingData) {
try {
imgData.drawingData = JSON.parse(imgData.drawingData);
} catch (error) {
console.error(`Image ${imgData.id}: Error parsing drawingData:`, error);
}
}
return imgData;
});
// Setze images Array
groupActivity.groupPredefinedActivity.images = imagesWithParsedData;
const firstImage = allImages.length > 0 ? allImages[0] : null;
// Füge Zeichnungsdaten hinzu, falls vorhanden
// Priorität: 1. drawingData direkt auf PredefinedActivity, 2. drawingData aus firstImage
if (groupActivity.groupPredefinedActivity.drawingData) {
try {
if (typeof groupActivity.groupPredefinedActivity.drawingData === 'string') {
groupActivity.groupPredefinedActivity.drawingData = JSON.parse(groupActivity.groupPredefinedActivity.drawingData);
}
} catch (error) {
console.error(`GroupActivity ${groupActivity.groupPredefinedActivity.id}: Error parsing drawingData:`, error);
}
} else if (firstImage && firstImage.drawingData) {
try {
groupActivity.groupPredefinedActivity.drawingData = JSON.parse(firstImage.drawingData);
} catch (error) {
console.error(`GroupActivity ${groupActivity.groupPredefinedActivity.id}: Error parsing drawingData from image:`, error);
}
}
if (firstImage) {
groupActivity.groupPredefinedActivity.imageUrl = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image/${firstImage.id}`;
groupActivity.groupPredefinedActivity.imageLink = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image/${firstImage.id}`;
// Load groupActivities separately
const groupActivities = await GroupActivity.findAll({
where: { diaryDateActivity: activityData.id },
order: [['orderId', 'ASC'], ['id', 'ASC']]
});
const groupActivitiesData = [];
for (const ga of groupActivities) {
const gad = ga.toJSON();
if (gad.groupId) {
const g = await Group.findByPk(gad.groupId);
gad.groupsGroupActivity = g ? g.toJSON() : null;
}
if (gad.customActivity) {
const gp = await PredefinedActivity.findByPk(gad.customActivity);
if (gp) {
const gpJson = gp.toJSON();
const gpImages = await PredefinedActivityImage.findAll({ where: { predefinedActivityId: gpJson.id }, order: [['createdAt','ASC']] });
gpJson.images = gpImages.map(i => { const ii = i.toJSON(); try { if (ii.drawingData) ii.drawingData = JSON.parse(ii.drawingData); } catch (e){}; return ii; });
const firstImg = gpImages[0];
if (firstImg) {
gpJson.imageUrl = `/api/predefined-activities/${gpJson.id}/image/${firstImg.id}`;
gpJson.imageLink = `/api/predefined-activities/${gpJson.id}/image/${firstImg.id}`;
} else {
groupActivity.groupPredefinedActivity.imageUrl = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image`;
groupActivity.groupPredefinedActivity.imageLink = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image`;
gpJson.imageUrl = `/api/predefined-activities/${gpJson.id}/image`;
gpJson.imageLink = `/api/predefined-activities/${gpJson.id}/image`;
}
gad.groupPredefinedActivity = gpJson;
}
}
groupActivitiesData.push(gad);
}
return activityData;
}));
activityData.groupActivities = groupActivitiesData;
activitiesWithImages.push(activityData);
}
return activitiesWithImages;
}