Entfernt die myTischtennis-Integration aus dem Backend und Frontend. Löscht Controller, Routen und Service für myTischtennis. Aktualisiert die Datenmodelle, um die neue ExternalServiceAccount-Integration zu unterstützen. Ändert die API-Routen und Frontend-Komponenten, um die neuen Endpunkte zu verwenden.

This commit is contained in:
Torsten Schulz (local)
2025-10-01 21:01:09 +02:00
parent 1ef1711eea
commit 7be98ffeeb
18 changed files with 2008 additions and 441 deletions

View File

@@ -0,0 +1,132 @@
import { DataTypes } from 'sequelize';
import sequelize from '../database.js';
import { encryptData, decryptData } from '../utils/encrypt.js';
const ExternalServiceAccount = sequelize.define('ExternalServiceAccount', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'user',
key: 'id'
},
onDelete: 'CASCADE'
},
service: {
type: DataTypes.STRING(50),
allowNull: false,
defaultValue: 'mytischtennis'
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
encryptedPassword: {
type: DataTypes.TEXT,
allowNull: true,
field: 'encrypted_password'
},
savePassword: {
type: DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
field: 'save_password'
},
accessToken: {
type: DataTypes.TEXT,
allowNull: true,
field: 'access_token'
},
refreshToken: {
type: DataTypes.TEXT,
allowNull: true,
field: 'refresh_token'
},
expiresAt: {
type: DataTypes.BIGINT,
allowNull: true,
field: 'expires_at'
},
cookie: {
type: DataTypes.TEXT,
allowNull: true
},
userData: {
type: DataTypes.JSON,
allowNull: true,
field: 'user_data'
},
clubId: {
type: DataTypes.STRING,
allowNull: true,
field: 'club_id'
},
clubName: {
type: DataTypes.STRING,
allowNull: true,
field: 'club_name'
},
fedNickname: {
type: DataTypes.STRING,
allowNull: true,
field: 'fed_nickname'
},
lastLoginAttempt: {
type: DataTypes.DATE,
allowNull: true,
field: 'last_login_attempt'
},
lastLoginSuccess: {
type: DataTypes.DATE,
allowNull: true,
field: 'last_login_success'
}
}, {
underscored: true,
tableName: 'external_service_account',
timestamps: true,
indexes: [
{
unique: true,
fields: ['user_id', 'service']
}
],
hooks: {
beforeSave: async (instance) => {
// Wenn savePassword false ist, password auf null setzen
if (!instance.savePassword) {
instance.encryptedPassword = null;
}
}
}
});
// Virtuelle Felder für password handling
ExternalServiceAccount.prototype.setPassword = function(password) {
if (password && this.savePassword) {
this.encryptedPassword = encryptData(password);
} else {
this.encryptedPassword = null;
}
};
ExternalServiceAccount.prototype.getPassword = function() {
if (this.encryptedPassword) {
try {
return decryptData(this.encryptedPassword);
} catch (error) {
console.error('Error decrypting password:', error);
return null;
}
}
return null;
};
export default ExternalServiceAccount;

View File

@@ -2,7 +2,7 @@ import { DataTypes } from 'sequelize';
import sequelize from '../database.js';
import { encryptData, decryptData } from '../utils/encrypt.js';
const MyTischtennis = sequelize.define('MyTischtennis', {
const ExternalServiceAccount = sequelize.define('ExternalServiceAccount', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
@@ -12,13 +12,17 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
userId: {
type: DataTypes.INTEGER,
allowNull: false,
unique: true,
references: {
model: 'user',
key: 'id'
},
onDelete: 'CASCADE'
},
service: {
type: DataTypes.STRING(50),
allowNull: false,
defaultValue: 'mytischtennis'
},
email: {
type: DataTypes.STRING,
allowNull: false,
@@ -85,8 +89,14 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
}
}, {
underscored: true,
tableName: 'my_tischtennis',
tableName: 'external_service_account',
timestamps: true,
indexes: [
{
unique: true,
fields: ['user_id', 'service']
}
],
hooks: {
beforeSave: async (instance) => {
// Wenn savePassword false ist, password auf null setzen
@@ -98,7 +108,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
});
// Virtuelle Felder für password handling
MyTischtennis.prototype.setPassword = function(password) {
ExternalServiceAccount.prototype.setPassword = function(password) {
if (password && this.savePassword) {
this.encryptedPassword = encryptData(password);
} else {
@@ -106,17 +116,17 @@ MyTischtennis.prototype.setPassword = function(password) {
}
};
MyTischtennis.prototype.getPassword = function() {
ExternalServiceAccount.prototype.getPassword = function() {
if (this.encryptedPassword) {
try {
return decryptData(this.encryptedPassword);
} catch (error) {
console.error('Error decrypting myTischtennis password:', error);
console.error('Error decrypting password:', error);
return null;
}
}
return null;
};
export default MyTischtennis;
export default ExternalServiceAccount;

View File

@@ -33,7 +33,7 @@ import UserToken from './UserToken.js';
import OfficialTournament from './OfficialTournament.js';
import OfficialCompetition from './OfficialCompetition.js';
import OfficialCompetitionMember from './OfficialCompetitionMember.js';
import MyTischtennis from './MyTischtennis.js';
import ExternalServiceAccount from './ExternalServiceAccount.js';
// Official tournaments relations
OfficialTournament.hasMany(OfficialCompetition, { foreignKey: 'tournamentId', as: 'competitions' });
OfficialCompetition.belongsTo(OfficialTournament, { foreignKey: 'tournamentId', as: 'tournament' });
@@ -205,8 +205,8 @@ Member.hasMany(Accident, { foreignKey: 'memberId', as: 'accidents' });
Accident.belongsTo(DiaryDate, { foreignKey: 'diaryDateId', as: 'diaryDates' });
DiaryDate.hasMany(Accident, { foreignKey: 'diaryDateId', as: 'accidents' });
User.hasOne(MyTischtennis, { foreignKey: 'userId', as: 'myTischtennis' });
MyTischtennis.belongsTo(User, { foreignKey: 'userId', as: 'user' });
User.hasMany(ExternalServiceAccount, { foreignKey: 'userId', as: 'externalServiceAccounts' });
ExternalServiceAccount.belongsTo(User, { foreignKey: 'userId', as: 'user' });
export {
User,
@@ -243,5 +243,5 @@ export {
OfficialTournament,
OfficialCompetition,
OfficialCompetitionMember,
MyTischtennis,
ExternalServiceAccount,
};