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

Back to python #33

Merged
merged 29 commits into from
Mar 15, 2024
Merged

Back to python #33

merged 29 commits into from
Mar 15, 2024

Conversation

csikb
Copy link
Collaborator

@csikb csikb commented Mar 15, 2024

Summary by CodeRabbit

  • New Features
    • Introduced health check endpoints for application monitoring.
    • Enhanced video upload process with organized folders for each member and video.
    • Implemented image service to generate images in multiple formats.
  • Enhancements
    • Optimized Docker build process with a separate builder stage and non-root user setup.
    • Restructured project functionality to better facilitate video uploads.
    • Improved error handling and content type validation for image uploads.
  • Refactor
    • Updated folder structure creation for members and videos.
    • Refined symlink handling across services.
  • Documentation
    • Added comprehensive docstrings to model classes.
    • Updated README to reflect shift in project functionality.
  • Tests
    • Modified video model tests to support list of URLs.
  • Chores
    • Enhanced CI/CD pipeline with new jobs for linting, testing, and Docker image publishing.

Copy link
Contributor

coderabbitai bot commented Mar 15, 2024

Walkthrough

The project saw significant enhancements, shifting its focus towards video upload management. Major updates include Docker and GitHub CLI integration for improved CI/CD workflows, code quality improvements through linting and testing, and Dockerfile restructuring for efficiency. The backend now supports health checks and has enhanced media file handling, organizing them per member using UUIDs and improving file processing capabilities.

Changes

Files Change Summary
.circleci/config.yml Integrated Docker, GitHub CLI; added jobs for linting, testing, Docker image building, and releasing.
.dockerignore, Dockerfile Optimized Docker build process, including better file exclusion and multi-stage builds.
README.md Updated project description to focus on video upload management.
src/bss_web_file_server/main.py Enhanced router organization, added health checks, and improved startup event handling.
src/bss_web_file_server/models/... Added/updated docstrings in models; modified Video model to support multiple URLs.
src/bss_web_file_server/routers/health.py Introduced health check endpoints.
src/bss_web_file_server/routers/member.py,
src/bss_web_file_server/routers/video.py
Updated endpoint paths, logic for media handling, and improved error handling.
src/bss_web_file_server/services/... Refined logic for image and video services, including format conversion and folder structure.
src/bss_web_file_server/settings.py Added settings management for the server.
tests/bss_web_file_server/models/test_video.py Updated tests to reflect changes in the Video model's URL handling.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

Copy link

sonarcloud bot commented Mar 15, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

