Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
MBetterd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mbetter
MBetterd
Commits
e643bc63
Commit
e643bc63
authored
Feb 01, 2026
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix syntax errors in app/main/routes.py - Clean up duplicate and broken code
parent
79ef3b52
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
285 additions
and
288 deletions
+285
-288
routes.py
app/main/routes.py
+285
-288
No files found.
app/main/routes.py
View file @
e643bc63
...
...
@@ -8,6 +8,9 @@ from app import db, csrf
from
app.upload.file_handler
import
get_file_upload_handler
from
app.upload.fixture_parser
import
get_fixture_parser
from
app.utils.security
import
require_admin
,
require_active_user
import
pandas
as
pd
from
io
import
BytesIO
,
StringIO
from
flask
import
Response
,
make_response
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -671,7 +674,7 @@ def admin_edit_user(user_id):
from
app.models
import
User
user
=
User
.
query
.
get_or_404
(
user_id
)
# Prevent editing
the
current admin user's admin status
# Prevent editing current admin user's admin status
if
user
.
id
==
current_user
.
id
and
request
.
json
.
get
(
'is_admin'
)
==
False
:
return
jsonify
({
'error'
:
'Cannot remove admin status from your own account'
}),
400
...
...
@@ -720,7 +723,7 @@ def admin_delete_user(user_id):
from
app.models
import
User
user
=
User
.
query
.
get_or_404
(
user_id
)
# Prevent deleting
the
current admin user
# Prevent deleting current admin user
if
user
.
id
==
current_user
.
id
:
return
jsonify
({
'error'
:
'Cannot delete your own account'
}),
400
...
...
@@ -1125,7 +1128,7 @@ def create_api_token():
if
existing_token
:
return
jsonify
({
'error'
:
'A token with this name already exists'
}),
400
# Generate t
he t
oken
# Generate token
api_token
=
current_user
.
generate_api_token
(
token_name
)
logger
.
info
(
f
"API token '{token_name}' created by user {current_user.username}"
)
...
...
@@ -1148,7 +1151,7 @@ def delete_api_token(token_id):
try
:
from
app.models
import
APIToken
# Get t
he t
oken (ensure it belongs to current user)
# Get token (ensure it belongs to current user)
token
=
APIToken
.
query
.
filter_by
(
id
=
token_id
,
user_id
=
current_user
.
id
...
...
@@ -1177,7 +1180,7 @@ def revoke_api_token(token_id):
try
:
from
app.models
import
APIToken
# Get t
he t
oken (ensure it belongs to current user)
# Get token (ensure it belongs to current user)
token
=
APIToken
.
query
.
filter_by
(
id
=
token_id
,
user_id
=
current_user
.
id
...
...
@@ -1191,7 +1194,7 @@ def revoke_api_token(token_id):
logger
.
info
(
f
"API token '{token.name}' revoked by user {current_user.username}"
)
return
jsonify
({
'message'
:
f
'API token "{token
.
name}" revoked successfully'
,
'message'
:
f
'API token "{token
_
name}" revoked successfully'
,
'token'
:
token
.
to_dict
()
}),
200
...
...
@@ -1208,7 +1211,7 @@ def extend_api_token(token_id):
try
:
from
app.models
import
APIToken
# Get t
he t
oken (ensure it belongs to current user)
# Get token (ensure it belongs to current user)
token
=
APIToken
.
query
.
filter_by
(
id
=
token_id
,
user_id
=
current_user
.
id
...
...
@@ -1386,7 +1389,7 @@ def download_zip(match_id):
from
app.models
import
Match
from
flask
import
send_file
,
abort
# Get
the
match
# Get match
if
current_user
.
is_admin
:
match
=
Match
.
query
.
get_or_404
(
match_id
)
else
:
...
...
@@ -1423,7 +1426,7 @@ def clients():
try
:
from
app.models
import
ClientActivity
,
SystemSettings
,
APIToken
from
datetime
import
datetime
,
timedelta
# Clean up clients with inactive or revoked tokens
# Delete ClientActivity records where the associated token is inactive or doesn't exist
inactive_clients
=
ClientActivity
.
query
.
filter
(
...
...
@@ -1523,12 +1526,14 @@ def clients():
clients
=
clients_data
,
status_filter
=
status_filter
,
search_query
=
search_query
)
except
Exception
as
e
:
logger
.
error
(
f
"Clients page error: {str(e)}"
)
flash
(
'Error loading clients'
,
'error'
)
return
render_template
(
'main/clients.html'
,
clients
=
[])
# Reports Routes
@
csrf
.
exempt
@
bp
.
route
(
'/reports'
)
@
login_required
...
...
@@ -1687,56 +1692,291 @@ def export_reports(query, export_format):
"""Export reports to various formats"""
try
:
from
app.models
import
ReportSync
,
Bet
,
ExtractionStats
import
pandas
as
pd
from
flask
import
Response
import
io
# Get all reports matching
the
query
# Get all reports matching query
reports
=
query
.
all
()
if
not
reports
:
flash
(
'No reports to export'
,
'warning'
)
return
redirect
(
url_for
(
'main.reports'
))
@
csrf
.
exempt
@
bp
.
route
(
'/sync-logs'
)
@
login_required
@
require_active_user
def
sync_logs
():
"""Sync logs page with filtering and search"""
try
:
from
app.models
import
ReportSyncLog
from
sqlalchemy
import
and_
,
or_
# Prepare data for export
export_data
=
[]
for
report
in
reports
:
# Get bets and stats for this report
bets
=
Bet
.
query
.
filter_by
(
sync_id
=
report
.
id
)
.
all
()
stats
=
ExtractionStats
.
query
.
filter_by
(
sync_id
=
report
.
id
)
.
all
()
# Check for export request
export_format
=
request
.
args
.
get
(
'export'
)
if
export_format
:
return
export_sync_logs
(
export_format
)
# Add summary row
export_data
.
append
({
'Type'
:
'Summary'
,
'Sync ID'
:
report
.
sync_id
,
'Client ID'
:
report
.
client_id
,
'Sync Timestamp'
:
report
.
sync_timestamp
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
report
.
sync_timestamp
else
''
,
'Date Range'
:
report
.
date_range
,
'Start Date'
:
report
.
start_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
start_date
else
''
,
'End Date'
:
report
.
end_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
end_date
else
''
,
'Total Payin'
:
float
(
report
.
total_payin
)
if
report
.
total_payin
else
0.0
,
'Total Payout'
:
float
(
report
.
total_payout
)
if
report
.
total_payout
else
0.0
,
'Net Profit'
:
float
(
report
.
net_profit
)
if
report
.
net_profit
else
0.0
,
'Total Bets'
:
report
.
total_bets
,
'Total Matches'
:
report
.
total_matches
,
'Bet UUID'
:
''
,
'Match ID'
:
''
,
'Outcome'
:
''
,
'Amount'
:
''
,
'Result'
:
''
})
# Get filter parameters
client_id_filter
=
request
.
args
.
get
(
'client_id'
,
''
)
.
strip
()
operation_type_filter
=
request
.
args
.
get
(
'operation_type'
,
''
)
.
strip
()
status_filter
=
request
.
args
.
get
(
'status'
,
''
)
.
strip
()
search_query
=
request
.
args
.
get
(
'search'
,
''
)
.
strip
()
start_date_filter
=
request
.
args
.
get
(
'start_date'
,
''
)
.
strip
()
end_date_filter
=
request
.
args
.
get
(
'end_date'
,
''
)
.
strip
()
sort_by
=
request
.
args
.
get
(
'sort_by'
,
'created_at'
)
sort_order
=
request
.
args
.
get
(
'sort_order'
,
'desc'
)
# Add bet details
for
bet
in
bets
:
for
detail
in
bet
.
details
:
export_data
.
append
({
'Type'
:
'Bet Detail'
,
'Sync ID'
:
report
.
sync_id
,
'Client ID'
:
report
.
client_id
,
'Sync Timestamp'
:
report
.
sync_timestamp
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
report
.
sync_timestamp
else
''
,
'Date Range'
:
report
.
date_range
,
'Start Date'
:
report
.
start_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
start_date
else
''
,
'End Date'
:
report
.
end_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
end_date
else
''
,
'Total Payin'
:
''
,
'Total Payout'
:
''
,
'Net Profit'
:
''
,
'Total Bets'
:
''
,
'Total Matches'
:
''
,
'Bet UUID'
:
bet
.
uuid
,
'Match ID'
:
detail
.
match_id
,
'Outcome'
:
detail
.
outcome
,
'Amount'
:
float
(
detail
.
amount
)
if
detail
.
amount
else
0.0
,
'Result'
:
detail
.
result
})
# Pagination
page
=
request
.
args
.
get
(
'page'
,
1
,
type
=
int
)
per_page
=
min
(
request
.
args
.
get
(
'per_page'
,
50
,
type
=
int
),
200
)
# Add extraction stats
for
stat
in
stats
:
export_data
.
append
({
'Type'
:
'Extraction Stats'
,
'Sync ID'
:
report
.
sync_id
,
'Client ID'
:
report
.
client_id
,
'Sync Timestamp'
:
report
.
sync_timestamp
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
report
.
sync_timestamp
else
''
,
'Date Range'
:
report
.
date_range
,
'Start Date'
:
report
.
start_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
start_date
else
''
,
'End Date'
:
report
.
end_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
end_date
else
''
,
'Total Payin'
:
float
(
stat
.
total_amount_collected
)
if
stat
.
total_amount_collected
else
0.0
,
'Total Payout'
:
float
(
stat
.
total_redistributed
)
if
stat
.
total_redistributed
else
0.0
,
'Net Profit'
:
''
,
'Total Bets'
:
stat
.
total_bets
,
'Total Matches'
:
''
,
'Bet UUID'
:
''
,
'Match ID'
:
stat
.
match_id
,
'Outcome'
:
stat
.
actual_result
,
'Amount'
:
''
,
'Result'
:
stat
.
extraction_result
})
# Create DataFrame
df
=
pd
.
DataFrame
(
export_data
)
# Export based on format
if
export_format
==
'csv'
:
output
=
StringIO
()
df
.
to_csv
(
output
,
index
=
False
)
output
.
seek
(
0
)
return
Response
(
output
.
getvalue
(),
mimetype
=
'text/csv'
,
headers
=
{
'Content-Disposition'
:
'attachment; filename=reports_export.csv'
}
)
elif
export_format
==
'xlsx'
:
output
=
BytesIO
()
with
pd
.
ExcelWriter
(
output
,
engine
=
'openpyxl'
)
as
writer
:
df
.
to_excel
(
writer
,
index
=
False
,
sheet_name
=
'Reports'
)
output
.
seek
(
0
)
return
Response
(
output
.
getvalue
(),
mimetype
=
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
,
headers
=
{
'Content-Disposition'
:
'attachment; filename=reports_export.xlsx'
}
)
elif
export_format
==
'pdf'
:
# For PDF, we'll create a simple HTML table and convert it
from
weasyprint
import
HTML
import
tempfile
# Create HTML table
html_table
=
df
.
to_html
(
index
=
False
,
classes
=
'table table-striped table-bordered'
)
html_content
=
f
"""
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
table {{ border-collapse: collapse; width: 100
%
; margin-bottom: 20px; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
th {{ background-color: #4CAF50; color: white; }}
tr:nth-child(even) {{ background-color: #f2f2f2; }}
</style>
</head>
<body>
<h1>Reports Export</h1>
<p>Generated on: {datetime.utcnow().strftime('
%
Y-
%
m-
%
d
%
H:
%
M:
%
S')}</p>
{html_table}
</body>
</html>
"""
# Generate PDF
pdf_bytes
=
HTML
(
string
=
html_content
)
.
write_pdf
()
return
Response
(
pdf_bytes
,
mimetype
=
'application/pdf'
,
headers
=
{
'Content-Disposition'
:
'attachment; filename=reports_export.pdf'
}
)
else
:
flash
(
'Invalid export format'
,
'error'
)
return
redirect
(
url_for
(
'main.reports'
))
except
Exception
as
e
:
logger
.
error
(
f
"Export reports error: {str(e)}"
)
flash
(
'Error exporting reports'
,
'error'
)
return
redirect
(
url_for
(
'main.reports'
))
@
csrf
.
exempt
@
bp
.
route
(
'/sync-logs'
)
@
login_required
@
require_active_user
def
sync_logs
():
"""Sync logs page with filtering and search"""
try
:
from
app.models
import
ReportSyncLog
from
sqlalchemy
import
and_
,
or_
# Check for export request
export_format
=
request
.
args
.
get
(
'export'
)
if
export_format
:
return
export_sync_logs
(
export_format
)
# Get filter parameters
client_id_filter
=
request
.
args
.
get
(
'client_id'
,
''
)
.
strip
()
operation_type_filter
=
request
.
args
.
get
(
'operation_type'
,
''
)
.
strip
()
status_filter
=
request
.
args
.
get
(
'status'
,
''
)
.
strip
()
search_query
=
request
.
args
.
get
(
'search'
,
''
)
.
strip
()
start_date_filter
=
request
.
args
.
get
(
'start_date'
,
''
)
.
strip
()
end_date_filter
=
request
.
args
.
get
(
'end_date'
,
''
)
.
strip
()
sort_by
=
request
.
args
.
get
(
'sort_by'
,
'created_at'
)
sort_order
=
request
.
args
.
get
(
'sort_order'
,
'desc'
)
# Pagination
page
=
request
.
args
.
get
(
'page'
,
1
,
type
=
int
)
per_page
=
min
(
request
.
args
.
get
(
'per_page'
,
50
,
type
=
int
),
200
)
# Base query
if
current_user
.
is_admin
:
query
=
ReportSyncLog
.
query
else
:
# Non-admin users can only see logs from their own clients
from
app.models
import
APIToken
,
ClientActivity
user_token_ids
=
[
t
.
id
for
t
in
APIToken
.
query
.
filter_by
(
user_id
=
current_user
.
id
)
.
all
()]
if
user_token_ids
:
client_ids
=
[
c
.
rustdesk_id
for
c
in
ClientActivity
.
query
.
filter
(
ClientActivity
.
api_token_id
.
in_
(
user_token_ids
)
)
.
all
()]
if
client_ids
:
query
=
ReportSyncLog
.
query
.
filter
(
ReportSyncLog
.
client_id
.
in_
(
client_ids
))
else
:
query
=
ReportSyncLog
.
query
.
filter
(
ReportSyncLog
.
client_id
==
'none'
)
else
:
query
=
ReportSyncLog
.
query
.
filter
(
ReportSyncLog
.
client_id
==
'none'
)
# Apply filters
if
client_id_filter
:
query
=
query
.
filter
(
ReportSyncLog
.
client_id
==
client_id_filter
)
if
operation_type_filter
:
query
=
query
.
filter
(
ReportSyncLog
.
operation_type
==
operation_type_filter
)
if
status_filter
:
query
=
query
.
filter
(
ReportSyncLog
.
status
==
status_filter
)
if
start_date_filter
:
try
:
start_date
=
datetime
.
strptime
(
start_date_filter
,
'
%
Y-
%
m-
%
d'
)
query
=
query
.
filter
(
ReportSyncLog
.
created_at
>=
start_date
)
except
ValueError
:
pass
if
end_date_filter
:
try
:
end_date
=
datetime
.
strptime
(
end_date_filter
,
'
%
Y-
%
m-
%
d'
)
# Include the entire end date
end_date
=
end_date
.
replace
(
hour
=
23
,
minute
=
59
,
second
=
59
)
query
=
query
.
filter
(
ReportSyncLog
.
created_at
<=
end_date
)
except
ValueError
:
pass
# Search functionality
if
search_query
:
search_pattern
=
f
"
%
{search_query}
%
"
query
=
query
.
filter
(
or_
(
ReportSyncLog
.
sync_id
.
ilike
(
search_pattern
),
ReportSyncLog
.
client_id
.
ilike
(
search_pattern
),
ReportSyncLog
.
error_message
.
ilike
(
search_pattern
)
)
)
# Sorting
if
hasattr
(
ReportSyncLog
,
sort_by
):
sort_column
=
getattr
(
ReportSyncLog
,
sort_by
)
if
sort_order
==
'asc'
:
query
=
query
.
order_by
(
sort_column
.
asc
())
else
:
query
=
query
.
order_by
(
sort_column
.
desc
())
else
:
query
=
query
.
order_by
(
ReportSyncLog
.
created_at
.
desc
())
# Pagination
logs_pagination
=
query
.
paginate
(
page
=
page
,
per_page
=
per_page
,
error_out
=
False
)
# Get unique client IDs for filter dropdown
if
current_user
.
is_admin
:
all_client_ids
=
db
.
session
.
query
(
ReportSyncLog
.
client_id
)
.
distinct
()
.
all
()
else
:
if
user_token_ids
:
all_client_ids
=
db
.
session
.
query
(
ClientActivity
.
rustdesk_id
)
.
filter
(
ClientActivity
.
api_token_id
.
in_
(
user_token_ids
)
)
.
distinct
()
.
all
()
else
:
all_client_ids
=
[]
client_ids
=
[
cid
[
0
]
for
cid
in
all_client_ids
if
cid
[
0
]]
return
render_template
(
'main/sync_logs.html'
,
logs
=
logs_pagination
.
items
,
pagination
=
logs_pagination
,
client_ids
=
client_ids
,
filters
=
{
'client_id'
:
client_id_filter
,
'operation_type'
:
operation_type_filter
,
'status'
:
status_filter
,
'search'
:
search_query
,
'start_date'
:
start_date_filter
,
'end_date'
:
end_date_filter
,
'sort_by'
:
sort_by
,
'sort_order'
:
sort_order
})
except
Exception
as
e
:
logger
.
error
(
f
"Sync logs page error: {str(e)}"
)
flash
(
'Error loading sync logs'
,
'error'
)
return
render_template
(
'main/sync_logs.html'
,
logs
=
[],
pagination
=
None
,
client_ids
=
[])
def
export_sync_logs
(
export_format
):
"""Export sync logs to CSV, XLSX, or PDF"""
try
:
from
app.models
import
ReportSyncLog
from
sqlalchemy
import
and_
,
or_
from
flask
import
make_response
,
send_file
import
pandas
as
pd
from
io
import
BytesIO
from
datetime
import
datetime
# Get filter parameters
client_id_filter
=
request
.
args
.
get
(
'client_id'
,
''
)
.
strip
()
...
...
@@ -1979,247 +2219,4 @@ def export_sync_logs(export_format):
except
Exception
as
e
:
logger
.
error
(
f
"Export sync logs error: {str(e)}"
)
flash
(
'Error exporting sync logs'
,
'error'
)
return
redirect
(
url_for
(
'main.sync_logs'
))
# Base query
if
current_user
.
is_admin
:
query
=
ReportSyncLog
.
query
else
:
# Non-admin users can only see logs from their own clients
from
app.models
import
APIToken
,
ClientActivity
user_token_ids
=
[
t
.
id
for
t
in
APIToken
.
query
.
filter_by
(
user_id
=
current_user
.
id
)
.
all
()]
if
user_token_ids
:
client_ids
=
[
c
.
rustdesk_id
for
c
in
ClientActivity
.
query
.
filter
(
ClientActivity
.
api_token_id
.
in_
(
user_token_ids
)
)
.
all
()]
if
client_ids
:
query
=
ReportSyncLog
.
query
.
filter
(
ReportSyncLog
.
client_id
.
in_
(
client_ids
))
else
:
query
=
ReportSyncLog
.
query
.
filter
(
ReportSyncLog
.
client_id
==
'none'
)
else
:
query
=
ReportSyncLog
.
query
.
filter
(
ReportSyncLog
.
client_id
==
'none'
)
# Apply filters
if
client_id_filter
:
query
=
query
.
filter
(
ReportSyncLog
.
client_id
==
client_id_filter
)
if
operation_type_filter
:
query
=
query
.
filter
(
ReportSyncLog
.
operation_type
==
operation_type_filter
)
if
status_filter
:
query
=
query
.
filter
(
ReportSyncLog
.
status
==
status_filter
)
if
start_date_filter
:
try
:
start_date
=
datetime
.
strptime
(
start_date_filter
,
'
%
Y-
%
m-
%
d'
)
query
=
query
.
filter
(
ReportSyncLog
.
created_at
>=
start_date
)
except
ValueError
:
pass
if
end_date_filter
:
try
:
end_date
=
datetime
.
strptime
(
end_date_filter
,
'
%
Y-
%
m-
%
d'
)
# Include the entire end date
end_date
=
end_date
.
replace
(
hour
=
23
,
minute
=
59
,
second
=
59
)
query
=
query
.
filter
(
ReportSyncLog
.
created_at
<=
end_date
)
except
ValueError
:
pass
# Search functionality
if
search_query
:
search_pattern
=
f
"
%
{search_query}
%
"
query
=
query
.
filter
(
or_
(
ReportSyncLog
.
sync_id
.
ilike
(
search_pattern
),
ReportSyncLog
.
client_id
.
ilike
(
search_pattern
),
ReportSyncLog
.
error_message
.
ilike
(
search_pattern
)
)
)
# Sorting
if
hasattr
(
ReportSyncLog
,
sort_by
):
sort_column
=
getattr
(
ReportSyncLog
,
sort_by
)
if
sort_order
==
'asc'
:
query
=
query
.
order_by
(
sort_column
.
asc
())
else
:
query
=
query
.
order_by
(
sort_column
.
desc
())
else
:
query
=
query
.
order_by
(
ReportSyncLog
.
created_at
.
desc
())
# Pagination
logs_pagination
=
query
.
paginate
(
page
=
page
,
per_page
=
per_page
,
error_out
=
False
)
# Get unique client IDs for filter dropdown
if
current_user
.
is_admin
:
all_client_ids
=
db
.
session
.
query
(
ReportSyncLog
.
client_id
)
.
distinct
()
.
all
()
else
:
if
user_token_ids
:
all_client_ids
=
db
.
session
.
query
(
ClientActivity
.
rustdesk_id
)
.
filter
(
ClientActivity
.
api_token_id
.
in_
(
user_token_ids
)
)
.
distinct
()
.
all
()
else
:
all_client_ids
=
[]
client_ids
=
[
cid
[
0
]
for
cid
in
all_client_ids
if
cid
[
0
]]
return
render_template
(
'main/sync_logs.html'
,
logs
=
logs_pagination
.
items
,
pagination
=
logs_pagination
,
client_ids
=
client_ids
,
filters
=
{
'client_id'
:
client_id_filter
,
'operation_type'
:
operation_type_filter
,
'status'
:
status_filter
,
'search'
:
search_query
,
'start_date'
:
start_date_filter
,
'end_date'
:
end_date_filter
,
'sort_by'
:
sort_by
,
'sort_order'
:
sort_order
})
except
Exception
as
e
:
logger
.
error
(
f
"Sync logs page error: {str(e)}"
)
flash
(
'Error loading sync logs'
,
'error'
)
return
render_template
(
'main/sync_logs.html'
,
logs
=
[],
pagination
=
None
,
client_ids
=
[])
# Prepare data for export
export_data
=
[]
for
report
in
reports
:
# Get bets and stats for this report
bets
=
Bet
.
query
.
filter_by
(
sync_id
=
report
.
id
)
.
all
()
stats
=
ExtractionStats
.
query
.
filter_by
(
sync_id
=
report
.
id
)
.
all
()
# Add summary row
export_data
.
append
({
'Type'
:
'Summary'
,
'Sync ID'
:
report
.
sync_id
,
'Client ID'
:
report
.
client_id
,
'Sync Timestamp'
:
report
.
sync_timestamp
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
report
.
sync_timestamp
else
''
,
'Date Range'
:
report
.
date_range
,
'Start Date'
:
report
.
start_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
start_date
else
''
,
'End Date'
:
report
.
end_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
end_date
else
''
,
'Total Payin'
:
float
(
report
.
total_payin
)
if
report
.
total_payin
else
0.0
,
'Total Payout'
:
float
(
report
.
total_payout
)
if
report
.
total_payout
else
0.0
,
'Net Profit'
:
float
(
report
.
net_profit
)
if
report
.
net_profit
else
0.0
,
'Total Bets'
:
report
.
total_bets
,
'Total Matches'
:
report
.
total_matches
,
'Bet UUID'
:
''
,
'Match ID'
:
''
,
'Outcome'
:
''
,
'Amount'
:
''
,
'Result'
:
''
})
# Add bet details
for
bet
in
bets
:
for
detail
in
bet
.
details
:
export_data
.
append
({
'Type'
:
'Bet Detail'
,
'Sync ID'
:
report
.
sync_id
,
'Client ID'
:
report
.
client_id
,
'Sync Timestamp'
:
report
.
sync_timestamp
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
report
.
sync_timestamp
else
''
,
'Date Range'
:
report
.
date_range
,
'Start Date'
:
report
.
start_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
start_date
else
''
,
'End Date'
:
report
.
end_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
end_date
else
''
,
'Total Payin'
:
''
,
'Total Payout'
:
''
,
'Net Profit'
:
''
,
'Total Bets'
:
''
,
'Total Matches'
:
''
,
'Bet UUID'
:
bet
.
uuid
,
'Match ID'
:
detail
.
match_id
,
'Outcome'
:
detail
.
outcome
,
'Amount'
:
float
(
detail
.
amount
)
if
detail
.
amount
else
0.0
,
'Result'
:
detail
.
result
})
# Add extraction stats
for
stat
in
stats
:
export_data
.
append
({
'Type'
:
'Extraction Stats'
,
'Sync ID'
:
report
.
sync_id
,
'Client ID'
:
report
.
client_id
,
'Sync Timestamp'
:
report
.
sync_timestamp
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
report
.
sync_timestamp
else
''
,
'Date Range'
:
report
.
date_range
,
'Start Date'
:
report
.
start_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
start_date
else
''
,
'End Date'
:
report
.
end_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
if
report
.
end_date
else
''
,
'Total Payin'
:
float
(
stat
.
total_amount_collected
)
if
stat
.
total_amount_collected
else
0.0
,
'Total Payout'
:
float
(
stat
.
total_redistributed
)
if
stat
.
total_redistributed
else
0.0
,
'Net Profit'
:
''
,
'Total Bets'
:
stat
.
total_bets
,
'Total Matches'
:
''
,
'Bet UUID'
:
''
,
'Match ID'
:
stat
.
match_id
,
'Outcome'
:
stat
.
actual_result
,
'Amount'
:
''
,
'Result'
:
stat
.
extraction_result
})
# Create DataFrame
df
=
pd
.
DataFrame
(
export_data
)
# Export based on format
if
export_format
==
'csv'
:
output
=
io
.
StringIO
()
df
.
to_csv
(
output
,
index
=
False
)
output
.
seek
(
0
)
return
Response
(
output
.
getvalue
(),
mimetype
=
'text/csv'
,
headers
=
{
'Content-Disposition'
:
'attachment; filename=reports_export.csv'
}
)
elif
export_format
==
'xlsx'
:
output
=
io
.
BytesIO
()
with
pd
.
ExcelWriter
(
output
,
engine
=
'openpyxl'
)
as
writer
:
df
.
to_excel
(
writer
,
index
=
False
,
sheet_name
=
'Reports'
)
output
.
seek
(
0
)
return
Response
(
output
.
getvalue
(),
mimetype
=
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
,
headers
=
{
'Content-Disposition'
:
'attachment; filename=reports_export.xlsx'
}
)
elif
export_format
==
'pdf'
:
# For PDF, we'll create a simple HTML table and convert it
from
weasyprint
import
HTML
import
tempfile
# Create HTML table
html_table
=
df
.
to_html
(
index
=
False
,
classes
=
'table table-striped table-bordered'
)
html_content
=
f
"""
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
table {{ border-collapse: collapse; width: 100
%
; margin-bottom: 20px; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
th {{ background-color: #4CAF50; color: white; }}
tr:nth-child(even) {{ background-color: #f2f2f2; }}
</style>
</head>
<body>
<h1>Reports Export</h1>
<p>Generated on: {datetime.utcnow().strftime('
%
Y-
%
m-
%
d
%
H:
%
M:
%
S')}</p>
{html_table}
</body>
</html>
"""
# Generate PDF
pdf_bytes
=
HTML
(
string
=
html_content
)
.
write_pdf
()
return
Response
(
pdf_bytes
,
mimetype
=
'application/pdf'
,
headers
=
{
'Content-Disposition'
:
'attachment; filename=reports_export.pdf'
}
)
else
:
flash
(
'Invalid export format'
,
'error'
)
return
redirect
(
url_for
(
'main.reports'
))
except
Exception
as
e
:
logger
.
error
(
f
"Export reports error: {str(e)}"
)
flash
(
'Error exporting reports'
,
'error'
)
return
redirect
(
url_for
(
'main.reports'
))
\ No newline at end of file
return
redirect
(
url_for
(
'main.sync_logs'
))
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment