Compare commits
13 Commits
3.3.0-dev.1
..
3.3.6
| Author | SHA1 | Date | |
|---|---|---|---|
| 0361a6e5b7 | |||
| 0e97782c29 | |||
| 298dedc3af | |||
| efc38d8f5c | |||
| 8d3985f93b | |||
| 915a18dc98 | |||
| 5fcb3223d6 | |||
| 21851c06d2 | |||
| 3a9a633d30 | |||
| 7f092d529c | |||
| a4f0e0e4aa | |||
| 227729a0df | |||
| 178085f3f8 |
@@ -100,6 +100,8 @@ services:
|
||||
POSTGRES_PASSWORD: "speckle"
|
||||
POSTGRES_DB: "speckle"
|
||||
ENABLE_MP: "false"
|
||||
|
||||
LOG_PRETTY: "true"
|
||||
|
||||
networks:
|
||||
default:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Speckle.Objects.Geometry;
|
||||
using Speckle.Sdk.Models;
|
||||
using Point = Speckle.Objects.Geometry.Point;
|
||||
|
||||
namespace Speckle.Objects.Annotation;
|
||||
|
||||
@@ -15,11 +14,6 @@ public class Text : Base
|
||||
/// </summary>
|
||||
public required string value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Origin point, relation to the text is defined by AlignmentHorizontal and AlignmentVertical
|
||||
/// </summary>
|
||||
public required Point origin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Height in linear units or pixels (if Units.None)
|
||||
/// </summary>
|
||||
@@ -31,6 +25,11 @@ public class Text : Base
|
||||
/// </summary>
|
||||
public required string units { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the text is oriented to face the screen (camera-aligned).
|
||||
/// </summary>
|
||||
public required bool screenOriented { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal alignment: Left, Center or Right
|
||||
/// </summary>
|
||||
@@ -42,9 +41,9 @@ public class Text : Base
|
||||
public AlignmentVertical alignmentV { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Plane will be null if the text object orientation follows camera view
|
||||
/// Plane axis vectors will be ignored if screenOriented is true
|
||||
/// </summary>
|
||||
public Plane? plane { get; set; }
|
||||
public required Plane plane { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum width of the text field (in 'units').
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
namespace Speckle.Sdk.Api.GraphQL.Enums;
|
||||
namespace Speckle.Sdk.Api.GraphQL.Enums;
|
||||
|
||||
public enum ProjectVisibility
|
||||
{
|
||||
Private = 0,
|
||||
Private,
|
||||
Public,
|
||||
|
||||
[Obsolete("Use Unlisted instead", true)]
|
||||
Public = 1,
|
||||
Unlisted = 2,
|
||||
[Obsolete("Use Public instead")]
|
||||
Unlisted,
|
||||
Workspace,
|
||||
}
|
||||
|
||||
@@ -26,3 +26,8 @@ public sealed class ProjectWithTeam : Project
|
||||
public List<PendingStreamCollaborator> invitedTeam { get; init; }
|
||||
public List<ProjectCollaborator> team { get; init; }
|
||||
}
|
||||
|
||||
public sealed class ProjectWithPermissions : Project
|
||||
{
|
||||
public ProjectPermissionChecks permissions { get; init; }
|
||||
}
|
||||
|
||||
@@ -4,4 +4,6 @@ public sealed class ProjectPermissionChecks
|
||||
{
|
||||
public PermissionCheckResult canCreateModel { get; init; }
|
||||
public PermissionCheckResult canDelete { get; init; }
|
||||
public PermissionCheckResult canLoad { get; init; }
|
||||
public PermissionCheckResult canPublish { get; init; }
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ public sealed class Workspace
|
||||
public string role { get; init; }
|
||||
public string slug { get; init; }
|
||||
public string? description { get; init; }
|
||||
public string? logo { get; init; }
|
||||
public DateTime? createdAt { get; init; }
|
||||
public DateTime? updatedAt { get; init; }
|
||||
public bool? readOnly { get; init; }
|
||||
public WorkspacePermissionChecks permissions { get; init; }
|
||||
public WorkspaceCreationState? creationState { get; init; }
|
||||
}
|
||||
|
||||
@@ -361,4 +361,89 @@ public sealed class ActiveUserResource
|
||||
|
||||
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>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <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<ResourceCollection<ProjectWithPermissions>> GetProjectsWithPermissions(
|
||||
int limit = ServerLimits.DEFAULT_PAGINATION_REQUEST,
|
||||
string? cursor = null,
|
||||
UserProjectsFilter? filter = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
query User($limit: Int!, $cursor: String, $filter: UserProjectsFilter) {
|
||||
data: activeUser {
|
||||
data: projects(limit: $limit, cursor: $cursor, filter: $filter) {
|
||||
totalCount
|
||||
cursor
|
||||
items {
|
||||
id
|
||||
name
|
||||
description
|
||||
visibility
|
||||
allowPublicComments
|
||||
role
|
||||
createdAt
|
||||
updatedAt
|
||||
sourceApps
|
||||
workspaceId
|
||||
permissions {
|
||||
canCreateModel {
|
||||
code
|
||||
authorized
|
||||
message
|
||||
}
|
||||
canDelete {
|
||||
code
|
||||
authorized
|
||||
message
|
||||
}
|
||||
canLoad {
|
||||
code
|
||||
authorized
|
||||
message
|
||||
}
|
||||
canPublish {
|
||||
code
|
||||
authorized
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
var request = new GraphQLRequest
|
||||
{
|
||||
Query = QUERY,
|
||||
Variables = new
|
||||
{
|
||||
limit,
|
||||
cursor,
|
||||
filter,
|
||||
},
|
||||
};
|
||||
|
||||
var response = await _client
|
||||
.ExecuteGraphQLRequest<NullableResponse<RequiredResponse<ResourceCollection<ProjectWithPermissions>>?>>(
|
||||
request,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,16 @@ public sealed class ProjectResource
|
||||
code
|
||||
message
|
||||
}
|
||||
canLoad {
|
||||
authorized
|
||||
code
|
||||
message
|
||||
}
|
||||
canPublish {
|
||||
authorized
|
||||
code
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +50,10 @@ public sealed class WorkspaceResource
|
||||
var request = new GraphQLRequest { Query = QUERY, Variables = new { workspaceId } };
|
||||
|
||||
var response = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<Workspace>>>(request, cancellationToken)
|
||||
.ExecuteGraphQLRequest<RequiredResponse<Workspace>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return response.data.data;
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/// <param name="workspaceId"></param>
|
||||
|
||||
@@ -69,6 +69,10 @@ public sealed class SerializeProcess(
|
||||
NodeInfo
|
||||
>();
|
||||
|
||||
private readonly Pool<List<Task<Dictionary<Id, NodeInfo>>>> _taskResultPool = Pools.CreateListPool<
|
||||
Task<Dictionary<Id, NodeInfo>>
|
||||
>();
|
||||
|
||||
private long _objectCount;
|
||||
private long _objectsFound;
|
||||
|
||||
@@ -163,7 +167,7 @@ public sealed class SerializeProcess(
|
||||
|
||||
try
|
||||
{
|
||||
var tasks = new List<Task<Dictionary<Id, NodeInfo>>>();
|
||||
var tasks = _taskResultPool.Get();
|
||||
foreach (var child in baseChildFinder.GetChildren(obj))
|
||||
{
|
||||
// tmp is necessary because of the way closures close over loop variables
|
||||
@@ -190,30 +194,27 @@ public sealed class SerializeProcess(
|
||||
return EMPTY_CLOSURES;
|
||||
}
|
||||
|
||||
List<Dictionary<Id, NodeInfo>> taskClosures = new();
|
||||
Dictionary<Id, NodeInfo>[] taskClosures = [];
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
var currentTasks = tasks.ToList();
|
||||
do
|
||||
//get child results
|
||||
var childTask = Task.WhenAll(tasks);
|
||||
await Task.WhenAny(childTask, Task.Delay(Timeout.InfiniteTimeSpan, _processSource.Token)).ConfigureAwait(false);
|
||||
if (childTask.IsFaulted)
|
||||
{
|
||||
//grab when any Task is done and see if we're cancelling
|
||||
var t = await Task.WhenAny(currentTasks).ConfigureAwait(false);
|
||||
if (t.IsCanceled)
|
||||
if (childTask.Exception is not null)
|
||||
{
|
||||
return EMPTY_CLOSURES;
|
||||
RecordException(childTask.Exception);
|
||||
}
|
||||
if (t.IsFaulted)
|
||||
{
|
||||
if (t.Exception is not null)
|
||||
{
|
||||
RecordException(t.Exception);
|
||||
}
|
||||
return EMPTY_CLOSURES;
|
||||
}
|
||||
taskClosures.Add(t.Result);
|
||||
currentTasks.Remove(t);
|
||||
} while (currentTasks.Count > 0);
|
||||
return EMPTY_CLOSURES;
|
||||
}
|
||||
if (!childTask.IsCompleted)
|
||||
{
|
||||
return EMPTY_CLOSURES;
|
||||
}
|
||||
taskClosures = childTask.Result;
|
||||
}
|
||||
_taskResultPool.Return(tasks);
|
||||
|
||||
if (_processSource.Token.IsCancellationRequested)
|
||||
{
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"displayValue": null,
|
||||
"id": "15168a13ce3f336dee9aa1807cbf375c",
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject:Objects.Data.ArcgisObject",
|
||||
"type": null,
|
||||
"units": null
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"displayValue": null,
|
||||
"elements": null,
|
||||
"id": "bf80e8a10eca2264f11c39bae42538da",
|
||||
"level": null,
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject:Objects.Data.ArchicadObject",
|
||||
"type": null
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"baseCurves": null,
|
||||
"displayValue": null,
|
||||
"elements": null,
|
||||
"id": "76b7634117981a9fb9d3cffca5464f26",
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject:Objects.Data.Civil3dObject",
|
||||
"type": null,
|
||||
"units": null
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"displayValue": null,
|
||||
"id": "a1567a1cf10417294c93b70bf5ca97c1",
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject"
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"displayValue": null,
|
||||
"elements": null,
|
||||
"id": "39d4deaa7cd20e7004812304f41a68d5",
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject:Objects.Data.EtabsObject",
|
||||
"type": null,
|
||||
"units": null
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"displayValue": null,
|
||||
"id": "fbda4ea7bb1b3722ca28e97573742a4e",
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject:Objects.Data.NavisworksObject",
|
||||
"units": null
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"category": null,
|
||||
"displayValue": null,
|
||||
"elements": null,
|
||||
"family": null,
|
||||
"id": "7e285508a71c55589bbc053451f687d2",
|
||||
"level": null,
|
||||
"location": null,
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject:Objects.Data.RevitObject",
|
||||
"type": null,
|
||||
"units": null
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"applicationId": null,
|
||||
"displayValue": null,
|
||||
"elements": null,
|
||||
"id": "c07f15678d8b4a48a7ecab9eb30e69a8",
|
||||
"name": null,
|
||||
"properties": null,
|
||||
"speckle_type": "Objects.Data.DataObject:Objects.Data.TeklaObject",
|
||||
"type": null,
|
||||
"units": null
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Speckle.Objects.Data;
|
||||
using Speckle.Objects.Geometry;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Serialisation;
|
||||
using Speckle.Sdk.Serialisation.V2;
|
||||
using Speckle.Sdk.Serialisation.V2.Send;
|
||||
|
||||
namespace Speckle.Sdk.Serialization.Tests;
|
||||
|
||||
public class DataObjectTests
|
||||
{
|
||||
private readonly ISerializeProcessFactory _factory;
|
||||
|
||||
public DataObjectTests()
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddSpeckleSdk(new("Tests", "test"), "v3", typeof(TestClass).Assembly, typeof(Polyline).Assembly);
|
||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
|
||||
_factory = serviceProvider.GetRequiredService<ISerializeProcessFactory>();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(ArcgisObject))]
|
||||
[InlineData(typeof(ArchicadObject))]
|
||||
[InlineData(typeof(Civil3dObject))]
|
||||
[InlineData(typeof(DataObject))]
|
||||
[InlineData(typeof(EtabsObject))]
|
||||
[InlineData(typeof(NavisworksObject))]
|
||||
[InlineData(typeof(RevitObject))]
|
||||
[InlineData(typeof(TeklaObject))]
|
||||
public async Task ValidateDataObject(Type type)
|
||||
{
|
||||
Base x = (Base)(Activator.CreateInstance(type) ?? throw new Exception("Could not create instance of " + type.Name));
|
||||
|
||||
var json = new ConcurrentDictionary<Id, Json>();
|
||||
await using var serializeProcess = _factory.CreateSerializeProcess(
|
||||
new MemoryJsonCacheManager(json),
|
||||
new DummyServerObjectManager(),
|
||||
null,
|
||||
default,
|
||||
new SerializeProcessOptions(true, true, false, true)
|
||||
);
|
||||
await serializeProcess.Serialize(x);
|
||||
await VerifyJson(json.Single().Value.Value).UseParameters(type);
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,19 @@ public class ActiveUserResourceTests : IAsyncLifetime
|
||||
res.items.Count.Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActiveUserGetProjectsWithPermissions()
|
||||
{
|
||||
var p1 = await _testUser.Project.Create(new("Project 3", null, null));
|
||||
var p2 = await _testUser.Project.Create(new("Project 4", null, null));
|
||||
|
||||
var res = await Sut.GetProjectsWithPermissions();
|
||||
|
||||
res.items.Should().Contain(x => x.id == p1.id);
|
||||
res.items.Should().Contain(x => x.id == p2.id);
|
||||
res.items.Count.Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActiveUserGetProjects_NoAuth()
|
||||
{
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
using FluentAssertions;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Api.GraphQL;
|
||||
using Speckle.Sdk.Api.GraphQL.Enums;
|
||||
using Speckle.Sdk.Api.GraphQL.Inputs;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Common;
|
||||
@@ -18,7 +19,7 @@ public class ProjectInviteResourceTests : IAsyncLifetime
|
||||
{
|
||||
_inviter = await Fixtures.SeedUserWithClient();
|
||||
_invitee = await Fixtures.SeedUserWithClient();
|
||||
_project = await _inviter.Project.Create(new("test", null, null));
|
||||
_project = await _inviter.Project.Create(new("test", null, ProjectVisibility.Public));
|
||||
_createdInvite = await SeedInvite();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ public class ProjectResourceExceptionalTests : IAsyncLifetime
|
||||
{
|
||||
var ex = await Assert.ThrowsAsync<AggregateException>(async () =>
|
||||
_ = await _unauthedUser.Project.CreateInWorkspace(
|
||||
new(_testProject.id, "My new name", ProjectVisibility.Unlisted, "NonExistentWorkspace")
|
||||
new(_testProject.id, "My new name", ProjectVisibility.Public, "NonExistentWorkspace")
|
||||
)
|
||||
);
|
||||
ex.InnerExceptions.Single().Should().BeOfType<SpeckleGraphQLException>();
|
||||
|
||||
@@ -29,7 +29,7 @@ public class ProjectResourceTests
|
||||
|
||||
[Theory]
|
||||
[InlineData("Very private project", "My secret project", ProjectVisibility.Private)]
|
||||
[InlineData("Very unlisted project", null, ProjectVisibility.Unlisted)]
|
||||
[InlineData("Very unlisted project", null, ProjectVisibility.Public)]
|
||||
public async Task ProjectCreate_Should_CreateProjectSuccessfully(
|
||||
string name,
|
||||
string? description,
|
||||
@@ -70,7 +70,7 @@ public class ProjectResourceTests
|
||||
// Arrange
|
||||
const string NEW_NAME = "MY new name";
|
||||
const string NEW_DESCRIPTION = "MY new desc";
|
||||
const ProjectVisibility NEW_VISIBILITY = ProjectVisibility.Unlisted;
|
||||
const ProjectVisibility NEW_VISIBILITY = ProjectVisibility.Public;
|
||||
|
||||
// Act
|
||||
var newProject = await Sut.Update(
|
||||
|
||||
@@ -57,7 +57,7 @@ public class GeneralSendTest
|
||||
client = TestDataHelper.ServiceProvider.GetRequiredService<IClientFactory>().Create(acc);
|
||||
|
||||
_project = await client.Project.Create(
|
||||
new($"General Send Test run {Guid.NewGuid()}", null, ProjectVisibility.Unlisted)
|
||||
new($"General Send Test run {Guid.NewGuid()}", null, ProjectVisibility.Public)
|
||||
);
|
||||
_remote = TestDataHelper.ServiceProvider.GetRequiredService<IServerTransportFactory>().Create(acc, _project.id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user