Notifications, div fixes, kekse für last location
This commit is contained in:
141
scripts/best_time_notifications.js
Normal file
141
scripts/best_time_notifications.js
Normal file
@@ -0,0 +1,141 @@
|
||||
const { Pool } = require('pg');
|
||||
const cron = require('node-cron');
|
||||
|
||||
// Database connection
|
||||
const pool = new Pool({
|
||||
user: 'postgres',
|
||||
host: 'localhost',
|
||||
database: 'ninjacross',
|
||||
password: 'postgres',
|
||||
port: 5432,
|
||||
});
|
||||
|
||||
async function checkAndNotifyBestTimes() {
|
||||
try {
|
||||
console.log('🔔 Checking best times for notifications...');
|
||||
|
||||
const currentDate = new Date();
|
||||
const today = currentDate.toISOString().split('T')[0];
|
||||
const weekStart = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay()));
|
||||
const monthStart = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
|
||||
|
||||
// Check daily best times
|
||||
const dailyBestQuery = `
|
||||
WITH daily_best AS (
|
||||
SELECT
|
||||
t.player_id,
|
||||
MIN(t.recorded_time) as best_time,
|
||||
p.name as player_name,
|
||||
p.email
|
||||
FROM times t
|
||||
JOIN players p ON t.player_id = p.id
|
||||
WHERE DATE(t.created_at AT TIME ZONE 'Europe/Berlin') = $1
|
||||
GROUP BY t.player_id, p.name, p.email
|
||||
),
|
||||
global_daily_best AS (
|
||||
SELECT MIN(best_time) as global_best
|
||||
FROM daily_best
|
||||
)
|
||||
SELECT
|
||||
db.player_id,
|
||||
db.player_name,
|
||||
db.email,
|
||||
db.best_time,
|
||||
gdb.global_best
|
||||
FROM daily_best db
|
||||
CROSS JOIN global_daily_best gdb
|
||||
WHERE db.best_time = gdb.global_best
|
||||
`;
|
||||
|
||||
const dailyResult = await pool.query(dailyBestQuery, [today]);
|
||||
|
||||
for (const row of dailyResult.rows) {
|
||||
console.log(`🏆 Daily best time: ${row.player_name} with ${row.best_time}`);
|
||||
// Here we would send the notification
|
||||
// For now, just log it
|
||||
}
|
||||
|
||||
// Check weekly best times
|
||||
const weeklyBestQuery = `
|
||||
WITH weekly_best AS (
|
||||
SELECT
|
||||
t.player_id,
|
||||
MIN(t.recorded_time) as best_time,
|
||||
p.name as player_name,
|
||||
p.email
|
||||
FROM times t
|
||||
JOIN players p ON t.player_id = p.id
|
||||
WHERE DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $1
|
||||
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $2
|
||||
GROUP BY t.player_id, p.name, p.email
|
||||
),
|
||||
global_weekly_best AS (
|
||||
SELECT MIN(best_time) as global_best
|
||||
FROM weekly_best
|
||||
)
|
||||
SELECT
|
||||
wb.player_id,
|
||||
wb.player_name,
|
||||
wb.email,
|
||||
wb.best_time,
|
||||
gwb.global_best
|
||||
FROM weekly_best wb
|
||||
CROSS JOIN global_weekly_best gwb
|
||||
WHERE wb.best_time = gwb.global_best
|
||||
`;
|
||||
|
||||
const weeklyResult = await pool.query(weeklyBestQuery, [weekStart.toISOString().split('T')[0], today]);
|
||||
|
||||
for (const row of weeklyResult.rows) {
|
||||
console.log(`🏆 Weekly best time: ${row.player_name} with ${row.best_time}`);
|
||||
}
|
||||
|
||||
// Check monthly best times
|
||||
const monthlyBestQuery = `
|
||||
WITH monthly_best AS (
|
||||
SELECT
|
||||
t.player_id,
|
||||
MIN(t.recorded_time) as best_time,
|
||||
p.name as player_name,
|
||||
p.email
|
||||
FROM times t
|
||||
JOIN players p ON t.player_id = p.id
|
||||
WHERE DATE(t.created_at AT TIME ZONE 'Europe/Berlin') >= $1
|
||||
AND DATE(t.created_at AT TIME ZONE 'Europe/Berlin') <= $2
|
||||
GROUP BY t.player_id, p.name, p.email
|
||||
),
|
||||
global_monthly_best AS (
|
||||
SELECT MIN(best_time) as global_best
|
||||
FROM monthly_best
|
||||
)
|
||||
SELECT
|
||||
mb.player_id,
|
||||
mb.player_name,
|
||||
mb.email,
|
||||
mb.best_time,
|
||||
gmb.global_best
|
||||
FROM monthly_best mb
|
||||
CROSS JOIN global_monthly_best gmb
|
||||
WHERE mb.best_time = gmb.global_best
|
||||
`;
|
||||
|
||||
const monthlyResult = await pool.query(monthlyBestQuery, [monthStart.toISOString().split('T')[0], today]);
|
||||
|
||||
for (const row of monthlyResult.rows) {
|
||||
console.log(`🏆 Monthly best time: ${row.player_name} with ${row.best_time}`);
|
||||
}
|
||||
|
||||
console.log('✅ Best time notifications check completed');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error checking best times:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule to run every day at 19:00 (7 PM)
|
||||
cron.schedule('0 19 * * *', () => {
|
||||
console.log('🕐 Running best time notifications check...');
|
||||
checkAndNotifyBestTimes();
|
||||
});
|
||||
|
||||
console.log('📅 Best time notifications scheduler started - runs daily at 19:00');
|
||||
135
scripts/iphone_notifications.js
Normal file
135
scripts/iphone_notifications.js
Normal file
@@ -0,0 +1,135 @@
|
||||
const { Pool } = require('pg');
|
||||
const webpush = require('web-push');
|
||||
|
||||
// Database connection
|
||||
const pool = new Pool({
|
||||
user: 'postgres',
|
||||
host: 'localhost',
|
||||
database: 'ninjacross',
|
||||
password: 'postgres',
|
||||
port: 5432,
|
||||
});
|
||||
|
||||
// VAPID Keys (generate with: webpush.generateVAPIDKeys())
|
||||
const vapidKeys = {
|
||||
publicKey: 'BEl62iUYgUivxIkv69yViEuiBIa40HI6F2B5L4h7Q8Y',
|
||||
privateKey: 'your-private-key-here'
|
||||
};
|
||||
|
||||
webpush.setVapidDetails(
|
||||
'mailto:admin@ninjacross.es',
|
||||
vapidKeys.publicKey,
|
||||
vapidKeys.privateKey
|
||||
);
|
||||
|
||||
// Store subscription endpoint for each player
|
||||
async function storePlayerSubscription(playerId, subscription) {
|
||||
try {
|
||||
await pool.query(`
|
||||
INSERT INTO player_subscriptions (player_id, endpoint, p256dh, auth)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (player_id)
|
||||
DO UPDATE SET
|
||||
endpoint = EXCLUDED.endpoint,
|
||||
p256dh = EXCLUDED.p256dh,
|
||||
auth = EXCLUDED.auth,
|
||||
updated_at = NOW()
|
||||
`, [
|
||||
playerId,
|
||||
subscription.endpoint,
|
||||
subscription.keys.p256dh,
|
||||
subscription.keys.auth
|
||||
]);
|
||||
console.log(`✅ Subscription stored for player ${playerId}`);
|
||||
} catch (error) {
|
||||
console.error('Error storing subscription:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Send push notification to player
|
||||
async function sendPushNotification(playerId, title, message, icon = '🏆') {
|
||||
try {
|
||||
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;
|
||||
}
|
||||
|
||||
const subscription = {
|
||||
endpoint: result.rows[0].endpoint,
|
||||
keys: {
|
||||
p256dh: result.rows[0].p256dh,
|
||||
auth: result.rows[0].auth
|
||||
}
|
||||
};
|
||||
|
||||
const payload = JSON.stringify({
|
||||
title: title,
|
||||
body: message,
|
||||
icon: '/pictures/favicon.ico',
|
||||
badge: '/pictures/favicon.ico',
|
||||
data: {
|
||||
url: '/dashboard.html'
|
||||
}
|
||||
});
|
||||
|
||||
await webpush.sendNotification(subscription, payload);
|
||||
console.log(`✅ Push notification sent to player ${playerId}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error sending push notification:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Send best time notifications
|
||||
async function sendBestTimeNotifications() {
|
||||
try {
|
||||
console.log('🔔 Sending best time notifications...');
|
||||
|
||||
// Get daily best
|
||||
const dailyResult = await pool.query(`
|
||||
WITH daily_best AS (
|
||||
SELECT
|
||||
t.player_id,
|
||||
MIN(t.recorded_time) as best_time,
|
||||
CONCAT(p.firstname, ' ', p.lastname) as player_name
|
||||
FROM times t
|
||||
JOIN players p ON t.player_id = p.id
|
||||
WHERE DATE(t.created_at AT TIME ZONE 'Europe/Berlin') = CURRENT_DATE
|
||||
GROUP BY t.player_id, p.firstname, p.lastname
|
||||
)
|
||||
SELECT
|
||||
player_id,
|
||||
player_name,
|
||||
best_time
|
||||
FROM daily_best
|
||||
WHERE best_time = (SELECT MIN(best_time) FROM daily_best)
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
if (dailyResult.rows.length > 0) {
|
||||
const daily = dailyResult.rows[0];
|
||||
await sendPushNotification(
|
||||
daily.player_id,
|
||||
'🏆 Tageskönig!',
|
||||
`Glückwunsch ${daily.player_name}! Du hast die beste Zeit des Tages mit ${daily.best_time} erreicht!`
|
||||
);
|
||||
}
|
||||
|
||||
console.log('✅ Best time notifications sent');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error sending best time notifications:', error);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
storePlayerSubscription,
|
||||
sendPushNotification,
|
||||
sendBestTimeNotifications
|
||||
};
|
||||
Reference in New Issue
Block a user