Pin nixpkgs to the revision used by itc.componentware: the channel version ships a latexminted that crashes on Python 3.14, which made every listing fail and sent latexmk into an endless error prompt. Also force nonstopmode/halt-on-error so a broken listing can never loop again.
42 lines
1.4 KiB
C#
42 lines
1.4 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using System.Text;
|
|
using Microsoft.AspNetCore.WebUtilities;
|
|
|
|
namespace Houston.Model.Documents;
|
|
|
|
/// <summary>
|
|
/// Public URL id of a customer document.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The identifier used in URLs (e.g. <c>/document/{id}/download</c> or <c>/document/{id}/share</c>)
|
|
/// is the URL base64 encoding of the document path <em>without</em> the customer/organization
|
|
/// folder. For an object stored at <c>OrgX/TypeY/FileZ.pdf</c> the id therefore encodes
|
|
/// <c>TypeY/FileZ.pdf</c>. The organization part is never part of the id, so it can only ever be
|
|
/// derived server side from the authenticated user.
|
|
/// </remarks>
|
|
public readonly record struct DocumentId(string Value)
|
|
{
|
|
public static DocumentId Encode(DocumentRelativePath relativePath)
|
|
=> new(WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(relativePath.ToString())));
|
|
|
|
public bool TryDecode([NotNullWhen(true)] out DocumentRelativePath? relativePath)
|
|
{
|
|
relativePath = null;
|
|
|
|
if (String.IsNullOrEmpty(Value))
|
|
return false;
|
|
|
|
try
|
|
{
|
|
var decoded = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Value));
|
|
return DocumentRelativePath.TryFromS3Key(decoded, out relativePath);
|
|
}
|
|
catch (FormatException)
|
|
{
|
|
relativePath = null;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override string ToString() => Value;
|
|
} |