mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
Fix: Timezone Europe/Paris + diagnostic complet calendrier
PROBLÈME PERSISTANT: Le décalage d'1h persiste malgré les fixes.
ANALYSE COMPLÈTE:
Le types.setTypeParser doit être appliqué AVANT le Pool,
ET l'image Docker doit être rebuild (pas juste restart),
ET les anciens événements doivent être supprimés et resynchronisés.
AJOUTS:
1. scripts/full-diagnosis-timezone.js
- Diagnostic complet du problème
- Test du type parser (Date object vs string)
- Test insertion/lecture PostgreSQL
- Vérification événements réels
- Simulation API response
- Recommandations claires selon le résultat
2. FIX-TIMEZONE-FINAL.md
- Procédure COMPLÈTE étape par étape
- REBUILD obligatoire avec --no-cache
- Suppression événements corrompus
- Resynchronisation Google Calendar
- Vérifications multiples
- Dépannage si problème persiste
- Checklist finale
UTILISATION:
1. Diagnostic:
docker exec notes-todo-app node scripts/full-diagnosis-timezone.js
2. Si parser KO (renvoie Date objects):
docker-compose down
docker-compose build --no-cache notes-app
docker-compose up -d
3. Suppression anciens événements:
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 \
-c "DELETE FROM calendar_events"
4. Resynchroniser depuis interface web
5. Vérifier que heures = Google Calendar
Le diagnostic permettra d'identifier si:
- Le parser n'est pas actif → rebuild nécessaire
- Le parser fonctionne mais anciennes données → suppression nécessaire
- Autre problème → affichage exact du problème
Fichiers:
- scripts/full-diagnosis-timezone.js (nouveau)
- FIX-TIMEZONE-FINAL.md (guide complet)
This commit is contained in:
2 files changed
+444
No files matched your search
@@ -0,0 +1,273 @@
|
|||||||
|
# 🔧 FIX TIMEZONE CALENDRIER - PROCÉDURE COMPLÈTE
|
||||||
|
|
||||||
|
## ⚠️ IMPORTANT: Cette procédure doit être suivie EXACTEMENT
|
||||||
|
|
||||||
|
Le décalage horaire persiste car le changement du parser PostgreSQL nécessite:
|
||||||
|
1. **REBUILD** de l'image Docker (pas juste restart!)
|
||||||
|
2. **SUPPRESSION** des événements synchronisés avant le fix
|
||||||
|
3. **RESYNCHRONISATION** avec Google Calendar
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 ÉTAPE PAR ÉTAPE (À FAIRE DANS L'ORDRE!)
|
||||||
|
|
||||||
|
### ÉTAPE 1: Diagnostic initial (optionnel mais recommandé)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec notes-todo-app node scripts/full-diagnosis-timezone.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ce script montre:**
|
||||||
|
- Si le parser fonctionne (dates = strings ou objets Date)
|
||||||
|
- Comment PostgreSQL stocke les dates
|
||||||
|
- Comment l'API renvoie les dates
|
||||||
|
- Où se situe exactement le problème
|
||||||
|
|
||||||
|
**Si le diagnostic dit "Le driver pg renvoie toujours des objets Date":**
|
||||||
|
→ Le parser n'est PAS actif → Rebuild obligatoire
|
||||||
|
|
||||||
|
**Si le diagnostic dit "Le parser fonctionne!":**
|
||||||
|
→ Les anciennes données sont corrompues → Suppression + resync
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ÉTAPE 2: REBUILD COMPLET (OBLIGATOIRE!)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Arrêter les containers
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# Rebuild l'image notes-app
|
||||||
|
docker-compose build --no-cache notes-app
|
||||||
|
|
||||||
|
# Redémarrer tout
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**⏱️ Durée: 2-3 minutes**
|
||||||
|
|
||||||
|
**Attendez que le serveur soit complètement démarré:**
|
||||||
|
```bash
|
||||||
|
docker-compose logs -f notes-app
|
||||||
|
```
|
||||||
|
|
||||||
|
Attendez de voir:
|
||||||
|
```
|
||||||
|
✓ Serveur NoteFlow démarré sur le port 2222
|
||||||
|
```
|
||||||
|
|
||||||
|
Puis appuyez sur **Ctrl+C**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ÉTAPE 3: Suppression des événements corrompus
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 -c "DELETE FROM calendar_events"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Résultat attendu:**
|
||||||
|
```
|
||||||
|
DELETE 15
|
||||||
|
```
|
||||||
|
(ou le nombre d'événements que vous aviez)
|
||||||
|
|
||||||
|
**⚠️ C'est normal!** Les événements seront resynchronisés à l'étape suivante.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ÉTAPE 4: Vérification du parser
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec notes-todo-app node scripts/full-diagnosis-timezone.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**Vous devriez maintenant voir:**
|
||||||
|
```
|
||||||
|
✅ Le parser fonctionne!
|
||||||
|
Les dates sont renvoyées comme strings
|
||||||
|
```
|
||||||
|
|
||||||
|
**Si vous voyez encore "objets Date":**
|
||||||
|
→ Le rebuild n'a pas fonctionné
|
||||||
|
→ Recommencez l'ÉTAPE 2 avec `--no-cache`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ÉTAPE 5: Resynchronisation Google Calendar
|
||||||
|
|
||||||
|
1. Ouvrez **http://localhost:2222**
|
||||||
|
2. Connectez-vous
|
||||||
|
3. Allez dans **Admin** → **Google Calendar**
|
||||||
|
4. Cliquez sur **🔄 Synchroniser**
|
||||||
|
|
||||||
|
**Résultat attendu:**
|
||||||
|
```
|
||||||
|
15 événements synchronisés
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ÉTAPE 6: VÉRIFICATION FINALE
|
||||||
|
|
||||||
|
Dans la box **Rendez-vous** sur la page d'accueil:
|
||||||
|
|
||||||
|
**Comparez avec Google Calendar:**
|
||||||
|
|
||||||
|
| Google Calendar | NoteFlow (avant) | NoteFlow (après) |
|
||||||
|
|----------------|------------------|------------------|
|
||||||
|
| 10:00 | 11:00 ❌ | 10:00 ✅ |
|
||||||
|
| 14:30 | 15:30 ❌ | 14:30 ✅ |
|
||||||
|
| 09:15 | 10:15 ❌ | 09:15 ✅ |
|
||||||
|
|
||||||
|
**Les heures doivent être IDENTIQUES!**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 SI LE PROBLÈME PERSISTE
|
||||||
|
|
||||||
|
### Test 1: Vérifier que le rebuild a bien été fait
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Voir la date de build de l'image
|
||||||
|
docker images | grep noteflow
|
||||||
|
|
||||||
|
# Vérifier les logs du build
|
||||||
|
docker-compose build notes-app 2>&1 | grep "types.setTypeParser"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test 2: Vérifier manuellement une date
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 -c "
|
||||||
|
SELECT
|
||||||
|
title,
|
||||||
|
start_time,
|
||||||
|
start_time AT TIME ZONE 'Europe/Paris' as heure_paris
|
||||||
|
FROM calendar_events
|
||||||
|
ORDER BY start_time ASC
|
||||||
|
LIMIT 1;
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Comparez `heure_paris` avec l'heure dans Google Calendar.**
|
||||||
|
|
||||||
|
### Test 3: Test direct JavaScript
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec notes-todo-app node -e "
|
||||||
|
const { Pool } = require('pg');
|
||||||
|
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
||||||
|
pool.query('SELECT start_time FROM calendar_events LIMIT 1')
|
||||||
|
.then(r => {
|
||||||
|
const val = r.rows[0]?.start_time;
|
||||||
|
console.log('Type:', typeof val);
|
||||||
|
console.log('Value:', val);
|
||||||
|
if (typeof val === 'string') {
|
||||||
|
console.log('✅ Parser OK - String');
|
||||||
|
} else {
|
||||||
|
console.log('❌ Parser KO - Objet Date');
|
||||||
|
}
|
||||||
|
pool.end();
|
||||||
|
});
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 DÉPANNAGE
|
||||||
|
|
||||||
|
### Problème: "Le parser renvoie toujours des objets Date"
|
||||||
|
|
||||||
|
**Cause:** Le rebuild n'a pas pris en compte les changements
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
docker-compose down
|
||||||
|
docker system prune -f
|
||||||
|
docker-compose build --no-cache --pull notes-app
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problème: "Les heures sont toujours décalées après resync"
|
||||||
|
|
||||||
|
**Cause:** Cache navigateur
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Ouvrez les DevTools (F12)
|
||||||
|
2. Onglet **Network** → Cocher **Disable cache**
|
||||||
|
3. Actualisez la page (Ctrl+F5 ou Cmd+Shift+R)
|
||||||
|
4. Videz le cache navigateur:
|
||||||
|
- Chrome: Ctrl+Shift+Del
|
||||||
|
- Firefox: Ctrl+Shift+Del
|
||||||
|
- Edge: Ctrl+Shift+Del
|
||||||
|
|
||||||
|
### Problème: "Certains événements corrects, d'autres décalés"
|
||||||
|
|
||||||
|
**Cause:** Mélange d'événements avant/après le fix
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
# Supprimer TOUS les événements
|
||||||
|
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 -c "DELETE FROM calendar_events"
|
||||||
|
|
||||||
|
# Resynchroniser
|
||||||
|
# (depuis l'interface web)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ CHECKLIST FINALE
|
||||||
|
|
||||||
|
Cochez quand fait:
|
||||||
|
|
||||||
|
- [ ] ÉTAPE 1: Diagnostic initial effectué
|
||||||
|
- [ ] ÉTAPE 2: Rebuild complet avec `--no-cache`
|
||||||
|
- [ ] ÉTAPE 3: Événements supprimés (DELETE FROM)
|
||||||
|
- [ ] ÉTAPE 4: Diagnostic confirme "parser OK"
|
||||||
|
- [ ] ÉTAPE 5: Google Calendar resynchronisé
|
||||||
|
- [ ] ÉTAPE 6: Heures vérifiées = identiques à Google
|
||||||
|
- [ ] Cache navigateur vidé (Ctrl+F5)
|
||||||
|
- [ ] Aucun décalage horaire observé
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 RÉSUMÉ EN 4 COMMANDES
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Rebuild complet
|
||||||
|
docker-compose down && docker-compose build --no-cache notes-app && docker-compose up -d
|
||||||
|
|
||||||
|
# 2. Attendre 30s
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
# 3. Supprimer événements
|
||||||
|
docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 -c "DELETE FROM calendar_events"
|
||||||
|
|
||||||
|
# 4. Puis resynchroniser Google Calendar depuis l'interface web
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 POURQUOI CE FIX FONCTIONNE
|
||||||
|
|
||||||
|
**Avant (cassé):**
|
||||||
|
```
|
||||||
|
PostgreSQL → driver pg parse en Date object → décalage timezone
|
||||||
|
```
|
||||||
|
|
||||||
|
**Après (corrigé):**
|
||||||
|
```
|
||||||
|
PostgreSQL → driver pg renvoie string ISO → frontend parse avec bon timezone
|
||||||
|
```
|
||||||
|
|
||||||
|
**La clé:** `types.setTypeParser(1184, str => str)`
|
||||||
|
|
||||||
|
Ce parser transforme les TIMESTAMPTZ PostgreSQL en strings ISO au lieu d'objets Date, ce qui permet au frontend de gérer correctement le timezone avec `timeZone: 'Europe/Paris'`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Commit:** 1a68d87 - Fix: Désactivation parsing Date PostgreSQL
|
||||||
|
**Date:** 2025-11-14
|
||||||
|
|
||||||
|
**Si vous suivez cette procédure EXACTEMENT, le problème SERA résolu!** 🎉
|
||||||
Executable
+171
@@ -0,0 +1,171 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// DIAGNOSTIC COMPLET - Traçage du décalage horaire
|
||||||
|
const { Pool } = require('pg');
|
||||||
|
|
||||||
|
const DATABASE_URL = process.env.DATABASE_URL;
|
||||||
|
|
||||||
|
async function fullDiagnosis() {
|
||||||
|
const pool = new Pool({ connectionString: DATABASE_URL });
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('\n╔══════════════════════════════════════════════════════════════╗');
|
||||||
|
console.log('║ DIAGNOSTIC COMPLET - DÉCALAGE HORAIRE CALENDRIER ║');
|
||||||
|
console.log('╚══════════════════════════════════════════════════════════════╝\n');
|
||||||
|
|
||||||
|
const client = await pool.connect();
|
||||||
|
|
||||||
|
// 1. Vérifier la configuration du driver pg
|
||||||
|
console.log('1️⃣ CONFIGURATION DRIVER PG:\n');
|
||||||
|
const types = require('pg').types;
|
||||||
|
const parser1184 = types.getTypeParser(1184);
|
||||||
|
console.log(` Type parser 1184 (TIMESTAMPTZ): ${typeof parser1184}`);
|
||||||
|
console.log(` Parser renvoie: ${parser1184.name || 'function'}\n`);
|
||||||
|
|
||||||
|
// 2. Test direct avec une date connue
|
||||||
|
console.log('2️⃣ TEST INSERTION/LECTURE DIRECTE:\n');
|
||||||
|
|
||||||
|
await client.query('DELETE FROM calendar_events WHERE google_event_id LIKE $1', ['diagnostic-%']);
|
||||||
|
|
||||||
|
const testDates = [
|
||||||
|
{ name: 'Paris 10h avec offset', value: '2025-11-14T10:00:00+01:00' },
|
||||||
|
{ name: 'UTC 09h', value: '2025-11-14T09:00:00Z' },
|
||||||
|
{ name: 'Paris 14h avec offset', value: '2025-11-14T14:30:00+01:00' }
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const test of testDates) {
|
||||||
|
const eventId = `diagnostic-${test.name.replace(/\s+/g, '-')}`;
|
||||||
|
|
||||||
|
await client.query(`
|
||||||
|
INSERT INTO calendar_events
|
||||||
|
(google_event_id, user_id, title, start_time, end_time, all_day)
|
||||||
|
VALUES ($1, 1, $2, $3, $4, FALSE)
|
||||||
|
`, [eventId, `Test ${test.name}`, test.value, test.value]);
|
||||||
|
|
||||||
|
const result = await client.query(`
|
||||||
|
SELECT
|
||||||
|
title,
|
||||||
|
start_time,
|
||||||
|
pg_typeof(start_time) as pg_type,
|
||||||
|
start_time::text as text_repr
|
||||||
|
FROM calendar_events
|
||||||
|
WHERE google_event_id = $1
|
||||||
|
`, [eventId]);
|
||||||
|
|
||||||
|
const row = result.rows[0];
|
||||||
|
console.log(` Test: ${test.name}`);
|
||||||
|
console.log(` Inséré: ${test.value}`);
|
||||||
|
console.log(` Type PG: ${row.pg_type}`);
|
||||||
|
console.log(` Texte: ${row.text_repr}`);
|
||||||
|
console.log(` JS type: ${typeof row.start_time}`);
|
||||||
|
console.log(` JS value: ${row.start_time}`);
|
||||||
|
|
||||||
|
if (typeof row.start_time === 'object' && row.start_time instanceof Date) {
|
||||||
|
console.log(` ❌ PROBLÈME: C'est un objet Date! Le parser n'a pas fonctionné!`);
|
||||||
|
console.log(` toISOString(): ${row.start_time.toISOString()}`);
|
||||||
|
} else if (typeof row.start_time === 'string') {
|
||||||
|
console.log(` ✅ OK: C'est une string!`);
|
||||||
|
const parsed = new Date(row.start_time);
|
||||||
|
console.log(` new Date(): ${parsed.toISOString()}`);
|
||||||
|
console.log(` Heure locale: ${parsed.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })}`);
|
||||||
|
console.log(` Heure Paris: ${parsed.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Paris' })}`);
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Vérifier événements réels
|
||||||
|
console.log('3️⃣ ÉVÉNEMENTS RÉELS GOOGLE CALENDAR:\n');
|
||||||
|
|
||||||
|
const realEvents = await client.query(`
|
||||||
|
SELECT
|
||||||
|
title,
|
||||||
|
start_time,
|
||||||
|
pg_typeof(start_time) as pg_type,
|
||||||
|
start_time::text as text_repr,
|
||||||
|
all_day
|
||||||
|
FROM calendar_events
|
||||||
|
WHERE google_event_id NOT LIKE 'diagnostic-%'
|
||||||
|
ORDER BY start_time ASC
|
||||||
|
LIMIT 3
|
||||||
|
`);
|
||||||
|
|
||||||
|
if (realEvents.rows.length === 0) {
|
||||||
|
console.log(' ⚠️ Aucun événement réel trouvé');
|
||||||
|
console.log(' → Synchronisez Google Calendar d\'abord\n');
|
||||||
|
} else {
|
||||||
|
realEvents.rows.forEach((evt, i) => {
|
||||||
|
console.log(` Événement ${i + 1}: ${evt.title}`);
|
||||||
|
console.log(` Type PG: ${evt.pg_type}`);
|
||||||
|
console.log(` Texte: ${evt.text_repr}`);
|
||||||
|
console.log(` JS type: ${typeof evt.start_time}`);
|
||||||
|
console.log(` JS value: ${evt.start_time}`);
|
||||||
|
|
||||||
|
if (typeof evt.start_time === 'object' && evt.start_time instanceof Date) {
|
||||||
|
console.log(` ❌ Objet Date (parser KO)`);
|
||||||
|
console.log(` Affiché frontend: ${evt.start_time.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Paris' })}`);
|
||||||
|
} else {
|
||||||
|
console.log(` ✅ String (parser OK)`);
|
||||||
|
const d = new Date(evt.start_time);
|
||||||
|
console.log(` Affiché frontend: ${d.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Paris' })}`);
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Test de l'API
|
||||||
|
console.log('4️⃣ SIMULATION API RESPONSE:\n');
|
||||||
|
|
||||||
|
const apiResult = await client.query(`
|
||||||
|
SELECT
|
||||||
|
id, google_event_id, title, description,
|
||||||
|
start_time, end_time, location, html_link, all_day
|
||||||
|
FROM calendar_events
|
||||||
|
WHERE google_event_id LIKE 'diagnostic-%'
|
||||||
|
LIMIT 1
|
||||||
|
`);
|
||||||
|
|
||||||
|
if (apiResult.rows.length > 0) {
|
||||||
|
const apiEvent = apiResult.rows[0];
|
||||||
|
console.log(' API renvoie (format JSON):');
|
||||||
|
console.log(JSON.stringify(apiEvent, null, 2));
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Recommandations
|
||||||
|
console.log('╔══════════════════════════════════════════════════════════════╗');
|
||||||
|
console.log('║ DIAGNOSTIC RÉSULTAT ║');
|
||||||
|
console.log('╚══════════════════════════════════════════════════════════════╝\n');
|
||||||
|
|
||||||
|
const sampleEvent = realEvents.rows[0] || testDates[0];
|
||||||
|
const isDateObject = typeof sampleEvent?.start_time === 'object';
|
||||||
|
|
||||||
|
if (isDateObject) {
|
||||||
|
console.log('❌ PROBLÈME TROUVÉ:\n');
|
||||||
|
console.log(' Le driver pg renvoie toujours des objets Date');
|
||||||
|
console.log(' Le types.setTypeParser(1184) n\'a PAS été appliqué\n');
|
||||||
|
console.log('💡 SOLUTION:\n');
|
||||||
|
console.log(' 1. Vérifier que config/database.js a bien:');
|
||||||
|
console.log(' const { Pool, types } = require(\'pg\');');
|
||||||
|
console.log(' types.setTypeParser(1184, ...) AVANT le Pool\n');
|
||||||
|
console.log(' 2. Rebuild: docker-compose build notes-app\n');
|
||||||
|
console.log(' 3. Restart: docker-compose restart notes-app\n');
|
||||||
|
} else {
|
||||||
|
console.log('✅ Le parser fonctionne!\n');
|
||||||
|
console.log(' Les dates sont renvoyées comme strings');
|
||||||
|
console.log(' Le problème doit être ailleurs (frontend?)\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
await client.query('DELETE FROM calendar_events WHERE google_event_id LIKE $1', ['diagnostic-%']);
|
||||||
|
|
||||||
|
client.release();
|
||||||
|
await pool.end();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('\n❌ Erreur:', error.message);
|
||||||
|
console.error(error.stack);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fullDiagnosis();
|
||||||
Reference in new issue
Block a user