droplyvictor89 commited on
Commit
af97c6b
·
verified ·
1 Parent(s): 87e00cf

Upload 4 files

Browse files
Files changed (3) hide show
  1. START_RAPID_v2.1.txt +275 -0
  2. app.py +288 -33
  3. requirements-1.txt +3 -0
START_RAPID_v2.1.txt ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ╔═══════════════════════════════════════════════════════════════╗
2
+ ║ 🚀 DROPLY! v2.1 - START RAPID & DEMO ║
3
+ ╚═══════════════════════════════════════════════════════════════╝
4
+
5
+ 📦 INSTALARE ȘI PORNIRE (3 PAȘI):
6
+
7
+ 1️⃣ pip install -r requirements.txt
8
+ 2️⃣ python app.py
9
+ 3️⃣ Deschide: http://localhost:7860
10
+
11
+ ═══════════════════════════════════════════════════════════════
12
+
13
+ 🔐 CREDENȚIALE ADMIN PRESTABILITE:
14
+
15
+ Email: victor89@admindroply.md
16
+ Parolă: 122012
17
+ ID: admin001
18
+
19
+ ✅ Cont creat automat la prima pornire
20
+ ✅ Acces complet la toate funcțiile
21
+
22
+ ═══════════════════════════════════════════════════════════════
23
+
24
+ 🎯 DEMO RAPID - TESTARE FUNCȚIONALITĂȚI:
25
+
26
+ 📝 CREEAZĂ CONT NOU:
27
+ 1. Click "Generează Cont"
28
+ 2. Username: test1
29
+ 3. Parolă: 123456
30
+ 4. Primești: test1@droply.md + ID unic
31
+
32
+ 🔒 AUTO-LOGIN:
33
+ 1. Login cu contul creat
34
+ 2. Închide browser-ul
35
+ 3. Redeschide aplicația
36
+ 4. ✨ Ești automat logat!
37
+
38
+ 📧 TESTEAZĂ INBOX:
39
+ 1. Login ca admin (victor89@admindroply.md)
40
+ 2. Mergi la "Trimite"
41
+ 3. ID Destinatar: (ID-ul contului test1)
42
+ 4. Scrie mesaj + atașează fișier
43
+ 5. Trimite
44
+ 6. Login ca test1
45
+ 7. ✨ Vezi mesajul în Inbox!
46
+ 8. Click pe mesaj → Pop-up detaliat
47
+ 9. Click 🗑️ → Șterge mesaj
48
+
49
+ 💬 TESTEAZĂ GRUP:
50
+ 1. Login ca test1 (non-membru)
51
+ 2. Mergi la "Grup"
52
+ 3. Vezi mesajele dar nu poți trimite
53
+ 4. Click "Cere Invitație"
54
+ 5. Login ca admin
55
+ 6. Mergi la "Admin Panel"
56
+ 7. Vezi cererea în "Cereri Invitații Grup"
57
+ 8. Click "✅ Aprobă"
58
+ 9. Login înapoi ca test1
59
+ 10. ✨ Acum poți trimite în grup!
60
+
61
+ 🔧 TESTEAZĂ ADMIN PANEL (doar admin):
62
+ 1. Login ca victor89@admindroply.md
63
+ 2. Mergi la "Admin Panel" (apare în sidebar)
64
+ 3. Vezi toți utilizatorii + IP-uri
65
+ 4. Aprobă invitații grup
66
+ 5. ⚠️ ATENȚIE: Nu testa Maintenance Mode dacă vrei să continui!
67
+
68
+ 🚨 TESTEAZĂ MAINTENANCE (OPȚIONAL):
69
+ 1. Login ca admin
70
+ 2. Admin Panel → "ACTIVEAZĂ MENTENANȚĂ"
71
+ 3. Confirmă
72
+ 4. ✨ Banner roșu apare pentru toți
73
+ 5. Countdown 60 secunde
74
+ 6. Server se închide automat
75
+
76
+ ═══════════════════════════════════════════════════════════════
77
+
78
+ ✨ FUNCȚIONALITĂȚI NOI v2.1 - CHECKLIST:
79
+
80
+ ✅ Setări:
81
+ [ ] Resetare parolă - testează în "Setări"
82
+ [ ] Notificări ON/OFF - toggle în "Setări"
83
+ [ ] Server ping - click "Verifică Ping"
84
+
85
+ ✅ Grup:
86
+ [ ] Vizualizare mesaje (toți utilizatorii)
87
+ [ ] Cere invitație (non-membri)
88
+ [ ] Trimite mesaje (doar membri)
89
+ [ ] Șterge mesaje (doar admin)
90
+
91
+ ✅ Inbox:
92
+ [ ] Pop-up detaliat - click pe mesaj
93
+ [ ] Șterge mesaje - buton 🗑️
94
+ [ ] Download fișiere - din pop-up
95
+
96
+ ✅ Trimitere:
97
+ [ ] Simplă (fără cod secret)
98
+ [ ] Raportare bug - buton dedicat
99
+
100
+ ✅ Admin:
101
+ [ ] Vezi utilizatori + IP
102
+ [ ] Aprobă invitații
103
+ [ ] Broadcast warning + shutdown
104
+
105
+ ═══════════════════════════════════════════════════════════════
106
+
107
+ 🔔 TESTARE NOTIFICĂRI:
108
+
109
+ 1. Asigură-te că browser-ul are permisiune pentru notificări
110
+ 2. Login cu cont A
111
+ 3. Deschide în alt browser/tab incognito
112
+ 4. Login cu cont B
113
+ 5. Cont B trimite mesaj către Cont A
114
+ 6. ✨ Cont A primește:
115
+ - Sunet notification.mp3
116
+ - Banner "MESAJ NOU!"
117
+ - Browser notification (dacă tab în fundal)
118
+
119
+ ═══════════════════════════════════════════════════════════════
120
+
121
+ 📱 TESTARE MOBILE:
122
+
123
+ 1. Află IP-ul computerului: ipconfig / ifconfig
124
+ 2. Pe telefon accesează: http://IP_COMPUTER:7860
125
+ 3. Testează toate funcțiile
126
+ 4. Verifică notificări când ecranul e blocat
127
+ 5. Testează Service Worker (funcționare offline)
128
+
129
+ ═══════════════════════════════════════════════════════════════
130
+
131
+ 🐛 DEPANARE RAPIDĂ:
132
+
133
+ ❌ "ModuleNotFoundError: Flask"
134
+ → pip install -r requirements.txt
135
+
136
+ ❌ Port 7860 ocupat
137
+ → Schimbă în app.py, ultima linie: port=8080
138
+
139
+ ❌ Adminul nu apare
140
+ → Șterge droply.db și restart server
141
+
142
+ ❌ Auto-login nu merge
143
+ → localStorage.clear() în browser console
144
+
145
+ ❌ Notificări nu se redau
146
+ → Verifică permisiuni browser (Settings)
147
+
148
+ ❌ Sunetul nu merge
149
+ → Click oriunde pe pagină (browser blochează autoplay)
150
+
151
+ ═══════════════════════════════════════════════════════════════
152
+
153
+ 📊 VERIFICARE POST-INSTALARE:
154
+
155
+ Rulează aceste comenzi pentru verificare:
156
+
157
+ # Verifică Python
158
+ python --version
159
+ # Ar trebui: Python 3.8+
160
+
161
+ # Verifică dependențe
162
+ pip list | grep Flask
163
+ # Ar trebui: Flask 3.0.0
164
+
165
+ # Verifică fișiere
166
+ ls -la
167
+ # Ar trebui să vezi: app.py, index.html, sw.js, logo.png, notification.mp3
168
+
169
+ # Pornește server
170
+ python app.py
171
+ # Ar trebui: "Running on http://0.0.0.0:7860"
172
+
173
+ ═══════════════════════════════════════════════════════════════
174
+
175
+ 🌐 DEPLOY PE HUGGINGFACE:
176
+
177
+ 1. Creează Space nou cu SDK: Docker
178
+ 2. Upload fișierele:
179
+ - app.py
180
+ - index.html
181
+ - sw.js
182
+ - logo.png
183
+ - notification.mp3
184
+ - requirements.txt
185
+ - Dockerfile
186
+ - README_HF.md (redenumește în README.md)
187
+
188
+ 3. Așteaptă build (2-3 min)
189
+ 4. ✨ Gata! Aplicația rulează
190
+
191
+ Pentru detalii: vezi GHID_HUGGINGFACE.txt
192
+
193
+ ═══════════════════════════════════════════════════════════════
194
+
195
+ 💾 BACKUP & RESTORE:
196
+
197
+ Backup Database:
198
+ cp droply.db droply_backup_$(date +%Y%m%d).db
199
+
200
+ Restore Database:
201
+ cp droply_backup_20250206.db droply.db
202
+
203
+ Export Contacte (în browser console):
204
+ console.log(localStorage.getItem('droply_contacts'))
205
+
206
+ ═══════════════════════════════════════════════════════════════
207
+
208
+ 📈 MONITORIZARE:
209
+
210
+ Watch Logs în Timp Real:
211
+ python app.py | tee server.log
212
+
213
+ Verifică Utilizatori Activi:
214
+ sqlite3 droply.db "SELECT email, last_ip FROM users WHERE session_token IS NOT NULL;"
215
+
216
+ Verifică Mesaje Grup:
217
+ sqlite3 droply.db "SELECT COUNT(*) FROM group_messages;"
218
+
219
+ ═══════════════════════════════════════════════════════════════
220
+
221
+ 🎓 TUTORIAL PENTRU UTILIZATORI NOI:
222
+
223
+ 1. ÎNREGISTRARE:
224
+ - Click "Generează Cont"
225
+ - Alege username unic
226
+ - Setează parolă puternică
227
+ - Notează ID-ul primit!
228
+
229
+ 2. PRIMUL MESAJ:
230
+ - Mergi la "Trimite"
231
+ - Introduce ID-ul destinatarului
232
+ - Scrie mesajul
233
+ - Opțional: atașează fișier
234
+ - Click "Trimite"
235
+
236
+ 3. VERIFICĂ INBOX:
237
+ - Mergi la "Inbox"
238
+ - Mesajele se actualizează automat la 0.5s
239
+ - Click pe mesaj pentru detalii
240
+ - Download fișiere dacă există
241
+
242
+ 4. INTRĂ ÎN GRUP:
243
+ - Mergi la "Grup"
244
+ - Vezi mesajele publice
245
+ - Click "Cere Invitație"
246
+ - Așteaptă aprobare admin
247
+ - După aprobare, poți trimite mesaje
248
+
249
+ 5. SETĂRI:
250
+ - Ajustează vizibilitate (public/privat)
251
+ - Activează/Dezactivează notificări
252
+ - Schimbă parola periodic
253
+ - Salvează contacte frecvente
254
+
255
+ ═══════════════════════════════════════════════════════════════
256
+
257
+ ✅ CHECKLIST FINAL ÎNAINTE DE PRODUCȚIE:
258
+
259
+ [ ] Schimbat parola admin de la 122012
260
+ [ ] Verificat toate funcționalitățile
261
+ [ ] Testat pe mobile și desktop
262
+ [ ] Configurat notificările corect
263
+ [ ] Făcut backup la droply.db
264
+ [ ] Citit documentația completă
265
+ [ ] Pregătit plan de mentenanță
266
+ [ ] Setat monitoring (dacă e cazul)
267
+
268
+ ═══════════════════════════════════════════════════════════════
269
+
270
+ 🎉 Gata! DROPLY! v2.1 e complet funcțional!
271
+
272
+ Pentru documentație detaliată: DROPLY_v2.1_CHANGELOG.txt
273
+ Pentru deploy HuggingFace: GHID_HUGGINGFACE.txt
274
+
275
+ Mult succes! 🚀
app.py CHANGED
@@ -7,9 +7,11 @@ import hashlib
7
  import secrets
