Fügt eine neue Skriptfunktion zum Bereinigen von Benutzertoken hinzu und aktualisiert die Logik zum Synchronisieren des UserToken-Modells. Implementiert eine neue Controller-Methode zum Löschen von Datumsangaben für Clubs und passt die Routen entsprechend an. Ergänzt die Benutzeroberfläche in DiaryView.vue um die Möglichkeit, ein Datum zu löschen, und aktualisiert die Logik zur Überprüfung der Datumsaktualität.
This commit is contained in:
@@ -116,3 +116,15 @@ const deleteTagFromDiaryDate = async (req, res) => {
|
||||
|
||||
export { getDatesForClub, createDateForClub, updateTrainingTimes, addDiaryNote, deleteDiaryNote, addDiaryTag,
|
||||
addTagToDiaryDate, deleteTagFromDiaryDate };
|
||||
|
||||
export const deleteDateForClub = async (req, res) => {
|
||||
try {
|
||||
const { clubId, dateId } = req.params;
|
||||
const { authcode: userToken } = req.headers;
|
||||
const result = await diaryService.removeDateForClub(userToken, clubId, dateId);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
console.error('[deleteDateForClub] - Error:', error);
|
||||
res.status(error.statusCode || 500).json({ error: error.message || 'systemerror' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"postinstall": "cd ../frontend && npm install && npm run build",
|
||||
"dev": "nodemon server.js"
|
||||
"dev": "nodemon server.js",
|
||||
"cleanup:usertoken": "node ./scripts/cleanupUserTokenKeys.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
deleteDiaryNote,
|
||||
addDiaryTag,
|
||||
addTagToDiaryDate,
|
||||
deleteTagFromDiaryDate
|
||||
deleteTagFromDiaryDate,
|
||||
deleteDateForClub,
|
||||
} from '../controllers/diaryController.js';
|
||||
|
||||
const router = express.Router();
|
||||
@@ -21,5 +22,6 @@ router.delete('/:clubId/tag', authenticate, deleteTagFromDiaryDate);
|
||||
router.get('/:clubId', authenticate, getDatesForClub);
|
||||
router.post('/:clubId', authenticate, createDateForClub);
|
||||
router.put('/:clubId', authenticate, updateTrainingTimes);
|
||||
router.delete('/:clubId/:dateId', authenticate, deleteDateForClub);
|
||||
|
||||
export default router;
|
||||
|
||||
90
backend/scripts/cleanupUserTokenKeys.js
Normal file
90
backend/scripts/cleanupUserTokenKeys.js
Normal file
@@ -0,0 +1,90 @@
|
||||
import mysql from 'mysql2/promise';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
user: process.env.DB_USER || 'root',
|
||||
password: process.env.DB_PASSWORD || '',
|
||||
database: process.env.DB_NAME || 'trainingdiary',
|
||||
};
|
||||
|
||||
async function getIndexSummary(connection, table) {
|
||||
const [rows] = await connection.execute(`SHOW INDEX FROM \`${table}\``);
|
||||
const summary = rows.reduce((acc, r) => {
|
||||
const key = r.Key_name;
|
||||
acc[key] = acc[key] || { unique: r.Non_unique === 0, columns: [] };
|
||||
acc[key].columns.push(r.Column_name);
|
||||
return acc;
|
||||
}, {});
|
||||
return summary;
|
||||
}
|
||||
|
||||
async function cleanupUserTokenKeys() {
|
||||
let connection;
|
||||
const table = 'UserToken';
|
||||
|
||||
try {
|
||||
console.log('Connecting to DB:', dbConfig);
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
|
||||
console.log(`\nBefore cleanup (indexes on ${table}):`);
|
||||
let before = await getIndexSummary(connection, table);
|
||||
Object.entries(before).forEach(([name, info]) => {
|
||||
console.log(` - ${name} ${info.unique ? '(UNIQUE)' : ''} -> [${info.columns.join(', ')}]`);
|
||||
});
|
||||
|
||||
// Drop all non-PRIMARY indexes on UserToken
|
||||
const [indexes] = await connection.execute(`SHOW INDEX FROM \`${table}\``);
|
||||
const keyNames = Array.from(new Set(indexes.map(i => i.Key_name))).filter(k => k !== 'PRIMARY');
|
||||
|
||||
for (const keyName of keyNames) {
|
||||
try {
|
||||
await connection.execute(`DROP INDEX \`${keyName}\` ON \`${table}\``);
|
||||
console.log(`Dropped index: ${keyName}`);
|
||||
} catch (err) {
|
||||
console.warn(`Could not drop ${keyName}: ${err.code || err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-create minimal, deterministic indexes
|
||||
// Unique on token (column is 'token')
|
||||
try {
|
||||
await connection.execute(`CREATE UNIQUE INDEX \`uniq_UserToken_token\` ON \`${table}\` (\`token\`)`);
|
||||
console.log('Created UNIQUE index: uniq_UserToken_token (token)');
|
||||
} catch (err) {
|
||||
console.warn('Could not create uniq_UserToken_token:', err.code || err.message);
|
||||
}
|
||||
|
||||
// Helpful index on user_id if column exists
|
||||
try {
|
||||
const [cols] = await connection.execute(`SHOW COLUMNS FROM \`${table}\` LIKE 'user_id'`);
|
||||
if (cols && cols.length > 0) {
|
||||
await connection.execute(`CREATE INDEX \`idx_UserToken_user_id\` ON \`${table}\` (\`user_id\`)`);
|
||||
console.log('Created INDEX: idx_UserToken_user_id (user_id)');
|
||||
} else {
|
||||
console.log('Column user_id not found, skip creating idx_UserToken_user_id');
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Could not create idx_UserToken_user_id:', err.code || err.message);
|
||||
}
|
||||
|
||||
console.log(`\nAfter cleanup (indexes on ${table}):`);
|
||||
const after = await getIndexSummary(connection, table);
|
||||
Object.entries(after).forEach(([name, info]) => {
|
||||
console.log(` - ${name} ${info.unique ? '(UNIQUE)' : ''} -> [${info.columns.join(', ')}]`);
|
||||
});
|
||||
|
||||
console.log('\nDone.');
|
||||
} catch (err) {
|
||||
console.error('Cleanup failed:', err);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
if (connection) await connection.end();
|
||||
}
|
||||
}
|
||||
|
||||
cleanupUserTokenKeys();
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ app.get('*', (req, res) => {
|
||||
await TournamentMatch.sync({ alter: true });
|
||||
await TournamentResult.sync({ alter: true });
|
||||
await Accident.sync({ alter: true });
|
||||
await UserToken.sync({ alter: true });
|
||||
await UserToken.sync();
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on http://localhost:${port}`);
|
||||
|
||||
@@ -20,7 +20,7 @@ class DiaryDateActivityService {
|
||||
duration: data.duration
|
||||
});
|
||||
}
|
||||
restData.predefinedActivityId = predefinedActivity.id;
|
||||
restData.predefinedActivityId = predefinedActivity.id;
|
||||
const maxOrderId = await DiaryDateActivity.max('orderId', {
|
||||
where: { diaryDateId: data.diaryDateId }
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import DiaryDate from '../models/DiaryDates.js';
|
||||
import DiaryDateActivity from '../models/DiaryDateActivity.js';
|
||||
import Club from '../models/Club.js';
|
||||
import DiaryNote from '../models/DiaryNote.js';
|
||||
import { DiaryTag } from '../models/DiaryTag.js';
|
||||
@@ -151,6 +152,23 @@ class DiaryService {
|
||||
await DiaryDateTag.destroy({ where: { tagId } });
|
||||
}
|
||||
|
||||
async removeDateForClub(userToken, clubId, dateId) {
|
||||
console.log('[DiaryService::removeDateForClub] - Check user access');
|
||||
await checkAccess(userToken, clubId);
|
||||
console.log('[DiaryService::removeDateForClub] - Validate date');
|
||||
const diaryDate = await DiaryDate.findOne({ where: { id: dateId, clubId } });
|
||||
if (!diaryDate) {
|
||||
throw new HttpError('Diary entry not found', 404);
|
||||
}
|
||||
console.log('[DiaryService::removeDateForClub] - Check for activities');
|
||||
const activityCount = await DiaryDateActivity.count({ where: { diaryDateId: dateId } });
|
||||
if (activityCount > 0) {
|
||||
throw new HttpError('Cannot delete date with activities', 409);
|
||||
}
|
||||
console.log('[DiaryService::removeDateForClub] - Delete diary date');
|
||||
await diaryDate.destroy();
|
||||
return { ok: true };
|
||||
}
|
||||
}
|
||||
|
||||
export default new DiaryService();
|
||||
|
||||
Reference in New Issue
Block a user