Skip to content

delete bytes from video#2168

Merged
jo-elimu merged 6 commits intomainfrom
2137-store-file-size-of-videos
Apr 29, 2025
Merged

delete bytes from video#2168
jo-elimu merged 6 commits intomainfrom
2137-store-file-size-of-videos

Conversation

@jo-elimu
Copy link
Copy Markdown
Member

Issue Number

Purpose

Technical Details

Testing Instructions

Screenshots


Format Checks

Note

Files in PRs are automatically checked for format violations with mvn spotless:check.

If this PR contains files with format violations, run mvn spotless:apply to fix them.

@jo-elimu jo-elimu self-assigned this Apr 29, 2025
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 29, 2025

Codecov Report

Attention: Patch coverage is 0% with 40 lines in your changes missing coverage. Please review.

Project coverage is 15.32%. Comparing base (5bd9df9) to head (9c5804d).
Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
.../ai/elimu/web/servlet/CustomDispatcherServlet.java 0.00% 16 Missing ⚠️
...ontent/multimedia/video/VideoCreateController.java 0.00% 8 Missing ⚠️
.../content/multimedia/video/VideoEditController.java 0.00% 8 Missing ⚠️
src/main/java/ai/elimu/dao/jpa/VideoDaoJpa.java 0.00% 5 Missing ⚠️
...ent/multimedia/video/VideoCsvExportController.java 0.00% 2 Missing ⚠️
...main/java/ai/elimu/rest/v2/JpaToGsonConverter.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #2168      +/-   ##
============================================
- Coverage     15.33%   15.32%   -0.02%     
  Complexity      391      391              
============================================
  Files           233      233              
  Lines          6148     6153       +5     
  Branches        710      711       +1     
============================================
  Hits            943      943              
- Misses         5154     5159       +5     
  Partials         51       51              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jo-elimu jo-elimu marked this pull request as ready for review April 29, 2025 13:24
@jo-elimu jo-elimu requested a review from a team as a code owner April 29, 2025 13:24
@jo-elimu jo-elimu requested review from AshishBagdane, shiv810 and vuriaval and removed request for a team April 29, 2025 13:24
@jo-elimu jo-elimu changed the title store file size of videos delete bytes from video Apr 29, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 29, 2025

Walkthrough

This update removes the storage of raw video file bytes from the Video entity and database schema, replacing it with a fileSize property to retain file size information. The video upload and edit controllers are refactored to avoid redundant uploads by checking for existing videos with matching MD5 checksums and reusing their GitHub LFS references. The CSV export and UI are updated to display the file size. A new DAO method allows retrieval of videos by checksum. Selenium UI tests and a REST controller test are added for video content management. Database migration and schema files are updated accordingly.

Changes

