Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-pr-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Set up .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
dotnet-version: 10.0.x
- name: Set up Node.js
uses: actions/setup-node@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ We ask that you practice effective communication, preferably through comments on
## Prerequisites
You can build and run CareTogether on any operating system supported by Node.js and .NET, including Windows, MacOS, and Linux. Install the following:
- [Node.js 18 LTS](https://nodejs.org/en/download)
- [.NET 8 LTS](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- [.NET 10](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)
- [Visual Studio Code](https://code.visualstudio.com/Download) (recommended)

You will also need to allow PowerShell scripts to run on your computer (see [documentation](https://learn.microsoft.com/en-us/previous-versions//bb613481(v=vs.85)?redirectedfrom=MSDN#how-to-allow-scripts-to-run)). To do this, open an administrative PowerShell session and run the following command:
Expand Down
31 changes: 16 additions & 15 deletions src/CareTogether.Api/CareTogether.Api.csproj
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<UserSecretsId>aspnet-CareTogether.Api-0706AF60-30BE-4CB4-868D-366CBB379CA7</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="idunno.Authentication.Basic" Version="2.3.1" />
<PackageReference Include="idunno.Authentication.Basic" Version="2.4.0" />
<PackageReference Include="LazyCache.AspNetCore" Version="2.4.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.7" />
<PackageReference Include="Microsoft.AspNetCore.OData" Version="8.2.5" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="3.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="10.0.8" />
<PackageReference Include="Microsoft.AspNetCore.OData" Version="9.4.1" />
<PackageReference Include="Microsoft.AspNetCore.OData.NewtonsoftJson" Version="8.2.0" />
<PackageReference Include="Microsoft.Azure.AppConfiguration.AspNetCore" Version="7.2.0" />
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="3.4.0" />
<PackageReference Include="Microsoft.Identity.Web" Version="2.20.0" />
<PackageReference Include="Microsoft.PowerBI.Api" Version="4.22.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NSwag.AspNetCore" Version="14.0.8" />
<PackageReference Include="NSwag.MSBuild" Version="14.0.8">
<PackageReference Include="Microsoft.Azure.AppConfiguration.AspNetCore" Version="8.5.0" />
<PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="4.5.0" />
<PackageReference Include="Microsoft.Identity.Web" Version="4.9.0" />
<PackageReference Include="Microsoft.PowerBI.Api" Version="5.1.0" />
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="3.0.3" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="NSwag.AspNetCore" Version="14.7.1" />
<PackageReference Include="NSwag.MSBuild" Version="14.7.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand All @@ -38,8 +39,8 @@
</PropertyGroup>

<Target Name="NSwag" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Debug'">
<Exec WorkingDirectory="$(ProjectDir)" Command="$(NSwagExe_Net80) aspnetcore2openapi /NoBuild:true /Project:$(ProjectDir) /output:$(ProjectDir)..\..\swagger.json" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development;OpenApiGen=true" />
<Exec WorkingDirectory="$(ProjectDir)" Command="$(NSwagExe_Net80) openapi2tsclient /Input:$(ProjectDir)..\..\swagger.json /output:$(ProjectDir)..\caretogether-pwa\src\GeneratedClient.ts" />
<Exec WorkingDirectory="$(ProjectDir)" Command="$(NSwagExe_Net100) aspnetcore2openapi /NoBuild:true /Project:$(ProjectDir) /output:$(ProjectDir)..\..\swagger.json" EnvironmentVariables="ASPNETCORE_ENVIRONMENT=Development;OpenApiGen=true" />
<Exec WorkingDirectory="$(ProjectDir)" Command="$(NSwagExe_Net100) openapi2tsclient /Input:$(ProjectDir)..\..\swagger.json /output:$(ProjectDir)..\caretogether-pwa\src\GeneratedClient.ts" />
</Target>

</Project>
4 changes: 2 additions & 2 deletions src/CareTogether.Api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
# More info at https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/docker/building-net-docker-images?view=aspnetcore-6.0

FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine-amd64 AS base
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine-amd64 AS base
RUN apk add --no-cache tzdata
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine-amd64 AS build
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine-amd64 AS build
WORKDIR /src
COPY ["src/CareTogether.Api/CareTogether.Api.csproj", "src/CareTogether.Api/"]
COPY ["test/CareTogether.TestData/CareTogether.TestData.csproj", "test/CareTogether.TestData/"]
Expand Down
127 changes: 69 additions & 58 deletions src/CareTogether.Api/Services/PbiEmbedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ namespace CareTogether.Api.Controllers.AppOwnsData.Services
using AppOwnsData.Models;
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.Rest;

public class PbiEmbedService
{
Expand All @@ -32,8 +31,7 @@ public PbiEmbedService(AadService aadService)
public async Task<PowerBIClient> GetPowerBIClient()
{
var accessToken = await aadService.GetAccessToken();
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
return new PowerBIClient(new Uri(powerBiApiUrl), tokenCredentials);
return new PowerBIClient(accessToken, new Uri(powerBiApiUrl));
}

/// <summary>
Expand All @@ -50,7 +48,7 @@ [Optional] Guid additionalDatasetId
PowerBIClient pbiClient = await this.GetPowerBIClient();

// Get report info
var pbiReport = pbiClient.Reports.GetReportInGroup(workspaceId, reportId);
var pbiReport = pbiClient.Reports.GetReportInGroup(workspaceId, reportId).Value;

// Check if dataset is present for the corresponding report
// If isRDLReport is true then it is a RDL Report
Expand Down Expand Up @@ -130,7 +128,7 @@ [Optional] IList<Guid> additionalDatasetIds
foreach (var reportId in reportIds)
{
// Get report info
var pbiReport = pbiClient.Reports.GetReportInGroup(workspaceId, reportId);
var pbiReport = pbiClient.Reports.GetReportInGroup(workspaceId, reportId).Value;

datasetIds.Add(Guid.Parse(pbiReport.DatasetId));

Expand Down Expand Up @@ -181,28 +179,15 @@ [Optional] Guid targetWorkspaceId

// Create a request for getting Embed token
// This method works only with new Power BI V2 workspace experience
var tokenRequest = new GenerateTokenRequestV2(
reports: new List<GenerateTokenRequestV2Report>()
{
new GenerateTokenRequestV2Report(reportId),
},
var tokenRequest = CreateGenerateTokenRequest(
reports: [new GenerateTokenRequestV2Report(reportId)],
datasets: datasetIds
.Select(datasetId => new GenerateTokenRequestV2Dataset(datasetId.ToString()))
.ToList(),
targetWorkspaces: targetWorkspaceId != Guid.Empty
? new List<GenerateTokenRequestV2TargetWorkspace>()
{
new GenerateTokenRequestV2TargetWorkspace(targetWorkspaceId),
}
: null,
identities: new List<EffectiveIdentity>()
{
new EffectiveIdentity(
username: userId.ToString(),
datasets: datasetIds.Select(datasetId => datasetId.ToString()).ToList(),
roles: [ "Dynamic" ]
),
}
? [new GenerateTokenRequestV2TargetWorkspace(targetWorkspaceId)]
: [],
identities: [CreateEffectiveIdentity(userId, datasetIds, ["Dynamic"])]
);

// Generate Embed token
Expand Down Expand Up @@ -239,22 +224,13 @@ [Optional] Guid targetWorkspaceId

// Create a request for getting Embed token
// This method works only with new Power BI V2 workspace experience
var tokenRequest = new GenerateTokenRequestV2(
datasets: datasets,
reports: reports,
targetWorkspaces: targetWorkspaceId != Guid.Empty
? new List<GenerateTokenRequestV2TargetWorkspace>()
{
new GenerateTokenRequestV2TargetWorkspace(targetWorkspaceId),
}
: null,
identities: new List<EffectiveIdentity>()
{
new EffectiveIdentity(
username: userId.ToString(),
datasets: datasetIds.Select(datasetId => datasetId.ToString()).ToList()
),
}
var tokenRequest = CreateGenerateTokenRequest(
reports,
datasets,
targetWorkspaceId != Guid.Empty
? [new GenerateTokenRequestV2TargetWorkspace(targetWorkspaceId)]
: [],
[CreateEffectiveIdentity(userId, datasetIds, [])]
);

// Generate Embed token
Expand Down Expand Up @@ -290,29 +266,20 @@ [Optional] IList<Guid> targetWorkspaceIds
.ToList();

// Convert target workspace Ids to required types
IList<GenerateTokenRequestV2TargetWorkspace> targetWorkspaces = null;
if (targetWorkspaceIds != null)
{
targetWorkspaces = targetWorkspaceIds
.Select(targetWorkspaceId => new GenerateTokenRequestV2TargetWorkspace(
var targetWorkspaces =
targetWorkspaceIds
?.Select(targetWorkspaceId => new GenerateTokenRequestV2TargetWorkspace(
targetWorkspaceId
))
.ToList();
}
.ToList() ?? [];

// Create a request for getting Embed token
// This method works only with new Power BI V2 workspace experience
var tokenRequest = new GenerateTokenRequestV2(
datasets: datasets,
reports: reports,
targetWorkspaces: targetWorkspaceIds != null ? targetWorkspaces : null,
identities: new List<EffectiveIdentity>()
{
new EffectiveIdentity(
username: userId.ToString(),
datasets: datasetIds.Select(datasetId => datasetId.ToString()).ToList()
),
}
var tokenRequest = CreateGenerateTokenRequest(
reports,
datasets,
targetWorkspaces,
[CreateEffectiveIdentity(userId, datasetIds, [])]
);

// Generate Embed token
Expand All @@ -334,7 +301,10 @@ public async Task<EmbedToken> GetEmbedTokenForRDLReport(
PowerBIClient pbiClient = await this.GetPowerBIClient();

// Generate token request for RDL Report
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: accessLevel);
var generateTokenRequestParameters = new GenerateTokenRequest
{
AccessLevel = Enum.Parse<TokenAccessLevel>(accessLevel, ignoreCase: true),
};

// Generate Embed token
var embedToken = pbiClient.Reports.GenerateTokenInGroup(
Expand All @@ -345,5 +315,46 @@ public async Task<EmbedToken> GetEmbedTokenForRDLReport(

return embedToken;
}

private static GenerateTokenRequestV2 CreateGenerateTokenRequest(
IEnumerable<GenerateTokenRequestV2Report> reports,
IEnumerable<GenerateTokenRequestV2Dataset> datasets,
IEnumerable<GenerateTokenRequestV2TargetWorkspace> targetWorkspaces,
IEnumerable<EffectiveIdentity> identities
)
{
var request = new GenerateTokenRequestV2();

foreach (var report in reports)
request.Reports.Add(report);

foreach (var dataset in datasets)
request.Datasets.Add(dataset);

foreach (var targetWorkspace in targetWorkspaces)
request.TargetWorkspaces.Add(targetWorkspace);

foreach (var identity in identities)
request.Identities.Add(identity);

return request;
}

private static EffectiveIdentity CreateEffectiveIdentity(
Guid userId,
IEnumerable<Guid> datasetIds,
IEnumerable<string> roles
)
{
var identity = new EffectiveIdentity { Username = userId.ToString() };

foreach (var datasetId in datasetIds)
identity.Datasets.Add(datasetId.ToString());

foreach (var role in roles)
identity.Roles.Add(role);

return identity;
}
}
}
17 changes: 8 additions & 9 deletions src/CareTogether.Core/CareTogether.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>CareTogether</RootNamespace>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.12.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.20.0" />
<PackageReference Include="Azure.Identity" Version="1.21.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.28.0" />
<PackageReference Include="JsonPolymorph" Version="1.1.3" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Graph" Version="5.56.0" />
<PackageReference Include="Microsoft.PowerBI.Api" Version="4.22.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.Graph" Version="5.105.0" />
<PackageReference Include="Microsoft.PowerBI.Api" Version="5.1.0" />
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="Plivo" Version="5.47.3" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Plivo" Version="5.52.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ Guid locationId
var blob in tenantContainer.GetBlobsAsync(
BlobTraits.None,
BlobStates.None,
$"{locationId}/{logType}"
$"{locationId}/{logType}",
default
)
)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,12 @@ public async IAsyncEnumerable<string> ListAsync(Guid organizationId, Guid locati
var tenantContainer = await CreateContainerIfNotExists(organizationId);

await foreach (
var blob in tenantContainer.GetBlobsAsync(prefix: $"{locationId}/{objectType}/")
var blob in tenantContainer.GetBlobsAsync(
BlobTraits.None,
BlobStates.None,
$"{locationId}/{objectType}/",
default
)
)
{
var objectId = blob
Expand Down
2 changes: 1 addition & 1 deletion src/Timelines/Timelines.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
Loading
Loading