Update app.py
Browse files
app.py
CHANGED
@@ -1,35 +1,654 @@
|
|
1 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
-
|
4 |
-
|
|
|
5 |
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
-
if
|
17 |
-
|
|
|
18 |
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
-
if
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
if __name__ == '__main__':
|
35 |
-
|
|
|
1 |
+
import os
|
2 |
+
import json
|
3 |
+
import time
|
4 |
+
import threading
|
5 |
+
from flask import Flask, render_template, request, redirect, url_for, jsonify, session
|
6 |
+
from flask_socketio import SocketIO, emit
|
7 |
+
from functools import wraps
|
8 |
+
from database.db import fetch_json_from_github as fetch_user_json
|
9 |
+
from database.db import update_user_json_file as update_user_json
|
10 |
+
from database.db import fetch_authenticity_token_and_commit_oid as fetch_user_tokens
|
11 |
+
from database.msg import fetch_json_from_github as fetch_messages_json
|
12 |
+
from database.msg import update_user_json_file as update_messages_json
|
13 |
+
from database.msg import fetch_authenticity_token_and_commit_oid as fetch_messages_tokens
|
14 |
|
15 |
+
app = Flask(__name__)
|
16 |
+
app.secret_key = os.urandom(24)
|
17 |
+
socketio = SocketIO(app, cors_allowed_origins="*")
|
18 |
|
19 |
+
# Cache for user data and messages
|
20 |
+
user_data_cache = {}
|
21 |
+
messages_cache = {}
|
22 |
+
last_fetch_time = 0
|
23 |
+
CACHE_TIMEOUT = 60 # seconds
|
24 |
|
25 |
+
# Background thread for checking updates
|
26 |
+
thread = None
|
27 |
+
thread_lock = threading.Lock()
|
28 |
+
|
29 |
+
def login_required(f):
|
30 |
+
@wraps(f)
|
31 |
+
def decorated_function(*args, **kwargs):
|
32 |
+
if 'logged_in' not in session or not session['logged_in']:
|
33 |
+
return redirect(url_for('login'))
|
34 |
+
return f(*args, **kwargs)
|
35 |
+
return decorated_function
|
36 |
+
|
37 |
+
def background_thread():
|
38 |
+
"""Background thread for checking updates in messages"""
|
39 |
+
while True:
|
40 |
+
with thread_lock:
|
41 |
+
# Check for new messages every 10 seconds
|
42 |
+
fetch_and_update_messages()
|
43 |
+
socketio.sleep(10)
|
44 |
+
|
45 |
+
def fetch_and_update_messages():
|
46 |
+
"""Fetch messages and notify clients if there are changes"""
|
47 |
+
global messages_cache
|
48 |
|
49 |
+
# Only fetch if we have active users
|
50 |
+
if not user_data_cache:
|
51 |
+
return
|
52 |
|
53 |
+
for page_id in user_data_cache.get('page_ids', []):
|
54 |
+
result = fetch_messages_json()
|
55 |
+
if result['success']:
|
56 |
+
new_messages = result['data'].get(page_id, [])
|
57 |
+
old_messages = messages_cache.get(page_id, [])
|
58 |
+
|
59 |
+
# Check if there are new messages
|
60 |
+
if len(new_messages) > len(old_messages):
|
61 |
+
messages_cache[page_id] = new_messages
|
62 |
+
# Notify clients about new messages
|
63 |
+
socketio.emit('new_messages', {
|
64 |
+
'page_id': page_id,
|
65 |
+
'count': len(new_messages) - len(old_messages)
|
66 |
+
})
|
67 |
+
|
68 |
+
def get_user_data(force_refresh=False):
|
69 |
+
"""Get user data from GitHub or cache"""
|
70 |
+
global user_data_cache, last_fetch_time
|
71 |
|
72 |
+
current_time = time.time()
|
73 |
+
if force_refresh or not user_data_cache or (current_time - last_fetch_time) > CACHE_TIMEOUT:
|
74 |
+
result = fetch_user_json()
|
75 |
+
if result['success']:
|
76 |
+
# Process the data to make it easier to work with
|
77 |
+
pages = result['data'].get('pages', [])
|
78 |
+
page_ids = [page.get('page_id') for page in pages]
|
79 |
+
|
80 |
+
user_data_cache = {
|
81 |
+
'pages': pages,
|
82 |
+
'page_ids': page_ids,
|
83 |
+
'raw_data': result['data']
|
84 |
+
}
|
85 |
+
last_fetch_time = current_time
|
86 |
+
return user_data_cache
|
87 |
+
|
88 |
+
return user_data_cache
|
89 |
+
|
90 |
+
def get_messages(page_id, force_refresh=False):
|
91 |
+
"""Get messages for a specific page from GitHub or cache"""
|
92 |
+
global messages_cache
|
93 |
+
|
94 |
+
if force_refresh or page_id not in messages_cache:
|
95 |
+
result = fetch_messages_json()
|
96 |
+
if result['success']:
|
97 |
+
messages = result['data'].get(page_id, [])
|
98 |
+
messages_cache[page_id] = messages
|
99 |
+
return messages
|
100 |
+
|
101 |
+
return messages_cache.get(page_id, [])
|
102 |
+
|
103 |
+
@app.route('/')
|
104 |
+
def index():
|
105 |
+
if 'logged_in' in session and session['logged_in']:
|
106 |
+
return redirect(url_for('dashboard'))
|
107 |
+
return redirect(url_for('login'))
|
108 |
+
|
109 |
+
@app.route('/login', methods=['GET', 'POST'])
|
110 |
+
def login():
|
111 |
+
error = None
|
112 |
+
if request.method == 'POST':
|
113 |
+
username = request.form['username']
|
114 |
+
password = request.form['password']
|
115 |
+
|
116 |
+
# Get user data
|
117 |
+
user_data = get_user_data(force_refresh=True)
|
118 |
+
|
119 |
+
# Check credentials
|
120 |
+
authenticated = False
|
121 |
+
for page in user_data.get('pages', []):
|
122 |
+
if page.get('username') == username and page.get('password') == password:
|
123 |
+
authenticated = True
|
124 |
+
session['logged_in'] = True
|
125 |
+
session['page_id'] = page.get('page_id')
|
126 |
+
session['username'] = username
|
127 |
+
|
128 |
+
# Start background thread if not already running
|
129 |
+
global thread
|
130 |
+
with thread_lock:
|
131 |
+
if thread is None:
|
132 |
+
thread = socketio.start_background_task(background_thread)
|
133 |
+
|
134 |
+
return redirect(url_for('dashboard'))
|
135 |
|
136 |
+
if not authenticated:
|
137 |
+
error = 'اسم المستخدم أو كلمة المرور غير صحيح. الرجاء المحاولة مرة أخرى'
|
138 |
+
|
139 |
+
return render_template('login.html', error=error)
|
140 |
+
|
141 |
+
@app.route('/logout')
|
142 |
+
def logout():
|
143 |
+
session.clear()
|
144 |
+
return redirect(url_for('login'))
|
145 |
+
|
146 |
+
@app.route('/dashboard')
|
147 |
+
@login_required
|
148 |
+
def dashboard():
|
149 |
+
page_id = session.get('page_id')
|
150 |
+
user_data = get_user_data()
|
151 |
+
|
152 |
+
# Find the current page data
|
153 |
+
current_page = None
|
154 |
+
for page in user_data.get('pages', []):
|
155 |
+
if page.get('page_id') == page_id:
|
156 |
+
current_page = page
|
157 |
+
break
|
158 |
+
|
159 |
+
if not current_page:
|
160 |
+
return redirect(url_for('logout'))
|
161 |
+
|
162 |
+
# Extract system prompt, style, and products
|
163 |
+
system_prompt = current_page.get('system', '')
|
164 |
+
|
165 |
+
# Extract style if it exists
|
166 |
+
style = ""
|
167 |
+
style_start = system_prompt.find('<style>')
|
168 |
+
style_end = system_prompt.find('</style>')
|
169 |
+
if style_start != -1 and style_end != -1:
|
170 |
+
style = system_prompt[style_start + 7:style_end]
|
171 |
+
|
172 |
+
# Extract products if they exist and pre-parse them
|
173 |
+
products = []
|
174 |
+
product_start = system_prompt.find('<product>')
|
175 |
+
while product_start != -1:
|
176 |
+
product_end = system_prompt.find('</product>', product_start)
|
177 |
+
if product_end != -1:
|
178 |
+
product_text = system_prompt[product_start + 9:product_end]
|
179 |
+
|
180 |
+
# Parse the product text into a dictionary
|
181 |
+
product_data = {
|
182 |
+
'name': '',
|
183 |
+
'price': '',
|
184 |
+
'description': '',
|
185 |
+
'info': '',
|
186 |
+
'raw_text': product_text # Keep the raw text for editing/deleting
|
187 |
+
}
|
188 |
+
|
189 |
+
lines = product_text.split('\n')
|
190 |
+
for line in lines:
|
191 |
+
if 'NAME:' in line:
|
192 |
+
product_data['name'] = line.replace('NAME:', '').strip()
|
193 |
+
elif 'PRICE (LIBYAN DINNER):' in line:
|
194 |
+
product_data['price'] = line.replace('PRICE (LIBYAN DINNER):', '').strip()
|
195 |
+
elif 'DESCRIPTION:' in line:
|
196 |
+
product_data['description'] = line.replace('DESCRIPTION:', '').strip()
|
197 |
+
elif 'ANOTHER INFO:' in line:
|
198 |
+
product_data['info'] = line.replace('ANOTHER INFO:', '').strip()
|
199 |
+
|
200 |
+
products.append(product_data)
|
201 |
+
product_start = system_prompt.find('<product>', product_end)
|
202 |
+
else:
|
203 |
+
break
|
204 |
+
|
205 |
+
# Get bot status
|
206 |
+
bot_status = current_page.get('status', 'OFF')
|
207 |
+
|
208 |
+
# Get subscription info from the actual JSON structure and translate to Arabic
|
209 |
+
subscription_type = current_page.get('subscription', None)
|
210 |
+
subscription_message = None
|
211 |
+
|
212 |
+
if subscription_type == 'Basic':
|
213 |
+
subscription_status = 'اشتراك عادي'
|
214 |
+
elif subscription_type == 'Plus':
|
215 |
+
subscription_status = 'اشتراك +'
|
216 |
+
elif subscription_type == 'Premium':
|
217 |
+
subscription_status = 'اشتراك مميز'
|
218 |
+
elif subscription_type == 'Free':
|
219 |
+
subscription_status = 'اشتراك مجاني'
|
220 |
+
else:
|
221 |
+
subscription_status = 'لا يوجد اشتراك'
|
222 |
+
subscription_message = 'يرجى الاشتراك للاستفادة من جميع المميزات'
|
223 |
+
|
224 |
+
expiration_date = current_page.get('expiration', '2023-12-31')
|
225 |
+
|
226 |
+
# Calculate days until expiration
|
227 |
+
import datetime
|
228 |
+
is_expired = False
|
229 |
+
expiration_message = None
|
230 |
+
try:
|
231 |
+
exp_date = datetime.datetime.strptime(expiration_date, '%Y-%m-%d')
|
232 |
+
today = datetime.datetime.now()
|
233 |
+
days_left = (exp_date - today).days
|
234 |
+
|
235 |
+
if days_left <= 0:
|
236 |
+
is_expired = True
|
237 |
+
expiration_message = 'انتهت صلاحية اشتراكك! يرجى التجديد للاستمرار في استخدام الخدمة'
|
238 |
+
elif days_left <= 3:
|
239 |
+
expiration_message = f'سينتهي اشتراكك خلال {days_left} أيام!'
|
240 |
+
except:
|
241 |
+
days_left = 0
|
242 |
+
is_expired = True
|
243 |
+
expiration_message = 'تاريخ انتهاء غير صالح! يرجى التواصل مع الدعم الفني'
|
244 |
+
|
245 |
+
# Get unread messages count
|
246 |
+
messages = get_messages(page_id, force_refresh=True)
|
247 |
+
unread_count = sum(1 for msg in messages if not msg.get('seen', False))
|
248 |
+
|
249 |
+
return render_template(
|
250 |
+
'dashboard.html',
|
251 |
+
page=current_page,
|
252 |
+
style=style,
|
253 |
+
products=products,
|
254 |
+
system_prompt=system_prompt,
|
255 |
+
bot_status=bot_status,
|
256 |
+
subscription_status=subscription_status,
|
257 |
+
subscription_message=subscription_message,
|
258 |
+
expiration_date=expiration_date,
|
259 |
+
days_left=days_left,
|
260 |
+
is_expired=is_expired,
|
261 |
+
expiration_message=expiration_message,
|
262 |
+
unread_count=unread_count
|
263 |
+
)
|
264 |
+
|
265 |
+
@app.route('/messages')
|
266 |
+
@login_required
|
267 |
+
def messages_page():
|
268 |
+
page_id = session.get('page_id')
|
269 |
+
messages = get_messages(page_id, force_refresh=True)
|
270 |
+
|
271 |
+
# Sort messages by timestamp (newest first)
|
272 |
+
messages = sorted(messages, key=lambda x: x.get('timestamp', ''), reverse=True)
|
273 |
+
|
274 |
+
user_data = get_user_data()
|
275 |
+
current_page = None
|
276 |
+
for page in user_data.get('pages', []):
|
277 |
+
if page.get('page_id') == page_id:
|
278 |
+
current_page = page
|
279 |
+
break
|
280 |
+
|
281 |
+
if not current_page:
|
282 |
+
return redirect(url_for('logout'))
|
283 |
+
|
284 |
+
return render_template(
|
285 |
+
'messages.html',
|
286 |
+
page=current_page,
|
287 |
+
messages=messages
|
288 |
+
)
|
289 |
+
|
290 |
+
@app.route('/api/update_status', methods=['POST'])
|
291 |
+
@login_required
|
292 |
+
def update_status():
|
293 |
+
page_id = session.get('page_id')
|
294 |
+
status = request.json.get('status')
|
295 |
+
|
296 |
+
if status not in ['ON', 'OFF']:
|
297 |
+
return jsonify({'success': False, 'message': 'Invalid status value'})
|
298 |
+
|
299 |
+
# Get current data
|
300 |
+
user_data = get_user_data(force_refresh=True)
|
301 |
+
raw_data = user_data.get('raw_data', {})
|
302 |
+
|
303 |
+
# Update the status for the current page
|
304 |
+
for page in raw_data.get('pages', []):
|
305 |
+
if page.get('page_id') == page_id:
|
306 |
+
page['status'] = status
|
307 |
+
break
|
308 |
+
|
309 |
+
# Get tokens for updating
|
310 |
+
auth_token, commit_oid = fetch_user_tokens()
|
311 |
+
if not auth_token or not commit_oid:
|
312 |
+
return jsonify({'success': False, 'message': 'Failed to get authentication tokens'})
|
313 |
+
|
314 |
+
# Update the file
|
315 |
+
result = update_user_json(auth_token, commit_oid, json.dumps(raw_data))
|
316 |
+
|
317 |
+
if result['success']:
|
318 |
+
# Update cache
|
319 |
+
get_user_data(force_refresh=True)
|
320 |
+
# Notify all clients about the status change
|
321 |
+
socketio.emit('status_updated', {'page_id': page_id, 'status': status})
|
322 |
+
return jsonify({'success': True, 'message': 'Status updated successfully'})
|
323 |
+
else:
|
324 |
+
return jsonify({'success': False, 'message': 'Failed to update status'})
|
325 |
+
|
326 |
+
@app.route('/api/update_system', methods=['POST'])
|
327 |
+
@login_required
|
328 |
+
def update_system():
|
329 |
+
page_id = session.get('page_id')
|
330 |
+
style = request.json.get('style', '')
|
331 |
+
|
332 |
+
# Get current data
|
333 |
+
user_data = get_user_data(force_refresh=True)
|
334 |
+
raw_data = user_data.get('raw_data', {})
|
335 |
+
|
336 |
+
# Find the current page
|
337 |
+
current_page = None
|
338 |
+
for page in raw_data.get('pages', []):
|
339 |
+
if page.get('page_id') == page_id:
|
340 |
+
current_page = page
|
341 |
+
break
|
342 |
+
|
343 |
+
if not current_page:
|
344 |
+
return jsonify({'success': False, 'message': 'Page not found'})
|
345 |
+
|
346 |
+
# Get the current system prompt
|
347 |
+
system_prompt = current_page.get('system', '')
|
348 |
+
|
349 |
+
# Check if style tag already exists
|
350 |
+
style_start = system_prompt.find('<style>')
|
351 |
+
style_end = system_prompt.find('</style>')
|
352 |
+
|
353 |
+
if style_start != -1 and style_end != -1:
|
354 |
+
# Replace existing style
|
355 |
+
new_system = system_prompt[:style_start] + f'<style>{style}</style>' + system_prompt[style_end + 8:]
|
356 |
+
else:
|
357 |
+
# Add style at the end of the system prompt
|
358 |
+
base_prompt_end = system_prompt.find('here how to talk style and products if there : ')
|
359 |
+
if base_prompt_end != -1:
|
360 |
+
new_system = system_prompt[:base_prompt_end + 46] + f'<style>{style}</style>'
|
361 |
+
else:
|
362 |
+
new_system = system_prompt + f' <style>{style}</style>'
|
363 |
+
|
364 |
+
# Update the system prompt
|
365 |
+
current_page['system'] = new_system
|
366 |
+
|
367 |
+
# Get tokens for updating
|
368 |
+
auth_token, commit_oid = fetch_user_tokens()
|
369 |
+
if not auth_token or not commit_oid:
|
370 |
+
return jsonify({'success': False, 'message': 'Failed to get authentication tokens'})
|
371 |
+
|
372 |
+
# Update the file
|
373 |
+
result = update_user_json(auth_token, commit_oid, json.dumps(raw_data))
|
374 |
+
|
375 |
+
if result['success']:
|
376 |
+
# Update cache
|
377 |
+
get_user_data(force_refresh=True)
|
378 |
+
return jsonify({'success': True, 'message': 'System prompt updated successfully'})
|
379 |
+
else:
|
380 |
+
return jsonify({'success': False, 'message': 'Failed to update system prompt'})
|
381 |
+
|
382 |
+
@app.route('/api/add_product', methods=['POST'])
|
383 |
+
@login_required
|
384 |
+
def add_product():
|
385 |
+
page_id = session.get('page_id')
|
386 |
+
product_data = request.json.get('product', {})
|
387 |
+
|
388 |
+
# Format product data
|
389 |
+
product_text = f"NAME: {product_data.get('name', '')}\n"
|
390 |
+
product_text += f"DESCRIPTION: {product_data.get('description', '')}\n"
|
391 |
+
product_text += f"PRICE (LIBYAN DINNER): {product_data.get('price', '')}\n"
|
392 |
+
product_text += f"ANOTHER INFO: {product_data.get('info', '')}"
|
393 |
+
|
394 |
+
# Get current data
|
395 |
+
user_data = get_user_data(force_refresh=True)
|
396 |
+
raw_data = user_data.get('raw_data', {})
|
397 |
+
|
398 |
+
# Find the current page
|
399 |
+
current_page = None
|
400 |
+
for page in raw_data.get('pages', []):
|
401 |
+
if page.get('page_id') == page_id:
|
402 |
+
current_page = page
|
403 |
+
break
|
404 |
+
|
405 |
+
if not current_page:
|
406 |
+
return jsonify({'success': False, 'message': 'Page not found'})
|
407 |
+
|
408 |
+
# Get the current system prompt
|
409 |
+
system_prompt = current_page.get('system', '')
|
410 |
+
|
411 |
+
# Add product tag at the end
|
412 |
+
new_system = system_prompt + f' <product>{product_text}</product>'
|
413 |
+
|
414 |
+
# Update the system prompt
|
415 |
+
current_page['system'] = new_system
|
416 |
+
|
417 |
+
# Get tokens for updating
|
418 |
+
auth_token, commit_oid = fetch_user_tokens()
|
419 |
+
if not auth_token or not commit_oid:
|
420 |
+
return jsonify({'success': False, 'message': 'Failed to get authentication tokens'})
|
421 |
+
|
422 |
+
# Update the file
|
423 |
+
result = update_user_json(auth_token, commit_oid, json.dumps(raw_data))
|
424 |
+
|
425 |
+
if result['success']:
|
426 |
+
# Update cache
|
427 |
+
get_user_data(force_refresh=True)
|
428 |
+
return jsonify({'success': True, 'message': 'Product added successfully'})
|
429 |
+
else:
|
430 |
+
return jsonify({'success': False, 'message': 'Failed to add product'})
|
431 |
+
|
432 |
+
@app.route('/api/delete_product', methods=['POST'])
|
433 |
+
@login_required
|
434 |
+
def delete_product():
|
435 |
+
page_id = session.get('page_id')
|
436 |
+
product_index = request.json.get('index')
|
437 |
+
|
438 |
+
# Get current data
|
439 |
+
user_data = get_user_data(force_refresh=True)
|
440 |
+
raw_data = user_data.get('raw_data', {})
|
441 |
+
|
442 |
+
# Find the current page
|
443 |
+
current_page = None
|
444 |
+
for page in raw_data.get('pages', []):
|
445 |
+
if page.get('page_id') == page_id:
|
446 |
+
current_page = page
|
447 |
+
break
|
448 |
+
|
449 |
+
if not current_page:
|
450 |
+
return jsonify({'success': False, 'message': 'Page not found'})
|
451 |
+
|
452 |
+
# Get the current system prompt
|
453 |
+
system_prompt = current_page.get('system', '')
|
454 |
+
|
455 |
+
# Find all products
|
456 |
+
products = []
|
457 |
+
product_start = system_prompt.find('<product>')
|
458 |
+
while product_start != -1:
|
459 |
+
product_end = system_prompt.find('</product>', product_start)
|
460 |
+
if product_end != -1:
|
461 |
+
products.append({
|
462 |
+
'start': product_start,
|
463 |
+
'end': product_end + 10, # Include the closing tag
|
464 |
+
'text': system_prompt[product_start:product_end + 10]
|
465 |
+
})
|
466 |
+
product_start = system_prompt.find('<product>', product_end)
|
467 |
+
else:
|
468 |
+
break
|
469 |
+
|
470 |
+
# Check if the index is valid
|
471 |
+
if product_index < 0 or product_index >= len(products):
|
472 |
+
return jsonify({'success': False, 'message': 'Invalid product index'})
|
473 |
+
|
474 |
+
# Remove the product
|
475 |
+
product_to_remove = products[product_index]
|
476 |
+
new_system = system_prompt[:product_to_remove['start']] + system_prompt[product_to_remove['end']:]
|
477 |
+
|
478 |
+
# Update the system prompt
|
479 |
+
current_page['system'] = new_system
|
480 |
+
|
481 |
+
# Get tokens for updating
|
482 |
+
auth_token, commit_oid = fetch_user_tokens()
|
483 |
+
if not auth_token or not commit_oid:
|
484 |
+
return jsonify({'success': False, 'message': 'Failed to get authentication tokens'})
|
485 |
+
|
486 |
+
# Update the file
|
487 |
+
result = update_user_json(auth_token, commit_oid, json.dumps(raw_data))
|
488 |
+
|
489 |
+
if result['success']:
|
490 |
+
# Update cache
|
491 |
+
get_user_data(force_refresh=True)
|
492 |
+
return jsonify({'success': True, 'message': 'Product deleted successfully'})
|
493 |
+
else:
|
494 |
+
return jsonify({'success': False, 'message': 'Failed to delete product'})
|
495 |
+
|
496 |
+
|
497 |
+
@app.route('/api/refresh_data', methods=['POST'])
|
498 |
+
@login_required
|
499 |
+
def refresh_data():
|
500 |
+
data_type = request.json.get('type', 'all')
|
501 |
+
|
502 |
+
if data_type == 'messages' or data_type == 'all':
|
503 |
+
# Force refresh messages
|
504 |
+
page_id = session.get('page_id')
|
505 |
+
messages = get_messages(page_id, force_refresh=True)
|
506 |
+
|
507 |
+
# Notify clients about the refresh
|
508 |
+
socketio.emit('data_refreshed', {'type': data_type})
|
509 |
+
|
510 |
+
return jsonify({'success': True, 'message': 'تم تحديث البيانات بنجاح'})
|
511 |
+
|
512 |
+
return jsonify({'success': False, 'message': 'نوع البيانات غير صالح'})
|
513 |
+
|
514 |
+
|
515 |
+
@app.route('/api/mark_message_seen', methods=['POST'])
|
516 |
+
@login_required
|
517 |
+
def mark_message_seen():
|
518 |
+
page_id = session.get('page_id')
|
519 |
+
message_index = request.json.get('index')
|
520 |
+
|
521 |
+
# Ensure message_index is an integer
|
522 |
+
try:
|
523 |
+
message_index = int(message_index)
|
524 |
+
except (ValueError, TypeError):
|
525 |
+
return jsonify({'success': False, 'message': 'مؤشر الرسالة غير صالح'})
|
526 |
+
|
527 |
+
# Get current messages
|
528 |
+
result = fetch_messages_json()
|
529 |
+
if not result['success']:
|
530 |
+
return jsonify({'success': False, 'message': 'فشل في جلب الرسائل'})
|
531 |
+
|
532 |
+
messages_data = result['data']
|
533 |
+
page_messages = messages_data.get(page_id, [])
|
534 |
+
|
535 |
+
# Sort messages by timestamp (newest first) to match the display order
|
536 |
+
page_messages = sorted(page_messages, key=lambda x: x.get('timestamp', ''), reverse=True)
|
537 |
+
|
538 |
+
# Check if the index is valid
|
539 |
+
if message_index < 0 or message_index >= len(page_messages):
|
540 |
+
return jsonify({'success': False, 'message': 'مؤشر الرسالة غير صالح'})
|
541 |
+
|
542 |
+
# Mark the message as seen
|
543 |
+
page_messages[message_index]['seen'] = True
|
544 |
+
|
545 |
+
# Re-sort messages back to their original order before saving
|
546 |
+
# This is needed because we're working with the sorted list but need to update the original data
|
547 |
+
original_messages = messages_data.get(page_id, [])
|
548 |
+
|
549 |
+
# Find the corresponding message in the original list by matching properties
|
550 |
+
message_to_mark = page_messages[message_index]
|
551 |
+
for orig_msg in original_messages:
|
552 |
+
if (orig_msg.get('message') == message_to_mark.get('message') and
|
553 |
+
orig_msg.get('sender_id') == message_to_mark.get('sender_id') and
|
554 |
+
orig_msg.get('timestamp') == message_to_mark.get('timestamp')):
|
555 |
+
orig_msg['seen'] = True
|
556 |
+
break
|
557 |
+
|
558 |
+
# Update messages data
|
559 |
+
messages_data[page_id] = original_messages
|
560 |
+
|
561 |
+
# Get tokens for updating
|
562 |
+
auth_token, commit_oid = fetch_messages_tokens()
|
563 |
+
if not auth_token or not commit_oid:
|
564 |
+
return jsonify({'success': False, 'message': 'فشل في الحصول على رموز المصادقة'})
|
565 |
+
|
566 |
+
# Update the file
|
567 |
+
result = update_messages_json(auth_token, commit_oid, json.dumps(messages_data))
|
568 |
+
|
569 |
+
if result['success']:
|
570 |
+
# Update cache
|
571 |
+
messages_cache[page_id] = original_messages
|
572 |
+
# Notify clients about the message being seen
|
573 |
+
socketio.emit('message_seen', {'page_id': page_id, 'index': message_index})
|
574 |
+
return jsonify({'success': True, 'message': 'تم تعليم الرسالة كمقروءة'})
|
575 |
+
else:
|
576 |
+
return jsonify({'success': False, 'message': 'فشل في تحديث حالة الرسالة'})
|
577 |
+
@app.route('/api/delete_message', methods=['POST'])
|
578 |
+
@login_required
|
579 |
+
def delete_message():
|
580 |
+
page_id = session.get('page_id')
|
581 |
+
message_index = request.json.get('index')
|
582 |
+
|
583 |
+
# Ensure message_index is an integer
|
584 |
+
try:
|
585 |
+
message_index = int(message_index)
|
586 |
+
except (ValueError, TypeError):
|
587 |
+
return jsonify({'success': False, 'message': 'مؤشر الرسالة غير صالح'})
|
588 |
+
|
589 |
+
# Get current messages
|
590 |
+
result = fetch_messages_json()
|
591 |
+
if not result['success']:
|
592 |
+
return jsonify({'success': False, 'message': 'فشل في جلب الرسائل'})
|
593 |
+
|
594 |
+
messages_data = result['data']
|
595 |
+
page_messages = messages_data.get(page_id, [])
|
596 |
+
|
597 |
+
# Sort messages by timestamp (newest first) to match the display order
|
598 |
+
sorted_messages = sorted(page_messages, key=lambda x: x.get('timestamp', ''), reverse=True)
|
599 |
+
|
600 |
+
# Check if the index is valid
|
601 |
+
if message_index < 0 or message_index >= len(sorted_messages):
|
602 |
+
return jsonify({'success': False, 'message': 'مؤشر الرسالة غير صالح'})
|
603 |
+
|
604 |
+
# Get the message to delete
|
605 |
+
message_to_delete = sorted_messages[message_index]
|
606 |
+
|
607 |
+
# Find and remove the message from the original list
|
608 |
+
original_messages = messages_data.get(page_id, [])
|
609 |
+
for i, msg in enumerate(original_messages):
|
610 |
+
if (msg.get('message') == message_to_delete.get('message') and
|
611 |
+
msg.get('sender_id') == message_to_delete.get('sender_id') and
|
612 |
+
msg.get('timestamp') == message_to_delete.get('timestamp')):
|
613 |
+
original_messages.pop(i)
|
614 |
+
break
|
615 |
+
|
616 |
+
# Update messages data
|
617 |
+
messages_data[page_id] = original_messages
|
618 |
+
|
619 |
+
# Get tokens for updating
|
620 |
+
auth_token, commit_oid = fetch_messages_tokens()
|
621 |
+
if not auth_token or not commit_oid:
|
622 |
+
return jsonify({'success': False, 'message': 'فشل في الحصول على رموز المصادقة'})
|
623 |
+
|
624 |
+
# Update the file
|
625 |
+
result = update_messages_json(auth_token, commit_oid, json.dumps(messages_data))
|
626 |
+
|
627 |
+
if result['success']:
|
628 |
+
# Update cache
|
629 |
+
messages_cache[page_id] = original_messages
|
630 |
+
# Notify all clients about the message deletion
|
631 |
+
socketio.emit('message_deleted', {'page_id': page_id, 'index': message_index})
|
632 |
+
return jsonify({'success': True, 'message': 'تم حذف الرسالة بنجاح'})
|
633 |
+
else:
|
634 |
+
return jsonify({'success': False, 'message': 'فشل في حذف الرسالة'})
|
635 |
+
|
636 |
+
# WebSocket events
|
637 |
+
@socketio.on('connect')
|
638 |
+
def handle_connect():
|
639 |
+
# Start background thread if not already running
|
640 |
+
global thread
|
641 |
+
with thread_lock:
|
642 |
+
if thread is None:
|
643 |
+
thread = socketio.start_background_task(background_thread)
|
644 |
+
emit('connected', {'data': 'Connected'})
|
645 |
+
|
646 |
+
@socketio.on('request_messages_update')
|
647 |
+
def handle_messages_update(data):
|
648 |
+
page_id = data.get('page_id')
|
649 |
+
if page_id:
|
650 |
+
messages = get_messages(page_id, force_refresh=True)
|
651 |
+
emit('messages_updated', {'page_id': page_id, 'messages': messages})
|
652 |
|
653 |
if __name__ == '__main__':
|
654 |
+
socketio.run(host="0.0.0.0", port=7860, debug=True ,app)
|