File(s) Change Summary
src/main/java/ai/elimu/entity/content/multimedia/Video.java,
src/main/resources/META-INF/jpa-schema-export.sql,
src/main/resources/db/migration/2005109.sql
Removed the bytes field/column from the Video entity and schema; updated migration to drop the column. Marked thumbnail as deprecated.
src/main/java/ai/elimu/dao/VideoDao.java,
src/main/java/ai/elimu/dao/jpa/VideoDaoJpa.java
Added readByChecksumMd5 method to DAO interface and implementation for retrieving videos by MD5 checksum.
src/main/java/ai/elimu/rest/v2/JpaToGsonConverter.java Changed file size calculation in getVideoGson to use fileSize property instead of byte array length.
src/main/java/ai/elimu/web/content/multimedia/video/VideoCreateController.java,
src/main/java/ai/elimu/web/content/multimedia/video/VideoEditController.java
Refactored to remove setting video bytes, set file size and checksum, and reuse existing uploads based on checksum.
src/main/java/ai/elimu/web/content/multimedia/video/VideoCsvExportController.java Added file_size column to CSV export.
src/main/java/ai/elimu/web/download/VideoController.java Removed method for serving raw video bytes.
src/main/java/ai/elimu/web/servlet/CustomDispatcherServlet.java Added logic to populate database with a placeholder video entity for development.
src/main/webapp/WEB-INF/jsp/content/multimedia/video/create.jsp,
src/main/webapp/WEB-INF/jsp/content/multimedia/video/edit.jsp
Changed file input to plain HTML, removed Spring binding; added file size display in edit page.
src/main/webapp/WEB-INF/jsp/content/main.jsp,
src/main/webapp/WEB-INF/jsp/content/multimedia/video/list.jsp
Added IDs to video list and create page links/buttons for test automation.
src/test/java/ai/elimu/rest/v2/content/VideosRestControllerTest.java Added REST API integration test for /content/videos endpoint.
src/test/java/selenium/content/MainContentPage.java Added method to click video list link by ID.
src/test/java/selenium/content/video/VideoCreatePage.java,
src/test/java/selenium/content/video/VideoEditPage.java,
src/test/java/selenium/content/video/VideoListPage.java
Added Selenium page object classes for video create, edit, and list pages.
src/test/java/selenium/content/video/VideoTest.java Added Selenium UI test class for video content management.
pom-dependency-tree.txt Updated project artifact version from 2.5.108-SNAPSHOT to 2.5.109-SNAPSHOT.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant VideoCreateController
    participant VideoDao
    participant GitHubLFS

    User->>VideoCreateController: Uploads video file
    VideoCreateController->>VideoDao: readByChecksumMd5(checksum)
    alt Video with checksum exists
        VideoDao-->>VideoCreateController: Existing Video (with GitHub checksum)
        VideoCreateController->>VideoDao: Save new Video referencing existing GitHub checksum
    else No existing video
        VideoCreateController->>GitHubLFS: Upload video bytes
        GitHubLFS-->>VideoCreateController: Returns GitHub checksum
        VideoCreateController->>VideoDao: Save new Video with new GitHub checksum
    end
Loading

Assessment against linked issues

