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

Programming exercises: Fix code button showing HTTPS link when it should be disabled #9696

Merged
merged 11 commits into from
Nov 10, 2024

Conversation

SimonEntholzer
Copy link
Contributor

@SimonEntholzer SimonEntholzer commented Nov 7, 2024

Checklist

General

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the principle of data economy for all client-server REST calls.
  • I strictly followed the client coding and design guidelines.
  • I added multiple screenshots/screencasts of my UI changes.

Motivation and Context

With the show-clone-url-without-token variable, showing of the HTTPs clone link can be disabled. This feature seems to have broken recently, as initially it is shown now.

Description

This is cause by a race condition, where the user is not yet loaded, but accessed. Explicitly awaiting the user solves the issue.

Steps for Testing

  1. Run the server with the show-clone-url-without-token set to false
  2. Log in, in a private window, so the cache is empty.
  3. Go to a programming exercise, click the code button.
  4. Make sure the HTTPs clone link without token is not shown, only the links with Token and SSH.

Testserver States

Note

These badges show the state of the test servers.
Green = Currently available, Red = Currently locked
Click on the badges to get to the test servers.







Review Progress

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Test Coverage

Client

Class/File Line Coverage Confirmation (assert/expect)
code-button.component.ts 93.24% ✅ ❌

Screenshots

Before the bugfix:
image

After the fix:
image

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling for VCS access token retrieval, ensuring a new token is created when a 404 error occurs.
  • Improvements

    • Streamlined asynchronous handling for user identity retrieval, enhancing performance and readability.
    • Enhanced clarity of control flow when processing user profile data and SSH information.
    • Simplified test suite by removing unnecessary stubs and adopting modern asynchronous testing practices.

