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

Support the Attachment object💡 #2616 #2622

Merged
merged 7 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
50 changes: 50 additions & 0 deletions Src/Witsml/Data/WitsmlAttachment.cs
eliasbruvik marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Collections.Generic;
using System.Xml.Serialization;

using Witsml.Data.Measures;
eliasbruvik marked this conversation as resolved.
Show resolved Hide resolved
using Witsml.Extensions;

namespace Witsml.Data
{
public class WitsmlAttachment : WitsmlObjectOnWellbore
{
public override WitsmlAttachments AsItemInWitsmlList()
{
return new WitsmlAttachments()
{
Attachments = this.AsItemInList()
};
}

[XmlElement("objectReference")]
public WitsmlObjectReference ObjectReference { get; set; }

[XmlElement("subObjectReference")]
public WitsmlObjectReference SubObjectReference { get; set; }

[XmlElement("md")]
public WitsmlMeasuredDepthCoord Md { get; set; }

[XmlElement("mdBit")]
public WitsmlMeasuredDepthCoord MdBit { get; set; }

[XmlElement("param")]
public List<WitsmlIndexedObject> Param { get; set; }

[XmlElement("fileName")]
public string FileName { get; set; }

[XmlElement("description")]
public string Description { get; set; }

[XmlElement("fileType")]
public string FileType { get; set; }

[XmlElement("content")]
public string Content { get; set; }

[XmlElement("commonData")]
public WitsmlCommonData CommonData { get; set; }

}
}
25 changes: 25 additions & 0 deletions Src/Witsml/Data/WitsmlAttachments.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;

namespace Witsml.Data
{
[XmlRoot("attachments", Namespace = "http://www.witsml.org/schemas/1series")]
public class WitsmlAttachments : IWitsmlObjectList
{
[XmlAttribute("version")]
public string Version = "1.4.1.1";

[XmlElement("attachment")]
public List<WitsmlAttachment> Attachments { get; set; } = new();

public string TypeName => "attachment";

[XmlIgnore]
public IEnumerable<WitsmlObjectOnWellbore> Objects
{
get => Attachments;
set => Attachments = value.Select(obj => (WitsmlAttachment)obj).ToList();
}
}
}
26 changes: 26 additions & 0 deletions Src/WitsmlExplorer.Api/HttpHandlers/AttachmentHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

using WitsmlExplorer.Api.Models;
using WitsmlExplorer.Api.Services;

namespace WitsmlExplorer.Api.HttpHandlers
{
public static class AttachmentHandler
{
[Produces(typeof(IEnumerable<Attachment>))]
public static async Task<IResult> GetAttachments(string wellUid, string wellboreUid, IAttachmentService attachmentService)
{
return TypedResults.Ok(await attachmentService.GetAttachments(wellUid, wellboreUid));

}
[Produces(typeof(Attachment))]
public static async Task<IResult> GetAttachment(string wellUid, string wellboreUid, string attachmentUid, IAttachmentService attachmentService)
{
return TypedResults.Ok(await attachmentService.GetAttachment(wellUid, wellboreUid, attachmentUid));
}
}
}
30 changes: 30 additions & 0 deletions Src/WitsmlExplorer.Api/Models/Attachment.cs
eliasbruvik marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Witsml.Data;

namespace WitsmlExplorer.Api.Models
{
public class Attachment : ObjectOnWellbore
{
public string FileName { get; set; }
public string Description { get; set; }
public string FileType { get; set; }
public string Content { get; set; }
public CommonData CommonData { get; set; }
public override WitsmlAttachments ToWitsml()
{
return new WitsmlAttachment
{
UidWell = WellUid,
NameWell = WellName,
UidWellbore = WellboreUid,
NameWellbore = WellboreName,
Uid = Uid,
Name = Name,
FileName = FileName,
Description = Description,
FileType = FileType,
Content = Content,
CommonData = CommonData?.ToWitsml()
}.AsItemInWitsmlList();
}
}
}
4 changes: 4 additions & 0 deletions Src/WitsmlExplorer.Api/Models/EntityType.cs
eliasbruvik marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public enum EntityType
Tubular,
Trajectory,
WbGeometry,
Attachment
}

public static class EntityTypeHelper
Expand Down Expand Up @@ -62,6 +63,7 @@ public static WitsmlObjectOnWellbore ToObjectOnWellbore(EntityType type)
EntityType.WbGeometry => new WitsmlWbGeometry(),
EntityType.Well => null,
EntityType.Wellbore => null,
EntityType.Attachment => new WitsmlAttachment(),
_ => null,
};
}
Expand Down Expand Up @@ -92,6 +94,7 @@ public static IWitsmlObjectList ToObjectList(EntityType type)
EntityType.WbGeometry => new WitsmlWbGeometrys(),
EntityType.Well => null,
EntityType.Wellbore => null,
EntityType.Attachment => new WitsmlAttachments(),
_ => null,
};
}
Expand All @@ -113,6 +116,7 @@ public static Type GetApiTypeFromEntityType(EntityType type)
EntityType.WbGeometry => typeof(WbGeometry),
EntityType.Well => typeof(Well),
EntityType.Wellbore => typeof(Wellbore),
EntityType.Attachment => typeof(Attachment),
_ => null,
};
}
Expand Down
51 changes: 51 additions & 0 deletions Src/WitsmlExplorer.Api/Query/AttachmentQueries.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Witsml.Data;
using Witsml.Extensions;

