Update
This commit is contained in:
285
scripts/enhanced_player_notifications.js
Normal file
285
scripts/enhanced_player_notifications.js
Normal file
@@ -0,0 +1,285 @@
|
||||
const { Pool } = require('pg');
|
||||
const webpush = require('web-push');
|
||||
|
||||
// Database connection
|
||||
const pool = new Pool({
|
||||
user: process.env.DB_USER || 'postgres',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
database: process.env.DB_NAME || 'ninjacross',
|
||||
password: process.env.DB_PASSWORD || 'postgres',
|
||||
port: process.env.DB_PORT || 5432,
|
||||
});
|
||||
|
||||
// VAPID keys (same as push-service.js)
|
||||
const vapidKeys = {
|
||||
publicKey: 'BJmNVx0C3XeVxeKGTP9c-Z4HcuZNmdk6QdiLocZgCmb-miCS0ESFO3W2TvJlRhhNAShV63pWA5p36BTVSetyTds',
|
||||
privateKey: 'HBdRCtmZUAzsWpVjZ2LDaoWliIPHldAb5ExAt8bvDeg'
|
||||
};
|
||||
|
||||
webpush.setVapidDetails(
|
||||
'mailto:admin@ninjacross.com',
|
||||
vapidKeys.publicKey,
|
||||
vapidKeys.privateKey
|
||||
);
|
||||
|
||||
/**
|
||||
* Send push notification to a specific player
|
||||
*/
|
||||
async function sendPushToPlayer(playerId, title, message, data = {}) {
|
||||
try {
|
||||
console.log(`📱 Sending push to player ${playerId}: ${title}`);
|
||||
|
||||
const result = await pool.query(`
|
||||
SELECT endpoint, p256dh, auth
|
||||
FROM player_subscriptions
|
||||
WHERE player_id = $1
|
||||
`, [playerId]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
console.log(`❌ No subscription found for player ${playerId}`);
|
||||
return { success: false, reason: 'No subscription' };
|
||||
}
|
||||
|
||||
// Send to all subscriptions for this player
|
||||
const results = [];
|
||||
for (const row of result.rows) {
|
||||
const subscription = {
|
||||
endpoint: row.endpoint,
|
||||
keys: {
|
||||
p256dh: row.p256dh,
|
||||
auth: row.auth
|
||||
}
|
||||
};
|
||||
|
||||
const payload = JSON.stringify({
|
||||
title: title,
|
||||
body: message,
|
||||
icon: '/pictures/favicon.ico',
|
||||
badge: '/pictures/favicon.ico',
|
||||
data: {
|
||||
url: '/dashboard.html',
|
||||
timestamp: Date.now(),
|
||||
...data
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
action: 'view',
|
||||
title: 'Dashboard öffnen'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
try {
|
||||
await webpush.sendNotification(subscription, payload);
|
||||
results.push({ success: true });
|
||||
} catch (error) {
|
||||
console.error(`❌ Error sending to subscription:`, error);
|
||||
results.push({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
const successCount = results.filter(r => r.success).length;
|
||||
console.log(`✅ Push notification sent to ${successCount}/${result.rows.length} subscriptions for player ${playerId}`);
|
||||
|
||||
return {
|
||||
success: successCount > 0,
|
||||
sent: successCount,
|
||||
total: result.rows.length
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Error sending push to player ${playerId}:`, error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send achievement notification to player
|
||||
*/
|
||||
async function sendAchievementNotification(playerId, achievement) {
|
||||
const title = `🏆 ${achievement.name}`;
|
||||
const message = achievement.description;
|
||||
|
||||
return await sendPushToPlayer(playerId, title, message, {
|
||||
type: 'achievement',
|
||||
achievementId: achievement.id,
|
||||
points: achievement.points
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send best time notification to player
|
||||
*/
|
||||
async function sendBestTimeNotification(playerId, timeType, locationName, time) {
|
||||
const title = `🏁 ${timeType} Bestzeit!`;
|
||||
const message = `Du hast die beste Zeit in ${locationName} mit ${time} erreicht!`;
|
||||
|
||||
return await sendPushToPlayer(playerId, title, message, {
|
||||
type: 'best_time',
|
||||
timeType: timeType,
|
||||
location: locationName,
|
||||
time: time
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send daily summary notification to player
|
||||
*/
|
||||
async function sendDailySummaryNotification(playerId, summary) {
|
||||
const title = `📊 Dein Tagesrückblick`;
|
||||
const message = `Du hattest ${summary.runs} Läufe heute. Beste Zeit: ${summary.bestTime}`;
|
||||
|
||||
return await sendPushToPlayer(playerId, title, message, {
|
||||
type: 'daily_summary',
|
||||
runs: summary.runs,
|
||||
bestTime: summary.bestTime
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send weekly summary notification to player
|
||||
*/
|
||||
async function sendWeeklySummaryNotification(playerId, summary) {
|
||||
const title = `📈 Deine Wochenzusammenfassung`;
|
||||
const message = `Diese Woche: ${summary.runs} Läufe, ${summary.improvement}% Verbesserung!`;
|
||||
|
||||
return await sendPushToPlayer(playerId, title, message, {
|
||||
type: 'weekly_summary',
|
||||
runs: summary.runs,
|
||||
improvement: summary.improvement
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notification to all logged in players
|
||||
*/
|
||||
async function sendNotificationToAllPlayers(title, message, data = {}) {
|
||||
try {
|
||||
console.log(`📢 Sending notification to all players: ${title}`);
|
||||
|
||||
const result = await pool.query(`
|
||||
SELECT ps.player_id, ps.endpoint, ps.p256dh, ps.auth, p.firstname, p.lastname
|
||||
FROM player_subscriptions ps
|
||||
JOIN players p ON ps.player_id = p.id
|
||||
WHERE ps.player_id IS NOT NULL
|
||||
`);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
console.log('❌ No player subscriptions found');
|
||||
return { success: false, reason: 'No subscriptions' };
|
||||
}
|
||||
|
||||
const promises = result.rows.map(async (row) => {
|
||||
const subscription = {
|
||||
endpoint: row.endpoint,
|
||||
keys: {
|
||||
p256dh: row.p256dh,
|
||||
auth: row.auth
|
||||
}
|
||||
};
|
||||
|
||||
const payload = JSON.stringify({
|
||||
title: title,
|
||||
body: message,
|
||||
icon: '/pictures/favicon.ico',
|
||||
badge: '/pictures/favicon.ico',
|
||||
data: {
|
||||
url: '/dashboard.html',
|
||||
timestamp: Date.now(),
|
||||
...data
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await webpush.sendNotification(subscription, payload);
|
||||
return {
|
||||
playerId: row.player_id,
|
||||
playerName: `${row.firstname} ${row.lastname}`,
|
||||
success: true
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`❌ Error sending to player ${row.player_id}:`, error);
|
||||
return {
|
||||
playerId: row.player_id,
|
||||
playerName: `${row.firstname} ${row.lastname}`,
|
||||
success: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
const successCount = results.filter(r => r.success).length;
|
||||
|
||||
console.log(`✅ Sent notifications to ${successCount}/${results.length} players`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
sent: successCount,
|
||||
total: results.length,
|
||||
results: results
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error sending notifications to all players:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get player statistics for notifications
|
||||
*/
|
||||
async function getPlayerStats(playerId) {
|
||||
try {
|
||||
const result = await pool.query(`
|
||||
SELECT
|
||||
p.firstname,
|
||||
p.lastname,
|
||||
COUNT(t.id) as total_runs,
|
||||
MIN(t.recorded_time) as best_time,
|
||||
COUNT(DISTINCT t.location_id) as locations_visited
|
||||
FROM players p
|
||||
LEFT JOIN times t ON p.id = t.player_id
|
||||
WHERE p.id = $1
|
||||
GROUP BY p.id, p.firstname, p.lastname
|
||||
`, [playerId]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.rows[0];
|
||||
} catch (error) {
|
||||
console.error('Error getting player stats:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if player has push notifications enabled
|
||||
*/
|
||||
async function isPlayerPushEnabled(playerId) {
|
||||
try {
|
||||
const result = await pool.query(`
|
||||
SELECT COUNT(*) as count
|
||||
FROM player_subscriptions
|
||||
WHERE player_id = $1
|
||||
`, [playerId]);
|
||||
|
||||
return result.rows[0].count > 0;
|
||||
} catch (error) {
|
||||
console.error('Error checking push status:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sendPushToPlayer,
|
||||
sendAchievementNotification,
|
||||
sendBestTimeNotification,
|
||||
sendDailySummaryNotification,
|
||||
sendWeeklySummaryNotification,
|
||||
sendNotificationToAllPlayers,
|
||||
getPlayerStats,
|
||||
isPlayerPushEnabled
|
||||
};
|
||||
Reference in New Issue
Block a user