@github-actions github-actions bot added the client Pull requests that update TypeScript code. (Added Automatically!) label Nov 7, 2024
@SimonEntholzer SimonEntholzer changed the title Integraed code lifecycle: Do not show HTTPS link when it is disabled `Programming exercises: Fix code button showing HTTPS link when it is disabled Nov 7, 2024
@SimonEntholzer SimonEntholzer changed the title `Programming exercises: Fix code button showing HTTPS link when it is disabled `Programming exercises: Fix code button showing HTTPS link when they are disabled Nov 7, 2024
@SimonEntholzer SimonEntholzer marked this pull request as ready for review November 7, 2024 06:54
@SimonEntholzer SimonEntholzer requested a review from a team as a code owner November 7, 2024 06:54
Copy link

coderabbitai bot commented Nov 7, 2024

Walkthrough

The pull request updates the CodeButtonComponent by refactoring the ngOnInit method to utilize async/await syntax for user identity retrieval. An early return is introduced if the user is not found, and the logic for handling local storage observations is modified. The method loadParticipationVcsAccessTokens() is now called immediately after setting the user identity. Additionally, error handling in loadVcsAccessToken is refined to handle 404 errors by invoking createNewVcsAccessToken. These changes enhance the clarity and maintainability of the code.

Changes

File Path Change Summary
src/main/webapp/app/shared/components/code-button/code-button.component.ts Refactored ngOnInit to use async/await; added early return for user identity check; updated error handling in loadVcsAccessToken for 404 errors.
src/test/javascript/spec/component/shared/code-button.component.spec.ts Removed local storage stubs; transitioned tests to use async/await; updated assertions for SSH preferences.

Possibly related PRs

Suggested reviewers

  • krusche
  • DominikRemo
  • JohannesStoehr

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>, 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 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 or @coderabbitai title anywhere in the PR title to generate the title automatically.

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

@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: 0

🧹 Outside diff range and nitpick comments (3)
src/main/webapp/app/shared/components/code-button/code-button.component.ts (3)

82-97: LGTM with a suggestion for error handling.

The refactoring to async/await improves readability and fixes the race condition by ensuring user data is loaded before access. However, consider adding error handling for the identity retrieval.

Consider adding try-catch block:

 async ngOnInit() {
+    try {
         this.user = (await this.accountService.identity())!;
         this.refreshTokenState();
+    } catch (error) {
+        console.error('Failed to load user identity:', error);
+        // Handle error appropriately
+    }
🧰 Tools
🪛 Biome

[error] 89-89: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 90-90: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


89-90: Improve readability of localStorage observers.

The assignments within expressions can be confusing. Consider using more explicit arrow function bodies.

-        this.localStorage.observe('useSsh').subscribe((useSsh) => (this.useSsh = useSsh || false));
-        this.localStorage.observe('useToken').subscribe((useToken) => (this.useToken = useToken || false));
+        this.localStorage.observe('useSsh').subscribe((useSsh) => {
+            this.useSsh = useSsh || false;
+        });
+        this.localStorage.observe('useToken').subscribe((useToken) => {
+            this.useToken = useToken || false;
+        });
🧰 Tools
🪛 Biome

[error] 89-89: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 90-90: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


Line range hint 282-289: Improve error handling in createNewVcsAccessToken.

The empty error handler could miss important failure scenarios. Consider logging the error and potentially notifying the user.

     createNewVcsAccessToken(participation: ProgrammingExerciseStudentParticipation) {
         this.accountService.createVcsAccessToken(participation!.id!).subscribe({
             next: (res: HttpResponse<string>) => {
                 if (res.body) {
                     participation.vcsAccessToken = res.body;
                     if (this.activeParticipation?.id == participation.id) {
                         this.user.vcsAccessToken = res.body;
                     }
                 }
             },
-            error: () => {},
+            error: (error) => {
+                console.error('Failed to create VCS access token:', error);
+                // Consider showing a user-friendly error message
+            },
         });
     }
🧰 Tools
🪛 Biome

[error] 89-89: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 90-90: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fdc2501 and 73e6a24.

📒 Files selected for processing (1)
  • src/main/webapp/app/shared/components/code-button/code-button.component.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/app/shared/components/code-button/code-button.component.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

🪛 Biome
src/main/webapp/app/shared/components/code-button/code-button.component.ts

[error] 89-89: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 90-90: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

🔇 Additional comments (1)
src/main/webapp/app/shared/components/code-button/code-button.component.ts (1)

82-97: Verify the fix for disabled HTTPS links.

The changes appear to address the race condition by ensuring user data is loaded before access. Let's verify the fix works as expected.

Also applies to: 282-289

✅ Verification successful

Let me gather more context about the code button component and its interaction with the showCloneUrlWithoutToken flag.


Based on the gathered information, I can now generate the final response:

Changes correctly handle HTTPS link visibility and user data loading

The implementation properly handles the HTTPS link visibility through:

  • Profile service correctly sets showCloneUrlWithoutToken from server configuration
  • Component template conditionally renders HTTPS option based on showCloneUrlWithoutToken flag
  • User data loading is properly sequenced with await accountService.identity()
  • Token state is correctly synchronized with local storage and profile settings
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the handling of show-clone-url-without-token flag
# and related user data loading

# Check for any other instances where showCloneUrlWithoutToken might be used
rg -l "showCloneUrlWithoutToken"

# Check for any timing-related issues in user data loading
ast-grep --pattern 'accountService.identity()' 

Length of output: 1179


Script:

#!/bin/bash
# Check the implementation of code-button component
rg -A 5 "showCloneUrlWithoutToken" src/main/webapp/app/shared/components/code-button/code-button.component.ts

# Check the template usage
cat src/main/webapp/app/shared/components/code-button/code-button.component.html

# Check profile service implementation
rg -A 5 "showCloneUrlWithoutToken" src/main/webapp/app/shared/layouts/profiles/profile.service.ts

Length of output: 7798

🧰 Tools
🪛 Biome

[error] 89-89: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


[error] 90-90: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 7, 2024
@SimonEntholzer SimonEntholzer changed the title `Programming exercises: Fix code button showing HTTPS link when they are disabled Programming exercises: Fix code button showing HTTPS link when they are disabled Nov 7, 2024
@SimonEntholzer SimonEntholzer changed the title Programming exercises: Fix code button showing HTTPS link when they are disabled Programming exercises: Fix code button showing HTTPS link when it should be disabled Nov 7, 2024
dfuchss
dfuchss previously approved these changes Nov 7, 2024
Copy link
Contributor

@dfuchss dfuchss left a comment

Choose a reason for hiding this comment

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

code

Copy link

