Skip to content

Commit

Permalink
Create Archival Group, introduce transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
tomcrane committed Dec 11, 2023
1 parent 500071a commit f5b4fb6
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 40 deletions.
5 changes: 4 additions & 1 deletion LeedsExperiment/Fedora/ApiModel/FedoraJsonLdResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class FedoraJsonLdResponse

[JsonPropertyName("@id")]
[JsonPropertyOrder(1)]
public string? Id { get; set; }
public string Id { get; set; }

[JsonPropertyName("@type")]
[JsonPropertyOrder(2)]
Expand All @@ -34,6 +34,9 @@ public class FedoraJsonLdResponse

// Our custom(ish) additions

/// <summary>
/// Assumes we are using dc:title and that Fedora maps it to title
/// </summary>
[JsonPropertyName("title")]
[JsonPropertyOrder(101)]
public string? Title { get; set; }
Expand Down
18 changes: 18 additions & 0 deletions LeedsExperiment/Fedora/ApiModel/Transaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Fedora.ApiModel
{
public class Transaction
{
public Uri Location { get; set; }
public DateTime Expires { get; set; }
public bool Expired { get; set; }
public bool Committed { get; set; }

public const string HeaderName = "Atomic-ID";
}
}
7 changes: 6 additions & 1 deletion LeedsExperiment/Fedora/ArchivalGroup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Fedora.ApiModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -8,5 +9,9 @@ namespace Fedora
{
public class ArchivalGroup : Directory
{
public ArchivalGroup(FedoraJsonLdResponse fedoraResponse) : base(fedoraResponse)
{

}
}
}
7 changes: 6 additions & 1 deletion LeedsExperiment/Fedora/Directory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Fedora.ApiModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -8,6 +9,10 @@ namespace Fedora
{
public class Directory : Resource
{
public Directory(FedoraJsonLdResponse jsonLdResponse) : base(jsonLdResponse)
{
}

public required List<Directory> Directories { get; set; } = new List<Directory>();
public required List<File> Files { get; set; } = new List<File>();
}
Expand Down
13 changes: 7 additions & 6 deletions LeedsExperiment/Fedora/File.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Fedora.ApiModel;

namespace Fedora
{
public class File : Resource
{
public File(FedoraJsonLdResponse jsonLdResponse) : base(jsonLdResponse)
{
}

public string Origin { get
public string Origin
{
get
{
return "origin";
}
Expand Down
15 changes: 9 additions & 6 deletions LeedsExperiment/Fedora/IFedora.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Fedora.ApiModel;

namespace Fedora
{
public interface IFedora
{
Task<string> Proxy(string contentType, string path, string? jsonLdMode = null, bool preferContained = false);
Task<ArchivalGroup?> CreateArchivalGroup(string parentPath, string slug, string name);
Task<ArchivalGroup?> CreateArchivalGroup(string parentPath, string slug, string name, Transaction? transaction = null);


// Transactions
Task<Transaction> BeginTransaction();
Task CheckTransaction(Transaction tx);
Task KeepTransactionAlive(Transaction tx);
Task CommitTransaction(Transaction tx);
Task RollbackTransaction(Transaction tx);
}
}
19 changes: 18 additions & 1 deletion LeedsExperiment/Fedora/RequestX.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using Fedora.ApiModel;
using Fedora.Vocab;

namespace Fedora
Expand All @@ -26,11 +27,21 @@ public static HttpRequestMessage WithContainedDescriptions(this HttpRequestMessa
return requestMessage;
}

public static HttpRequestMessage InTransaction(this HttpRequestMessage requestMessage, Transaction? transaction)
{
if(transaction != null)
{
requestMessage.Headers.Add(Transaction.HeaderName, transaction.Location.ToString());
}
return requestMessage;
}

public static HttpRequestMessage WithName(this HttpRequestMessage requestMessage, string? name)
{
if(requestMessage.Content == null && !string.IsNullOrWhiteSpace(name))
{
requestMessage.Content = new StringContent($"PREFIX dc: <http://purl.org/dc/elements/1.1/> <> dc:title \"{name}\"");
var turtle = MediaTypeHeaderValue.Parse("text/turtle");
requestMessage.Content = new StringContent($"PREFIX dc: <http://purl.org/dc/elements/1.1/> <> dc:title \"{name}\"", turtle);
}
return requestMessage;
}
Expand All @@ -40,5 +51,11 @@ public static HttpRequestMessage WithSlug(this HttpRequestMessage requestMessage
requestMessage.Headers.Add("slug", slug);
return requestMessage;
}

public static HttpRequestMessage AsArchivalGroup(this HttpRequestMessage requestMessage)
{
requestMessage.Headers.Add("Link", $"<{RepositoryTypes.ArchivalGroup}>;rel=\"type\"");
return requestMessage;
}
}
}
18 changes: 17 additions & 1 deletion LeedsExperiment/Fedora/Resource.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
using System;
using Fedora.ApiModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Fedora
{
public abstract class Resource
{
public Resource(FedoraJsonLdResponse jsonLdResponse)
{
Name = jsonLdResponse.Title;
Created = jsonLdResponse.Created;
CreatedBy = jsonLdResponse.CreatedBy;
LastModified = jsonLdResponse.LastModified;
LastModifiedBy = jsonLdResponse.LastModifiedBy;
}

// The original name of the resource (possibly non-filesystem-safe)
// Use dc:title on the fedora resource
public string? Name { get; set; }

// The Fedora identifier
public required string Identifier { get; set; }

public DateTime? Created { get; set; }
public string? CreatedBy { get; set; }
public DateTime? LastModified { get; set; }
public string? LastModifiedBy { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public async Task<IActionResult> Index(string contentTypeMajor, string contentTy
var result = await fedora.Proxy(contentType, fullPath, jsonLdMode, contained);
return Content(result, contentType);
}

public

}
}
135 changes: 115 additions & 20 deletions LeedsExperiment/Preservation/FedoraWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,35 +43,129 @@ public async Task<string> Proxy(string contentType, string path, string? jsonLdM
}


public async Task<ArchivalGroup?> CreateArchivalGroup(string parentPath, string slug, string name)
public async Task<ArchivalGroup?> CreateArchivalGroup(string parentPath, string slug, string name, Transaction? transaction = null)
{
var uri = new Uri(parentPath, UriKind.Relative);
var req = MakeHttpRequestMessage(parentPath, HttpMethod.Post);
// .ForJsonLd() // no? for POST?

// Now uncomment these:

// .WithName(name)
// .WithSlug(slug);
// req.Headers.Add("Link", $"<{RepositoryTypes.ArchivalGroup}>;rel=\"type\"");
var req = MakeHttpRequestMessage(parentPath, HttpMethod.Post)
.InTransaction(transaction)
.WithName(name)
.WithSlug(slug)
.AsArchivalGroup();
var response = await _httpClient.SendAsync(req);
response.EnsureSuccessStatusCode();

// The body is the new resource URL
var newReq = MakeHttpRequestMessage(response.Headers.Location!, HttpMethod.Get).ForJsonLd();
var newReq = MakeHttpRequestMessage(response.Headers.Location!, HttpMethod.Get)
.ForJsonLd();
var newResponse = await _httpClient.SendAsync(newReq);

var archivalGroupResponse = await MakeFedoraResponse<ArchivalGroupResponse>(newResponse);
var ag = new ArchivalGroup
if(archivalGroupResponse != null)
{
Name = archivalGroupResponse.Title,
Identifier = archivalGroupResponse.Id,
Directories = new List<Fedora.Directory>(),
Files = new List<Fedora.File>()
};

// add the extra created/modified/by fields to Fedora.Resource
return ag;
var archivalGroup = new ArchivalGroup(archivalGroupResponse)
{
Identifier = archivalGroupResponse.Id,
Directories = new List<Fedora.Directory>(),
Files = new List<Fedora.File>()
};

// add the extra created/modified/by fields to Fedora.Resource
return archivalGroup;
}
return null;
}

public async Task<Transaction> BeginTransaction()
{
var req = MakeHttpRequestMessage("fcr:tx", HttpMethod.Post);
var response = await _httpClient.SendAsync(req);
response.EnsureSuccessStatusCode();
var tx = new Transaction();
tx.Location = response.Headers.Location!;
if (response.Headers.TryGetValues("Atomic-Expires", out IEnumerable<string>? values))
{
tx.Expires = DateTime.Parse(values.First());
}
return tx;
}

public async Task CheckTransaction(Transaction tx)
{
HttpRequestMessage req = MakeHttpRequestMessage(tx.Location, HttpMethod.Get);
var response = await _httpClient.SendAsync(req);
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.NoContent:
tx.Expired = false;
break;
case System.Net.HttpStatusCode.NotFound:
// error?
break;
case System.Net.HttpStatusCode.Gone:
tx.Expired = true;
break;
default:
// error?
break;
}
}

public async Task KeepTransactionAlive(Transaction tx)
{
HttpRequestMessage req = MakeHttpRequestMessage(tx.Location, HttpMethod.Post);
var response = await _httpClient.SendAsync(req);
response.EnsureSuccessStatusCode();

if (response.Headers.TryGetValues("Atomic-Expires", out IEnumerable<string>? values))
{
tx.Expires = DateTime.Parse(values.First());
}
}

public async Task CommitTransaction(Transaction tx)
{
HttpRequestMessage req = MakeHttpRequestMessage(tx.Location, HttpMethod.Put);
var response = await _httpClient.SendAsync(req);
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.NoContent:
tx.Committed = true;
break;
case System.Net.HttpStatusCode.NotFound:
// error?
break;
case System.Net.HttpStatusCode.Conflict:
tx.Committed = false;
break;
case System.Net.HttpStatusCode.Gone:
tx.Expired = true;
break;
default:
// error?
break;
}
response.EnsureSuccessStatusCode();
}

public async Task RollbackTransaction(Transaction tx)
{
HttpRequestMessage req = MakeHttpRequestMessage(tx.Location, HttpMethod.Delete);
var response = await _httpClient.SendAsync(req);
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.NoContent:
tx.RolledBack = true;
break;
case System.Net.HttpStatusCode.NotFound:
// error?
break;
case System.Net.HttpStatusCode.Gone:
tx.Expired = true;
break;
default:
// error?
break;
}
response.EnsureSuccessStatusCode();
}

private HttpRequestMessage MakeHttpRequestMessage(string path, HttpMethod method)
Expand All @@ -98,4 +192,5 @@ private HttpRequestMessage MakeHttpRequestMessage(Uri uri, HttpMethod method)
}
return fedoraResponse;
}

}
3 changes: 2 additions & 1 deletion LeedsExperiment/SamplesWorker/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ private async Task EntryPoint(string[] args, CancellationToken stoppingToken)
private async Task DoDefault()
{
// Console.WriteLine("supply something");
await fedora.CreateArchivalGroup("ag-root", Now(), "But same title");
await fedora.CreateArchivalGroup("ag-demo-root", Now(), "This is the title");
}

private async Task OcflV1()
{
var path = @"C:\Users\TomCrane\Dropbox\digirati\leeds\fedora-experiments\versioned-example\working\v1";

// begin transaction
var transaction = await fedora.BeginTransaction();

// make an archival group named Now()

Expand Down

0 comments on commit f5b4fb6

Please sign in to comment.