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

feat(graphql): Create separate type for sub-parties #1510

Merged
merged 4 commits into from
Nov 22, 2024

Conversation

oskogstad
Copy link
Collaborator

@oskogstad oskogstad commented Nov 22, 2024

Description

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)

Documentation

  • Documentation is updated (either in docs-directory, Altinnpedia or a separate linked PR in altinn-studio-docs., if applicable)

Summary by CodeRabbit

  • New Features

    • Introduced new fields in the AuthorizedParty and AuthorizedSubParty types to enhance user representation and relationships.
    • Added a new type AuthorizedSubParty to support nested party structures.
  • Bug Fixes

    • Improved the GetAuthorizedParties method to return a more complex structure, including nested sub-party information.
  • Refactor

    • Updated class structure and inheritance for AuthorizedParty and AuthorizedSubParty to facilitate better organization and relationships.

@oskogstad oskogstad requested a review from a team as a code owner November 22, 2024 09:22
Copy link
Contributor

coderabbitai bot commented Nov 22, 2024

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

The pull request introduces significant changes to the GraphQL schema, particularly enhancing the AuthorizedParty and AuthorizedSubParty types by adding new fields and establishing a clearer structure. It modifies the mapping profile to support the transformation of AuthorizedPartyDto to AuthorizedSubParty. The class structure is redefined, renaming AuthorizedParty to AuthorizedPartyBase, and creating a new AuthorizedParty class that includes a list of AuthorizedSubParty. Additionally, the LocalDevelopmentAltinnAuthorization class is updated to enhance the return structure of the GetAuthorizedParties method.

Changes

File Change Summary
docs/schema/V1/schema.verified.graphql Updated AuthorizedParty type to include new fields and added AuthorizedSubParty type with similar fields, creating a clearer structure without recursion.
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/MappingProfile.cs Added mapping configuration from AuthorizedPartyDto to AuthorizedSubParty.
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/ObjectTypes.cs Renamed AuthorizedParty to AuthorizedPartyBase, created new AuthorizedParty class inheriting from it, and updated SubParties property type from List<AuthorizedParty> to List<AuthorizedSubParty>.
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs Updated GetAuthorizedParties method to return a more complex structure, including a nested SubParties list in AuthorizedPartiesResult.

Possibly related PRs

  • feat(graphql): Create separate type for sub-parties #1510: This PR introduces a separate type for sub-parties in the GraphQL schema, which is directly related to the changes made in the main PR that enhances the AuthorizedParty and AuthorizedSubParty types. Both PRs focus on defining and structuring these types within the GraphQL schema.

Suggested reviewers

  • knuhau
  • MagnusSandgren

Warning

Rate limit exceeded

@oskogstad has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 19 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 26e7c36 and 7a1db21.


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 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
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: 2

🧹 Outside diff range and nitpick comments (6)
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/ObjectTypes.cs (2)

16-19: Consider using IReadOnlyList for better immutability.

While the property is init-only, using List<T> still allows modification of the collection after initialization. Consider using IReadOnlyList<T> to ensure true immutability.

-    public List<AuthorizedSubParty>? SubParties { get; init; }
+    public IReadOnlyList<AuthorizedSubParty>? SubParties { get; init; }

Line range hint 3-22: Add XML documentation for GraphQL types.

Consider adding XML documentation to describe the relationship between these types and their intended usage. This will improve both developer experience and GraphQL schema documentation.

Example:

/// <summary>
/// Base class containing common properties for authorized parties.
/// </summary>
public class AuthorizedPartyBase
{
    /// <summary>
    /// The unique identifier of the party.
    /// </summary>
    public string Party { get; init; } = null!;
    // ... document other properties
}

/// <summary>
/// Represents an authorized party that may have sub-parties.
/// </summary>
public class AuthorizedParty : AuthorizedPartyBase
{
    /// <summary>
    /// Optional list of sub-parties authorized under this party.
    /// </summary>
    public List<AuthorizedSubParty>? SubParties { get; init; }
}
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs (1)

57-73: Consider using named constants for test data