namespace WitsmlExplorer.Api.Query
{
public static class AttachmentQueries
{
public static WitsmlAttachments GetWitsmlAttachment(string wellUid, string wellboreUid, string attachmentUid = "")
{
return new WitsmlAttachments
{
Attachments = new WitsmlAttachment
{
Uid = attachmentUid,
UidWell = wellUid,
UidWellbore = wellboreUid,
NameWell = "",
NameWellbore = "",
Name = "",
FileName = "",
Description = "",
FileType = "",
Content = "",
CommonData = new WitsmlCommonData()
{
ItemState = "",
SourceName = "",
DTimLastChange = "",
DTimCreation = "",
ServiceCategory = "",
Comments = "",
DefaultDatum = "",
}
}.AsItemInList()
};
}

public static WitsmlAttachments QueryById(string wellUid, string wellboreUid, string attachmentUid)
{
return new WitsmlAttachments()
{
Attachments = new WitsmlAttachment
{
Uid = attachmentUid,
UidWell = wellUid,
UidWellbore = wellboreUid
}.AsItemInList()
};
}
}
}
3 changes: 3 additions & 0 deletions Src/WitsmlExplorer.Api/Routes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public static void ConfigureApi(this WebApplication app, IConfiguration configur
app.MapGet(routes[EntityType.BhaRun], BhaRunHandler.GetBhaRuns, useOAuth2);
app.MapGet(routes[EntityType.BhaRun] + "/{bhaRunUid}", BhaRunHandler.GetBhaRun, useOAuth2);

app.MapGet(routes[EntityType.Attachment], AttachmentHandler.GetAttachments, useOAuth2);
app.MapGet(routes[EntityType.Attachment] + "/{attachmentUid}", AttachmentHandler.GetAttachment, useOAuth2);

app.MapGet("/wells/{wellUid}/wellbores/{wellboreUid}/changelogs", ChangeLogHandler.GetChangeLogs, useOAuth2);

app.MapGet(routes[EntityType.FluidsReport], FluidsReportHandler.GetFluidsReports, useOAuth2);
Expand Down
63 changes: 63 additions & 0 deletions Src/WitsmlExplorer.Api/Services/AttachmentService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using Witsml.Data;
using Witsml.ServiceReference;

using WitsmlExplorer.Api.Models;
using WitsmlExplorer.Api.Query;

namespace WitsmlExplorer.Api.Services
{
public interface IAttachmentService
{
Task<Attachment> GetAttachment(string wellUid, string wellboreUid, string attachmentUid);
Task<ICollection<Attachment>> GetAttachments(string wellUid, string wellboreUid);
}

public class AttachmentService : WitsmlService, IAttachmentService
{
public AttachmentService(IWitsmlClientProvider witsmlClientProvider) : base(witsmlClientProvider) { }

public async Task<Attachment> GetAttachment(string wellUid, string wellboreUid, string attachmentUid)
{
WitsmlAttachments query = AttachmentQueries.GetWitsmlAttachment(wellUid, wellboreUid, attachmentUid);
WitsmlAttachments result = await _witsmlClient.GetFromStoreAsync(query, new OptionsIn(ReturnElements.All));
return WitsmlToAttachment(result.Attachments.FirstOrDefault());
}
public async Task<ICollection<Attachment>> GetAttachments(string wellUid, string wellboreUid)
{
WitsmlAttachments witsmlAttachments = AttachmentQueries.GetWitsmlAttachment(wellUid, wellboreUid);
WitsmlAttachments result = await _witsmlClient.GetFromStoreAsync(witsmlAttachments, new OptionsIn(ReturnElements.Requested));
return result.Attachments.Select(WitsmlToAttachment).OrderBy(attachment => attachment.Name).ToList();
}

private static Attachment WitsmlToAttachment(WitsmlAttachment attachment)
{
return attachment == null ? null : new Attachment
{
Uid = attachment.Uid,
Name = attachment.Name,
WellUid = attachment.UidWell,
WellName = attachment.NameWell,
WellboreName = attachment.NameWellbore,
WellboreUid = attachment.UidWellbore,
FileName = attachment.FileName,
Description = attachment.Description,
FileType = attachment.FileType,
Content = attachment.Content,
CommonData = new CommonData()
{
ItemState = attachment.CommonData.ItemState,
SourceName = attachment.CommonData.SourceName,
DTimLastChange = attachment.CommonData.DTimLastChange,
DTimCreation = attachment.CommonData.DTimCreation,
ServiceCategory = attachment.CommonData.ServiceCategory,
Comments = attachment.CommonData.Comments,
DefaultDatum = attachment.CommonData.DefaultDatum,
}
};
}
}
}
11 changes: 11 additions & 0 deletions Src/WitsmlExplorer.Api/Workers/Modify/ModifyUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,17 @@ public static void VerifyAllowedValues(string value, List<string> allowedValues,
nameof(WbGeometry.CommonData)
}
},
{
EntityType.Attachment, new HashSet<string>
{
nameof(Attachment.Name),
nameof(Attachment.FileName),
nameof(Attachment.Description),
nameof(Attachment.FileType),
nameof(Attachment.Content),
nameof(Attachment.CommonData)
}
},
};