8
  from datetime import datetime
9
  import sqlite3
 
 
10
 
11
  app = Flask(__name__)
12
- app.secret_key = secrets.token_hex(32) # Secret key pentru sesiuni
13
  CORS(app)
14
 
15
  # Configurări
@@ -17,12 +19,15 @@ UPLOAD_FOLDER = 'uploads'
17
  DATABASE = 'droply.db'
18
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
19
 
 
 
 
20
  # Inițializare baza de date
21
  def init_db():
22
  conn = sqlite3.connect(DATABASE)
23
  c = conn.cursor()
24
 
25
- # Tabelul utilizatori
26
  c.execute('''CREATE TABLE IF NOT EXISTS users (
27
  id TEXT PRIMARY KEY,
28
  username TEXT UNIQUE,
@@ -31,7 +36,11 @@ def init_db():
31
  visibility TEXT DEFAULT 'public',
32
  secret_code TEXT,
33
  sara_ai INTEGER DEFAULT 0,
34
- session_token TEXT
 
 
 
 
35
  )''')
36
 
37
  # Tabelul mesaje inbox
@@ -45,8 +54,27 @@ def init_db():
45
  FOREIGN KEY(recipient_id) REFERENCES users(id)
46
  )''')
47
 
48
- # Tabelul mesaje grup
49
  c.execute('''CREATE TABLE IF NOT EXISTS group_messages (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  id INTEGER PRIMARY KEY AUTOINCREMENT,
51
  user_email TEXT,
52
  content TEXT,
@@ -54,6 +82,19 @@ def init_db():
54
  )''')
55
 
56
  conn.commit()
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  conn.close()
58
 
59
  init_db()
@@ -69,6 +110,12 @@ def hash_password(password):
69
  def generate_user_id(username):
70
  return hashlib.md5((username + secrets.token_hex(8)).encode()).hexdigest()[:12]
71
 
 
 
 
 
 
 
72
  # ===== ROUTES =====
73
 
74
  @app.route('/')
@@ -122,19 +169,19 @@ def login():
122
  data = request.json
123
  email = data.get('email')
124
  password = data.get('password')
 
125
 
126
  db = get_db()
127
  user = db.execute('SELECT * FROM users WHERE email = ? AND password = ?',
128
  (email, hash_password(password))).fetchone()
129
- db.close()
130
 
131
  if user:
132
  # Generăm token de sesiune
133
  session_token = secrets.token_hex(32)
134
 
135
- # Salvăm token-ul în DB
136
- db = get_db()
137
- db.execute('UPDATE users SET session_token = ? WHERE id = ?', (session_token, user['id']))
138
  db.commit()
139
  db.close()
140
 
@@ -149,11 +196,15 @@ def login():
149
  'id': user['id'],
150
  'visibility': user['visibility'],
151
  'secret_code': user['secret_code'],
152
- 'sara_ai': user['sara_ai']
 
 
 
153
  },
154
  'session_token': session_token
155
  })
156
 
 
157
  return jsonify({'success': False})
158
 
159
  @app.route('/api/check_session', methods=['POST'])
@@ -180,7 +231,10 @@ def check_session():
180
  'id': user['id'],
181
  'visibility': user['visibility'],
182
  'secret_code': user['secret_code'],
183
- 'sara_ai': user['sara_ai']
 
 
 
184
  }
185
  })
186
 
@@ -193,9 +247,8 @@ def send_mail():
193
 
194
  recipient_id = request.form.get('destinatar')
195
  message = request.form.get('mesaj')
196
- verification_code = request.form.get('cod_verificare', '')
197
 
198
- # Verificăm dacă destinatarul există și codul secret
199
  db = get_db()
200
  recipient = db.execute('SELECT * FROM users WHERE id = ?', (recipient_id,)).fetchone()
201
 
@@ -203,11 +256,6 @@ def send_mail():
203
  db.close()
204
  return jsonify({'success': False, 'error': 'Destinatar inexistent'})
205
 
206
- # Verificăm vizibilitatea și codul secret
207
- if recipient['visibility'] == 'private' and recipient['secret_code'] != verification_code:
208
- db.close()
209
- return jsonify({'success': False, 'error': 'Cod secret incorect'})
210
-
211
  # Procesăm fișierul dacă există
212
  file_path = None
213
  if 'fisier' in request.files:
@@ -246,6 +294,7 @@ def get_inbox():
246
  result = []
247
  for msg in messages:
248
  result.append({
 
249
  'from': msg['sender_email'],
250
  'content': msg['content'],
251
  'file': msg['file_path'],
@@ -254,20 +303,43 @@ def get_inbox():
254
 
255
  return jsonify(result)
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  @app.route('/api/group/send', methods=['POST'])
258
  def send_group_message():
259
  if 'user_id' not in session:
260
- return jsonify({'success': False})
 
 
 
 
 
 
 
 
261
 
262
  data = request.json
263
  content = data.get('content')
264
 
265
- db = get_db()
266
- user = db.execute('SELECT email FROM users WHERE id = ?', (session['user_id'],)).fetchone()
267
  timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
268
 
269
- db.execute('INSERT INTO group_messages (user_email, content, timestamp) VALUES (?, ?, ?)',
270
- (user['email'], content, timestamp))
271
  db.commit()
272
  db.close()
273
 
@@ -286,13 +358,62 @@ def get_group_messages():
286
  result = []
287
  for msg in messages:
288
  result.append({
 
289
  'user': msg['user_email'],
 
290
  'content': msg['content'],
291
  'timestamp': msg['timestamp']
292
  })
293
 
294
  return jsonify(list(reversed(result)))
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  @app.route('/api/update_settings', methods=['POST'])
297
  def update_settings():
298
  if 'user_id' not in session:
@@ -302,34 +423,168 @@ def update_settings():
302
  visibility = data.get('visibility')
303
  secret_code = data.get('secret_code')
304
  sara_ai = 1 if data.get('sara_ai') else 0
 
305
 
306
  db = get_db()
307
- db.execute('UPDATE users SET visibility = ?, secret_code = ?, sara_ai = ? WHERE id = ?',
308
- (visibility, secret_code, sara_ai, session['user_id']))
309
  db.commit()
310
  db.close()
311
 
312
  return jsonify({'success': True})
313
 
314
- @app.route('/api/admin_activate_email', methods=['POST'])
315
- def admin_activate_email():
 
316
  if 'user_id' not in session:
317
  return jsonify({'success': False})
318
 
319
  data = request.json
320
- admin_code = data.get('code')
321
- new_email = data.get('new_email')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
- # Cod admin hardcodat (poți să-l schimbi)
324
- if admin_code != 'ADMIN2025':
325
- return jsonify({'success': False, 'error': 'Cod admin invalid'})
 
 
 
 
326
 
327
  db = get_db()
328
- db.execute('UPDATE users SET email = ? WHERE id = ?', (new_email, session['user_id']))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  db.commit()
330
  db.close()
331
 
332
  return jsonify({'success': True})
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  if __name__ == '__main__':
335
- app.run(host='0.0.0.0', port=7860, debug=True)
 
 
 
7
  import secrets
8
  from datetime import datetime
9
  import sqlite3
10
+ import threading
11
+ import time
12
 
13
  app = Flask(__name__)
14
+ app.secret_key = secrets.token_hex(32)
15
  CORS(app)
16
 
17
  # Configurări
 
19
  DATABASE = 'droply.db'
20
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
21
 
22
+ # Variabilă globală pentru shutdown
23
+ shutdown_scheduled = False
24
+
25
  # Inițializare baza de date
26
  def init_db():
27
  conn = sqlite3.connect(DATABASE)
28
  c = conn.cursor()
29
 
30
+ # Tabelul utilizatori - ACTUALIZAT cu notif_enabled și is_group_member
31
  c.execute('''CREATE TABLE IF NOT EXISTS users (
32
  id TEXT PRIMARY KEY,
33
  username TEXT UNIQUE,
 
36
  visibility TEXT DEFAULT 'public',
37
  secret_code TEXT,
38
  sara_ai INTEGER DEFAULT 0,
39
+ session_token TEXT,
40
+ notif_enabled INTEGER DEFAULT 1,
41
+ is_admin INTEGER DEFAULT 0,
42
+ is_group_member INTEGER DEFAULT 0,
43
+ last_ip TEXT
44
  )''')
45
 
46
  # Tabelul mesaje inbox
 
54
  FOREIGN KEY(recipient_id) REFERENCES users(id)
55
  )''')
