Merge branch 'release/v23.9.0'
This commit is contained in:
@@ -357,6 +357,78 @@ def correct_intensity(workout):
|
||||
|
||||
return workout
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import io
|
||||
import zipfile
|
||||
|
||||
@app.task
|
||||
def email_all_user_workouts_zip(rower, start_date=None, end_date=None, debug=False, **kwargs):
|
||||
# Get all workouts for this user, optionally filtered by date range
|
||||
workouts = Workout.objects.filter(user=rower).order_by('-date')
|
||||
|
||||
# Apply date filters if provided
|
||||
if start_date:
|
||||
workouts = workouts.filter(date__gte=start_date)
|
||||
if end_date:
|
||||
workouts = workouts.filter(date__lte=end_date)
|
||||
|
||||
# for debug, limit to 5 workouts
|
||||
if settings.DEBUG:
|
||||
workouts = workouts[:5]
|
||||
|
||||
if not workouts.exists():
|
||||
dologging('export_all_workouts.log', f"No workouts found for user {rower.user.id} in date range {start_date} to {end_date}")
|
||||
return 0
|
||||
|
||||
# Create ZIP file in memory
|
||||
zip_buffer = io.BytesIO()
|
||||
|
||||
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
|
||||
for workout in workouts:
|
||||
try:
|
||||
rowdata = rdata(csvfile=workout.csvfilename)
|
||||
workouttype = mytypes.fitmapping.get(workout.workouttype, 'generic')
|
||||
|
||||
fit_filename = f"workout_{workout.id}_{workout.date.strftime('%Y%m%d')}.fit"
|
||||
# exporttofit creates a file, we need to add it to the zip_file
|
||||
rowdata.exporttofit(fit_filename, sport=workouttype, notes=workout.name)
|
||||
zip_file.write(fit_filename, arcname=fit_filename)
|
||||
os.remove(fit_filename)
|
||||
except Exception as e: # pragma: no cover
|
||||
dologging('export_all_workouts.log', f"Error exporting workout {workout.id}: {str(e)}")
|
||||
continue
|
||||
|
||||
# Save ZIP file to disk
|
||||
export_date = datetime.datetime.now().strftime('%Y%m%d')
|
||||
filename = f"{rower.user.username}_workouts_{export_date}_from_{start_date}_to_{end_date}_{uuid4().hex[:8]}.zip"
|
||||
zip_file_path = os.path.join(settings.MEDIA_ROOT, filename)
|
||||
|
||||
try:
|
||||
with open(zip_file_path, 'wb') as f:
|
||||
f.write(zip_buffer.getvalue())
|
||||
except Exception as e: # pragma: no cover
|
||||
dologging('export_all_workouts.log', f"Error saving ZIP file: {str(e)}")
|
||||
return 0
|
||||
|
||||
# Send email with download link
|
||||
subject = "Rowsandall Workouts Export"
|
||||
from_email = 'Rowsandall <info@rowsandall.com>'
|
||||
useremail = rower.user.email
|
||||
|
||||
# Generate download URL
|
||||
download_url = f"{SITE_URL}/rowers/workouts/download/?file={filename}"
|
||||
|
||||
_ = send_template_email(
|
||||
from_email, [useremail],
|
||||
subject,
|
||||
'workouts_export_email.html',
|
||||
{'download_url': download_url, 'filename': filename},
|
||||
)
|
||||
|
||||
return 1
|
||||
|
||||
>>>>>>> release/v23.9.0
|
||||
|
||||
@app.task
|
||||
def handle_loadnextweek(rower, debug=False, **kwargs):
|
||||
|
||||
@@ -260,6 +260,11 @@
|
||||
TCX
|
||||
</a>
|
||||
</li>
|
||||
<li id="export-fit">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/emailfit/">
|
||||
FIT
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="has-children" id="data">
|
||||
|
||||
@@ -490,6 +490,8 @@ urlpatterns = [
|
||||
name='workout_comment_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/emailtcx/$', views.workout_tcxemail_view,
|
||||
name='workout_tcxemail_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/emailfit/$', views.workout_fitemail_view,
|
||||
name='workout_fitemail_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/emailgpx/$', views.workout_gpxemail_view,
|
||||
name='workout_gpxemail_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/emailcsv/$', views.workout_csvemail_view,
|
||||
|
||||
@@ -22,6 +22,27 @@ def workout_tcxemail_view(request, id=0):
|
||||
os.remove(tcxfilename)
|
||||
return response
|
||||
|
||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
||||
def workout_fitemail_view(request, id=0):
|
||||
w = get_workout(id)
|
||||
|
||||
row = rdata(csvfile=w.csvfilename)
|
||||
|
||||
code = str(uuid4())
|
||||
fitfilename = code+'.fit'
|
||||
|
||||
workouttype = mytypes.fitmapping.get(w.workouttype, 'generic')
|
||||
|
||||
row.exporttofit(fitfilename, sport=workouttype, notes=w.name)
|
||||
|
||||
with open(fitfilename, 'rb') as f:
|
||||
response = HttpResponse(f)
|
||||
response['Content-Disposition'] = 'attachment; filename="%s"' % fitfilename
|
||||
response['Content-Type'] = 'application/octet-stream'
|
||||
|
||||
os.remove(fitfilename)
|
||||
return response
|
||||
|
||||
|
||||
@login_required()
|
||||
def plannedsessions_icsemail_view(request, userid=0):
|
||||
|
||||
Reference in New Issue
Block a user