The hardcoded values like "Local Party" and "123456789" should be defined as named constants at the class level to make it clear they are test data and to facilitate updates.

 internal sealed class LocalDevelopmentAltinnAuthorization : IAltinnAuthorization
 {
+    private const string TEST_PARTY_NAME = "Local Party";
+    private const string TEST_SUB_PARTY_NAME = "Local Sub Party";
+    private const string TEST_ORG_NUMBER = "123456789";
     private readonly IDialogDbContext _db;
docs/schema/V1/schema.verified.graphql (3)

69-79: Consider making subParties non-nullable for consistency.

The subParties field is currently nullable while all other fields in the type are non-nullable. This inconsistency might lead to unnecessary null checks in clients. Consider making it non-nullable with an empty array as the default state:

-  subParties: [AuthorizedSubParty!]
+  subParties: [AuthorizedSubParty!]!

81-82: Add depth limit to prevent infinite nesting.

The recursive structure of AuthorizedSubParty with its own subParties field allows for infinite nesting, which could lead to performance issues or stack overflow errors if deeply nested data is queried. Consider:

  1. Adding a depth limit through a custom directive
  2. Documenting the maximum allowed depth
  3. Implementing server-side validation

Example directive definition to add:

directive @maxDepth(limit: Int!) on FIELD_DEFINITION

type AuthorizedSubParty {
  subParties: [AuthorizedSubParty!] @maxDepth(limit: 5)
  # ... other fields
}

69-82: Add documentation for type fields.

Both AuthorizedParty and AuthorizedSubParty types lack field descriptions. Consider adding documentation comments to explain:

  • The purpose and usage of each field
  • The relationship between parties and sub-parties
  • The meaning of boolean flags (e.g., hasKeyRole, isAccessManager)
  • Any business rules or constraints

Example documentation:

type AuthorizedParty {
  """
  List of sub-parties that this party has authority over.
  Empty array indicates no sub-parties.
  """
  subParties: [AuthorizedSubParty!]

  """
  Unique identifier of the party in the format specified by the system.
  """
  party: String!

  # ... document other fields similarly
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d18bb76 and 8026f0a.

📒 Files selected for processing (4)
  • docs/schema/V1/schema.verified.graphql (1 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/MappingProfile.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/ObjectTypes.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs (2 hunks)
🔇 Additional comments (6)
src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/MappingProfile.cs (1)

11-11: Verify the mapping configuration for AuthorizedSubParty

While the mapping is syntactically correct, we should verify:

  1. That all properties from AuthorizedPartyDto are appropriate to map to AuthorizedSubParty
  2. Whether any custom property mappings or transformations are needed
  3. That there's no risk of infinite recursion if AuthorizedParty contains SubParties

Let's analyze the type definitions and their usage:

✅ Verification successful

Based on the shell script results, I can now generate the final response:

The mapping configuration is correct and safe to use

The code analysis reveals that:

  1. AuthorizedSubParty is a sealed class that inherits from AuthorizedParty, which in turn inherits from AuthorizedPartyBase
  2. All properties from AuthorizedPartyDto (Party, Name, PartyType, IsDeleted, SubParties) align with the base properties in AuthorizedPartyBase
  3. The inheritance hierarchy ensures that AuthorizedSubParty has the same structure as AuthorizedParty, making the mapping compatible
  4. No risk of infinite recursion as the SubParties property is properly typed as List<AuthorizedSubParty>? in both DTO and model classes
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Analyze the structure of the involved types and their relationships

# Find the type definitions
echo "=== Type Definitions ==="
ast-grep --pattern 'class AuthorizedPartyDto {
  $$$
}'

ast-grep --pattern 'class AuthorizedParty {
  $$$
}'

ast-grep --pattern 'class AuthorizedSubParty {
  $$$
}'

# Find usages of these types
echo "=== Type Usages ==="
rg -A 5 "AuthorizedPartyDto|AuthorizedParty|AuthorizedSubParty"

Length of output: 13897

src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/ObjectTypes.cs (1)

Line range hint 3-14: LGTM! Well-structured base class.

The base class effectively encapsulates common properties with appropriate immutability and null-checking.

