Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c517dead03 | |||
| 2b61ab7d2e | |||
| 4b319499c3 | |||
| d4055c6ff1 | |||
| af0fc9f669 | |||
| edbc884d74 | |||
| 025d7f70ba | |||
| 70acc06f37 | |||
| abf86eda03 |
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
- name: 🔐 Login to Github Container Registry
|
||||
if: ${{ inputs.use-internal-image }}
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: "ghcr.io"
|
||||
username: ${{ github.actor }}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Speckle.Connectors.Logging;
|
||||
|
||||
namespace Speckle.Sdk.Logging;
|
||||
|
||||
public interface ISdkActivityFactory : IDisposable
|
||||
{
|
||||
/// <param name="name"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
ISdkActivity? Start(string? name = default, [CallerMemberName] string source = "");
|
||||
ISdkActivity? Start(
|
||||
string? name = null,
|
||||
SdkActivityKind kind = SdkActivityKind.Internal,
|
||||
[CallerMemberName] string source = ""
|
||||
);
|
||||
|
||||
ISdkActivity? StartRemote(
|
||||
string traceId,
|
||||
string parentSpanId,
|
||||
string? name = default,
|
||||
string traceContext,
|
||||
SdkActivityKind kind,
|
||||
string? name = null,
|
||||
[CallerMemberName] string source = ""
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Speckle.Connectors.Logging;
|
||||
|
||||
public enum SdkActivityKind
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value.
|
||||
/// Indicates that the Activity represents an internal operation within an application, as opposed to an operations with remote parents or children.
|
||||
/// </summary>
|
||||
Internal = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Server activity represents request incoming from external component.
|
||||
/// </summary>
|
||||
Server = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Client activity represents outgoing request to the external component.
|
||||
/// </summary>
|
||||
Client = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Producer activity represents output provided to external components.
|
||||
/// </summary>
|
||||
Producer = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Consumer activity represents output received from an external component.
|
||||
/// </summary>
|
||||
Consumer = 4,
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using Speckle.Newtonsoft.Json;
|
||||
|
||||
namespace Speckle.Sdk.Api.GraphQL.Models;
|
||||
|
||||
public class LimitedWorkspace
|
||||
@@ -6,8 +8,12 @@ public class LimitedWorkspace
|
||||
public string name { get; init; }
|
||||
public string? role { get; init; }
|
||||
public string slug { get; init; }
|
||||
public string? logo { get; init; }
|
||||
public string? logoUri { get; init; }
|
||||
public string? description { get; init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Obsolete($"Deprecated, use {nameof(logoUri)} instead", true)]
|
||||
public string? logo { get; init; }
|
||||
}
|
||||
|
||||
public class Workspace : LimitedWorkspace
|
||||
@@ -16,9 +22,13 @@ public class Workspace : LimitedWorkspace
|
||||
public DateTime updatedAt { get; init; }
|
||||
public bool readOnly { get; init; }
|
||||
public WorkspacePermissionChecks permissions { get; init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Obsolete("Workspaces no longer have creation state, is always created true", true)]
|
||||
public WorkspaceCreationState? creationState { get; init; }
|
||||
}
|
||||
|
||||
[Obsolete("Workspaces no longer have creation state, is always created true")]
|
||||
public sealed class WorkspaceCreationState
|
||||
{
|
||||
public bool completed { get; init; }
|
||||
|
||||
@@ -264,15 +264,11 @@ public sealed class ActiveUserResource
|
||||
name
|
||||
role
|
||||
slug
|
||||
logo
|
||||
logoUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
readOnly
|
||||
description
|
||||
creationState
|
||||
{
|
||||
completed
|
||||
}
|
||||
permissions {
|
||||
canCreateProject {
|
||||
authorized
|
||||
@@ -317,7 +313,7 @@ public sealed class ActiveUserResource
|
||||
/// <remarks>note this returns a <see cref="LimitedWorkspace"/>, because it may be a workspace the user is not a member of</remarks>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
/// <exception cref="SpeckleException">The ActiveUser could not be found (e.g. the client is not authenticated)</exception>
|
||||
public async Task<LimitedWorkspace?> GetActiveWorkspace(CancellationToken cancellationToken = default)
|
||||
private async Task<LimitedWorkspace?> GetActiveWorkspace_Legacy(CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
@@ -328,7 +324,6 @@ public sealed class ActiveUserResource
|
||||
name
|
||||
role
|
||||
slug
|
||||
logo
|
||||
description
|
||||
}
|
||||
}
|
||||
@@ -349,6 +344,47 @@ public sealed class ActiveUserResource
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
public async Task<LimitedWorkspace?> GetActiveWorkspace(CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
query ActiveUser {
|
||||
data:activeUser {
|
||||
data:activeWorkspace {
|
||||
id
|
||||
name
|
||||
role
|
||||
slug
|
||||
logoUrl
|
||||
description
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
var request = new GraphQLRequest { Query = QUERY };
|
||||
|
||||
NullableResponse<NullableResponse<LimitedWorkspace?>?> response;
|
||||
try
|
||||
{
|
||||
response = await _client
|
||||
.ExecuteGraphQLRequest<NullableResponse<NullableResponse<LimitedWorkspace?>?>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (SpeckleGraphQLInvalidQueryException)
|
||||
{
|
||||
//v2.x.x servers do not have a logoUrl property
|
||||
return await GetActiveWorkspace_Legacy(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response.data is null)
|
||||
{
|
||||
throw new SpeckleException("GraphQL response indicated that the ActiveUser could not be found");
|
||||
}
|
||||
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
/// <param name="limit">Max number of projects to fetch</param>
|
||||
/// <param name="cursor">Optional cursor for pagination</param>
|
||||
/// <param name="filter">Optional filter</param>
|
||||
|
||||
@@ -52,7 +52,6 @@ public sealed class OtherUserResource
|
||||
/// <param name="query">String to search for. Must be at least 3 characters</param>
|
||||
/// <param name="limit">Max number of users to fetch</param>
|
||||
/// <param name="cursor">Optional cursor for pagination</param>
|
||||
/// <param name="archived"></param>
|
||||
/// <param name="emailOnly"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
@@ -61,26 +60,25 @@ public sealed class OtherUserResource
|
||||
string query,
|
||||
int limit = ServerLimits.DEFAULT_PAGINATION_REQUEST,
|
||||
string? cursor = null,
|
||||
bool archived = false,
|
||||
bool emailOnly = false,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
query UserSearch($query: String!, $limit: Int!, $cursor: String, $archived: Boolean, $emailOnly: Boolean) {
|
||||
data:userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived, emailOnly: $emailOnly) {
|
||||
query Users($input: UsersRetrievalInput!) {
|
||||
data:users(input: $input) {
|
||||
cursor
|
||||
items {
|
||||
id
|
||||
name
|
||||
bio
|
||||
company
|
||||
avatar
|
||||
verified
|
||||
role
|
||||
}
|
||||
}
|
||||
id
|
||||
name
|
||||
bio
|
||||
company
|
||||
avatar
|
||||
verified
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
@@ -89,11 +87,13 @@ public sealed class OtherUserResource
|
||||
Query = QUERY,
|
||||
Variables = new
|
||||
{
|
||||
query,
|
||||
limit,
|
||||
cursor,
|
||||
archived,
|
||||
emailOnly,
|
||||
input = new
|
||||
{
|
||||
query,
|
||||
limit,
|
||||
emailOnly,
|
||||
cursor,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ public sealed class SubscriptionResource : IDisposable
|
||||
/// <summary>Subscribe to updates to resource comments/threads. Optionally specify resource ID string to only receive updates regarding comments for those resources</summary>
|
||||
/// <remarks><inheritdoc cref="CreateUserProjectsUpdatedSubscription"/></remarks>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.SubscribeTo{T}"/>
|
||||
[Obsolete("Comments are now issues, and we've not update SDKs with the new subs")]
|
||||
public Subscription<ProjectCommentsUpdatedMessage> CreateProjectCommentsUpdatedSubscription(
|
||||
ViewerUpdateTrackingTarget target
|
||||
)
|
||||
|
||||
@@ -28,15 +28,11 @@ public sealed class WorkspaceResource
|
||||
name
|
||||
role
|
||||
slug
|
||||
logo
|
||||
logoUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
readOnly
|
||||
description
|
||||
creationState
|
||||
{
|
||||
completed
|
||||
}
|
||||
permissions {
|
||||
canCreateProject {
|
||||
authorized
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
namespace Speckle.Sdk.Logging;
|
||||
using Speckle.Connectors.Logging;
|
||||
|
||||
namespace Speckle.Sdk.Logging;
|
||||
|
||||
public sealed class NullActivityFactory : ISdkActivityFactory
|
||||
{
|
||||
public void Dispose() { }
|
||||
|
||||
public ISdkActivity? Start(string? name = default, string source = "") => null;
|
||||
public ISdkActivity? Start(string? name, SdkActivityKind kind, string source) => null;
|
||||
|
||||
public ISdkActivity? StartRemote(string traceId, string parentSpanId, string? name = default, string source = "") =>
|
||||
null;
|
||||
public ISdkActivity? StartRemote(string traceContext, SdkActivityKind kind, string? name, string source) => null;
|
||||
}
|
||||
|
||||
@@ -7,32 +7,33 @@ namespace Speckle.Sdk.Models;
|
||||
public enum DynamicBaseMemberType
|
||||
{
|
||||
/// <summary>
|
||||
/// The typed members of the DynamicBase object
|
||||
/// The typed members of the <see cref="DynamicBase"/> object
|
||||
/// </summary>
|
||||
Instance = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The dynamically added members of the DynamicBase object
|
||||
/// The dynamically added members of the <see cref="DynamicBase"/> object
|
||||
/// </summary>
|
||||
Dynamic = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The typed members flagged with ObsoleteAttribute attribute.
|
||||
/// The typed members flagged with <see cref="ObsoleteAttribute"/> attribute.
|
||||
/// </summary>
|
||||
Obsolete = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The typed methods flagged with TODO:
|
||||
/// Old feature supported in v2 for grasshopper
|
||||
/// </summary>
|
||||
[Obsolete("Feature no longer supported")]
|
||||
SchemaComputed = 16,
|
||||
|
||||
/// <summary>
|
||||
/// All the typed members, including ones with ObsoleteAttribute attributes.
|
||||
/// All the typed members, including ones with <see cref="ObsoleteAttribute"/> attributes.
|
||||
/// </summary>
|
||||
InstanceAll = Instance + Obsolete,
|
||||
|
||||
/// <summary>
|
||||
/// All the members, including dynamic and instance members flagged with ObsoleteAttribute attributes
|
||||
/// All the members, including dynamic and instance members flagged with <see cref="ObsoleteAttribute"/> attributes
|
||||
/// </summary>
|
||||
All = InstanceAll + Dynamic,
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ServerObjectManagerTests : MoqTest
|
||||
http.Setup(x => x.CreateHttpClient(It.IsAny<HttpClientHandler>(), timeout, token)).Returns(httpClient);
|
||||
|
||||
var activityFactory = Create<ISdkActivityFactory>();
|
||||
activityFactory.Setup(x => x.Start(null, "DownloadObjects")).Returns((ISdkActivity?)null);
|
||||
activityFactory.Setup(x => x.Start(null, default, "DownloadObjects")).Returns((ISdkActivity?)null);
|
||||
|
||||
var serverObjectManager = new ServerObjectManager(
|
||||
http.Object,
|
||||
@@ -91,7 +91,7 @@ public class ServerObjectManagerTests : MoqTest
|
||||
http.Setup(x => x.CreateHttpClient(It.IsAny<HttpClientHandler>(), timeout, token)).Returns(httpClient);
|
||||
|
||||
var activityFactory = Create<ISdkActivityFactory>();
|
||||
activityFactory.Setup(x => x.Start(null, "DownloadSingleObject")).Returns((ISdkActivity?)null);
|
||||
activityFactory.Setup(x => x.Start(null, default, "DownloadSingleObject")).Returns((ISdkActivity?)null);
|
||||
|
||||
var serverObjectManager = new ServerObjectManager(
|
||||
http.Object,
|
||||
@@ -132,7 +132,7 @@ public class ServerObjectManagerTests : MoqTest
|
||||
http.Setup(x => x.CreateHttpClient(It.IsAny<HttpClientHandler>(), timeout, token)).Returns(httpClient);
|
||||
|
||||
var activityFactory = Create<ISdkActivityFactory>();
|
||||
activityFactory.Setup(x => x.Start(null, "HasObjects")).Returns((ISdkActivity?)null);
|
||||
activityFactory.Setup(x => x.Start(null, default, "HasObjects")).Returns((ISdkActivity?)null);
|
||||
|
||||
var serverObjectManager = new ServerObjectManager(
|
||||
http.Object,
|
||||
@@ -171,7 +171,7 @@ public class ServerObjectManagerTests : MoqTest
|
||||
http.Setup(x => x.CreateHttpClient(It.IsAny<HttpClientHandler>(), timeout, token)).Returns(httpClient);
|
||||
|
||||
var activityFactory = Create<ISdkActivityFactory>();
|
||||
activityFactory.Setup(x => x.Start(null, "UploadObjects")).Returns((ISdkActivity?)null);
|
||||
activityFactory.Setup(x => x.Start(null, default, "UploadObjects")).Returns((ISdkActivity?)null);
|
||||
|
||||
var serverObjectManager = new ServerObjectManager(
|
||||
http.Object,
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"Type": "AggregateException",
|
||||
"InnerException": {
|
||||
"Data": {},
|
||||
"Message": "FORBIDDEN: Your auth token does not have the required scope: workspace:read.",
|
||||
"Type": "SpeckleGraphQLForbiddenException"
|
||||
}
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"Type": "AggregateException",
|
||||
"InnerException": {
|
||||
"Data": {},
|
||||
"Message": "FORBIDDEN: Your auth token does not have the required scope: workspace:read.",
|
||||
"Type": "SpeckleGraphQLForbiddenException"
|
||||
}
|
||||
}
|
||||
@@ -21,17 +21,19 @@ public class WorkspaceResourceTests
|
||||
return testUser;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact, Trait("Server", "Internal")]
|
||||
public async Task TestGetWorkspace()
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<AggregateException>(async () => _ = await Sut.Get("non-existent-id"));
|
||||
await Verify(ex);
|
||||
Assert.Single(ex.InnerExceptions);
|
||||
Assert.All(ex.InnerExceptions, item => Assert.IsType<SpeckleGraphQLForbiddenException>(item));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestGetProjects()
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<AggregateException>(async () => _ = await Sut.GetProjects("non-existent-id"));
|
||||
await Verify(ex);
|
||||
Assert.Single(ex.InnerExceptions);
|
||||
Assert.All(ex.InnerExceptions, item => Assert.IsType<SpeckleGraphQLForbiddenException>(item));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user