56
 
57
+ # Tabelul mesaje grup - ACTUALIZAT cu mesaj_id pentru ștergere
58
  c.execute('''CREATE TABLE IF NOT EXISTS group_messages (
59
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
60
+ user_email TEXT,
61
+ user_id TEXT,
62
+ content TEXT,
63
+ timestamp TEXT
64
+ )''')
65
+
66
+ # Tabelul invitații grup
67
+ c.execute('''CREATE TABLE IF NOT EXISTS group_invitations (
68
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
69
+ user_id TEXT,
70
+ user_email TEXT,
71
+ status TEXT DEFAULT 'pending',
72
+ timestamp TEXT,
73
+ FOREIGN KEY(user_id) REFERENCES users(id)
74
+ )''')
75
+
76
+ # Tabelul raportări bug
77
+ c.execute('''CREATE TABLE IF NOT EXISTS bug_reports (
78
  id INTEGER PRIMARY KEY AUTOINCREMENT,
79
  user_email TEXT,
80
  content TEXT,
 
82
  )''')
83
 
84
  conn.commit()
85
+
86
+ # Creăm adminul dacă nu există
87
+ admin_exists = c.execute('SELECT * FROM users WHERE email = ?', ('victor89@admindroply.md',)).fetchone()
88
+ if not admin_exists:
89
+ admin_id = 'admin001'
90
+ admin_pass = hash_password('122012')
91
+ c.execute('''INSERT INTO users
92
+ (id, username, password, email, secret_code, is_admin, is_group_member)
93
+ VALUES (?, ?, ?, ?, ?, ?, ?)''',
94
+ (admin_id, 'victor89', admin_pass, 'victor89@admindroply.md', 'ADMIN', 1, 1))
95
+ conn.commit()
96
+ print("✅ Admin creat: victor89@admindroply.md | Parolă: 122012")
97
+
98
  conn.close()
