Skip to content

Commit

Permalink
Merge pull request #230 from tuttle-dev/dev-packaging
Browse files Browse the repository at this point in the history
fix: profile photo upload
  • Loading branch information
clstaudt authored Apr 16, 2023
2 parents e3d6d2f + 5bfeda4 commit fc1ea49
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,4 @@ app/assets/uploads

# visual studio workspaces
*.code-workspace
assets/uploads/*
20 changes: 0 additions & 20 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,38 +105,19 @@ def page_resize(self, e):
def pick_file_callback(
self,
on_file_picker_result,
on_upload_progress,
allowed_extensions,
dialog_title,
file_type,
):
# used by views to request a file upload
self.file_picker.on_result = on_file_picker_result
self.file_picker.on_upload = on_upload_progress
self.file_picker.pick_files(
allow_multiple=False,
allowed_extensions=allowed_extensions,
dialog_title=dialog_title,
file_type=file_type,
)

def upload_file_callback(self, file):
try:
upload_to = self.page.get_upload_url(file.name, 600)
upload_item = FilePickerUploadFile(
file.name,
upload_url=upload_to,
)
self.file_picker.upload([upload_item])

upload_path_in_assets = f"{get_assets_uploads_url()}/{file.name}"
return upload_path_in_assets
except Exception as e:
logger.error(
f"Exception @app.upload_file_callback raised during file upload {e.__class__.__name__}"
)
logger.exception(e)
return None

def on_theme_mode_changed(self, selected_theme: str):
"""callback function used by views for changing app theme mode"""
Expand Down Expand Up @@ -281,7 +262,6 @@ def __init__(self, app: TuttleApp):
dialog_controller=app.control_alert_dialog,
on_navigate_back=app.on_view_pop,
client_storage=app.client_storage,
upload_file_callback=app.upload_file_callback,
pick_file_callback=app.pick_file_callback,
)

Expand Down
50 changes: 24 additions & 26 deletions tuttle/app/auth/view.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Callable, Optional

from pathlib import Path
from flet import (
Column,
Container,
Expand Down Expand Up @@ -501,7 +501,6 @@ def on_update_photo_clicked(self, e):
"""Callback for when user clicks on the update photo button"""
self.pick_file_callback(
on_file_picker_result=self.on_profile_photo_picked,
on_upload_progress=self.uploading_profile_pic_progress_listener,
allowed_extensions=["png", "jpeg", "jpg"],
dialog_title="Tuttle profile photo",
file_type="custom",
Expand All @@ -511,30 +510,29 @@ def on_profile_photo_picked(self, e):
"""Callback for when profile photo has been picked"""
if e.files and len(e.files) > 0:
file = e.files[0]
upload_url = self.upload_file_callback(file)
upload_url = Path(file.path)
if upload_url:
self.uploaded_photo_path = upload_url

def uploading_profile_pic_progress_listener(self, e):
"""Callback for when profile photo is being uploaded"""
if e.progress == 1.0:
if self.uploaded_photo_path:
result = self.intent.update_user_photo_path(
self.user_profile,
self.uploaded_photo_path,
)
# assume error occurred
msg = result.error_msg
is_err = True
if result.was_intent_successful:
self.profile_photo_img.src = self.uploaded_photo_path
msg = "Profile photo updated"
is_err = False
self.show_snack(msg, is_err)
if is_err:
self.user_profile.profile_photo_path = ""
self.uploaded_photo_path = None # clear
self.update_self()
self.uploaded_photo_path = str(upload_url)
self.setProfilePic()

def setProfilePic(self):
"""Updates the profile photo"""
if not self.uploaded_photo_path:
return
result = self.intent.update_user_photo_path(self.user_profile, self.uploaded_photo_path,)
# assume error occurred
msg = result.error_msg
is_err = True
if result.was_intent_successful:
self.profile_photo_img.src_base64 = utils.toBase64(self.uploaded_photo_path)
msg = "Profile photo updated"
is_err = False
self.show_snack(msg, is_err)
if is_err:
self.user_profile.profile_photo_path = ""
self.uploaded_photo_path = None # clear
self.update_self()


def build(self):
self.profile_photo_img = views.TProfilePhotoImg()
Expand Down Expand Up @@ -564,7 +562,7 @@ def did_mount(self):
else:
self.user_profile: User = result.data
if self.user_profile.profile_photo_path:
self.profile_photo_img.src = self.user_profile.profile_photo_path
self.profile_photo_img.src_base64 = utils.toBase64(self.user_profile.profile_photo_path)
self.update_self()

def will_unmount(self):
Expand Down
2 changes: 0 additions & 2 deletions tuttle/app/core/abstractions.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ class TViewParams:
navigate_to_route: Callable
show_snack: Callable
dialog_controller: Callable
upload_file_callback: Callable
pick_file_callback: Callable[[file_picker.FilePickerFile], str]
client_storage: ClientStorage
vertical_alignment_in_parent: str = START_ALIGNMENT
Expand All @@ -118,7 +117,6 @@ def __init__(self, params: TViewParams):
self.keep_back_stack = params.keep_back_stack
self.navigate_back = params.on_navigate_back
self.page_scroll_type = params.page_scroll_type
self.upload_file_callback = params.upload_file_callback
self.pick_file_callback = params.pick_file_callback
self.client_storage = params.client_storage
self.mounted = False
Expand Down
15 changes: 15 additions & 0 deletions tuttle/app/core/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import warnings
import base64

warnings.warn(
"wastebasket module, content will be moved to other modules",
Expand Down Expand Up @@ -144,3 +145,17 @@ def get_currencies() -> List[Tuple[str, str, str]]:
# sort alphabetically by abbreviation
currencies.sort(key=lambda tup: tup[1])
return currencies


def toBase64(
image_path,
) -> str:
"""Returns base64 encoded image from the path"""

# Read the image file as bytes
with open(image_path, "rb") as image_file:
image_bytes = image_file.read()
# Convert the bytes to a base64
stringbase64_string = base64.b64encode(image_bytes).decode("utf-8")

return stringbase64_string
47 changes: 25 additions & 22 deletions tuttle/app/timetracking/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,12 @@ def on_add_timetrack_from_file(
):
"""Open file picker to select a file to upload"""
self.close_pop_up_if_open()
if not is_spreadsheet and not is_ics:
return
allowed_exts = ["ics"] if is_ics else ["xlsx", "csv", "xls", "tsv", "ods"]
title = "Select .ics file" if is_ics else "Select excel file"
self.pick_file_callback(
on_file_picker_result=self.on_file_picker_result,
on_upload_progress=self.on_upload_progress,
allowed_extensions=allowed_exts,
dialog_title=title,
file_type="custom",
Expand All @@ -220,33 +221,35 @@ def on_file_picker_result(self, e: FilePickerResultEvent):
if e.files and len(e.files) > 0:
file = e.files[0]
self.set_progress_hint(f"Uploading file {file.name}")
self.upload_file_callback(file)
upload_path = Path(file.path)
if upload_path:
self.uploaded_file_path = upload_path
self.extract_dataframe_from_file()
else:
self.set_progress_hint(hide_progress=True)

def on_upload_progress(self, e: FilePickerUploadEvent):
"""Handle file upload progress"""
if e.progress == 1.0:
# upload complete
self.set_progress_hint(f"Upload complete, processing file...")
intent_result = self.intent.process_timetracking_file(
self.uploaded_file_path,
)
msg = (
"New work progress recorded."
if intent_result.was_intent_successful
else intent_result.error_msg
)
is_error = not intent_result.was_intent_successful
self.show_snack(msg, is_error)
if intent_result.was_intent_successful:
self.dataframe_to_display = intent_result.data
self.update_timetracking_dataframe()
self.display_dataframe()
self.set_progress_hint(hide_progress=True)
def extract_dataframe_from_file(self,):

"""Execute intent to process file"""
if not self.uploaded_file_path:
return
# upload complete
self.set_progress_hint(f"Upload complete, processing file...")
intent_result = self.intent.process_timetracking_file(
self.uploaded_file_path,
)
msg = (
"New work progress recorded."
if intent_result.was_intent_successful
else intent_result.error_msg
)
is_error = not intent_result.was_intent_successful
self.show_snack(msg, is_error)
if intent_result.was_intent_successful:
self.dataframe_to_display = intent_result.data
self.update_timetracking_dataframe()
self.display_dataframe()
self.set_progress_hint(hide_progress=True)

"""Cloud calendar setup"""

Expand Down

0 comments on commit fc1ea49

Please sign in to comment.