Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new-download-fix #1057

Merged
merged 12 commits into from
Nov 14, 2023
Merged

new-download-fix #1057

merged 12 commits into from
Nov 14, 2023

Conversation

AnkurPrabhu
Copy link
Contributor

Issue Link #375 @derneuere
New Pr for #1055
what has been done :

have created a job type in long_running_job for download
created two method one for making the zip file i.e zip_photos_task and second which call the zip function i.e create_download_job
created a get api for the same view class which checks the status of the running job
Pending:

checking file system storage before starting the zipping process
test file

@AnkurPrabhu
Copy link
Contributor Author

AnkurPrabhu commented Oct 27, 2023

@derneuere the pre-commit hooks does not work for me in local while commiting code i run it manually with pre-commit run --all-files

@derneuere
Copy link
Member

I think you just have to install with pip install pre-commit and install the dev dependencies and then it should complain on all commits :)

@derneuere
Copy link
Member

Oh, and you need to do a pre-commit install once it's installed!

@derneuere
Copy link
Member

You don't have to change the proxy.conf folder as protected_media and its subfolders get already rerouted :)
Yes, from my understanding, nginx handles download automagically and should use chunking or something similar.

@AnkurPrabhu
Copy link
Contributor Author

hey i am a little confused here as in what are all the things that are pending for this issue. I have listed some below pls let me know if there are more
pending work for this pr :

  • test file
  • nginx/rerouting
  • front end pr for using the new downlaod api

@derneuere
Copy link
Member

Just think feature first. We are still trying to fix the bug and handle large downloads.

Right now, we should see a new long-running job, when we click on download with new api. This starts zipping the file. When the job is done, indicated with the long-running job, we should then call api/media/zip/.zip, to start downloading.

There are still two issues, feature wise. The user wants the zip to get deleted after the download, because he wants to conserve space. For this, we have now two new cases:

  1. We need to delete the zip when we successfully downloaded the file.
  2. If the user closes the window or quits the download process, we also need to handle the zip. We can either delete it with an expiry window, or if the download stops :)

@AnkurPrabhu
Copy link
Contributor Author

AnkurPrabhu commented Oct 28, 2023

i was thinking of making something like a cron job which schedules the delete_zip_from_local job one day after it has been created
also you want me to put these two use cases in the same pr or a different one ?

@derneuere
Copy link
Member

You can use this schedule function for it! Just schedule the job, when you create the zipping job https://django-q2.readthedocs.io/en/master/schedules.html

Yes this all belongs in the same PR as it is one feature :)

try:
job=LongRunningJob.objects.get(job_id=request.data["job_id"])
if job.finished:
zip_file_path = os.path.join("/protected_media/all_zip_folder/", request.data["url"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use constant from the settings (MEDIA_ROOT)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@AnkurPrabhu
Copy link
Contributor Author

AnkurPrabhu commented Oct 29, 2023

@derneuere @sickelap after using nginx its pretty fast and i loved it !! can you pls tell me how did you set nginx up for librephotos also the test file is remaining now can you pls guide me through it not sure how to go about it also should i start working on the frontend pr ?

@sickelap
Copy link
Contributor

Ideally, we should have a managed task that we could run as a cronjob. As a one of the tasks, we could do a cleanup for whatever we need to cleanup...
check commands for an inspiration

@AnkurPrabhu
Copy link
Contributor Author

Ideally, we should have a managed task that we could run as a cronjob. As a one of the tasks, we could do a cleanup for whatever we need to cleanup... check commands for an inspiration

so should i remove the delete function i schedule during creation ? or this cron job is a different one which admins can use ?

@AnkurPrabhu
Copy link
Contributor Author

AnkurPrabhu commented Oct 29, 2023

I have added a test file which tests 2 scenarios :-

  • when we have enough storage
  • when we do not have sufficient storage

@AnkurPrabhu
Copy link
Contributor Author

hey @derneuere can we have the label "HACKTOBERFEST-ACCEPTED" for both of my prs #1057 and #778 as hacktober will end soon and i just want 2 prs to be accepted/approved/merged it would really mean a lot and would motivate me, thank-you

@derneuere
Copy link
Member

Added the labels to the pull requests and to the ones, that were already merged :)

The nginx proxy gets configured in here: https://github.com/LibrePhotos/librephotos-docker/blob/main/proxy/nginx.conf

I don't think that you have to add another location, as the zip folder is a subfolder of protected_media.

You can either use cronjobs or the schedule function in django q2. Both mechanism can be used to solve the issue, that the zip gets deleted after a time period.

The scheduled async task or the cronjob should get added once a zip gets created. It als should handle it gracefully, if the zip is already missing.

I would prefer the schedule function as the user can see this in the django-admin dashboard.

The testcases look good! If you can think of other cases, which could break this function, then add cases for it too :)

@AnkurPrabhu
Copy link
Contributor Author

AnkurPrabhu commented Oct 30, 2023

Added the labels to the pull requests and to the ones, that were already merged :)

Hey thank-you soo much for this and all the time you have given for guiding me really ...means a lot <3

The nginx proxy gets configured in here: https://github.com/LibrePhotos/librephotos-docker/blob/main/proxy/nginx.conf

thankyou

I don't think that you have to add another location, as the zip folder is a subfolder of protected_media.

i did not understand this i am using the protected_media constant

You can either use cronjobs or the schedule function in django q2. Both mechanism can be used to solve the issue, that the zip gets deleted after a time period.

I have used schedule once the file is created in the file api/all_tasks.py

The scheduled async task or the cronjob should get added once a zip gets created. It als should handle it gracefully, if the zip is already missing.

i have addressed this in delete_zip_file function in the file api/all_tasks.py

The testcases look good! If you can think of other cases, which could break this function, then add cases for it too :)

sure

@AnkurPrabhu
Copy link
Contributor Author

@derneuere @sickelap can we discuss what is exactly missing/remaining here was planning to close this soon

@derneuere
Copy link
Member

  • A frontend PR, which makes it possible to test this end to end
  • A way that the zip gets removed after download
  • Removal of the old download method

@AnkurPrabhu
Copy link
Contributor Author

  • A way that the zip gets removed after download

i schedule the delete method once its created do you want to also delete it if it has been downloaded by the user ?

@derneuere
Copy link
Member

Yes, either by triggering an endpoint or by some other mechanisms. If I download multiple albums or have multiple users, I do not want my hard drive to be filled up, if it is not necessary.

@sickelap
Copy link
Contributor

One more thing. It seems that the archive will be accessible by anyone who know the link. Is this intentional? Should we have a check to validate that only an owner can download the archive? Just a thought...

@derneuere
Copy link
Member

Hmm, true. The easiest fix is, to put the user id into the filename, when zipping and checking for it when downloading. To enhance the security a bit more, the download name should not be guessable. so something like a <uuid + user id>.zip should work fine.

@AnkurPrabhu
Copy link
Contributor Author

Yes, either by triggering an endpoint or by some other mechanisms. If I download multiple albums or have multiple users, I do not want my hard drive to be filled up, if it is not necessary.

i just saw that we are storing everything(images,videos) locally right ? so for multiple users everyone will have photos on their local disk then why do we have a download option why are we not just pointing the disk location of the zip file instead of sending it to the user through frontend ?

@derneuere
Copy link
Member

In this case locally means a self-hosted system, which may or may not be the same system as the client. You can have users, which do not have direct access to the server like for example friends, which want to download the pictures from the last party. In that case a download function is still needed.

@AnkurPrabhu
Copy link
Contributor Author

AnkurPrabhu commented Oct 31, 2023

In this case locally means a self-hosted system, which may or may not be the same system as the client. You can have users, which do not have direct access to the server like for example friends, which want to download the pictures from the last party. In that case a download function is still needed.

oh okay so if i use libre photos and want to share access with my friends my friends can download images but those images will be from my device storage ? so if any other user uploads something it will be stored in my device ? asking these because i really wanted to know more about the product

@derneuere
Copy link
Member