public static void VerifyModificationProperties(ObjectOnWellbore obj, EntityType objectType, ILogger logger)
Expand Down
3 changes: 3 additions & 0 deletions Tests/WitsmlExplorer.Api.Tests/Models/EntityTypeTests.cs
eliasbruvik marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public void EntityTypeToPluralLowercase_Get_CorrectResult()
Assert.Equal("trajectories", strings[EntityType.Trajectory]);
Assert.Equal("tubulars", strings[EntityType.Tubular]);
Assert.Equal("wbgeometries", strings[EntityType.WbGeometry]);
Assert.Equal("attachments", strings[EntityType.Attachment]);
}

[Fact]
Expand All @@ -40,6 +41,7 @@ public void EntityTypeToObjectOnWellbore_GetAllWellboreObjects_CorrectType()
Assert.IsType<WitsmlTrajectory>(EntityTypeHelper.ToObjectOnWellbore(EntityType.Trajectory));
Assert.IsType<WitsmlTubular>(EntityTypeHelper.ToObjectOnWellbore(EntityType.Tubular));
Assert.IsType<WitsmlWbGeometry>(EntityTypeHelper.ToObjectOnWellbore(EntityType.WbGeometry));
Assert.IsType<WitsmlAttachment>(EntityTypeHelper.ToObjectOnWellbore(EntityType.Attachment));
}

[Fact]
Expand All @@ -54,6 +56,7 @@ public void EntityTypeToObjectList_GetAllWellboreObjectLists_CorrectType()
Assert.IsType<WitsmlTrajectories>(EntityTypeHelper.ToObjectList(EntityType.Trajectory));
Assert.IsType<WitsmlTubulars>(EntityTypeHelper.ToObjectList(EntityType.Tubular));
Assert.IsType<WitsmlWbGeometrys>(EntityTypeHelper.ToObjectList(EntityType.WbGeometry));
Assert.IsType<WitsmlAttachments>(EntityTypeHelper.ToObjectList(EntityType.Attachment));
}
}
}
21 changes: 21 additions & 0 deletions Tests/WitsmlExplorer.IntegrationTests/Resources/attachment.xml
eliasbruvik marked this conversation as resolved.
Show resolved Hide resolved

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Threading.Tasks;

using Witsml;
using Witsml.Data;
using Witsml.ServiceReference;
using Witsml.Xml;

using WitsmlExplorer.Api.Query;

using Xunit;

namespace WitsmlExplorer.IntegrationTests.Witsml.GetFromStore
{
public partial class AttachmentTests
{
private readonly WitsmlClient _client;

public AttachmentTests()
{
WitsmlConfiguration config = ConfigurationReader.GetWitsmlConfiguration();
_client = new WitsmlClient(options =>
{
options.Hostname = config.Hostname;
options.Credentials = new WitsmlCredentials(config.Username, config.Password);
});
}

[Fact(Skip = "Should only be run manually")]
public async Task GetAttachmentSerializesCorrectly()
{
// if the following attachment does not exit, add the file attachment to the server manually
// this affects wellUid, wellboreUid, nameWell, and nameWellbore values during comparison so adjust them here and in the file accordingly
string wellUid = "8c77de13-4fad-4b2e-ba3d-7e6b0e35a394";
string wellboreUid = "ae75db48-5cef-4bd1-9ddf-6035b0d2cd49";
string attachmentUid = "attachmentUid";
WitsmlAttachments queryExisting = AttachmentQueries.GetWitsmlAttachment(wellUid, wellboreUid, attachmentUid);
WitsmlAttachments serverAttachment = await _client.GetFromStoreAsync(queryExisting, new OptionsIn(ReturnElements.All));
string responseXml = XmlHelper.Serialize(serverAttachment);
string serverAttachmentXml = TestUtils.CleanResponse(responseXml);
string fileAttachmentXml = TestUtils.GetTestXml("Attachment");
Assert.Equal(fileAttachmentXml, serverAttachmentXml);
}
}
}
Loading