Objective (Issue #) Addressed Explanation
Add fileSize property to the Video entity (#2137)
Retain file size info after deleting bytes property (#2137)

Possibly related PRs

  • upload video to lfs #2138: Implements video upload to GitHub LFS and related URL handling, which is related to this PR's changes in video storage and upload logic.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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>, please review it.
    • Generate unit testing code 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 testing code 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 gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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 using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • 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/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
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.

Actionable comments posted: 3

🧹 Nitpick comments (8)
src/test/java/selenium/content/video/VideoCreatePage.java (1)

1-15: Page object implementation is appropriate

The VideoCreatePage follows the Page Object pattern correctly, which helps maintain clean separation between test logic and page interactions. The validation in the constructor ensures the driver is on the correct page.

Consider enhancing this page object with methods for interacting with form elements and submitting data to make it more useful in tests.

 package selenium.content.video;

 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import java.io.File;

 public class VideoCreatePage {
     
     private WebDriver driver;

     public VideoCreatePage(WebDriver driver) {
         this.driver = driver;

         driver.findElement(By.id("videoCreatePage"));
     }
+    
+    public void setTitle(String title) {
+        WebElement titleField = driver.findElement(By.id("title"));
+        titleField.clear();
+        titleField.sendKeys(title);
+    }
+    
+    public void selectVideoFile(File videoFile) {
+        WebElement fileInput = driver.findElement(By.id("videoFile"));
+        fileInput.sendKeys(videoFile.getAbsolutePath());
+    }
+    
+    public void submit() {
+        driver.findElement(By.id("submitButton")).click();
+    }
 }
src/test/java/selenium/content/video/VideoEditPage.java (1)

1-15: Page object implementation is appropriate

The VideoEditPage follows the Page Object pattern correctly, which helps maintain clean separation between test logic and page interactions. The validation in the constructor ensures the driver is on the correct page.

Similar to the VideoCreatePage, consider enhancing this page object with methods for interacting with form elements and submitting changes to make it more useful in tests.

 package selenium.content.video;

 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import java.io.File;

 public class VideoEditPage {
     
     private WebDriver driver;

     public VideoEditPage(WebDriver driver) {
         this.driver = driver;

         driver.findElement(By.id("videoEditPage"));
     }
+    
+    public void setTitle(String title) {
+        WebElement titleField = driver.findElement(By.id("title"));
+        titleField.clear();
+        titleField.sendKeys(title);
+    }
+    
+    public void updateVideoFile(File videoFile) {
+        WebElement fileInput = driver.findElement(By.id("videoFile"));
+        fileInput.sendKeys(videoFile.getAbsolutePath());
+    }
+    
+    public void submit() {
+        driver.findElement(By.id("submitButton")).click();
+    }
 }
src/test/java/ai/elimu/rest/v2/content/VideosRestControllerTest.java (1)

16-27: Good test coverage for the videos REST endpoint.

This test validates that the /content/videos endpoint returns proper JSON data with videos that have titles. However, it could be enhanced to verify more fields, especially the new fileSize property.

Consider adding assertions for the fileSize field to ensure it's properly included in the REST response:

 JSONObject videoJsonObject = videosJSONArray.getJSONObject(0);
 assertNotNull(videoJsonObject.getString("title"));
+assertNotNull(videoJsonObject.getInt("fileSize"));
src/main/java/ai/elimu/web/servlet/CustomDispatcherServlet.java (1)

277-277: Consider applying the same pattern for thumbnail as for video content.

While the video content is no longer stored in the database, the thumbnail is still loaded as a byte array and stored directly. For consistency, consider handling the thumbnail the same way as video content in the future.

Since the thumbnail field is already marked as deprecated in the Video entity, you might want to consider storing thumbnail references externally as well and just keeping metadata in the database.

src/main/java/ai/elimu/web/content/multimedia/video/VideoEditController.java (1)

121-123: Consider stronger hashing algorithm for future-proof deduplication

MD5 is fast but collision-prone; for binary artefacts SHA-256 (or at least SHA-1) is the contemporary baseline.
If changing the column type is expensive now, at least add a TODO for migrating to a stronger checksum to avoid deliberate hash-collision attacks on the LFS store.
[security]

src/test/java/selenium/content/video/VideoTest.java (3)

19-35: Add implicit wait & Chrome options for stability in CI

Hard navigation without waits is brittle; slow environments may fail sporadically.
In addition, enabling --no-sandbox / --disable-gpu is often required in headless CI.

ChromeOptions chromeOptions = new ChromeOptions();
+chromeOptions.addArguments("--no-sandbox", "--disable-gpu");
...
driver = new ChromeDriver(chromeOptions);
-driver.get(DomainHelper.getBaseUrl() + "/content");
+driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
+driver.get(DomainHelper.getBaseUrl() + "/content");

This small tweak greatly improves reliability of the UI tests.


45-57: Assert page state to give the test a purpose

Currently the test only navigates; it never verifies that the target edit page actually loaded, so a broken page could pass unnoticed.

VideoEditPage videoEditPage = new VideoEditPage(driver);
assertTrue(videoEditPage.isAt(), "Video Edit page did not load correctly");

Expose an isAt() helper in each page object to assert on a unique element (id="videoEditPage").


59-70: Same assertion missing for creation flow

Mirror the previous suggestion for the create page to ensure both navigation paths are validated.

VideoCreatePage videoCreatePage = new VideoCreatePage(driver);
assertTrue(videoCreatePage.isAt(), "Video Create page did not load correctly");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae1aef0 and 9c5804d.

⛔ Files ignored due to path filters (1)
  • src/main/resources/ai/elimu/web/servlet/placeholder.mp4 is excluded by !**/*.mp4, !**/*.mp4
📒 Files selected for processing (22)
  • pom-dependency-tree.txt (1 hunks)
  • src/main/java/ai/elimu/dao/VideoDao.java (1 hunks)
  • src/main/java/ai/elimu/dao/jpa/VideoDaoJpa.java (1 hunks)
  • src/main/java/ai/elimu/entity/content/multimedia/Video.java (1 hunks)
  • src/main/java/ai/elimu/rest/v2/JpaToGsonConverter.java (1 hunks)
  • src/main/java/ai/elimu/web/content/multimedia/video/VideoCreateController.java (3 hunks)
  • src/main/java/ai/elimu/web/content/multimedia/video/VideoCsvExportController.java (2 hunks)
  • src/main/java/ai/elimu/web/content/multimedia/video/VideoEditController.java (3 hunks)
  • src/main/java/ai/elimu/web/download/VideoController.java (0 hunks)
  • src/main/java/ai/elimu/web/servlet/CustomDispatcherServlet.java (3 hunks)
  • src/main/resources/META-INF/jpa-schema-export.sql (0 hunks)
  • src/main/resources/db/migration/2005109.sql (1 hunks)
  • src/main/webapp/WEB-INF/jsp/content/main.jsp (1 hunks)
  • src/main/webapp/WEB-INF/jsp/content/multimedia/video/create.jsp (1 hunks)
  • src/main/webapp/WEB-INF/jsp/content/multimedia/video/edit.jsp (2 hunks)
  • src/main/webapp/WEB-INF/jsp/content/multimedia/video/list.jsp (1 hunks)
  • src/test/java/ai/elimu/rest/v2/content/VideosRestControllerTest.java (1 hunks)
  • src/test/java/selenium/content/MainContentPage.java (1 hunks)
  • src/test/java/selenium/content/video/VideoCreatePage.java (1 hunks)
  • src/test/java/selenium/content/video/VideoEditPage.java (1 hunks)
  • src/test/java/selenium/content/video/VideoListPage.java (1 hunks)
  • src/test/java/selenium/content/video/VideoTest.java (1 hunks)
💤 Files with no reviewable changes (2)
  • src/main/resources/META-INF/jpa-schema-export.sql
  • src/main/java/ai/elimu/web/download/VideoController.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/test/java/ai/elimu/rest/v2/content/VideosRestControllerTest.java (1)
src/test/java/selenium/content/video/VideoTest.java (1)
  • Slf4j (14-71)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: test_ui
  • GitHub Check: test_ui
  • GitHub Check: test_ui
  • GitHub Check: test_ui
  • GitHub Check: test_ui
  • GitHub Check: test_rest
🔇 Additional comments (19)
pom-dependency-tree.txt (1)

1-1: Artifact version bumped correctly
The project’s main artifact version has been updated from 2.5.108-SNAPSHOT to 2.5.109-SNAPSHOT, which matches the coordinated schema and code changes in this PR.

src/main/webapp/WEB-INF/jsp/content/main.jsp (1)

120-120: LGTM! ID attribute added consistently with other content links.

The addition of the "videoListLink" ID attribute follows the same pattern used for other content links in this file, enabling consistent UI test automation.

src/main/webapp/WEB-INF/jsp/content/multimedia/video/list.jsp (1)

74-74: LGTM! ID attribute added to support UI test automation.

Adding the "createButton" ID to the video creation link enables reliable interaction in Selenium tests, improving test automation capabilities without affecting functionality.

src/test/java/selenium/content/MainContentPage.java (1)

57-60: LGTM! Method added consistently with existing patterns.

The pressVideoListLink() method follows the same implementation pattern as other navigation methods in this class, maintaining code consistency while enabling video list page testing.

src/main/resources/db/migration/2005109.sql (1)

1-3: LGTM! Database migration correctly removes the bytes column.

This migration script properly removes the bytes column from the Video table, aligning with the architectural change to stop storing raw video content in the database and use file size metadata instead.

src/main/java/ai/elimu/dao/VideoDao.java (1)

13-13: Good addition of a method to fetch videos by checksum.

Adding the readByChecksumMd5 method is a good approach for supporting deduplication of videos with identical content, which aligns with the PR's objective of optimizing video storage.

src/main/webapp/WEB-INF/jsp/content/multimedia/video/edit.jsp (2)

92-92: Appropriate change to file upload field.

Changing from Spring form tag to a plain HTML input correctly aligns with the removal of the bytes field from the Video entity. This approach decouples the UI from the old data model that directly stored binary content.


361-364: Good addition of file size display in the UI.

Adding the file size display provides useful metadata to users and aligns with the new storage approach where file size is an explicit property rather than derived from the binary content.

src/main/java/ai/elimu/web/content/multimedia/video/VideoCsvExportController.java (1)

30-30: CSV export properly updated to include file size.

The CSV export functionality has been properly updated to include the file size as a column, maintaining consistency with the entity model changes.

Also applies to: 41-41

src/main/webapp/WEB-INF/jsp/content/multimedia/video/create.jsp (1)

84-84: Appropriate change to file upload field in creation form.

Similar to the edit page, changing from Spring form tag to a plain HTML input correctly aligns with the removal of the bytes field from the Video entity in the creation workflow.

src/main/java/ai/elimu/rest/v2/JpaToGsonConverter.java (1)

357-357: Implementation looks good

The change to use video.getFileSize() directly aligns with the architectural change of not storing raw video bytes in the database, but rather storing file size metadata. This approach is more efficient for handling large media files.

src/main/java/ai/elimu/dao/jpa/VideoDaoJpa.java (1)

27-39: Well-implemented DAO method

The readByChecksumMd5 method is correctly implemented following the same pattern as other methods in the class. It properly handles the case when no result is found by catching the NoResultException.

This method will help prevent duplicate uploads by allowing the system to check if a video with the same content (identified by MD5 checksum) already exists in the database.

src/main/java/ai/elimu/entity/content/multimedia/Video.java (3)

42-42: Note the deprecated thumbnail field.

The thumbnail field is now marked as @Deprecated, suggesting that it will be removed in a future release. This is consistent with the overall approach of removing direct storage of binary data from the entity.

Consider adding a deprecation message to explain why it's deprecated and what alternatives should be used instead:

-  @Deprecated
+  @Deprecated(since = "2.0", forRemoval = true)

26-27: The fileSize field properly replaces bytes storage.

The fileSize field with @NotNull constraint effectively replaces the need for storing the actual video bytes while still maintaining information about the video's size.


52-57: URL construction logic is working appropriately.

The getUrl() method correctly constructs the URL to fetch the video from GitHub LFS using the MD5 checksum and video format. This approach is efficient and aligns with the removal of direct byte storage.

src/main/java/ai/elimu/web/content/multimedia/video/VideoCreateController.java (3)

72-74: Improved byte array declaration for better scope management.

Moving the byte array declaration outside the try block ensures it remains accessible throughout the method, which is a good practice for variable scoping.


93-95: Properly sets video metadata instead of storing raw bytes.

The code now sets the fileSize property and MD5 checksum instead of storing the raw video bytes in the entity. This approach is more efficient for database storage.


126-133: Excellent optimization to avoid duplicate uploads.

This new block of code checks if a video with the same MD5 checksum already exists in the database before uploading it to GitHub LFS. If found, it reuses the existing GitHub checksum, preventing redundant uploads and saving storage space and network bandwidth.

src/main/java/ai/elimu/web/servlet/CustomDispatcherServlet.java (1)

266-283: Properly added placeholder video initialization for development environment.

The code correctly initializes a placeholder video in the development environment, setting all required fields including the file size and checksum without storing the raw bytes. This is consistent with the new approach of not storing video bytes directly in the database.

Comment on lines +145 to +152
Video existingVideoWithSameFileContent = videoDao.readByChecksumMd5(video.getChecksumMd5());
if (existingVideoWithSameFileContent != null) {
// Re-use existing file
video.setChecksumGitHub(existingVideoWithSameFileContent.getChecksumGitHub());
} else {
String checksumGitHub = GitHubLfsHelper.uploadVideoToLfs(video, bytes);
video.setChecksumGitHub(checksumGitHub);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

bytes may be null here, leading to NPE inside GitHubLfsHelper.uploadVideoToLfs

Even after the earlier null-protection, there is still a corner case: editing a video’s metadata without uploading a new file (multipartFile.isEmpty() == true).
In that flow bytes is never assigned and the deduplication branch falls through to uploadVideoToLfs, causing a crash.

Add an explicit guard:

if (existingVideoWithSameFileContent != null) {
    // Re-use existing file
    video.setChecksumGitHub(existingVideoWithSameFileContent.getChecksumGitHub());
-} else {
+} else if (bytes != null) {
    String checksumGitHub = GitHubLfsHelper.uploadVideoToLfs(video, bytes);
    video.setChecksumGitHub(checksumGitHub);
+} else {
+    // No new file supplied; keep the current GitHub checksum unchanged
}

This allows metadata-only edits while preserving the existing file reference.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Video existingVideoWithSameFileContent = videoDao.readByChecksumMd5(video.getChecksumMd5());
if (existingVideoWithSameFileContent != null) {
// Re-use existing file
video.setChecksumGitHub(existingVideoWithSameFileContent.getChecksumGitHub());
} else {
String checksumGitHub = GitHubLfsHelper.uploadVideoToLfs(video, bytes);
video.setChecksumGitHub(checksumGitHub);
}
Video existingVideoWithSameFileContent = videoDao.readByChecksumMd5(video.getChecksumMd5());
if (existingVideoWithSameFileContent != null) {
// Re-use existing file
video.setChecksumGitHub(existingVideoWithSameFileContent.getChecksumGitHub());
} else if (bytes != null) {
String checksumGitHub = GitHubLfsHelper.uploadVideoToLfs(video, bytes);
video.setChecksumGitHub(checksumGitHub);
} else {
// No new file supplied; keep the current GitHub checksum unchanged
}

Comment on lines +100 to 103
byte[] bytes = null;
try {
byte[] bytes = multipartFile.getBytes();
bytes = multipartFile.getBytes();
if (multipartFile.isEmpty() || (bytes == null) || (bytes.length == 0)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Guard against bytes == null before further processing

MultipartFile#getBytes() can throw IOException, in which case bytes remains null.
Because the catch-block only logs the exception, execution continues and bytes is later dereferenced (e.g. when calculating file size or uploading to GitHub LFS), which will trigger an NPE.

byte[] bytes = null;
try {
    bytes = multipartFile.getBytes();
+} catch (IOException e) {
+    log.error("Unable to read uploaded bytes", e);
+    result.rejectValue("bytes", "NotReadable");
+}
+
+if (bytes == null) {
+    // Bail out early – the rest of the logic depends on non-null bytes
+    model.addAttribute("video", video);
+    ...
+    return "content/multimedia/video/edit";
}

-if (multipartFile.isEmpty() || (bytes == null) || (bytes.length == 0)) {
+if (multipartFile.isEmpty() || (bytes.length == 0)) {
     result.rejectValue("bytes", "NotNull");

This ensures we never reach the later upload step with a null payload.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
byte[] bytes = null;
try {
byte[] bytes = multipartFile.getBytes();
bytes = multipartFile.getBytes();
if (multipartFile.isEmpty() || (bytes == null) || (bytes.length == 0)) {
byte[] bytes = null;
try {
bytes = multipartFile.getBytes();
} catch (IOException e) {
log.error("Unable to read uploaded bytes", e);
result.rejectValue("bytes", "NotReadable");
}
if (bytes == null) {
// Bail out early – the rest of the logic depends on non-null bytes
model.addAttribute("video", video);
// ... any other attributes you need to repopulate ...
return "content/multimedia/video/edit";
}
if (multipartFile.isEmpty() || (bytes.length == 0)) {
result.rejectValue("bytes", "NotNull");
}

Comment on lines +19 to +24
public void pressRandomVideo() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int) (Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Handle empty video list gracefully

links.size() can be 0, in which case Math.random() * 0 yields NaN and get(int) throws IndexOutOfBoundsException, breaking the test suite when the database has no videos.

public void pressRandomVideo() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
-    int randomIndex = (int) (Math.random() * links.size());
-    WebElement randomLink = links.get(randomIndex);
-    randomLink.click();
+    if (links.isEmpty()) {
+        throw new IllegalStateException("No videos present on the page");
+    }
+    int randomIndex = ThreadLocalRandom.current().nextInt(links.size());
+    links.get(randomIndex).click();
}

Also switched to ThreadLocalRandom for better statistical properties.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void pressRandomVideo() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int) (Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
public void pressRandomVideo() {
List<WebElement> links = driver.findElements(By.className("editLink"));
+ if (links.isEmpty()) {
+ throw new IllegalStateException("No videos present on the page");
+ }
+ int randomIndex = ThreadLocalRandom.current().nextInt(links.size());
+ links.get(randomIndex).click();
}

@jo-elimu jo-elimu merged commit 5a48238 into main Apr 29, 2025
13 of 19 checks passed
@jo-elimu jo-elimu deleted the 2137-store-file-size-of-videos branch April 29, 2025 13:31
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.

Store file size of videos

1 participant