@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: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 73e6a24 and e7ada88.

📒 Files selected for processing (1)
  • src/main/webapp/app/shared/components/code-button/code-button.component.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/webapp/app/shared/components/code-button/code-button.component.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

🔇 Additional comments (2)
src/main/webapp/app/shared/components/code-button/code-button.component.ts (2)

82-88: LGTM! Good improvement in error handling.

The conversion to async/await and addition of early return for null user case improves error handling and prevents potential null reference issues.


91-106: 🛠️ Refactor suggestion

Review state initialization order to prevent inconsistencies.

The current initialization sequence could lead to state inconsistencies:

  1. useToken is initialized from localStorage
  2. A subscription to useToken changes is set up
  3. Later, useToken might be overwritten based on showCloneUrlWithoutToken

This could trigger unnecessary state updates or leave the component in an inconsistent state.

Let's verify the potential state inconsistency:

Consider reorganizing the initialization:

 async ngOnInit() {
     const user = await this.accountService.identity();
     if (!user) {
         return;
     }
     this.user = user;

     this.refreshTokenState();
+    await this.initializeProfileSettings();
 
     this.copyEnabled = true;
     this.useSsh = this.localStorage.retrieve('useSsh') || false;
-    this.useToken = this.localStorage.retrieve('useToken') || false;
+    // Only initialize useToken from localStorage if showCloneUrlWithoutToken allows it
+    const storedUseToken = this.localStorage.retrieve('useToken') || false;
+    this.useToken = this.showCloneUrlWithoutToken ? storedUseToken : true;
 
     // ... rest of the initialization
 }

+private async initializeProfileSettings(): Promise<void> {
+    const profileInfo = await firstValueFrom(this.profileService.getProfileInfo());
+    this.showCloneUrlWithoutToken = profileInfo.showCloneUrlWithoutToken ?? true;
+    // ... other profile settings
+}

coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 7, 2024
Copy link

@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: 1

🧹 Outside diff range and nitpick comments (2)
src/test/javascript/spec/component/shared/code-button.component.spec.ts (2)

140-149: Consider adding more specific expectations.

The async initialization test looks good, but could be enhanced with additional assertions to verify the component's state more thoroughly.

Consider adding these expectations:

expect(component.accessTokensEnabled).toBeTrue();
expect(component.useParticipationVcsAccessToken).toBeFalse();
expect(component.user).toBeDefined();

151-179: Consider adding error case verification.

The VCS token handling tests look good, but could be enhanced with error case verification.

Consider adding a test case for other error scenarios:

it('should handle other errors when getting vcsAccessToken', async () => {
    getVcsAccessTokenSpy = jest.spyOn(accountService, 'getVcsAccessToken')
        .mockReturnValue(throwError(() => new HttpErrorResponse({ status: 500, statusText: 'Server Error' })));
    stubServices();
    participation.id = 1;
    component.useParticipationVcsAccessToken = true;
    component.participations = [participation];

    await component.ngOnInit();
    component.ngOnChanges();

    expect(component.accessTokensEnabled).toBeTrue();
    expect(component.user.vcsAccessToken).toBeUndefined();
    expect(getVcsAccessTokenSpy).toHaveBeenCalled();
    expect(createVcsAccessTokenSpy).not.toHaveBeenCalled();
});
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1b7efe9 and 0f081ef.

📒 Files selected for processing (1)
  • src/test/javascript/spec/component/shared/code-button.component.spec.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/test/javascript/spec/component/shared/code-button.component.spec.ts (1)

Pattern src/test/javascript/spec/**/*.ts: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}

🔇 Additional comments (1)
src/test/javascript/spec/component/shared/code-button.component.spec.ts (1)

22-22: LGTM!

The addition of BehaviorSubject import is appropriate for mocking the ProfileService response.

Copy link
Contributor

@dfuchss dfuchss left a comment

Choose a reason for hiding this comment

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

Code

Copy link
Contributor

@b-fein b-fein left a comment

Choose a reason for hiding this comment

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

Code looks good after fixing the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix client Pull requests that update TypeScript code. (Added Automatically!) ready for review tests
Projects
Status: Merged
Development

Successfully merging this pull request may close these issues.

6 participants