It's similar to other photo management systems. The systems which hosts the docker container acts as a cloud for the other devices. Other devices can upload images to your cloud, if they have an account and can share them from your cloud.

LibrePhotos acts as a multi user system, which means it can have multiple accounts. The images will then just be placed in a subfolder for each user.

@sickelap
Copy link
Contributor

sickelap commented Nov 1, 2023

My opinion LP is not a file sharing platform. As I understood the feature is to download your photos to local machine, not to create an archive for others to download. I agree with @derneuere and photo sharing feature within the LP should be enough for sharing.

@AnkurPrabhu
Copy link
Contributor Author

@derneuere @sickelap i have created a delete api which we can call from front-end as soon as the download is successfull
also the changes for uuid+username has been added will start working on the front-end pr now

return Response(status=404)


class DeleteZipView(APIView):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be part of ZipListPhotosView_V2, I think :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh okay cool then will implement the delete inside the zip view only

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey i can do this but then i need the file path so sending it through body wont be good for a delete request moreover would have to edit the urls.py for make call to a function based view but then the pattern of all class based views would not continue so i was thinking of making it as a separate view class

@@ -251,6 +253,7 @@ class MediaAccessView(APIView):
permission_classes = (AllowAny,)

def _get_protected_media_url(self, path, fname):
print(fname)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you forgot to remove this :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do it

lrj.save()
# scheduling a task to delete the zip file after a day
execution_time = timezone.now() + timezone.timedelta(days=1)
schedule("api.all_tasks.delete_zip_file", filename, next_run=execution_time)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sickelap The first point is already implemented. Right now, the zip file will get deleted after a day. The delete endpoint is the happy path, this clean up job is the edge case, where the user never downloads the zip.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will start with the front-end pr 🚀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, I have missed this one. I think this should be enough for automated cleanup.

@derneuere
Copy link
Member

I think we thought of most edge cases and looks pretty good. Found some smaller things and it would be great if you could remove the old view. Next step is to create the frontend pr, so that we can test it end to end :)

@AnkurPrabhu
Copy link
Contributor Author

@sickelap @derneuere
hey my plan for front-end implementation :

  • create a data for download so that it can be shared across components (redux store)
  • there are 3 componenets download_component, download_tray, and download_pannel
  • download pannel will be a left side menu panel
Screenshot 2023-11-03 at 8 46 02 PM
  • download tray will open when clicked on download pannel where we can see individual tasks
Screenshot 2023-11-03 at 8 47 18 PM
  • create a download component which replaces the current downlod option it basically sends data to the component download_pannel(left sidemenu) which creates a tray object and when clicked we can see the download progress n stuff
  • once the download is completed it can have the same code where it make a window object and click on the link automatically
  • thing is i dont have a lot of idea about redux so can you tell me how to go about it
  • pls let me know if changes are needed

@sickelap
Copy link
Contributor

sickelap commented Nov 3, 2023

I would recommend not over-complicate things and don't think about redux. Focus on the more simple download option first. When that's done you could think of other use case scenarios.

@sickelap
Copy link
Contributor

sickelap commented Nov 3, 2023

and be sure that all checks are green ;)

@AnkurPrabhu
Copy link
Contributor Author

I would recommend not over-complicate things and don't think about redux. Focus on the more simple download option first. When that's done you could think of other use case scenarios.

okay got it

@derneuere
Copy link
Member

Also, just use the notifications (https://v5.mantine.dev/core/notification/) to communicate, that zipping started or that the download is now starting. No need to make it work as a new component on the side.

Copy link

sonarcloud bot commented Nov 14, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 2 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@AnkurPrabhu
Copy link
Contributor Author

@sickelap commit hooks were failing because of some other files have fixed it mostly were because of unused imports

@sickelap sickelap merged commit d92681e into LibrePhotos:dev Nov 14, 2023
2 checks passed
@derneuere
Copy link
Member

Great work @AnkurPrabhu !!! 🎉

@AnkurPrabhu
Copy link
Contributor Author

@derneuere hey just wanted to know is it working as expected ?

@derneuere
Copy link
Member

@AnkurPrabhu I think so :) It will be part of the next release!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants