From 4ac71d967fcccbba77f0294ac614bc696a1ec8ed Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 1 Oct 2025 12:09:55 +0200 Subject: [PATCH] =?UTF-8?q?F=C3=BCgt=20Unterst=C3=BCtzung=20f=C3=BCr=20myT?= =?UTF-8?q?ischtennis-Integration=20hinzu.=20Aktualisiert=20die=20Mitglied?= =?UTF-8?q?er-Controller=20und=20-Routen,=20um=20die=20Aktualisierung=20vo?= =?UTF-8?q?n=20TTR/QTTR-Werten=20zu=20erm=C3=B6glichen.=20Erg=C3=A4nzt=20d?= =?UTF-8?q?ie=20Benutzeroberfl=C3=A4che=20in=20MembersView.vue=20zur=20Akt?= =?UTF-8?q?ualisierung=20der=20Bewertungen=20und=20f=C3=BCgt=20neue=20Rout?= =?UTF-8?q?en=20f=C3=BCr=20die=20myTischtennis-Daten=20hinzu.=20Aktualisie?= =?UTF-8?q?rt=20die=20Datenmodelle,=20um=20die=20neuen=20Felder=20f=C3=BCr?= =?UTF-8?q?=20TTR=20und=20QTTR=20zu=20integrieren.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/clients/myTischtennisClient.js | 284 ++++++++++++ backend/controllers/memberController.js | 19 +- .../controllers/myTischtennisController.js | 133 ++++++ backend/models/Member.js | 10 + backend/models/MyTischtennis.js | 122 +++++ backend/models/index.js | 5 + backend/node_modules/.package-lock.json | 236 ++++++++-- .../es-define-property/CHANGELOG.md | 14 + .../node_modules/es-define-property/index.js | 4 +- .../es-define-property/package.json | 24 +- .../es-define-property/test/index.js | 1 + .../es-define-property/tsconfig.json | 44 +- backend/node_modules/get-intrinsic/.eslintrc | 4 + .../node_modules/get-intrinsic/CHANGELOG.md | 43 ++ backend/node_modules/get-intrinsic/index.js | 61 ++- .../node_modules/get-intrinsic/package.json | 44 +- .../get-intrinsic/test/GetIntrinsic.js | 4 +- backend/node_modules/gopd/CHANGELOG.md | 20 + backend/node_modules/gopd/index.js | 5 +- backend/node_modules/gopd/package.json | 26 +- backend/node_modules/gopd/test/index.js | 3 +- backend/node_modules/has-proto/.eslintrc | 5 - .../has-proto/.github/FUNDING.yml | 12 - backend/node_modules/has-proto/CHANGELOG.md | 38 -- backend/node_modules/has-proto/LICENSE | 21 - backend/node_modules/has-proto/README.md | 38 -- backend/node_modules/has-proto/index.d.ts | 3 - backend/node_modules/has-proto/index.js | 15 - backend/node_modules/has-proto/package.json | 78 ---- backend/node_modules/has-proto/test/index.js | 19 - backend/node_modules/has-proto/tsconfig.json | 49 -- backend/node_modules/has-symbols/CHANGELOG.md | 16 + backend/node_modules/has-symbols/index.js | 1 + backend/node_modules/has-symbols/package.json | 28 +- backend/node_modules/has-symbols/shams.js | 7 +- .../has-symbols/test/shams/core-js.js | 1 + .../test/shams/get-own-property-symbols.js | 1 + .../node_modules/has-symbols/test/tests.js | 6 +- backend/package-lock.json | 238 ++++++++-- backend/package.json | 1 + backend/routes/memberRoutes.js | 3 +- backend/routes/myTischtennisRoutes.js | 29 ++ backend/server.js | 12 +- backend/services/memberService.js | 189 +++++++- backend/services/myTischtennisService.js | 256 +++++++++++ backend/services/tournamentService.js | 2 +- frontend/src/App.vue | 10 + .../src/components/MyTischtennisDialog.vue | 293 ++++++++++++ frontend/src/router.js | 2 + frontend/src/views/MembersView.vue | 100 ++++- frontend/src/views/MyTischtennisAccount.vue | 423 ++++++++++++++++++ 51 files changed, 2536 insertions(+), 466 deletions(-) create mode 100644 backend/clients/myTischtennisClient.js create mode 100644 backend/controllers/myTischtennisController.js create mode 100644 backend/models/MyTischtennis.js delete mode 100644 backend/node_modules/has-proto/.eslintrc delete mode 100644 backend/node_modules/has-proto/.github/FUNDING.yml delete mode 100644 backend/node_modules/has-proto/CHANGELOG.md delete mode 100644 backend/node_modules/has-proto/LICENSE delete mode 100644 backend/node_modules/has-proto/README.md delete mode 100644 backend/node_modules/has-proto/index.d.ts delete mode 100644 backend/node_modules/has-proto/index.js delete mode 100644 backend/node_modules/has-proto/package.json delete mode 100644 backend/node_modules/has-proto/test/index.js delete mode 100644 backend/node_modules/has-proto/tsconfig.json create mode 100644 backend/routes/myTischtennisRoutes.js create mode 100644 backend/services/myTischtennisService.js create mode 100644 frontend/src/components/MyTischtennisDialog.vue create mode 100644 frontend/src/views/MyTischtennisAccount.vue diff --git a/backend/clients/myTischtennisClient.js b/backend/clients/myTischtennisClient.js new file mode 100644 index 0000000..f286bf5 --- /dev/null +++ b/backend/clients/myTischtennisClient.js @@ -0,0 +1,284 @@ +import axios from 'axios'; + +const BASE_URL = 'https://www.mytischtennis.de'; + +class MyTischtennisClient { + constructor() { + this.baseURL = BASE_URL; + this.client = axios.create({ + baseURL: this.baseURL, + timeout: 10000, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': '*/*' + }, + maxRedirects: 0, // Don't follow redirects automatically + validateStatus: (status) => status >= 200 && status < 400 // Accept 3xx as success + }); + } + + /** + * Login to myTischtennis API + * @param {string} email - myTischtennis email (not username!) + * @param {string} password - myTischtennis password + * @returns {Promise} Login response with token and session data + */ + async login(email, password) { + try { + // Create form data + const formData = new URLSearchParams(); + formData.append('email', email); + formData.append('password', password); + formData.append('intent', 'login'); + + const response = await this.client.post( + '/login?next=%2F&_data=routes%2F_auth%2B%2Flogin', + formData.toString() + ); + + // Extract the cookie from response headers + const setCookie = response.headers['set-cookie']; + if (!setCookie || !Array.isArray(setCookie)) { + return { + success: false, + error: 'Keine Session-Cookie erhalten' + }; + } + + // Find the sb-10-auth-token cookie + const authCookie = setCookie.find(cookie => cookie.startsWith('sb-10-auth-token=')); + if (!authCookie) { + return { + success: false, + error: 'Kein Auth-Token in Response gefunden' + }; + } + + // Extract and decode the token + const tokenMatch = authCookie.match(/sb-10-auth-token=base64-([^;]+)/); + if (!tokenMatch) { + return { + success: false, + error: 'Token-Format ungültig' + }; + } + + const base64Token = tokenMatch[1]; + let tokenData; + try { + const decodedToken = Buffer.from(base64Token, 'base64').toString('utf-8'); + tokenData = JSON.parse(decodedToken); + } catch (decodeError) { + console.error('Error decoding token:', decodeError); + return { + success: false, + error: 'Token konnte nicht dekodiert werden' + }; + } + + return { + success: true, + accessToken: tokenData.access_token, + refreshToken: tokenData.refresh_token, + expiresAt: tokenData.expires_at, + expiresIn: tokenData.expires_in, + user: tokenData.user, + cookie: authCookie.split(';')[0] // Just the cookie value without attributes + }; + } catch (error) { + console.error('MyTischtennis login error:', error.message); + return { + success: false, + error: error.response?.data?.message || 'Login fehlgeschlagen', + status: error.response?.status || 500 + }; + } + } + + /** + * Verify login credentials + * @param {string} email - myTischtennis email + * @param {string} password - myTischtennis password + * @returns {Promise} True if credentials are valid + */ + async verifyCredentials(email, password) { + const result = await this.login(email, password); + return result.success; + } + + /** + * Make an authenticated request + * @param {string} endpoint - API endpoint + * @param {string} cookie - Authentication cookie (sb-10-auth-token) + * @param {Object} options - Additional axios options + * @returns {Promise} API response + */ + async authenticatedRequest(endpoint, cookie, options = {}) { + try { + const response = await this.client.request({ + url: endpoint, + ...options, + headers: { + ...options.headers, + 'Cookie': cookie, + 'Accept': '*/*', + 'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7', + 'Referer': 'https://www.mytischtennis.de/', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin' + } + }); + return { + success: true, + data: response.data + }; + } catch (error) { + console.error('MyTischtennis API error:', error.message); + return { + success: false, + error: error.response?.data?.message || 'API-Anfrage fehlgeschlagen', + status: error.response?.status || 500 + }; + } + } + + /** + * Get user profile and club information + * @param {string} cookie - Authentication cookie (sb-10-auth-token) + * @returns {Promise} User profile with club info + */ + async getUserProfile(cookie) { + console.log('[getUserProfile] - Calling /?_data=root with cookie:', cookie?.substring(0, 50) + '...'); + + const result = await this.authenticatedRequest('/?_data=root', cookie, { + method: 'GET' + }); + + console.log('[getUserProfile] - Result success:', result.success); + + if (result.success) { + console.log('[getUserProfile] - Response structure:', { + hasUserProfile: !!result.data?.userProfile, + hasClub: !!result.data?.userProfile?.club, + hasOrganization: !!result.data?.userProfile?.organization, + clubnr: result.data?.userProfile?.club?.clubnr, + clubName: result.data?.userProfile?.club?.name, + orgShort: result.data?.userProfile?.organization?.short, + ttr: result.data?.userProfile?.ttr, + qttr: result.data?.userProfile?.qttr + }); + + console.log('[getUserProfile] - Full userProfile.club:', result.data?.userProfile?.club); + console.log('[getUserProfile] - Full userProfile.organization:', result.data?.userProfile?.organization); + + return { + success: true, + clubId: result.data?.userProfile?.club?.clubnr || null, + clubName: result.data?.userProfile?.club?.name || null, + fedNickname: result.data?.userProfile?.organization?.short || null, + ttr: result.data?.userProfile?.ttr || null, + qttr: result.data?.userProfile?.qttr || null, + userProfile: result.data?.userProfile || null + }; + } + + console.error('[getUserProfile] - Failed:', result.error); + return result; + } + + /** + * Get club rankings (andro-Rangliste) + * @param {string} cookie - Authentication cookie + * @param {string} clubId - Club number (e.g., "43030") + * @param {string} fedNickname - Federation nickname (e.g., "HeTTV") + * @returns {Promise} Rankings with player entries (all pages) + */ + async getClubRankings(cookie, clubId, fedNickname) { + const allEntries = []; + let currentPage = 0; + let hasMorePages = true; + + console.log('[getClubRankings] - Starting to fetch rankings for club', clubId); + + while (hasMorePages) { + const endpoint = `/rankings/andro-rangliste?all-players=on&clubnr=${clubId}&fednickname=${fedNickname}&results-per-page=100&page=${currentPage}&_data=routes%2F%24`; + + console.log(`[getClubRankings] - Fetching page ${currentPage}...`); + + const result = await this.authenticatedRequest(endpoint, cookie, { + method: 'GET' + }); + + if (!result.success) { + console.error(`[getClubRankings] - Failed to fetch page ${currentPage}:`, result.error); + return result; + } + + // Find the dynamic key that contains entries + const blockLoaderData = result.data?.pageContent?.blockLoaderData; + if (!blockLoaderData) { + console.error('[getClubRankings] - No blockLoaderData found'); + return { + success: false, + error: 'Keine blockLoaderData gefunden' + }; + } + + // Finde den Schlüssel, der entries enthält + let entries = null; + let rankingData = null; + + for (const key in blockLoaderData) { + if (blockLoaderData[key]?.entries) { + entries = blockLoaderData[key].entries; + rankingData = blockLoaderData[key]; + break; + } + } + + if (!entries) { + console.error('[getClubRankings] - No entries found in blockLoaderData'); + return { + success: false, + error: 'Keine entries in blockLoaderData gefunden' + }; + } + + console.log(`[getClubRankings] - Page ${currentPage}: Found ${entries.length} entries`); + + // Füge Entries hinzu + allEntries.push(...entries); + + // Prüfe ob es weitere Seiten gibt + // Wenn die aktuelle Seite weniger Einträge hat als das Limit, sind wir am Ende + // Oder wenn wir alle erwarteten Einträge haben + if (entries.length === 0) { + hasMorePages = false; + console.log('[getClubRankings] - No more entries, stopping'); + } else if (rankingData.numberOfPages && currentPage >= rankingData.numberOfPages - 1) { + hasMorePages = false; + console.log(`[getClubRankings] - Reached last page (${rankingData.numberOfPages})`); + } else if (allEntries.length >= rankingData.resultLength) { + hasMorePages = false; + console.log(`[getClubRankings] - Got all entries (${allEntries.length}/${rankingData.resultLength})`); + } else { + currentPage++; + } + } + + console.log(`[getClubRankings] - Total entries fetched: ${allEntries.length}`); + + return { + success: true, + entries: allEntries, + metadata: { + totalEntries: allEntries.length, + pagesFetched: currentPage + 1 + } + }; + } +} + +export default new MyTischtennisClient(); + diff --git a/backend/controllers/memberController.js b/backend/controllers/memberController.js index 35829a4..190c5e5 100644 --- a/backend/controllers/memberController.js +++ b/backend/controllers/memberController.js @@ -34,11 +34,11 @@ const getWaitingApprovals = async(req, res) => { const setClubMembers = async (req, res) => { try { const { id: memberId, firstname: firstName, lastname: lastName, street, city, birthdate, phone, email, active, - testMembership, picsInInternetAllowed, gender } = req.body; + testMembership, picsInInternetAllowed, gender, ttr, qttr } = req.body; const { id: clubId } = req.params; const { authcode: userToken } = req.headers; const addResult = await MemberService.setClubMember(userToken, clubId, memberId, firstName, lastName, street, city, birthdate, - phone, email, active, testMembership, picsInInternetAllowed, gender); + phone, email, active, testMembership, picsInInternetAllowed, gender, ttr, qttr); res.status(addResult.status || 500).json(addResult.response); } catch (error) { console.error('[setClubMembers] - Error:', error); @@ -75,4 +75,17 @@ const getMemberImage = async (req, res) => { } }; -export { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage }; \ No newline at end of file +const updateRatingsFromMyTischtennis = async (req, res) => { + console.log('[updateRatingsFromMyTischtennis]'); + try { + const { id: clubId } = req.params; + const { authcode: userToken } = req.headers; + const result = await MemberService.updateRatingsFromMyTischtennis(userToken, clubId); + res.status(result.status).json(result.response); + } catch (error) { + console.error('[updateRatingsFromMyTischtennis] - Error:', error); + res.status(500).json({ error: 'Failed to update ratings' }); + } +}; + +export { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis }; \ No newline at end of file diff --git a/backend/controllers/myTischtennisController.js b/backend/controllers/myTischtennisController.js new file mode 100644 index 0000000..9c8d92c --- /dev/null +++ b/backend/controllers/myTischtennisController.js @@ -0,0 +1,133 @@ +import myTischtennisService from '../services/myTischtennisService.js'; +import HttpError from '../exceptions/HttpError.js'; + +class MyTischtennisController { + /** + * GET /api/mytischtennis/account + * Get current user's myTischtennis account + */ + async getAccount(req, res, next) { + try { + const userId = req.user.id; + const account = await myTischtennisService.getAccount(userId); + + if (!account) { + return res.status(200).json({ account: null }); + } + + res.status(200).json({ account }); + } catch (error) { + next(error); + } + } + + /** + * GET /api/mytischtennis/status + * Check account configuration status + */ + async getStatus(req, res, next) { + try { + const userId = req.user.id; + const status = await myTischtennisService.checkAccountStatus(userId); + res.status(200).json(status); + } catch (error) { + next(error); + } + } + + /** + * POST /api/mytischtennis/account + * Create or update myTischtennis account + */ + async upsertAccount(req, res, next) { + try { + const userId = req.user.id; + const { email, password, savePassword, userPassword } = req.body; + + if (!email) { + throw new HttpError(400, 'E-Mail-Adresse erforderlich'); + } + + // Wenn ein Passwort gesetzt wird, muss das App-Passwort angegeben werden + if (password && !userPassword) { + throw new HttpError(400, 'App-Passwort erforderlich zum Setzen des myTischtennis-Passworts'); + } + + const account = await myTischtennisService.upsertAccount( + userId, + email, + password, + savePassword || false, + userPassword + ); + + res.status(200).json({ + message: 'myTischtennis-Account erfolgreich gespeichert', + account + }); + } catch (error) { + next(error); + } + } + + /** + * DELETE /api/mytischtennis/account + * Delete myTischtennis account + */ + async deleteAccount(req, res, next) { + try { + const userId = req.user.id; + const deleted = await myTischtennisService.deleteAccount(userId); + + if (!deleted) { + throw new HttpError(404, 'Kein myTischtennis-Account gefunden'); + } + + res.status(200).json({ message: 'myTischtennis-Account gelöscht' }); + } catch (error) { + next(error); + } + } + + /** + * POST /api/mytischtennis/verify + * Verify login credentials + */ + async verifyLogin(req, res, next) { + try { + const userId = req.user.id; + const { password } = req.body; + + const result = await myTischtennisService.verifyLogin(userId, password); + + res.status(200).json({ + message: 'Login erfolgreich', + success: true, + accessToken: result.accessToken, + expiresAt: result.expiresAt, + clubId: result.clubId, + clubName: result.clubName + }); + } catch (error) { + next(error); + } + } + + /** + * GET /api/mytischtennis/session + * Get stored session data for authenticated requests + */ + async getSession(req, res, next) { + try { + const userId = req.user.id; + const session = await myTischtennisService.getSession(userId); + + res.status(200).json({ session }); + } catch (error) { + next(error); + } + } +} + +export default new MyTischtennisController(); + diff --git a/backend/models/Member.js b/backend/models/Member.js index 7d60fed..2c128ee 100644 --- a/backend/models/Member.js +++ b/backend/models/Member.js @@ -127,6 +127,16 @@ const Member = sequelize.define('Member', { type: DataTypes.ENUM('male','female','diverse','unknown'), allowNull: true, defaultValue: 'unknown' + }, + ttr: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: null + }, + qttr: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: null } }, { underscored: true, diff --git a/backend/models/MyTischtennis.js b/backend/models/MyTischtennis.js new file mode 100644 index 0000000..5517249 --- /dev/null +++ b/backend/models/MyTischtennis.js @@ -0,0 +1,122 @@ +import { DataTypes } from 'sequelize'; +import sequelize from '../database.js'; +import { encryptData, decryptData } from '../utils/encrypt.js'; + +const MyTischtennis = sequelize.define('MyTischtennis', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false + }, + userId: { + type: DataTypes.INTEGER, + allowNull: false, + unique: true, + references: { + model: 'user', + key: 'id' + }, + onDelete: 'CASCADE' + }, + 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: 'my_tischtennis', + timestamps: true, + hooks: { + beforeSave: async (instance) => { + // Wenn savePassword false ist, password auf null setzen + if (!instance.savePassword) { + instance.encryptedPassword = null; + } + } + } +}); + +// Virtuelle Felder für password handling +MyTischtennis.prototype.setPassword = function(password) { + if (password && this.savePassword) { + this.encryptedPassword = encryptData(password); + } else { + this.encryptedPassword = null; + } +}; + +MyTischtennis.prototype.getPassword = function() { + if (this.encryptedPassword) { + try { + return decryptData(this.encryptedPassword); + } catch (error) { + console.error('Error decrypting myTischtennis password:', error); + return null; + } + } + return null; +}; + +export default MyTischtennis; + diff --git a/backend/models/index.js b/backend/models/index.js index 7f747b0..993601a 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -33,6 +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'; // Official tournaments relations OfficialTournament.hasMany(OfficialCompetition, { foreignKey: 'tournamentId', as: 'competitions' }); OfficialCompetition.belongsTo(OfficialTournament, { foreignKey: 'tournamentId', as: 'tournament' }); @@ -204,6 +205,9 @@ 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' }); + export { User, Log, @@ -239,4 +243,5 @@ export { OfficialTournament, OfficialCompetition, OfficialCompetitionMember, + MyTischtennis, }; diff --git a/backend/node_modules/.package-lock.json b/backend/node_modules/.package-lock.json index 152f705..be5e579 100644 --- a/backend/node_modules/.package-lock.json +++ b/backend/node_modules/.package-lock.json @@ -4,6 +4,15 @@ "lockfileVersion": 3, "requires": true, "packages": { + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emnapi/runtime": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", @@ -810,6 +819,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/aws-ssl-profiles": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", @@ -818,6 +833,17 @@ "node": ">= 6.0.0" } }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -955,6 +981,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1084,6 +1123,18 @@ "color-support": "bin.js" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1227,6 +1278,22 @@ "node": ">= 10" } }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1259,6 +1326,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1315,6 +1391,20 @@ "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==" }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1342,13 +1432,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -1362,6 +1449,33 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1752,6 +1866,42 @@ "dev": true, "peer": true }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1849,16 +1999,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1867,6 +2022,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1913,12 +2081,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1945,10 +2113,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -1957,11 +2125,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -2405,6 +2576,15 @@ "semver": "bin/semver.js" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2972,6 +3152,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", diff --git a/backend/node_modules/es-define-property/CHANGELOG.md b/backend/node_modules/es-define-property/CHANGELOG.md index 4dce2ec..5f60cc0 100644 --- a/backend/node_modules/es-define-property/CHANGELOG.md +++ b/backend/node_modules/es-define-property/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.0.1](https://github.com/ljharb/es-define-property/compare/v1.0.0...v1.0.1) - 2024-12-06 + +### Commits + +- [types] use shared tsconfig [`954a663`](https://github.com/ljharb/es-define-property/commit/954a66360326e508a0e5daa4b07493d58f5e110e) +- [actions] split out node 10-20, and 20+ [`3a8e84b`](https://github.com/ljharb/es-define-property/commit/3a8e84b23883f26ff37b3e82ff283834228e18c6) +- [Dev Deps] update `@ljharb/eslint-config`, `@ljharb/tsconfig`, `@types/get-intrinsic`, `@types/tape`, `auto-changelog`, `gopd`, `tape` [`86ae27b`](https://github.com/ljharb/es-define-property/commit/86ae27bb8cc857b23885136fad9cbe965ae36612) +- [Refactor] avoid using `get-intrinsic` [`02480c0`](https://github.com/ljharb/es-define-property/commit/02480c0353ef6118965282977c3864aff53d98b1) +- [Tests] replace `aud` with `npm audit` [`f6093ff`](https://github.com/ljharb/es-define-property/commit/f6093ff74ab51c98015c2592cd393bd42478e773) +- [Tests] configure testling [`7139e66`](https://github.com/ljharb/es-define-property/commit/7139e66959247a56086d9977359caef27c6849e7) +- [Dev Deps] update `tape` [`b901b51`](https://github.com/ljharb/es-define-property/commit/b901b511a75e001a40ce1a59fef7d9ffcfc87482) +- [Tests] fix types in tests [`469d269`](https://github.com/ljharb/es-define-property/commit/469d269fd141b1e773ec053a9fa35843493583e0) +- [Dev Deps] add missing peer dep [`733acfb`](https://github.com/ljharb/es-define-property/commit/733acfb0c4c96edf337e470b89a25a5b3724c352) + ## v1.0.0 - 2024-02-12 ### Commits diff --git a/backend/node_modules/es-define-property/index.js b/backend/node_modules/es-define-property/index.js index f32737d..e0a2925 100644 --- a/backend/node_modules/es-define-property/index.js +++ b/backend/node_modules/es-define-property/index.js @@ -1,9 +1,7 @@ 'use strict'; -var GetIntrinsic = require('get-intrinsic'); - /** @type {import('.')} */ -var $defineProperty = GetIntrinsic('%Object.defineProperty%', true) || false; +var $defineProperty = Object.defineProperty || false; if ($defineProperty) { try { $defineProperty({}, 'a', { value: 1 }); diff --git a/backend/node_modules/es-define-property/package.json b/backend/node_modules/es-define-property/package.json index 45bc90f..fbed187 100644 --- a/backend/node_modules/es-define-property/package.json +++ b/backend/node_modules/es-define-property/package.json @@ -1,6 +1,6 @@ { "name": "es-define-property", - "version": "1.0.0", + "version": "1.0.1", "description": "`Object.defineProperty`, but not IE 8's broken one.", "main": "index.js", "types": "./index.d.ts", @@ -19,7 +19,7 @@ "pretest": "npm run lint", "tests-only": "nyc tape 'test/**/*.js'", "test": "npm run tests-only", - "posttest": "aud --production", + "posttest": "npx npm@'>= 10.2' audit --production", "version": "auto-changelog && git add CHANGELOG.md", "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" }, @@ -42,29 +42,29 @@ "url": "https://github.com/ljharb/es-define-property/issues" }, "homepage": "https://github.com/ljharb/es-define-property#readme", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "devDependencies": { - "@ljharb/eslint-config": "^21.1.0", - "@types/get-intrinsic": "^1.2.2", + "@ljharb/eslint-config": "^21.1.1", + "@ljharb/tsconfig": "^0.2.2", "@types/gopd": "^1.0.3", - "@types/tape": "^5.6.4", - "aud": "^2.0.4", - "auto-changelog": "^2.4.0", + "@types/tape": "^5.6.5", + "auto-changelog": "^2.5.0", + "encoding": "^0.1.13", "eslint": "^8.8.0", "evalmd": "^0.0.19", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "in-publish": "^2.0.1", "npmignore": "^0.3.1", "nyc": "^10.3.2", "safe-publish-latest": "^2.0.0", - "tape": "^5.7.4", + "tape": "^5.9.0", "typescript": "next" }, "engines": { "node": ">= 0.4" }, + "testling": { + "files": "test/index.js" + }, "auto-changelog": { "output": "CHANGELOG.md", "template": "keepachangelog", diff --git a/backend/node_modules/es-define-property/test/index.js b/backend/node_modules/es-define-property/test/index.js index dbc054e..b4b4688 100644 --- a/backend/node_modules/es-define-property/test/index.js +++ b/backend/node_modules/es-define-property/test/index.js @@ -10,6 +10,7 @@ test('defineProperty: supported', { skip: !$defineProperty }, function (t) { t.equal(typeof $defineProperty, 'function', 'defineProperty is supported'); if ($defineProperty && gOPD) { // this `if` check is just to shut TS up + /** @type {{ a: number, b?: number, c?: number }} */ var o = { a: 1 }; $defineProperty(o, 'b', { enumerable: true, value: 2 }); diff --git a/backend/node_modules/es-define-property/tsconfig.json b/backend/node_modules/es-define-property/tsconfig.json index fdfa155..5a49992 100644 --- a/backend/node_modules/es-define-property/tsconfig.json +++ b/backend/node_modules/es-define-property/tsconfig.json @@ -1,47 +1,7 @@ { + "extends": "@ljharb/tsconfig", "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Projects */ - - /* Language and Environment */ - "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": ["types"], /* Specify multiple folders that act like `./node_modules/@types`. */ - "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - - /* JavaScript Support */ - "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ - "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ - - /* Emit */ - "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - "declarationMap": true, /* Create sourcemaps for d.ts files. */ - "noEmit": true, /* Disable emitting files from a compilation. */ - - /* Interop Constraints */ - "allowSyntheticDefaultImports": true, /* Allow `import x from y` when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - - /* Completeness */ - // "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "target": "es2022", }, "exclude": [ "coverage", diff --git a/backend/node_modules/get-intrinsic/.eslintrc b/backend/node_modules/get-intrinsic/.eslintrc index 8376636..235fb79 100644 --- a/backend/node_modules/get-intrinsic/.eslintrc +++ b/backend/node_modules/get-intrinsic/.eslintrc @@ -11,6 +11,10 @@ "es2022": true, }, + "globals": { + "Float16Array": false, + }, + "rules": { "array-bracket-newline": 0, "complexity": 0, diff --git a/backend/node_modules/get-intrinsic/CHANGELOG.md b/backend/node_modules/get-intrinsic/CHANGELOG.md index 96d5397..ce1dd98 100644 --- a/backend/node_modules/get-intrinsic/CHANGELOG.md +++ b/backend/node_modules/get-intrinsic/CHANGELOG.md @@ -5,6 +5,49 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.3.0](https://github.com/ljharb/get-intrinsic/compare/v1.2.7...v1.3.0) - 2025-02-22 + +### Commits + +- [Dev Deps] update `es-abstract`, `es-value-fixtures`, `for-each`, `object-inspect` [`9b61553`](https://github.com/ljharb/get-intrinsic/commit/9b61553c587f1c1edbd435597e88c7d387da97dd) +- [Deps] update `call-bind-apply-helpers`, `es-object-atoms`, `get-proto` [`a341fee`](https://github.com/ljharb/get-intrinsic/commit/a341fee0f39a403b0f0069e82c97642d5eb11043) +- [New] add `Float16Array` [`de22116`](https://github.com/ljharb/get-intrinsic/commit/de22116b492fb989a0341bceb6e573abfaed73dc) + +## [v1.2.7](https://github.com/ljharb/get-intrinsic/compare/v1.2.6...v1.2.7) - 2025-01-02 + +### Commits + +- [Refactor] use `get-proto` directly [`00ab955`](https://github.com/ljharb/get-intrinsic/commit/00ab95546a0980c8ad42a84253daaa8d2adcedf9) +- [Deps] update `math-intrinsics` [`c716cdd`](https://github.com/ljharb/get-intrinsic/commit/c716cdd6bbe36b438057025561b8bb5a879ac8a0) +- [Dev Deps] update `call-bound`, `es-abstract` [`dc648a6`](https://github.com/ljharb/get-intrinsic/commit/dc648a67eb359037dff8d8619bfa71d86debccb1) + +## [v1.2.6](https://github.com/ljharb/get-intrinsic/compare/v1.2.5...v1.2.6) - 2024-12-11 + +### Commits + +- [Refactor] use `math-intrinsics` [`841be86`](https://github.com/ljharb/get-intrinsic/commit/841be8641a9254c4c75483b30c8871b5d5065926) +- [Refactor] use `es-object-atoms` [`42057df`](https://github.com/ljharb/get-intrinsic/commit/42057dfa16f66f64787e66482af381cc6f31d2c1) +- [Deps] update `call-bind-apply-helpers` [`45afa24`](https://github.com/ljharb/get-intrinsic/commit/45afa24a9ee4d6d3c172db1f555b16cb27843ef4) +- [Dev Deps] update `call-bound` [`9cba9c6`](https://github.com/ljharb/get-intrinsic/commit/9cba9c6e70212bc163b7a5529cb25df46071646f) + +## [v1.2.5](https://github.com/ljharb/get-intrinsic/compare/v1.2.4...v1.2.5) - 2024-12-06 + +### Commits + +- [actions] split out node 10-20, and 20+ [`6e2b9dd`](https://github.com/ljharb/get-intrinsic/commit/6e2b9dd23902665681ebe453256ccfe21d7966f0) +- [Refactor] use `dunder-proto` and `call-bind-apply-helpers` instead of `has-proto` [`c095d17`](https://github.com/ljharb/get-intrinsic/commit/c095d179ad0f4fbfff20c8a3e0cb4fe668018998) +- [Refactor] use `gopd` [`9841d5b`](https://github.com/ljharb/get-intrinsic/commit/9841d5b35f7ab4fd2d193f0c741a50a077920e90) +- [Dev Deps] update `@ljharb/eslint-config`, `auto-changelog`, `es-abstract`, `es-value-fixtures`, `gopd`, `mock-property`, `object-inspect`, `tape` [`2d07e01`](https://github.com/ljharb/get-intrinsic/commit/2d07e01310cee2cbaedfead6903df128b1f5d425) +- [Deps] update `gopd`, `has-proto`, `has-symbols`, `hasown` [`974d8bf`](https://github.com/ljharb/get-intrinsic/commit/974d8bf5baad7939eef35c25cc1dd88c10a30fa6) +- [Dev Deps] update `call-bind`, `es-abstract`, `tape` [`df9dde1`](https://github.com/ljharb/get-intrinsic/commit/df9dde178186631ab8a3165ede056549918ce4bc) +- [Refactor] cache `es-define-property` as well [`43ef543`](https://github.com/ljharb/get-intrinsic/commit/43ef543cb02194401420e3a914a4ca9168691926) +- [Deps] update `has-proto`, `has-symbols`, `hasown` [`ad4949d`](https://github.com/ljharb/get-intrinsic/commit/ad4949d5467316505aad89bf75f9417ed782f7af) +- [Tests] use `call-bound` directly [`ad5c406`](https://github.com/ljharb/get-intrinsic/commit/ad5c4069774bfe90e520a35eead5fe5ca9d69e80) +- [Deps] update `has-proto`, `hasown` [`45414ca`](https://github.com/ljharb/get-intrinsic/commit/45414caa312333a2798953682c68f85c550627dd) +- [Tests] replace `aud` with `npm audit` [`18d3509`](https://github.com/ljharb/get-intrinsic/commit/18d3509f79460e7924da70409ee81e5053087523) +- [Deps] update `es-define-property` [`aadaa3b`](https://github.com/ljharb/get-intrinsic/commit/aadaa3b2188d77ad9bff394ce5d4249c49eb21f5) +- [Dev Deps] add missing peer dep [`c296a16`](https://github.com/ljharb/get-intrinsic/commit/c296a16246d0c9a5981944f4cc5cf61fbda0cf6a) + ## [v1.2.4](https://github.com/ljharb/get-intrinsic/compare/v1.2.3...v1.2.4) - 2024-02-05 ### Commits diff --git a/backend/node_modules/get-intrinsic/index.js b/backend/node_modules/get-intrinsic/index.js index c25e2c4..bd1d94b 100644 --- a/backend/node_modules/get-intrinsic/index.js +++ b/backend/node_modules/get-intrinsic/index.js @@ -2,6 +2,8 @@ var undefined; +var $Object = require('es-object-atoms'); + var $Error = require('es-errors'); var $EvalError = require('es-errors/eval'); var $RangeError = require('es-errors/range'); @@ -10,6 +12,14 @@ var $SyntaxError = require('es-errors/syntax'); var $TypeError = require('es-errors/type'); var $URIError = require('es-errors/uri'); +var abs = require('math-intrinsics/abs'); +var floor = require('math-intrinsics/floor'); +var max = require('math-intrinsics/max'); +var min = require('math-intrinsics/min'); +var pow = require('math-intrinsics/pow'); +var round = require('math-intrinsics/round'); +var sign = require('math-intrinsics/sign'); + var $Function = Function; // eslint-disable-next-line consistent-return @@ -19,14 +29,8 @@ var getEvalledConstructor = function (expressionSyntax) { } catch (e) {} }; -var $gOPD = Object.getOwnPropertyDescriptor; -if ($gOPD) { - try { - $gOPD({}, ''); - } catch (e) { - $gOPD = null; // this is IE 8, which has a broken gOPD - } -} +var $gOPD = require('gopd'); +var $defineProperty = require('es-define-property'); var throwTypeError = function () { throw new $TypeError(); @@ -49,13 +53,13 @@ var ThrowTypeError = $gOPD : throwTypeError; var hasSymbols = require('has-symbols')(); -var hasProto = require('has-proto')(); -var getProto = Object.getPrototypeOf || ( - hasProto - ? function (x) { return x.__proto__; } // eslint-disable-line no-proto - : null -); +var getProto = require('get-proto'); +var $ObjectGPO = require('get-proto/Object.getPrototypeOf'); +var $ReflectGPO = require('get-proto/Reflect.getPrototypeOf'); + +var $apply = require('call-bind-apply-helpers/functionApply'); +var $call = require('call-bind-apply-helpers/functionCall'); var needsEval = {}; @@ -86,6 +90,7 @@ var INTRINSICS = { '%Error%': $Error, '%eval%': eval, // eslint-disable-line no-eval '%EvalError%': $EvalError, + '%Float16Array%': typeof Float16Array === 'undefined' ? undefined : Float16Array, '%Float32Array%': typeof Float32Array === 'undefined' ? undefined : Float32Array, '%Float64Array%': typeof Float64Array === 'undefined' ? undefined : Float64Array, '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined : FinalizationRegistry, @@ -102,7 +107,8 @@ var INTRINSICS = { '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Map()[Symbol.iterator]()), '%Math%': Math, '%Number%': Number, - '%Object%': Object, + '%Object%': $Object, + '%Object.getOwnPropertyDescriptor%': $gOPD, '%parseFloat%': parseFloat, '%parseInt%': parseInt, '%Promise%': typeof Promise === 'undefined' ? undefined : Promise, @@ -128,7 +134,20 @@ var INTRINSICS = { '%URIError%': $URIError, '%WeakMap%': typeof WeakMap === 'undefined' ? undefined : WeakMap, '%WeakRef%': typeof WeakRef === 'undefined' ? undefined : WeakRef, - '%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet + '%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet, + + '%Function.prototype.call%': $call, + '%Function.prototype.apply%': $apply, + '%Object.defineProperty%': $defineProperty, + '%Object.getPrototypeOf%': $ObjectGPO, + '%Math.abs%': abs, + '%Math.floor%': floor, + '%Math.max%': max, + '%Math.min%': min, + '%Math.pow%': pow, + '%Math.round%': round, + '%Math.sign%': sign, + '%Reflect.getPrototypeOf%': $ReflectGPO }; if (getProto) { @@ -223,11 +242,11 @@ var LEGACY_ALIASES = { var bind = require('function-bind'); var hasOwn = require('hasown'); -var $concat = bind.call(Function.call, Array.prototype.concat); -var $spliceApply = bind.call(Function.apply, Array.prototype.splice); -var $replace = bind.call(Function.call, String.prototype.replace); -var $strSlice = bind.call(Function.call, String.prototype.slice); -var $exec = bind.call(Function.call, RegExp.prototype.exec); +var $concat = bind.call($call, Array.prototype.concat); +var $spliceApply = bind.call($apply, Array.prototype.splice); +var $replace = bind.call($call, String.prototype.replace); +var $strSlice = bind.call($call, String.prototype.slice); +var $exec = bind.call($call, RegExp.prototype.exec); /* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */ var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; diff --git a/backend/node_modules/get-intrinsic/package.json b/backend/node_modules/get-intrinsic/package.json index 568dff9..2828e73 100644 --- a/backend/node_modules/get-intrinsic/package.json +++ b/backend/node_modules/get-intrinsic/package.json @@ -1,6 +1,6 @@ { "name": "get-intrinsic", - "version": "1.2.4", + "version": "1.3.0", "description": "Get and robustly cache all JS language-level intrinsics at first require time", "main": "index.js", "exports": { @@ -17,7 +17,7 @@ "pretest": "npm run lint", "tests-only": "nyc tape 'test/**/*.js'", "test": "npm run tests-only", - "posttest": "aud --production", + "posttest": "npx npm@'>= 10.2' audit --production", "version": "auto-changelog && git add CHANGELOG.md", "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" }, @@ -43,26 +43,37 @@ "url": "https://github.com/ljharb/get-intrinsic/issues" }, "homepage": "https://github.com/ljharb/get-intrinsic#readme", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, "devDependencies": { - "@ljharb/eslint-config": "^21.1.0", - "aud": "^2.0.4", - "auto-changelog": "^2.4.0", - "call-bind": "^1.0.5", - "es-abstract": "^1.22.3", - "es-value-fixtures": "^1.4.2", + "@ljharb/eslint-config": "^21.1.1", + "auto-changelog": "^2.5.0", + "call-bound": "^1.0.3", + "encoding": "^0.1.13", + "es-abstract": "^1.23.9", + "es-value-fixtures": "^1.7.1", "eslint": "=8.8.0", "evalmd": "^0.0.19", - "for-each": "^0.3.3", - "gopd": "^1.0.1", + "for-each": "^0.3.5", "make-async-function": "^1.0.0", "make-async-generator-function": "^1.0.0", "make-generator-function": "^2.0.0", - "mock-property": "^1.0.3", + "mock-property": "^1.1.0", "npmignore": "^0.3.1", "nyc": "^10.3.2", - "object-inspect": "^1.13.1", + "object-inspect": "^1.13.4", "safe-publish-latest": "^2.0.0", - "tape": "^5.7.4" + "tape": "^5.9.0" }, "auto-changelog": { "output": "CHANGELOG.md", @@ -72,13 +83,6 @@ "backfillLimit": false, "hideCredit": true }, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, "testling": { "files": "test/GetIntrinsic.js" }, diff --git a/backend/node_modules/get-intrinsic/test/GetIntrinsic.js b/backend/node_modules/get-intrinsic/test/GetIntrinsic.js index 1cc08e0..d9c0f30 100644 --- a/backend/node_modules/get-intrinsic/test/GetIntrinsic.js +++ b/backend/node_modules/get-intrinsic/test/GetIntrinsic.js @@ -10,10 +10,10 @@ var asyncFns = require('make-async-function').list(); var asyncGenFns = require('make-async-generator-function')(); var mockProperty = require('mock-property'); -var callBound = require('call-bind/callBound'); +var callBound = require('call-bound'); var v = require('es-value-fixtures'); var $gOPD = require('gopd'); -var DefinePropertyOrThrow = require('es-abstract/2021/DefinePropertyOrThrow'); +var DefinePropertyOrThrow = require('es-abstract/2023/DefinePropertyOrThrow'); var $isProto = callBound('%Object.prototype.isPrototypeOf%'); diff --git a/backend/node_modules/gopd/CHANGELOG.md b/backend/node_modules/gopd/CHANGELOG.md index f111eb1..87f5727 100644 --- a/backend/node_modules/gopd/CHANGELOG.md +++ b/backend/node_modules/gopd/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.2.0](https://github.com/ljharb/gopd/compare/v1.1.0...v1.2.0) - 2024-12-03 + +### Commits + +- [New] add `gOPD` entry point; remove `get-intrinsic` [`5b61232`](https://github.com/ljharb/gopd/commit/5b61232dedea4591a314bcf16101b1961cee024e) + +## [v1.1.0](https://github.com/ljharb/gopd/compare/v1.0.1...v1.1.0) - 2024-11-29 + +### Commits + +- [New] add types [`f585e39`](https://github.com/ljharb/gopd/commit/f585e397886d270e4ba84e53d226e4f9ca2eb0e6) +- [Dev Deps] update `@ljharb/eslint-config`, `auto-changelog`, `tape` [`0b8e4fd`](https://github.com/ljharb/gopd/commit/0b8e4fded64397a7726a9daa144a6cc9a5e2edfa) +- [Dev Deps] update `aud`, `npmignore`, `tape` [`48378b2`](https://github.com/ljharb/gopd/commit/48378b2443f09a4f7efbd0fb6c3ee845a6cabcf3) +- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `tape` [`78099ee`](https://github.com/ljharb/gopd/commit/78099eeed41bfdc134c912280483689cc8861c31) +- [Tests] replace `aud` with `npm audit` [`4e0d0ac`](https://github.com/ljharb/gopd/commit/4e0d0ac47619d24a75318a8e1f543ee04b2a2632) +- [meta] add missing `engines.node` [`1443316`](https://github.com/ljharb/gopd/commit/14433165d07835c680155b3dfd62d9217d735eca) +- [Deps] update `get-intrinsic` [`eee5f51`](https://github.com/ljharb/gopd/commit/eee5f51769f3dbaf578b70e2a3199116b01aa670) +- [Deps] update `get-intrinsic` [`550c378`](https://github.com/ljharb/gopd/commit/550c3780e3a9c77b62565712a001b4ed64ea61f5) +- [Dev Deps] add missing peer dep [`8c2ecf8`](https://github.com/ljharb/gopd/commit/8c2ecf848122e4e30abfc5b5086fb48b390dce75) + ## [v1.0.1](https://github.com/ljharb/gopd/compare/v1.0.0...v1.0.1) - 2022-11-01 ### Commits diff --git a/backend/node_modules/gopd/index.js b/backend/node_modules/gopd/index.js index fb6d3bb..a4081b0 100644 --- a/backend/node_modules/gopd/index.js +++ b/backend/node_modules/gopd/index.js @@ -1,8 +1,7 @@ 'use strict'; -var GetIntrinsic = require('get-intrinsic'); - -var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); +/** @type {import('.')} */ +var $gOPD = require('./gOPD'); if ($gOPD) { try { diff --git a/backend/node_modules/gopd/package.json b/backend/node_modules/gopd/package.json index d5e1fa4..01c5ffa 100644 --- a/backend/node_modules/gopd/package.json +++ b/backend/node_modules/gopd/package.json @@ -1,10 +1,11 @@ { "name": "gopd", - "version": "1.0.1", + "version": "1.2.0", "description": "`Object.getOwnPropertyDescriptor`, but accounts for IE's broken implementation.", "main": "index.js", "exports": { ".": "./index.js", + "./gOPD": "./gOPD.js", "./package.json": "./package.json" }, "sideEffects": false, @@ -12,12 +13,13 @@ "prepack": "npmignore --auto --commentLines=autogenerated", "prepublishOnly": "safe-publish-latest", "prepublish": "not-in-publish || npm run prepublishOnly", + "prelint": "tsc -p . && attw -P", "lint": "eslint --ext=js,mjs .", "postlint": "evalmd README.md", "pretest": "npm run lint", "tests-only": "tape 'test/**/*.js'", "test": "npm run tests-only", - "posttest": "aud --production", + "posttest": "npx npm@'>=10.2' audit --production", "version": "auto-changelog && git add CHANGELOG.md", "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" }, @@ -41,19 +43,20 @@ "url": "https://github.com/ljharb/gopd/issues" }, "homepage": "https://github.com/ljharb/gopd#readme", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, "devDependencies": { - "@ljharb/eslint-config": "^21.0.0", - "aud": "^2.0.1", - "auto-changelog": "^2.4.0", + "@arethetypeswrong/cli": "^0.17.0", + "@ljharb/eslint-config": "^21.1.1", + "@ljharb/tsconfig": "^0.2.0", + "@types/tape": "^5.6.5", + "auto-changelog": "^2.5.0", + "encoding": "^0.1.13", "eslint": "=8.8.0", "evalmd": "^0.0.19", "in-publish": "^2.0.1", - "npmignore": "^0.3.0", + "npmignore": "^0.3.1", "safe-publish-latest": "^2.0.0", - "tape": "^5.6.1" + "tape": "^5.9.0", + "typescript": "next" }, "auto-changelog": { "output": "CHANGELOG.md", @@ -67,5 +70,8 @@ "ignore": [ ".github/workflows" ] + }, + "engines": { + "node": ">= 0.4" } } diff --git a/backend/node_modules/gopd/test/index.js b/backend/node_modules/gopd/test/index.js index 0376bfb..6f43453 100644 --- a/backend/node_modules/gopd/test/index.js +++ b/backend/node_modules/gopd/test/index.js @@ -10,6 +10,7 @@ test('gOPD', function (t) { var obj = { x: 1 }; st.ok('x' in obj, 'property exists'); + // @ts-expect-error TS can't figure out narrowing from `skip` var desc = gOPD(obj, 'x'); st.deepEqual( desc, @@ -25,7 +26,7 @@ test('gOPD', function (t) { st.end(); }); - t.test('not supported', { skip: gOPD }, function (st) { + t.test('not supported', { skip: !!gOPD }, function (st) { st.notOk(gOPD, 'is falsy'); st.end(); diff --git a/backend/node_modules/has-proto/.eslintrc b/backend/node_modules/has-proto/.eslintrc deleted file mode 100644 index 3b5d9e9..0000000 --- a/backend/node_modules/has-proto/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "root": true, - - "extends": "@ljharb", -} diff --git a/backend/node_modules/has-proto/.github/FUNDING.yml b/backend/node_modules/has-proto/.github/FUNDING.yml deleted file mode 100644 index 613705c..0000000 --- a/backend/node_modules/has-proto/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: [ljharb] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: npm/has-proto -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/backend/node_modules/has-proto/CHANGELOG.md b/backend/node_modules/has-proto/CHANGELOG.md deleted file mode 100644 index 6690f28..0000000 --- a/backend/node_modules/has-proto/CHANGELOG.md +++ /dev/null @@ -1,38 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [v1.0.3](https://github.com/inspect-js/has-proto/compare/v1.0.2...v1.0.3) - 2024-02-19 - -### Commits - -- [types] add missing declaration file [`26ecade`](https://github.com/inspect-js/has-proto/commit/26ecade05d253bb5dc376945ee3186d1fbe334f8) - -## [v1.0.2](https://github.com/inspect-js/has-proto/compare/v1.0.1...v1.0.2) - 2024-02-19 - -### Commits - -- add types [`6435262`](https://github.com/inspect-js/has-proto/commit/64352626cf511c0276d5f4bb6be770a0bf0f8524) -- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `npmignore`, `tape` [`f16a5e4`](https://github.com/inspect-js/has-proto/commit/f16a5e4121651e551271419f9d60fdd3561fd82c) -- [Refactor] tiny cleanup [`d1f1a4b`](https://github.com/inspect-js/has-proto/commit/d1f1a4bdc135f115a10f148ce302676224534702) -- [meta] add `sideEffects` flag [`e7ab1a6`](https://github.com/inspect-js/has-proto/commit/e7ab1a6f153b3e80dee68d1748b71e46767a0531) - -## [v1.0.1](https://github.com/inspect-js/has-proto/compare/v1.0.0...v1.0.1) - 2022-12-21 - -### Commits - -- [meta] correct URLs and description [`ef34483`](https://github.com/inspect-js/has-proto/commit/ef34483ca0d35680f271b6b96e35526151b25dfc) -- [patch] add an additional criteria [`e81959e`](https://github.com/inspect-js/has-proto/commit/e81959ed7c7a77fbf459f00cb4ef824f1099497f) -- [Dev Deps] update `aud` [`2bec2c4`](https://github.com/inspect-js/has-proto/commit/2bec2c47b072b122ff5443fba0263f6dc649531f) - -## v1.0.0 - 2022-12-12 - -### Commits - -- Initial implementation, tests, readme [`6886fea`](https://github.com/inspect-js/has-proto/commit/6886fea578f67daf69a7920b2eb7637ea6ebb0bc) -- Initial commit [`99129c8`](https://github.com/inspect-js/has-proto/commit/99129c8f42471ac89cb681ba9cb9d52a583eb94f) -- npm init [`2844ad8`](https://github.com/inspect-js/has-proto/commit/2844ad8e75b84d66a46765b3bab9d2e8ea692e10) -- Only apps should have lockfiles [`c65bc5e`](https://github.com/inspect-js/has-proto/commit/c65bc5e40b9004463f7336d47c67245fb139a36a) diff --git a/backend/node_modules/has-proto/LICENSE b/backend/node_modules/has-proto/LICENSE deleted file mode 100644 index 2e7b9a3..0000000 --- a/backend/node_modules/has-proto/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 Inspect JS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/backend/node_modules/has-proto/README.md b/backend/node_modules/has-proto/README.md deleted file mode 100644 index 1456765..0000000 --- a/backend/node_modules/has-proto/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# has-proto [![Version Badge][npm-version-svg]][package-url] - -[![github actions][actions-image]][actions-url] -[![coverage][codecov-image]][codecov-url] -[![License][license-image]][license-url] -[![Downloads][downloads-image]][downloads-url] - -[![npm badge][npm-badge-png]][package-url] - -Does this environment have the ability to set the [[Prototype]] of an object on creation with `__proto__`? - -## Example - -```js -var hasProto = require('has-proto'); -var assert = require('assert'); - -assert.equal(typeof hasProto(), 'boolean'); -``` - -## Tests -Simply clone the repo, `npm install`, and run `npm test` - -[package-url]: https://npmjs.org/package/has-proto -[npm-version-svg]: https://versionbadg.es/inspect-js/has-proto.svg -[deps-svg]: https://david-dm.org/inspect-js/has-proto.svg -[deps-url]: https://david-dm.org/inspect-js/has-proto -[dev-deps-svg]: https://david-dm.org/inspect-js/has-proto/dev-status.svg -[dev-deps-url]: https://david-dm.org/inspect-js/has-proto#info=devDependencies -[npm-badge-png]: https://nodei.co/npm/has-proto.png?downloads=true&stars=true -[license-image]: https://img.shields.io/npm/l/has-proto.svg -[license-url]: LICENSE -[downloads-image]: https://img.shields.io/npm/dm/has-proto.svg -[downloads-url]: https://npm-stat.com/charts.html?package=has-proto -[codecov-image]: https://codecov.io/gh/inspect-js/has-proto/branch/main/graphs/badge.svg -[codecov-url]: https://app.codecov.io/gh/inspect-js/has-proto/ -[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/inspect-js/has-proto -[actions-url]: https://github.com/inspect-js/has-proto/actions diff --git a/backend/node_modules/has-proto/index.d.ts b/backend/node_modules/has-proto/index.d.ts deleted file mode 100644 index cfed695..0000000 --- a/backend/node_modules/has-proto/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare function hasProto(): boolean; - -export = hasProto; \ No newline at end of file diff --git a/backend/node_modules/has-proto/index.js b/backend/node_modules/has-proto/index.js deleted file mode 100644 index d3c8a0a..0000000 --- a/backend/node_modules/has-proto/index.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -var test = { - __proto__: null, - foo: {} -}; - -var $Object = Object; - -/** @type {import('.')} */ -module.exports = function hasProto() { - // @ts-expect-error: TS errors on an inherited property for some reason - return { __proto__: test }.foo === test.foo - && !(test instanceof $Object); -}; diff --git a/backend/node_modules/has-proto/package.json b/backend/node_modules/has-proto/package.json deleted file mode 100644 index 9d37e4e..0000000 --- a/backend/node_modules/has-proto/package.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "name": "has-proto", - "version": "1.0.3", - "description": "Does this environment have the ability to get the [[Prototype]] of an object on creation with `__proto__`?", - "main": "index.js", - "exports": { - ".": "./index.js", - "./package.json": "./package.json" - }, - "sideEffects": false, - "scripts": { - "prepack": "npmignore --auto --commentLines=autogenerated", - "prepublishOnly": "safe-publish-latest", - "prepublish": "not-in-publish || npm run prepublishOnly", - "lint": "eslint --ext=js,mjs .", - "postlint": "tsc -p .", - "pretest": "npm run lint", - "tests-only": "tape 'test/**/*.js'", - "test": "npm run tests-only", - "posttest": "aud --production", - "version": "auto-changelog && git add CHANGELOG.md", - "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/inspect-js/has-proto.git" - }, - "keywords": [ - "prototype", - "proto", - "set", - "get", - "__proto__", - "getPrototypeOf", - "setPrototypeOf", - "has" - ], - "author": "Jordan Harband ", - "funding": { - "url": "https://github.com/sponsors/ljharb" - }, - "license": "MIT", - "bugs": { - "url": "https://github.com/inspect-js/has-proto/issues" - }, - "homepage": "https://github.com/inspect-js/has-proto#readme", - "testling": { - "files": "test/index.js" - }, - "devDependencies": { - "@ljharb/eslint-config": "^21.1.0", - "@types/tape": "^5.6.4", - "aud": "^2.0.4", - "auto-changelog": "^2.4.0", - "eslint": "=8.8.0", - "in-publish": "^2.0.1", - "npmignore": "^0.3.1", - "safe-publish-latest": "^2.0.0", - "tape": "^5.7.5", - "typescript": "next" - }, - "engines": { - "node": ">= 0.4" - }, - "auto-changelog": { - "output": "CHANGELOG.md", - "template": "keepachangelog", - "unreleased": false, - "commitLimit": false, - "backfillLimit": false, - "hideCredit": true - }, - "publishConfig": { - "ignore": [ - ".github/workflows" - ] - } -} diff --git a/backend/node_modules/has-proto/test/index.js b/backend/node_modules/has-proto/test/index.js deleted file mode 100644 index 5da1a3a..0000000 --- a/backend/node_modules/has-proto/test/index.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -var test = require('tape'); -var hasProto = require('../'); - -test('hasProto', function (t) { - var result = hasProto(); - t.equal(typeof result, 'boolean', 'returns a boolean (' + result + ')'); - - var obj = { __proto__: null }; - if (result) { - t.notOk('toString' in obj, 'null object lacks toString'); - } else { - t.ok('toString' in obj, 'without proto, null object has toString'); - t.equal(obj.__proto__, null); // eslint-disable-line no-proto - } - - t.end(); -}); diff --git a/backend/node_modules/has-proto/tsconfig.json b/backend/node_modules/has-proto/tsconfig.json deleted file mode 100644 index 2002ce5..0000000 --- a/backend/node_modules/has-proto/tsconfig.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - - /* Language and Environment */ - "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - "typeRoots": ["types"], /* Specify multiple folders that act like './node_modules/@types'. */ - "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - - /* JavaScript Support */ - "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - "maxNodeModuleJsDepth": 0, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - "declarationMap": true, /* Create sourcemaps for d.ts files. */ - "noEmit": true, /* Disable emitting files from a compilation. */ - - /* Interop Constraints */ - "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - - /* Completeness */ - //"skipLibCheck": true /* Skip type checking all .d.ts files. */ - }, - "exclude": [ - "coverage" - ] -} diff --git a/backend/node_modules/has-symbols/CHANGELOG.md b/backend/node_modules/has-symbols/CHANGELOG.md index cd532a2..cc3cf83 100644 --- a/backend/node_modules/has-symbols/CHANGELOG.md +++ b/backend/node_modules/has-symbols/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.1.0](https://github.com/inspect-js/has-symbols/compare/v1.0.3...v1.1.0) - 2024-12-02 + +### Commits + +- [actions] update workflows [`548c0bf`](https://github.com/inspect-js/has-symbols/commit/548c0bf8c9b1235458df7a1c0490b0064647a282) +- [actions] further shard; update action deps [`bec56bb`](https://github.com/inspect-js/has-symbols/commit/bec56bb0fb44b43a786686b944875a3175cf3ff3) +- [meta] use `npmignore` to autogenerate an npmignore file [`ac81032`](https://github.com/inspect-js/has-symbols/commit/ac81032809157e0a079e5264e9ce9b6f1275777e) +- [New] add types [`6469cbf`](https://github.com/inspect-js/has-symbols/commit/6469cbff1866cfe367b2b3d181d9296ec14b2a3d) +- [actions] update rebase action to use reusable workflow [`9c9d4d0`](https://github.com/inspect-js/has-symbols/commit/9c9d4d0d8938e4b267acdf8e421f4e92d1716d72) +- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud`, `tape` [`adb5887`](https://github.com/inspect-js/has-symbols/commit/adb5887ca9444849b08beb5caaa9e1d42320cdfb) +- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `tape` [`13ec198`](https://github.com/inspect-js/has-symbols/commit/13ec198ec80f1993a87710af1606a1970b22c7cb) +- [Dev Deps] update `auto-changelog`, `core-js`, `tape` [`941be52`](https://github.com/inspect-js/has-symbols/commit/941be5248387cab1da72509b22acf3fdb223f057) +- [Tests] replace `aud` with `npm audit` [`74f49e9`](https://github.com/inspect-js/has-symbols/commit/74f49e9a9d17a443020784234a1c53ce765b3559) +- [Dev Deps] update `npmignore` [`9c0ac04`](https://github.com/inspect-js/has-symbols/commit/9c0ac0452a834f4c2a4b54044f2d6a89f17e9a70) +- [Dev Deps] add missing peer dep [`52337a5`](https://github.com/inspect-js/has-symbols/commit/52337a5621cced61f846f2afdab7707a8132cc12) + ## [v1.0.3](https://github.com/inspect-js/has-symbols/compare/v1.0.2...v1.0.3) - 2022-03-01 ### Commits diff --git a/backend/node_modules/has-symbols/index.js b/backend/node_modules/has-symbols/index.js index 17044fa..fa65265 100644 --- a/backend/node_modules/has-symbols/index.js +++ b/backend/node_modules/has-symbols/index.js @@ -3,6 +3,7 @@ var origSymbol = typeof Symbol !== 'undefined' && Symbol; var hasSymbolSham = require('./shams'); +/** @type {import('.')} */ module.exports = function hasNativeSymbols() { if (typeof origSymbol !== 'function') { return false; } if (typeof Symbol !== 'function') { return false; } diff --git a/backend/node_modules/has-symbols/package.json b/backend/node_modules/has-symbols/package.json index fe7004a..d835e20 100644 --- a/backend/node_modules/has-symbols/package.json +++ b/backend/node_modules/has-symbols/package.json @@ -1,21 +1,23 @@ { "name": "has-symbols", - "version": "1.0.3", + "version": "1.1.0", "description": "Determine if the JS environment has Symbol support. Supports spec, or shams.", "main": "index.js", "scripts": { + "prepack": "npmignore --auto --commentLines=autogenerated", "prepublishOnly": "safe-publish-latest", "prepublish": "not-in-publish || npm run prepublishOnly", "pretest": "npm run --silent lint", "test": "npm run tests-only", - "posttest": "aud --production", - "tests-only": "npm run test:stock && npm run test:staging && npm run test:shams", + "posttest": "npx npm@'>=10.2' audit --production", + "tests-only": "npm run test:stock && npm run test:shams", "test:stock": "nyc node test", "test:staging": "nyc node --harmony --es-staging test", "test:shams": "npm run --silent test:shams:getownpropertysymbols && npm run --silent test:shams:corejs", "test:shams:corejs": "nyc node test/shams/core-js.js", "test:shams:getownpropertysymbols": "nyc node test/shams/get-own-property-symbols.js", "lint": "eslint --ext=js,mjs .", + "postlint": "tsc -p . && attw -P", "version": "auto-changelog && git add CHANGELOG.md", "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" }, @@ -54,15 +56,22 @@ }, "homepage": "https://github.com/ljharb/has-symbols#readme", "devDependencies": { - "@ljharb/eslint-config": "^20.2.3", - "aud": "^2.0.0", - "auto-changelog": "^2.4.0", + "@arethetypeswrong/cli": "^0.17.0", + "@ljharb/eslint-config": "^21.1.1", + "@ljharb/tsconfig": "^0.2.0", + "@types/core-js": "^2.5.8", + "@types/tape": "^5.6.5", + "auto-changelog": "^2.5.0", "core-js": "^2.6.12", + "encoding": "^0.1.13", "eslint": "=8.8.0", "get-own-property-symbols": "^0.9.5", + "in-publish": "^2.0.1", + "npmignore": "^0.3.1", "nyc": "^10.3.2", "safe-publish-latest": "^2.0.0", - "tape": "^5.5.2" + "tape": "^5.9.0", + "typescript": "next" }, "testling": { "files": "test/index.js", @@ -93,9 +102,10 @@ "backfillLimit": false, "hideCredit": true }, - "greenkeeper": { + "publishConfig": { "ignore": [ - "core-js" + ".github/workflows", + "types" ] } } diff --git a/backend/node_modules/has-symbols/shams.js b/backend/node_modules/has-symbols/shams.js index 1285210..f97b474 100644 --- a/backend/node_modules/has-symbols/shams.js +++ b/backend/node_modules/has-symbols/shams.js @@ -1,10 +1,12 @@ 'use strict'; +/** @type {import('./shams')} */ /* eslint complexity: [2, 18], max-statements: [2, 33] */ module.exports = function hasSymbols() { if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } if (typeof Symbol.iterator === 'symbol') { return true; } + /** @type {{ [k in symbol]?: unknown }} */ var obj = {}; var sym = Symbol('test'); var symObj = Object(sym); @@ -23,7 +25,7 @@ module.exports = function hasSymbols() { var symVal = 42; obj[sym] = symVal; - for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop + for (var _ in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } @@ -34,7 +36,8 @@ module.exports = function hasSymbols() { if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } if (typeof Object.getOwnPropertyDescriptor === 'function') { - var descriptor = Object.getOwnPropertyDescriptor(obj, sym); + // eslint-disable-next-line no-extra-parens + var descriptor = /** @type {PropertyDescriptor} */ (Object.getOwnPropertyDescriptor(obj, sym)); if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } } diff --git a/backend/node_modules/has-symbols/test/shams/core-js.js b/backend/node_modules/has-symbols/test/shams/core-js.js index df5365c..1a29024 100644 --- a/backend/node_modules/has-symbols/test/shams/core-js.js +++ b/backend/node_modules/has-symbols/test/shams/core-js.js @@ -8,6 +8,7 @@ if (typeof Symbol === 'function' && typeof Symbol() === 'symbol') { t.equal(typeof Symbol(), 'symbol'); t.end(); }); + // @ts-expect-error TS is stupid and doesn't know about top level return return; } diff --git a/backend/node_modules/has-symbols/test/shams/get-own-property-symbols.js b/backend/node_modules/has-symbols/test/shams/get-own-property-symbols.js index 9191b24..e0296f8 100644 --- a/backend/node_modules/has-symbols/test/shams/get-own-property-symbols.js +++ b/backend/node_modules/has-symbols/test/shams/get-own-property-symbols.js @@ -8,6 +8,7 @@ if (typeof Symbol === 'function' && typeof Symbol() === 'symbol') { t.equal(typeof Symbol(), 'symbol'); t.end(); }); + // @ts-expect-error TS is stupid and doesn't know about top level return return; } diff --git a/backend/node_modules/has-symbols/test/tests.js b/backend/node_modules/has-symbols/test/tests.js index 89edd12..66a2cb8 100644 --- a/backend/node_modules/has-symbols/test/tests.js +++ b/backend/node_modules/has-symbols/test/tests.js @@ -1,5 +1,6 @@ 'use strict'; +/** @type {(t: import('tape').Test) => false | void} */ // eslint-disable-next-line consistent-return module.exports = function runSymbolTests(t) { t.equal(typeof Symbol, 'function', 'global Symbol is a function'); @@ -31,6 +32,7 @@ module.exports = function runSymbolTests(t) { t.equal(typeof Object.getOwnPropertySymbols, 'function', 'Object.getOwnPropertySymbols is a function'); + /** @type {{ [k in symbol]?: unknown }} */ var obj = {}; var sym = Symbol('test'); var symObj = Object(sym); @@ -40,8 +42,8 @@ module.exports = function runSymbolTests(t) { var symVal = 42; obj[sym] = symVal; - // eslint-disable-next-line no-restricted-syntax - for (sym in obj) { t.fail('symbol property key was found in for..in of object'); } + // eslint-disable-next-line no-restricted-syntax, no-unused-vars + for (var _ in obj) { t.fail('symbol property key was found in for..in of object'); } t.deepEqual(Object.keys(obj), [], 'no enumerable own keys on symbol-valued object'); t.deepEqual(Object.getOwnPropertyNames(obj), [], 'no own names on symbol-valued object'); diff --git a/backend/package-lock.json b/backend/package-lock.json index 57be75b..622f34b 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -10,10 +10,12 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { + "axios": "^1.12.2", "bcrypt": "^5.1.1", "cors": "^2.8.5", "crypto": "^1.0.1", "csv-parser": "^3.0.0", + "date-fns": "^2.30.0", "dotenv": "^16.4.5", "express": "^4.19.2", "iconv-lite": "^0.6.3", @@ -30,6 +32,15 @@ "vue-eslint-parser": "9.4.3" } }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emnapi/runtime": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", @@ -820,6 +831,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/aws-ssl-profiles": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", @@ -828,6 +845,17 @@ "node": ">= 6.0.0" } }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -965,6 +993,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1094,6 +1135,18 @@ "color-support": "bin.js" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1237,6 +1290,22 @@ "node": ">= 10" } }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1269,6 +1338,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1325,6 +1403,20 @@ "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==" }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1352,13 +1444,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -1372,6 +1461,33 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1762,6 +1878,42 @@ "dev": true, "peer": true }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1858,16 +2010,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1876,6 +2033,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1922,12 +2092,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1954,10 +2124,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -1966,11 +2136,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -2414,6 +2587,15 @@ "semver": "bin/semver.js" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2981,6 +3163,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", diff --git a/backend/package.json b/backend/package.json index a767177..d8d7371 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,6 +14,7 @@ "license": "ISC", "description": "", "dependencies": { + "axios": "^1.12.2", "bcrypt": "^5.1.1", "cors": "^2.8.5", "crypto": "^1.0.1", diff --git a/backend/routes/memberRoutes.js b/backend/routes/memberRoutes.js index 436e830..3b3b8ab 100644 --- a/backend/routes/memberRoutes.js +++ b/backend/routes/memberRoutes.js @@ -1,4 +1,4 @@ -import { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage } from '../controllers/memberController.js'; +import { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis } from '../controllers/memberController.js'; import express from 'express'; import { authenticate } from '../middleware/authMiddleware.js'; import multer from 'multer'; @@ -13,5 +13,6 @@ router.get('/image/:clubId/:memberId', authenticate, getMemberImage); router.get('/get/:id/:showAll', authenticate, getClubMembers); router.post('/set/:id', authenticate, setClubMembers); router.get('/notapproved/:id', authenticate, getWaitingApprovals); +router.post('/update-ratings/:id', authenticate, updateRatingsFromMyTischtennis); export default router; diff --git a/backend/routes/myTischtennisRoutes.js b/backend/routes/myTischtennisRoutes.js new file mode 100644 index 0000000..2a3c668 --- /dev/null +++ b/backend/routes/myTischtennisRoutes.js @@ -0,0 +1,29 @@ +import express from 'express'; +import myTischtennisController from '../controllers/myTischtennisController.js'; +import { authenticate } from '../middleware/authMiddleware.js'; + +const router = express.Router(); + +// All routes require authentication +router.use(authenticate); + +// GET /api/mytischtennis/account - Get account +router.get('/account', myTischtennisController.getAccount); + +// GET /api/mytischtennis/status - Check status +router.get('/status', myTischtennisController.getStatus); + +// POST /api/mytischtennis/account - Create or update account +router.post('/account', myTischtennisController.upsertAccount); + +// DELETE /api/mytischtennis/account - Delete account +router.delete('/account', myTischtennisController.deleteAccount); + +// POST /api/mytischtennis/verify - Verify login +router.post('/verify', myTischtennisController.verifyLogin); + +// GET /api/mytischtennis/session - Get stored session +router.get('/session', myTischtennisController.getSession); + +export default router; + diff --git a/backend/server.js b/backend/server.js index 3b61367..62d3d5a 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,7 +8,7 @@ import { DiaryNote, DiaryTag, MemberDiaryTag, DiaryDateTag, DiaryMemberNote, DiaryMemberTag, PredefinedActivity, PredefinedActivityImage, DiaryDateActivity, DiaryMemberActivity, Match, League, Team, Group, GroupActivity, Tournament, TournamentGroup, TournamentMatch, TournamentResult, - TournamentMember, Accident, UserToken, OfficialTournament, OfficialCompetition, OfficialCompetitionMember + TournamentMember, Accident, UserToken, OfficialTournament, OfficialCompetition, OfficialCompetitionMember, MyTischtennis } from './models/index.js'; import authRoutes from './routes/authRoutes.js'; import clubRoutes from './routes/clubRoutes.js'; @@ -33,6 +33,7 @@ import tournamentRoutes from './routes/tournamentRoutes.js'; import accidentRoutes from './routes/accidentRoutes.js'; import trainingStatsRoutes from './routes/trainingStatsRoutes.js'; import officialTournamentRoutes from './routes/officialTournamentRoutes.js'; +import myTischtennisRoutes from './routes/myTischtennisRoutes.js'; const app = express(); const port = process.env.PORT || 3000; @@ -40,7 +41,12 @@ const port = process.env.PORT || 3000; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -app.use(cors()); +app.use(cors({ + origin: true, + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization', 'authcode', 'userid'] +})); app.use(express.json()); // Globale Fehlerbehandlung, damit der Server bei unerwarteten Fehlern nicht hart abstürzt @@ -72,6 +78,7 @@ app.use('/api/tournament', tournamentRoutes); app.use('/api/accident', accidentRoutes); app.use('/api/training-stats', trainingStatsRoutes); app.use('/api/official-tournaments', officialTournamentRoutes); +app.use('/api/mytischtennis', myTischtennisRoutes); app.use(express.static(path.join(__dirname, '../frontend/dist'))); @@ -171,6 +178,7 @@ app.get('*', (req, res) => { await safeSync(TournamentResult); await safeSync(Accident); await safeSync(UserToken); + await safeSync(MyTischtennis); app.listen(port, () => { console.log(`Server is running on http://localhost:${port}`); diff --git a/backend/services/memberService.js b/backend/services/memberService.js index a5b750d..8c66e9b 100644 --- a/backend/services/memberService.js +++ b/backend/services/memberService.js @@ -54,7 +54,7 @@ class MemberService { } async setClubMember(userToken, clubId, memberId, firstName, lastName, street, city, birthdate, phone, email, active = true, testMembership = false, - picsInInternetAllowed = false, gender = 'unknown') { + picsInInternetAllowed = false, gender = 'unknown', ttr = null, qttr = null) { try { console.log('[setClubMembers] - Check access'); await checkAccess(userToken, clubId); @@ -77,6 +77,8 @@ class MemberService { member.testMembership = testMembership; member.picsInInternetAllowed = picsInInternetAllowed; if (gender) member.gender = gender; + if (ttr !== undefined) member.ttr = ttr; + if (qttr !== undefined) member.qttr = qttr; await member.save(); } else { await Member.create({ @@ -92,6 +94,8 @@ class MemberService { testMembership: testMembership, picsInInternetAllowed: picsInInternetAllowed, gender: gender || 'unknown', + ttr: ttr, + qttr: qttr, }); } console.log('[setClubMembers] - return response'); @@ -146,6 +150,189 @@ class MemberService { return { status: 500, error: 'Failed to retrieve image' }; } } + + async updateRatingsFromMyTischtennis(userToken, clubId) { + console.log('[updateRatingsFromMyTischtennis] - Check access'); + await checkAccess(userToken, clubId); + + const user = await getUserByToken(userToken); + console.log('[updateRatingsFromMyTischtennis] - User:', user.id); + + const myTischtennisService = (await import('./myTischtennisService.js')).default; + const myTischtennisClient = (await import('../clients/myTischtennisClient.js')).default; + + try { + // 1. myTischtennis-Session abrufen + console.log('[updateRatingsFromMyTischtennis] - Get session for user', user.id); + const session = await myTischtennisService.getSession(user.id); + console.log('[updateRatingsFromMyTischtennis] - Session retrieved:', { + hasAccessToken: !!session.accessToken, + hasCookie: !!session.cookie, + expiresAt: session.expiresAt + }); + + const account = await myTischtennisService.getAccount(user.id); + console.log('[updateRatingsFromMyTischtennis] - Account data:', { + id: account?.id, + email: account?.email, + clubId: account?.clubId, + clubName: account?.clubName, + fedNickname: account?.fedNickname, + hasSession: !!(account?.accessToken) + }); + + if (!account) { + console.error('[updateRatingsFromMyTischtennis] - No account found!'); + return { + status: 400, + response: { + message: 'Kein myTischtennis-Account gefunden.', + updated: 0, + errors: [], + debug: { userId: user.id } + } + }; + } + + if (!account.clubId || !account.fedNickname) { + console.error('[updateRatingsFromMyTischtennis] - Missing clubId or fedNickname:', { + clubId: account.clubId, + fedNickname: account.fedNickname + }); + return { + status: 400, + response: { + message: 'Club-ID oder Verbandskürzel nicht verfügbar. Bitte einmal einloggen.', + updated: 0, + errors: [], + debug: { + hasClubId: !!account.clubId, + hasFedNickname: !!account.fedNickname, + clubId: account.clubId, + fedNickname: account.fedNickname + } + } + }; + } + + // 2. Rangliste vom Verein abrufen + console.log('[updateRatingsFromMyTischtennis] - Get club rankings', { + clubId: account.clubId, + fedNickname: account.fedNickname, + hasCookie: !!session.cookie + }); + + const rankings = await myTischtennisClient.getClubRankings( + session.cookie, + account.clubId, + account.fedNickname + ); + + console.log('[updateRatingsFromMyTischtennis] - Rankings result:', { + success: rankings.success, + entriesCount: rankings.entries?.length || 0, + error: rankings.error + }); + + if (!rankings.success) { + return { + status: 500, + response: { + message: rankings.error || 'Fehler beim Abrufen der Rangliste', + updated: 0, + errors: [], + debug: { + clubId: account.clubId, + fedNickname: account.fedNickname, + rankingsError: rankings.error + } + } + }; + } + + // 3. Alle Mitglieder des Clubs laden + console.log('[updateRatingsFromMyTischtennis] - Load club members for clubId:', clubId); + const members = await Member.findAll({ where: { clubId } }); + console.log('[updateRatingsFromMyTischtennis] - Found members:', members.length); + + let updated = 0; + const errors = []; + const notFound = []; + const matched = []; + + // 4. Für jedes Mitglied TTR aktualisieren + for (const member of members) { + const firstName = member.firstName; + const lastName = member.lastName; + + // Suche nach Match in rankings entries + const rankingEntry = rankings.entries.find(entry => + entry.firstname.toLowerCase() === firstName.toLowerCase() && + entry.lastname.toLowerCase() === lastName.toLowerCase() + ); + + if (rankingEntry) { + try { + // fedRank ist der TTR-Wert + const oldTtr = member.ttr; + member.ttr = rankingEntry.fedRank; + // TODO: QTTR muss von einem anderen Endpoint geholt werden + await member.save(); + updated++; + matched.push({ + name: `${firstName} ${lastName}`, + oldTtr: oldTtr, + newTtr: rankingEntry.fedRank + }); + console.log(`[updateRatingsFromMyTischtennis] - Updated ${firstName} ${lastName}: TTR ${oldTtr} → ${rankingEntry.fedRank}`); + } catch (error) { + console.error(`[updateRatingsFromMyTischtennis] - Error updating ${firstName} ${lastName}:`, error); + errors.push({ + member: `${firstName} ${lastName}`, + error: error.message + }); + } + } else { + notFound.push(`${firstName} ${lastName}`); + console.log(`[updateRatingsFromMyTischtennis] - Not found in rankings: ${firstName} ${lastName}`); + } + } + + console.log('[updateRatingsFromMyTischtennis] - Update complete'); + console.log(`Updated: ${updated}, Not found: ${notFound.length}, Errors: ${errors.length}`); + + let message = `${updated} Mitglied(er) aktualisiert.`; + if (notFound.length > 0) { + message += ` ${notFound.length} nicht in myTischtennis-Rangliste gefunden.`; + } + if (errors.length > 0) { + message += ` ${errors.length} Fehler beim Speichern.`; + } + + return { + status: 200, + response: { + message: message, + updated: updated, + matched: matched, + notFound: notFound, + errors: errors, + totalEntries: rankings.entries.length, + totalMembers: members.length + } + }; + } catch (error) { + console.error('[updateRatingsFromMyTischtennis] - Error:', error); + return { + status: 500, + response: { + message: error.message || 'Fehler beim Aktualisieren', + updated: 0, + errors: [error.message] + } + }; + } + } } export default new MemberService(); \ No newline at end of file diff --git a/backend/services/myTischtennisService.js b/backend/services/myTischtennisService.js new file mode 100644 index 0000000..ac7c0a9 --- /dev/null +++ b/backend/services/myTischtennisService.js @@ -0,0 +1,256 @@ +import MyTischtennis from '../models/MyTischtennis.js'; +import User from '../models/User.js'; +import myTischtennisClient from '../clients/myTischtennisClient.js'; +import HttpError from '../exceptions/HttpError.js'; + +class MyTischtennisService { + /** + * Get myTischtennis account for user + */ + async getAccount(userId) { + const account = await MyTischtennis.findOne({ + where: { userId }, + attributes: ['id', 'email', 'savePassword', 'lastLoginAttempt', 'lastLoginSuccess', 'expiresAt', 'userData', 'clubId', 'clubName', 'fedNickname', 'createdAt', 'updatedAt'] + }); + return account; + } + + /** + * Create or update myTischtennis account + */ + async upsertAccount(userId, email, password, savePassword, userPassword) { + // Verify user's app password + const user = await User.findByPk(userId); + if (!user) { + throw new HttpError(404, 'Benutzer nicht gefunden'); + } + + let loginResult = null; + + // Wenn ein Passwort gesetzt/geändert wird, App-Passwort verifizieren + if (password) { + const isValidPassword = await user.validatePassword(userPassword); + if (!isValidPassword) { + throw new HttpError(401, 'Ungültiges Passwort'); + } + + // Login-Versuch bei myTischtennis + loginResult = await myTischtennisClient.login(email, password); + if (!loginResult.success) { + throw new HttpError(401, loginResult.error || 'myTischtennis-Login fehlgeschlagen. Bitte überprüfen Sie Ihre Zugangsdaten.'); + } + } + + // Find or create account + let account = await MyTischtennis.findOne({ where: { userId } }); + + const now = new Date(); + + if (account) { + // Update existing + account.email = email; + account.savePassword = savePassword; + + if (password && savePassword) { + account.setPassword(password); + } else if (!savePassword) { + account.encryptedPassword = null; + } + + if (loginResult && loginResult.success) { + account.lastLoginAttempt = now; + account.lastLoginSuccess = now; + account.accessToken = loginResult.accessToken; + account.refreshToken = loginResult.refreshToken; + account.expiresAt = loginResult.expiresAt; + account.cookie = loginResult.cookie; + account.userData = loginResult.user; + + // Hole Club-ID und Federation + console.log('[myTischtennisService] - Getting user profile...'); + const profileResult = await myTischtennisClient.getUserProfile(loginResult.cookie); + console.log('[myTischtennisService] - Profile result:', { + success: profileResult.success, + clubId: profileResult.clubId, + clubName: profileResult.clubName, + fedNickname: profileResult.fedNickname + }); + + if (profileResult.success) { + account.clubId = profileResult.clubId; + account.clubName = profileResult.clubName; + account.fedNickname = profileResult.fedNickname; + console.log('[myTischtennisService] - Updated account with club data'); + } else { + console.error('[myTischtennisService] - Failed to get profile:', profileResult.error); + } + } else if (password) { + account.lastLoginAttempt = now; + } + + await account.save(); + } else { + // Create new + const accountData = { + userId, + email, + savePassword, + lastLoginAttempt: password ? now : null, + lastLoginSuccess: loginResult?.success ? now : null + }; + + if (loginResult && loginResult.success) { + accountData.accessToken = loginResult.accessToken; + accountData.refreshToken = loginResult.refreshToken; + accountData.expiresAt = loginResult.expiresAt; + accountData.cookie = loginResult.cookie; + accountData.userData = loginResult.user; + + // Hole Club-ID + const profileResult = await myTischtennisClient.getUserProfile(loginResult.cookie); + if (profileResult.success) { + accountData.clubId = profileResult.clubId; + accountData.clubName = profileResult.clubName; + } + } + + account = await MyTischtennis.create(accountData); + + if (password && savePassword) { + account.setPassword(password); + await account.save(); + } + } + + return { + id: account.id, + email: account.email, + savePassword: account.savePassword, + lastLoginAttempt: account.lastLoginAttempt, + lastLoginSuccess: account.lastLoginSuccess, + expiresAt: account.expiresAt + }; + } + + /** + * Delete myTischtennis account + */ + async deleteAccount(userId) { + const deleted = await MyTischtennis.destroy({ + where: { userId } + }); + return deleted > 0; + } + + /** + * Verify login with stored or provided credentials + */ + async verifyLogin(userId, providedPassword = null) { + const account = await MyTischtennis.findOne({ where: { userId } }); + + if (!account) { + throw new HttpError(404, 'Kein myTischtennis-Account verknüpft'); + } + + let password = providedPassword; + + // Wenn kein Passwort übergeben wurde, versuche gespeichertes Passwort zu verwenden + if (!password) { + if (!account.savePassword || !account.encryptedPassword) { + throw new HttpError(400, 'Kein Passwort gespeichert. Bitte geben Sie Ihr Passwort ein.'); + } + password = account.getPassword(); + } + + // Login-Versuch + const now = new Date(); + account.lastLoginAttempt = now; + const loginResult = await myTischtennisClient.login(account.email, password); + + if (loginResult.success) { + account.lastLoginSuccess = now; + account.accessToken = loginResult.accessToken; + account.refreshToken = loginResult.refreshToken; + account.expiresAt = loginResult.expiresAt; + account.cookie = loginResult.cookie; + account.userData = loginResult.user; + + // Hole Club-ID und Federation + console.log('[myTischtennisService] - Getting user profile...'); + const profileResult = await myTischtennisClient.getUserProfile(loginResult.cookie); + console.log('[myTischtennisService] - Profile result:', { + success: profileResult.success, + clubId: profileResult.clubId, + clubName: profileResult.clubName, + fedNickname: profileResult.fedNickname + }); + + if (profileResult.success) { + account.clubId = profileResult.clubId; + account.clubName = profileResult.clubName; + account.fedNickname = profileResult.fedNickname; + console.log('[myTischtennisService] - Updated account with club data'); + } else { + console.error('[myTischtennisService] - Failed to get profile:', profileResult.error); + } + + await account.save(); + + return { + success: true, + accessToken: loginResult.accessToken, + refreshToken: loginResult.refreshToken, + expiresAt: loginResult.expiresAt, + user: loginResult.user, + clubId: account.clubId, + clubName: account.clubName + }; + } else { + await account.save(); // Save lastLoginAttempt + throw new HttpError(401, loginResult.error || 'myTischtennis-Login fehlgeschlagen'); + } + } + + /** + * Check if account is configured and ready + */ + async checkAccountStatus(userId) { + const account = await MyTischtennis.findOne({ where: { userId } }); + + return { + exists: !!account, + hasEmail: !!account?.email, + hasPassword: !!(account?.savePassword && account?.encryptedPassword), + hasValidSession: !!account?.accessToken && account?.expiresAt > Date.now() / 1000, + needsConfiguration: !account || !account.email, + needsPassword: !!account && (!account.savePassword || !account.encryptedPassword) + }; + } + + /** + * Get stored session for user (for authenticated API requests) + */ + async getSession(userId) { + const account = await MyTischtennis.findOne({ where: { userId } }); + + if (!account) { + throw new HttpError(404, 'Kein myTischtennis-Account verknüpft'); + } + + // Check if session is valid + if (!account.accessToken || !account.expiresAt || account.expiresAt < Date.now() / 1000) { + throw new HttpError(401, 'Session abgelaufen. Bitte erneut einloggen.'); + } + + return { + accessToken: account.accessToken, + refreshToken: account.refreshToken, + cookie: account.cookie, + expiresAt: account.expiresAt, + userData: account.userData + }; + } +} + +export default new MyTischtennisService(); + diff --git a/backend/services/tournamentService.js b/backend/services/tournamentService.js index 12b1c0b..dc7ffcb 100644 --- a/backend/services/tournamentService.js +++ b/backend/services/tournamentService.js @@ -88,7 +88,7 @@ class TournamentService { include: [{ model: Member, as: 'member', - attributes: ['id', 'firstName', 'lastName'], + attributes: ['id', 'firstName', 'lastName', 'ttr', 'qttr'], }], order: [[{ model: Member, as: 'member' }, 'firstName', 'ASC']] }); diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 6c46f02..2baee48 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -67,6 +67,16 @@ + +