Skip to content

Enhance MsPlanner project listing with additional metadata#892

Open
vladvysotsky wants to merge 1 commit intojoniles:masterfrom
vladvysotsky:enhance-msplanner-project-metadata
Open

Enhance MsPlanner project listing with additional metadata#892
vladvysotsky wants to merge 1 commit intojoniles:masterfrom
vladvysotsky:enhance-msplanner-project-metadata

Conversation

@vladvysotsky
Copy link

Summary

  • Add additional metadata fields to MsPlannerProject (modifiedOn, createdOn, stateCode, projectManagerName, programId, programName)
  • Expand getProjects() to fetch and populate these fields from the API
  • Add getPrograms() method to list available programs/portfolios
  • Add loadProgramNames() helper to resolve program names for projects
  • Add OData annotation request header for formatted value support
  • Fix typo: "Unititled" → "Untitled"

Test plan

  • Verify getProjects() returns projects with populated metadata fields
  • Verify getPrograms() returns programs with correct IDs and names
  • Verify program names are resolved correctly for projects linked to a program

- Add modifiedOn, createdOn, stateCode, projectManagerName, programId,
  programName fields to MsPlannerProject
- Expand getProjects() to fetch and populate additional fields
- Add getPrograms() method to list programs/portfolios
- Add loadProgramNames() to resolve program names for projects
- Add OData annotation header for formatted value support
- Fix typo: "Unititled" -> "Untitled"
Copilot AI review requested due to automatic review settings March 24, 2026 12:32
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances the Microsoft Planner/Dynamics project listing APIs by enriching MsPlannerProject with additional metadata, adding program/portfolio listing, and attempting to resolve program names for projects.

Changes:

  • Expanded getProjects() to request and populate additional project metadata fields (timestamps, state, manager display name, program reference).
  • Added getPrograms() plus a loadProgramNames() helper to resolve program names for projects.
  • Added OData annotation support via a Prefer request header and fixed a calendar name typo (“Unititled” → “Untitled”).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/main/java/org/mpxj/msplanner/MsPlannerReader.java Extends project/program retrieval and adds program-name resolution + OData annotation header + typo fix.
src/main/java/org/mpxj/msplanner/MsPlannerProject.java Adds new metadata fields and getters/setters to carry additional API data.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +814 to +817
}
catch (Exception e)
{
// Programs entity may not be available - ignore
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

loadProgramNames catches Exception and ignores it entirely. This will silently hide genuine failures (e.g., malformed URL, auth/network issues) and makes troubleshooting very difficult. Consider only treating "programs entity not available" as non-fatal by checking the HTTP status (e.g., 404/501) and rethrowing (or wrapping) other errors.

Suggested change
}
catch (Exception e)
{
// Programs entity may not be available - ignore
else if (code == 404 || code == 501)
{
// Programs entity may not be available - treat as non-fatal and return empty map
}
else
{
throw new MsPlannerException(getExceptionMessage(connection, code));
}
}
catch (IOException e)
{
// Unexpected I/O error when loading program names - propagate as runtime exception
throw new RuntimeException("Error loading program names", e);

Copilot uses AI. Check for mistakes.
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Accept-Encoding", "gzip");
connection.setRequestProperty("Authorization", "Bearer " + m_token);
connection.setRequestProperty("Prefer", "odata.include-annotations=\"*\"");
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

Setting Prefer: odata.include-annotations="*" on every request can significantly increase payload size (especially for large reads like readData) and may impact performance. Consider narrowing this to only the needed annotation (OData.Community.Display.V1.FormattedValue) and/or only applying it to calls that actually consume formatted values (e.g., the projects listing).

Suggested change
connection.setRequestProperty("Prefer", "odata.include-annotations=\"*\"");
connection.setRequestProperty("Prefer", "odata.include-annotations=\"OData.Community.Display.V1.FormattedValue\"");

Copilot uses AI. Check for mistakes.
Comment on lines 144 to +167
@@ -113,7 +159,12 @@ public List<MsPlannerProject> getProjects()
MapRow data = getMapRow(connection);

return data.getList("value").stream()
.map(d -> new MsPlannerProject(d.getUUID("msdyn_projectid"), d.getString("msdyn_subject")))
.map(d -> {
MsPlannerProject program = new MsPlannerProject(d.getUUID("msdyn_programid"), d.getString("msdyn_name"));
program.setModifiedOn(d.getDate("modifiedon"));
program.setCreatedOn(d.getDate("createdon"));
return program;
})
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

getPrograms() returns List<MsPlannerProject> but populates it with msdyn_programid/msdyn_name. This makes the API confusing because consumers must call getProjectId()/getProjectName() to get program identity/name. Consider introducing a dedicated MsPlannerProgram type or generalizing/renaming the model so the semantics match the data being returned.

Copilot uses AI. Check for mistakes.
.map(id -> "msdyn_programid eq " + id)
.collect(Collectors.joining(" or "));

HttpURLConnection connection = createConnection("msdyn_programs?$select=msdyn_programid,msdyn_name&$filter=" + filter);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

$filter is concatenated with unescaped spaces and or operators (e.g., "msdyn_programid eq " + id), but createConnection builds a raw URL without encoding. This will produce an invalid URL (spaces) and cause program name loading to fail (currently swallowed by the catch). Encode the filter/query string (e.g., replace spaces with %20 / use a proper URI builder) before passing it to createConnection.

Suggested change
HttpURLConnection connection = createConnection("msdyn_programs?$select=msdyn_programid,msdyn_name&$filter=" + filter);
String encodedFilter = filter.replace(" ", "%20");
HttpURLConnection connection = createConnection("msdyn_programs?$select=msdyn_programid,msdyn_name&$filter=" + encodedFilter);

Copilot uses AI. Check for mistakes.
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.

2 participants