src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/LocalDevelopmentAltinnAuthorization.cs (3)

6-6: LGTM: Using directive properly added

The new using directive is correctly placed and necessary for the sub-party functionality.


59-72: LGTM: Sub-party structure implementation

The implementation correctly reflects the PR objective of supporting sub-parties with a proper hierarchical structure. The mock data provides a good example of the parent-child relationship between parties.


68-68: Verify the test organization number format

The organization number "123456789" is concatenated with NorwegianOrganizationIdentifier.PrefixWithSeparator. Ensure this generates a valid test identifier format.

✅ Verification successful

Organization identifier format is valid

The test organization number "123456789" is correctly formatted when concatenated with NorwegianOrganizationIdentifier.PrefixWithSeparator. From the codebase:

  • The prefix is defined as "urn:altinn:organization:identifier-no" in NorwegianOrganizationIdentifier.cs
  • The format is used consistently throughout the codebase, including in tests with valid organization numbers
  • The validation logic is present in the NorwegianOrganizationIdentifier class
  • The format matches the error message in validation extensions: "'{{PropertyName}}' must be on format '{NorwegianOrganizationIdentifier.PrefixWithSeparator}{{norwegian org-nr}}'"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for NorwegianOrganizationIdentifier usage to verify format
ast-grep --pattern 'class NorwegianOrganizationIdentifier {
  $$$
}'

Length of output: 70


Script:

#!/bin/bash
# Search for NorwegianOrganizationIdentifier class definition and usage
rg -l "NorwegianOrganizationIdentifier" 

# Search for specific implementation details
rg "NorwegianOrganizationIdentifier" -A 5

Length of output: 15324

docs/schema/V1/schema.verified.graphql (1)

69-82: Verify the impact on existing queries.

The schema shows that parties query returns [AuthorizedParty!]!. With the new structure, ensure that:

  1. Existing clients can handle the new nested structure
  2. Performance remains acceptable when querying deeply nested parties
  3. GraphQL resolvers are properly implemented for the new fields
✅ Verification successful

The nested party structure is properly implemented with appropriate safeguards

The implementation shows that:

  1. The resolver and mapping are correctly implemented to handle the nested structure through AutoMapper
  2. Performance concerns are mitigated as the subparties are only populated when they exist (SubParties = dto.Subunits.Count > 0 ? ... : null)
  3. The mapping logic in AuthorizedPartiesHelper properly handles the recursive structure while maintaining all required fields
  4. The GraphQL type definitions match the implementation with proper null handling (SubParties is nullable in both schema and code)

The changes appear to be backward compatible since:

  • All required fields from the original schema are preserved
  • The nested structure is implemented as an optional field
  • The mapping maintains data integrity through the object hierarchy
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing GraphQL queries that fetch parties
rg -l 'query.*\{.*parties.*\}' --type ts --type js --type graphql

# Search for resolver implementations
ast-grep --pattern 'class $_ : IResolver<$_, $_> {
  $$$
  parties($_, $_) {
    $$$
  }
  $$$
}'

Length of output: 199


Script:

#!/bin/bash
# Search for GraphQL queries using parties, adjusting file type flags
rg -l 'query.*\{.*parties.*\}' --type typescript --type javascript

# Search for files containing 'parties' field or type definitions
rg -l 'type.*Authorized(Sub)?Party' --type typescript --type javascript

# Look for resolver implementations with different pattern
rg -A 5 'class.*Resolver.*implements.*' --type typescript --type javascript

# Search for files that might contain GraphQL queries
fd -e graphql -x rg -l 'query.*parties' {}

Length of output: 372


Script:

#!/bin/bash
# Search for GraphQL queries using parties without file type restrictions
rg -l 'query.*\{.*parties.*\}'

# Search for resolver implementations
rg -A 5 'class.*Resolver.*implements'

# Look for GraphQL operation files
fd -e gql -e graphql . 

# Search for any files mentioning AuthorizedParty or AuthorizedSubParty
rg -l 'AuthorizedParty|AuthorizedSubParty'

Length of output: 991


Script:

#!/bin/bash
# Check the implementation of PartyQueries to understand the resolver
cat src/Digdir.Domain.Dialogporten.GraphQL/EndUser/PartyQueries.cs

# Look at the object types to understand the mapping
cat src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/ObjectTypes.cs

# Check the mapping profile for any transformation logic
cat src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/MappingProfile.cs

# Look at the helper class that handles authorization
cat src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/Authorization/AuthorizedPartiesHelper.cs

Length of output: 5282

MagnusSandgren
MagnusSandgren previously approved these changes Nov 22, 2024
arealmaas
arealmaas previously approved these changes Nov 22, 2024
@oskogstad oskogstad dismissed stale reviews from arealmaas and MagnusSandgren via 26e7c36 November 22, 2024 09:37
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.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
docs/schema/V1/schema.verified.graphql (1)

Line range hint 81-90: Consider introducing an interface for shared fields

There's significant field duplication between AuthorizedParty and AuthorizedSubParty. Consider introducing an interface to share common fields:

+interface AuthorizedPartyBase {
+  party: String!
+  name: String!
+  partyType: String!
+  isDeleted: Boolean!
+  hasKeyRole: Boolean!
+  isCurrentEndUser: Boolean!
+  isMainAdministrator: Boolean!
+  isAccessManager: Boolean!
+  hasOnlyAccessToSubParties: Boolean!
+}
+
-type AuthorizedParty {
+type AuthorizedParty implements AuthorizedPartyBase {
   subParties: [AuthorizedSubParty!]!
   party: String!
   name: String!
   partyType: String!
   isDeleted: Boolean!
   hasKeyRole: Boolean!
   isCurrentEndUser: Boolean!
   isMainAdministrator: Boolean!
   isAccessManager: Boolean!
   hasOnlyAccessToSubParties: Boolean!
 }
 
-type AuthorizedSubParty {
+type AuthorizedSubParty implements AuthorizedPartyBase {
   party: String!
   name: String!
   partyType: String!
   isDeleted: Boolean!
   hasKeyRole: Boolean!
   isCurrentEndUser: Boolean!
   isMainAdministrator: Boolean!
   isAccessManager: Boolean!
   hasOnlyAccessToSubParties: Boolean!
}

This would:

  1. Reduce code duplication
  2. Make the relationship between the types explicit
  3. Simplify future maintenance
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8026f0a and 26e7c36.

📒 Files selected for processing (2)
  • docs/schema/V1/schema.verified.graphql (1 hunks)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/ObjectTypes.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Digdir.Domain.Dialogporten.GraphQL/EndUser/Parties/ObjectTypes.cs
🔇 Additional comments (1)
docs/schema/V1/schema.verified.graphql (1)

Line range hint 69-90: Overall schema changes look good

The introduction of the AuthorizedSubParty type and the updates to AuthorizedParty are well-structured and maintain schema consistency. The changes are properly contained and don't introduce breaking changes to existing queries.

docs/schema/V1/schema.verified.graphql Show resolved Hide resolved
@oskogstad oskogstad merged commit 9c75f11 into main Nov 22, 2024
19 checks passed
@oskogstad oskogstad deleted the feat/create-separate-gql-type-for-sub-parties branch November 22, 2024 09:45
Copy link

arealmaas pushed a commit that referenced this pull request Nov 25, 2024
🤖 I have created a release *beep* *boop*
---


##
[1.39.0](v1.38.0...v1.39.0)
(2024-11-22)


### Features

* **azure:** adjust SKU and storage for yt01 and prod
([b7e4909](b7e4909))
* **azure:** adjust SKU and storage for yt01 and prod
([#1508](#1508))
([5478275](5478275))
* **graphql:** Create separate type for sub-parties
([#1510](#1510))
([9c75f11](9c75f11))


### Bug Fixes

* **azure:** ensure correct properties are used when adjusting SKU and
storage for postgres
([#1514](#1514))
([c51d2f5](c51d2f5))
* Reenable party list cache, log party name look failure with negative
cache TTL ([#1395](#1395))
([d18bb76](d18bb76))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
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.

3 participants