99
 
100
  init_db()
 
110
  def generate_user_id(username):
111
  return hashlib.md5((username + secrets.token_hex(8)).encode()).hexdigest()[:12]
112
 
113
+ def get_client_ip():
114
+ """Obține IP-ul real al clientului"""
115
+ if request.headers.get('X-Forwarded-For'):
116
+ return request.headers.get('X-Forwarded-For').split(',')[0]
117
+ return request.remote_addr
118
+
119
  # ===== ROUTES =====
120
 
121
  @app.route('/')
 
169
  data = request.json
170
  email = data.get('email')
171
  password = data.get('password')
172
+ client_ip = get_client_ip()
173
 
174
  db = get_db()
175
  user = db.execute('SELECT * FROM users WHERE email = ? AND password = ?',
176
  (email, hash_password(password))).fetchone()
 
177
 
178
  if user:
179
  # Generăm token de sesiune
180
  session_token = secrets.token_hex(32)
181
 
182
+ # Salvăm token-ul și IP-ul în DB
183
+ db.execute('UPDATE users SET session_token = ?, last_ip = ? WHERE id = ?',
184
+ (session_token, client_ip, user['id']))
185
  db.commit()
186
  db.close()
187
 
 
196
  'id': user['id'],
197
  'visibility': user['visibility'],