@csikb csikb enabled auto-merge (squash) March 15, 2024 16:50
@csikb csikb merged commit 2194e4f into main Mar 15, 2024
6 checks passed
@csikb csikb deleted the python branch March 15, 2024 16:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 13

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 686f3a7 and 66a6b70.
Files ignored due to path filters (3)
  • docker-compose.yml is excluded by: !**/*.yml
  • poetry.lock is excluded by: !**/*.lock
  • pyproject.toml is excluded by: !**/*.toml
Files selected for processing (16)
  • .circleci/config.yml (1 hunks)
  • .dockerignore (1 hunks)
  • Dockerfile (1 hunks)
  • README.md (1 hunks)
  • requirements.txt (1 hunks)
  • src/bss_web_file_server/main.py (1 hunks)
  • src/bss_web_file_server/models/member.py (1 hunks)
  • src/bss_web_file_server/models/video.py (1 hunks)
  • src/bss_web_file_server/routers/health.py (1 hunks)
  • src/bss_web_file_server/routers/member.py (1 hunks)
  • src/bss_web_file_server/routers/video.py (1 hunks)
  • src/bss_web_file_server/services/image.py (1 hunks)
  • src/bss_web_file_server/services/member.py (1 hunks)
  • src/bss_web_file_server/services/video.py (1 hunks)
  • src/bss_web_file_server/settings.py (1 hunks)
  • tests/bss_web_file_server/models/test_video.py (1 hunks)
Files not summarized due to errors (1)
  • requirements.txt: Error: Message exceeds token limit
Additional comments: 20
src/bss_web_file_server/models/member.py (3)
  • 1-1: The module-level docstring provides a clear and concise explanation of the module's purpose.
  • 9-9: The class-level docstring effectively communicates the purpose of the Member class.
  • 10-10: The use of UUID for the id attribute is appropriate for ensuring unique identification of members.
src/bss_web_file_server/models/video.py (3)
  • 1-1: The module-level docstring provides a clear and concise explanation of the module's purpose.
  • 9-9: The class-level docstring effectively communicates the purpose of the Video class.
  • 12-12: Changing the Video class to store a list of URLs (urls: list[str]) instead of a single URL is a significant improvement for supporting multiple video sources or versions.
src/bss_web_file_server/settings.py (3)
  • 1-1: The module-level docstring clearly explains the purpose of the settings module.
  • 6-9: The Settings class is well-defined, with a clear class-level docstring explaining its purpose. It effectively reads settings from environment variables, showcasing a good practice for configuration management.
  • 12-12: Creating the settings instance at the module level is a common and effective pattern for making application settings accessible throughout the application.
src/bss_web_file_server/routers/health.py (3)
  • 1-1: The module-level docstring clearly explains the purpose of the health check endpoints.
  • 5-5: Creating the APIRouter instance with a specific tag ("Health") is a good practice for organizing and documenting the API.
  • 8-15: The /health and /ping endpoints are correctly defined and serve their purpose as basic health checks for the application.
src/bss_web_file_server/services/image.py (1)
  • 24-29: To improve efficiency, consider checking if the original image size is smaller than the target size before applying thumbnail. Resizing to a larger size can degrade image quality and is unnecessary if the original is already smaller.
.circleci/config.yml (3)
  • 3-9: The definition of orbs and the python executor are correctly configured and make good use of CircleCI's features to simplify the CI/CD process.
  • 35-42: Consider adding comments explaining the purpose of the verify-requirements job, especially for those unfamiliar with the workflow. This job checks for changes in the requirements.txt file, which is important for ensuring dependency consistency.
  • 54-79: The Build and Release workflows are well-structured and correctly use filters to ensure that release tasks are only run on tagged commits. This separation of build and release tasks is a best practice for CI/CD pipelines.
src/bss_web_file_server/services/member.py (1)
  • 1-91: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [67-111]

The utility functions for handling base paths and conversions between member IDs and paths are well-implemented. Consider enhancing the documentation for these functions to provide more context and examples, improving clarity for future maintainers.

requirements.txt (3)
  • 7-9: The version of certifi specified is 2024.2.2. While specifying future-dated versions can be a forward-looking approach to ensure the latest certificates are used, it's important to verify that this version is not a typo and actually intended, considering it significantly deviates from the current year.
  • 13-15: The conditional Python version and platform-specific dependency for colorama is correctly specified for Windows platforms. This is a good practice for ensuring cross-platform compatibility of the project.
  • 528-529: The dependency uvloop is specified with a platform constraint excluding Windows and Cygwin, which is appropriate given uvloop's Unix-only compatibility. This ensures that the project's dependencies are correctly tailored to the operating system capabilities.

Comment on lines +15 to +29
def create_images(img_file: bytes, image_path: Path, image_sizes: list[ImgFormat]):
"""
This method will create the images in three formats: avif, webp and jpeg
The files will be created in the given image_path with the given image_sizes
:param img_file: the image file
:param image_path: the path where the images will be saved
:param image_sizes: the sizes of the images
:return: None
"""
with Image.open(BytesIO(img_file)) as image:
for size in image_sizes:
i = image.copy()
i.thumbnail(size=(size.width, size.height))
for img_format in img_formats:
i.save(Path(image_path, size.name + "." + img_format))
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding error handling for the image processing steps to gracefully handle cases where the image cannot be opened or saved in the specified formats. This could include try-except blocks around the Image.open and i.save calls.

from PIL import Image

ImgFormat = namedtuple("ImgFormat", ["width", "height", "name"])
img_formats = ["avif", "webp", "jpeg"]
Copy link
Contributor

Choose a reason for hiding this comment

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

The use of a global variable img_formats for specifying image formats is not ideal for modularity and testability. Consider passing this as a parameter to the create_images function or defining it within the function if it's not intended to be modified externally.

Comment on lines +19 to +26
@router.post("", response_model=Video)
def create_video_folder(video: Video):
long_path = video_path(video.id)
if long_path.exists():
return Response(status_code=status.HTTP_204_NO_CONTENT)
create_folder_structure(video, with_symlinks=True)
"""
Create a folder structure for a video and return the video object.
:param video: Video object
:return: 200 and the original video object
"""
create_folder_structure(video)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider enhancing the response model to better reflect the operation's outcome, including potential errors. This could involve using a more detailed response model or HTTPException for error handling.

:param video: Video object
:return: 200 and the original video object
"""
if not to_id_path(video.id).exists():
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using HTTPException instead of a generic Response object for the 404 error to provide more informative error messages and maintain consistency with FastAPI's exception handling practices.

Comment on lines +58 to +62
if file.content_type is not None and not re.match("image/.+", file.content_type):
return Response(
content="Mime is not an image format",
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using a 400 (Bad Request) status code instead of 500 for invalid content type errors, as this more accurately reflects the nature of the error. Additionally, the content type validation logic appears to be duplicated; consider abstracting this into a utility function or middleware for reuse.

Comment on lines +14 to +27
def create_folder_structure(member: Member):
"""
This method will create the folder structure for a member.
/m/{member.id}/profile
And a symlink to the id folder from the url folder
/member/{member.url} -> /m/{member.id}
:param member: the member object
:return: None
"""
id_path = to_id_path(member.id)
id_path.mkdir(parents=True, exist_ok=True)
# create a folder for the profile pictures
Path(id_path, "profile").mkdir(exist_ok=True)
update_symlink(member)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding error handling for directory and symlink creation operations to gracefully handle potential filesystem errors. Additionally, verify that symlink creation is robust, especially in scenarios where the target or link might already exist or in case of filesystem permissions issues.

Comment on lines +30 to +44
def create_profile_picture(img_file: bytes, member_id: UUID):
"""
This method will create the profile picture in different formats
/m/{member.id}/profile/{size}.{format}
:param img_file: the image file
:param member_id: the id of the member
:return: None
"""
profile_picture_path = Path(to_id_path(member_id), "profile")
profile_picture_sizes = [
ImgFormat(1920, 1080, "xl"),
ImgFormat(1280, 720, "l"),
ImgFormat(854, 480, "m"),
]
create_images(img_file, profile_picture_path, profile_picture_sizes)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding error handling around the image processing steps in create_profile_picture to gracefully handle cases where the image cannot be processed or saved in the specified formats.

Comment on lines +47 to +62
def update_symlink(member: Member):
"""
This method will update the symlink to the id folder from the url folder
First it will remove all references to the id folder
Then it will create a new symlink to the id path
:param member: the member object
:return: None
"""
id_path = to_id_path(member.id)
for url_path in url_paths_base.glob("*/"):
if url_path.is_symlink() and url_path.readlink().samefile(id_path):
url_path.unlink(missing_ok=True)
to_url_path(member.url).symlink_to(
# use the absolute path to the id folder
target=id_path.resolve(),
target_is_directory=True,
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider optimizing the symlink update process by directly creating or updating the symlink if possible, rather than removing all references first. This could improve efficiency and reduce the risk of leaving the member without a valid symlink in case of errors.

Comment on lines +14 to +28
def create_folder_structure(video: Video):
"""
This method will create the folder structure for a video.
/v/{video.id}/thumbnail
And a symlink to the id folder from the url folders
/video/{video.url[0]} -> /v/{video.id}
/video/{video.url[1]} -> /v/{video.id}
...
:param video: the video object
:return: None
"""
to_id_path(video.id).mkdir(parents=True, exist_ok=True)
# create a folder for the thumbnails
Path(to_id_path(video.id), "thumbnail").mkdir(exist_ok=True)
update_symlinks(video)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding error handling for directory and symlink creation operations to gracefully handle potential filesystem errors. Additionally, verify that symlink creation is robust, especially in scenarios where the target or link might already exist or in case of filesystem permissions issues.

Comment on lines +31 to +45
def create_thumbnails(img_file: bytes, video_id: UUID):
"""
This method will create the thumbnails in different formats
/v/{video.id}/thumbnail/{size}.{format}
:param img_file: the image file
:param video_id: the id of the video
:return: None
"""
thumbnail_path = Path(to_id_path(video_id), "thumbnail")
poster_sizes = [
ImgFormat(1920, 1080, "fhd"),
ImgFormat(1280, 720, "hd"),
ImgFormat(854, 480, "sd"),
]
create_images(img_file, thumbnail_path, poster_sizes)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding error handling around the image processing steps in create_thumbnails to gracefully handle cases where the image cannot be processed or saved in the specified formats.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 66a6b70 and 79ef9e1.
Files selected for processing (1)
  • Dockerfile (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • Dockerfile

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

Successfully merging this pull request may close these issues.

1 participant