198
  'secret_code': user['secret_code'],
199
+ 'sara_ai': user['sara_ai'],
200
+ 'is_admin': user['is_admin'],
201
+ 'is_group_member': user['is_group_member'],
202
+ 'notif_enabled': user['notif_enabled']
203
  },
204
  'session_token': session_token
205
  })
206
 
207
+ db.close()
208
  return jsonify({'success': False})
209
 
210
  @app.route('/api/check_session', methods=['POST'])
 
231
  'id': user['id'],
232
  'visibility': user['visibility'],
233
  'secret_code': user['secret_code'],
234
+ 'sara_ai': user['sara_ai'],
235
+ 'is_admin': user['is_admin'],
236
+ 'is_group_member': user['is_group_member'],
237
+ 'notif_enabled': user['notif_enabled']
238
  }
239
  })
240
 
 
247
 
248
  recipient_id = request.form.get('destinatar')
249
  message = request.form.get('mesaj')
 
250
 
251
+ # Verificăm dacă destinatarul există
252
  db = get_db()
253
  recipient = db.execute('SELECT * FROM users WHERE id = ?', (recipient_id,)).fetchone()
254
 
 
256
  db.close()
257
  return jsonify({'success': False, 'error': 'Destinatar inexistent'})
258
 
 
 
 
 
 
259
  # Procesăm fișierul dacă există
260
  file_path = None
261
  if 'fisier' in request.files:
 
294
  result = []
295
  for msg in messages:
296
  result.append({
297
+ 'id': msg['id'],
298
  'from': msg['sender_email'],
299
  'content': msg['content'],
300
  'file': msg['file_path'],
 
303
 
304
  return jsonify(result)
305
 
306
+ @app.route('/api/delete_message', methods=['POST'])
307
+ def delete_message():
308
+ """Șterge mesaj din inbox"""
309
+ if 'user_id' not in session:
310
+ return jsonify({'success': False})
311
+
312
+ data = request.json
313
+ msg_id = data.get('message_id')
314
+
315
+ db = get_db()
316
+ db.execute('DELETE FROM messages WHERE id = ? AND recipient_id = ?',
317
+ (msg_id, session['user_id']))
318
+ db.commit()
319
+ db.close()
320
+
321
+ return jsonify({'success': True})
322
+
323
  @app.route('/api/group/send', methods=['POST'])
324
  def send_group_message():
325
  if 'user_id' not in session:
326
+ return jsonify({'success': False, 'error': 'Neautentificat'})
327
+
328
+ # Verificăm dacă user-ul are acces la grup
329
+ db = get_db()
330
+ user = db.execute('SELECT * FROM users WHERE id = ?', (session['user_id'],)).fetchone()
331
+
332
+ if not user['is_group_member']:
333
+ db.close()
334
+ return jsonify({'success': False, 'error': 'Nu ai acces la grup'})
335
 
336
  data = request.json
337
  content = data.get('content')
338
 
 
 
339
  timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
340
 
341
+ db.execute('INSERT INTO group_messages (user_email, user_id, content, timestamp) VALUES (?, ?, ?, ?)',
342
+ (user['email'], user['id'], content, timestamp))
343
  db.commit()
344
  db.close()
345
 
 
358
  result = []
359
  for msg in messages:
360
  result.append({
361
+ 'id': msg['id'],
362
  'user': msg['user_email'],
363
+ 'user_id': msg['user_id'],
364
  'content': msg['content'],
365
  'timestamp': msg['timestamp']
366
  })
367
 
368
  return jsonify(list(reversed(result)))
369
 
370
+ @app.route('/api/group/delete', methods=['POST'])
371
+ def delete_group_message():
372
+ """Șterge mesaj din grup (doar admin)"""
373
+ if 'user_id' not in session:
374
+ return jsonify({'success': False})
375
+
376
+ db = get_db()
377
+ user = db.execute('SELECT is_admin FROM users WHERE id = ?', (session['user_id'],)).fetchone()
378
+
379
+ if not user or not user['is_admin']:
380
+ db.close()
381
+ return jsonify({'success': False, 'error': 'Doar adminul poate șterge'})
382
+
383
+ data = request.json
384
+ msg_id = data.get('message_id')
385
+
386
+ db.execute('DELETE FROM group_messages WHERE id = ?', (msg_id,))
387
+ db.commit()
388
+ db.close()
389
+
390
+ return jsonify({'success': True})
391
+
392
+ @app.route('/api/group/request_invite', methods=['POST'])
393
+ def request_group_invite():
394
+ """Cerere invitație pentru grup"""
395
+ if 'user_id' not in session:
396
+ return jsonify({'success': False})
397
+
398
+ db = get_db()
399
+ user = db.execute('SELECT * FROM users WHERE id = ?', (session['user_id'],)).fetchone()
400
+
401
+ # Verificăm dacă nu are deja cerere pendinte
402
+ existing = db.execute('SELECT * FROM group_invitations WHERE user_id = ? AND status = ?',
403
+ (session['user_id'], 'pending')).fetchone()
404
+
405
+ if existing:
406
+ db.close()
407
+ return jsonify({'success': False, 'error': 'Ai deja o cerere în așteptare'})
408
+
409
+ timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
410
+ db.execute('INSERT INTO group_invitations (user_id, user_email, status, timestamp) VALUES (?, ?, ?, ?)',
411
+ (session['user_id'], user['email'], 'pending', timestamp))
412
+ db.commit()
413
+ db.close()
414
+
415
+ return jsonify({'success': True})
416
+
417
  @app.route('/api/update_settings', methods=['POST'])
418
  def update_settings():
419
  if 'user_id' not in session:
 
423
  visibility = data.get('visibility')
424
  secret_code = data.get('secret_code')
425
  sara_ai = 1 if data.get('sara_ai') else 0
426
+ notif_enabled = 1 if data.get('notif_enabled', True) else 0
427
 
428
  db = get_db()
429
+ db.execute('UPDATE users SET visibility = ?, secret_code = ?, sara_ai = ?, notif_enabled = ? WHERE id = ?',
430
+ (visibility, secret_code, sara_ai, notif_enabled, session['user_id']))
431
  db.commit()
432
  db.close()
433
 
434
  return jsonify({'success': True})
435
 
436
+ @app.route('/api/change_password', methods=['POST'])
437
+ def change_password():
438
+ """Resetare parolă din setări"""
439
  if 'user_id' not in session:
440
  return jsonify({'success': False})
441
 
442
  data = request.json
443
+ old_pass = data.get('old_password')
444
+ new_pass = data.get('new_password')
445
+
446
+ db = get_db()
447
+ user = db.execute('SELECT password FROM users WHERE id = ?', (session['user_id'],)).fetchone()
448
+
449
+ if user['password'] != hash_password(old_pass):
450
+ db.close()
451
+ return jsonify({'success': False, 'error': 'Parola veche incorectă'})
452
+
453
+ db.execute('UPDATE users SET password = ? WHERE id = ?',
454
+ (hash_password(new_pass), session['user_id']))
455
+ db.commit()
456
+ db.close()
457
+
458
+ return jsonify({'success': True})
459
+
460
+ @app.route('/api/server_ping', methods=['GET'])
461
+ def server_ping():
462
+ """Returnează ping-ul serverului"""
463
+ return jsonify({
464
+ 'success': True,
465
+ 'ping': 'OK',
466
+ 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
467
+ })
468
+
469
+ # ===== ADMIN ENDPOINTS =====
470
+
471
+ @app.route('/api/admin/get_users', methods=['GET'])
472
+ def admin_get_users():
473
+ """Lista tuturor utilizatorilor (doar admin)"""
474
+ if 'user_id' not in session:
475
+ return jsonify({'success': False})
476
+
477
+ db = get_db()
478
+ user = db.execute('SELECT is_admin FROM users WHERE id = ?', (session['user_id'],)).fetchone()
479
+
480
+ if not user or not user['is_admin']:
481
+ db.close()
482
+ return jsonify({'success': False, 'error': 'Doar adminul are acces'})
483
+
484
+ users = db.execute('SELECT id, username, email, last_ip FROM users').fetchall()
485
+ db.close()
486
+
487
+ result = []
488
+ for u in users:
489
+ result.append({
490
+ 'id': u['id'],
491
+ 'username': u['username'],
492
+ 'email': u['email'],
493
+ 'ip': u['last_ip'] or 'Unknown'
494
+ })
495
+
496
+ return jsonify({'success': True, 'users': result})
497
+
498
+ @app.route('/api/admin/get_invitations', methods=['GET'])
499
+ def admin_get_invitations():
500
+ """Lista cereri invitații grup (doar admin)"""
501
+ if 'user_id' not in session:
502
+ return jsonify({'success': False})
503
+
504
+ db = get_db()
505
+ user = db.execute('SELECT is_admin FROM users WHERE id = ?', (session['user_id'],)).fetchone()
506
+
507
+ if not user or not user['is_admin']:
508
+ db.close()
509
+ return jsonify({'success': False})
510
+
511
+ invites = db.execute('SELECT * FROM group_invitations WHERE status = ?', ('pending',)).fetchall()
512
+ db.close()
513
+
514
+ result = []
515
+ for inv in invites:
516
+ result.append({
517
+ 'id': inv['id'],
518
+ 'user_id': inv['user_id'],
519
+ 'user_email': inv['user_email'],
520
+ 'timestamp': inv['timestamp']
521
+ })
522
 
523
+ return jsonify({'success': True, 'invitations': result})
524
+
525
+ @app.route('/api/admin/approve_invitation', methods=['POST'])
526
+ def admin_approve_invitation():
527
+ """Aprobă invitație grup (doar admin)"""
528
+ if 'user_id' not in session:
529
+ return jsonify({'success': False})
530
 
531
  db = get_db()
532
+ user = db.execute('SELECT is_admin FROM users WHERE id = ?', (session['user_id'],)).fetchone()
533
+
534
+ if not user or not user['is_admin']:
535
+ db.close()
536
+ return jsonify({'success': False})
537
+
538
+ data = request.json
539
+ invite_id = data.get('invitation_id')
540
+
541
+ # Găsim invitația
542
+ invite = db.execute('SELECT * FROM group_invitations WHERE id = ?', (invite_id,)).fetchone()
543
+
544
+ if not invite:
545
+ db.close()
546
+ return jsonify({'success': False, 'error': 'Invitație inexistentă'})
547
+
548
+ # Actualizăm user-ul
549
+ db.execute('UPDATE users SET is_group_member = 1 WHERE id = ?', (invite['user_id'],))
550
+ db.execute('UPDATE group_invitations SET status = ? WHERE id = ?', ('approved', invite_id))
551
  db.commit()
552
  db.close()
553
 
554
  return jsonify({'success': True})
555
 
556
+ @app.route('/api/admin/broadcast_warning', methods=['POST'])
557
+ def admin_broadcast_warning():
558
+ """Trimite warning către toți utilizatorii și programează shutdown"""
559
+ if 'user_id' not in session:
560
+ return jsonify({'success': False})
561
+
562
+ db = get_db()
563
+ user = db.execute('SELECT is_admin FROM users WHERE id = ?', (session['user_id'],)).fetchone()
564
+ db.close()
565
+
566
+ if not user or not user['is_admin']:
567
+ return jsonify({'success': False, 'error': 'Doar adminul poate trimite warning'})
568
+
569
+ # Programăm shutdown în 60 de secunde
570
+ global shutdown_scheduled
571
+ shutdown_scheduled = True
572
+
573
+ def shutdown_server():
574
+ time.sleep(60)
575
+ print("⚠️ SERVER SHUTDOWN PROGRAMAT DE ADMIN")
576
+ os._exit(0)
577
+
578
+ threading.Thread(target=shutdown_server, daemon=True).start()
579
+
580
+ return jsonify({'success': True, 'message': 'Warning trimis, server se va închide în 60s'})
581
+
582
+ @app.route('/api/check_shutdown', methods=['GET'])
583
+ def check_shutdown():
584
+ """Verifică dacă shutdown-ul e programat"""
585
+ return jsonify({'shutdown_scheduled': shutdown_scheduled})
586
+
587
  if __name__ == '__main__':
588
+ import os
589
+ port = int(os.environ.get('PORT', 7860))
590
+ app.run(host='0.0.0.0', port=port, debug=False)
requirements-1.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ Flask==3.0.0
2
+ Flask-CORS==4.0.0
3
+ Werkzeug==3.0.1