Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/fuzzzerd/fmdata
Browse files Browse the repository at this point in the history
  • Loading branch information
fuzzzerd committed Oct 29, 2019
2 parents 0b0f8f2 + caa6a81 commit 3bbc64c
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 47 deletions.
66 changes: 57 additions & 9 deletions src/FMData.Rest/FileMakerRestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,55 @@ public override async Task<IEnumerable<T>> SendAsync<T>(
}
#endregion

/// <summary>
/// Runs a script with the specified layout context and with an optional (null/empty OK) paramater.
/// </summary>
/// <param name="layout">The layout to use for the context of the script.</param>
/// <param name="script">The name of the script to run.</param>
/// <param name="scriptParameter">The parameter to pass to the script. Null or Empty is OK.</param>
/// <returns>The script result when OK, or the error code if not OK.</returns>
public async override Task<string> RunScriptAsync(string layout, string script, string scriptParameter)
{
await UpdateTokenDateAsync(); // we're about to use the token so update date used

// generate request url{
var uri = $"{_fmsUri}/fmi/data/v1/databases/{_fileName}/layouts/{layout}/script/{script}";
if (!string.IsNullOrEmpty(scriptParameter))
{
uri += $"?script.param={scriptParameter}";
}
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

// run the patch action
var response = await _client.SendAsync(requestMessage);

if (response.StatusCode == HttpStatusCode.NotFound)
{
return null;
}

try
{
// process json as JObject and only grab the part we're interested in (response.productInfo).
var responseJson = await response.Content.ReadAsStringAsync();
var responseJObject = JObject.Parse(responseJson);
var responseObject = responseJObject["response"].ToObject<ActionResponse>();

if (responseObject.ScriptError == 0)
{
// if no script error, return the script result
return responseObject.ScriptResult;
}
// if there is a script error, return that.
return responseObject.ScriptError.ToString();
}
catch (Exception ex)
{
// something bad happened. TODO: improve non-OK response handling
throw new Exception($"Non-OK Response: Status = {response.StatusCode}.", ex);
}
}

/// <summary>
/// Executes a FileMaker Request to a JSON string.
/// </summary>
Expand Down Expand Up @@ -580,6 +629,7 @@ public async Task<HttpResponseMessage> ExecuteRequestAsync(
/// Helper For Getting Raw Responses from Data API.
/// </summary>
public Task<HttpResponseMessage> ExecuteRequestAsync<T>(IEditRequest<T> req) => ExecuteRequestAsync(new HttpMethod("PATCH"), UpdateEndpoint(req.Layout, req.RecordId), req);

/// <summary>
/// Helper For Getting Raw Responses from Data API.
/// </summary>
Expand Down Expand Up @@ -718,12 +768,12 @@ public async override Task<IReadOnlyCollection<string>> GetDatabasesAsync()
/// </summary>
/// <param name="database">The database to query.</param>
/// <returns>The names of the layouts in the specified database.</returns>
public async override Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync(string database)
public async override Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync()
{
await UpdateTokenDateAsync(); // we're about to use the token so update date used

// generate request url{
var uri = $"{_fmsUri}/fmi/data/v1/databases/{database}/layouts";
var uri = $"{_fmsUri}/fmi/data/v1/databases/{_fileName}/layouts";
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

// run the patch action
Expand All @@ -750,16 +800,15 @@ public async override Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync(
}

/// <summary>
/// Gets all the scripts within a database.
/// Gets all the scripts within the database.
/// </summary>
/// <param name="database">The database to query.</param>
/// <returns>The names of the scripts in the specified database.</returns>
public async override Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync(string database)
public async override Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync()
{
await UpdateTokenDateAsync(); // we're about to use the token so update date used

// generate request url{
var uri = $"{_fmsUri}/fmi/data/v1/databases/{database}/scripts";
var uri = $"{_fmsUri}/fmi/data/v1/databases/{_fileName}/scripts";
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

// run the patch action
Expand Down Expand Up @@ -788,16 +837,15 @@ public async override Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync(
/// <summary>
/// Gets the metadata for a layout object.
/// </summary>
/// <param name="database">The name of the database the layout is in.</param>
/// <param name="layout">The layout to get data about.</param>
/// <param name="recordId">Optional RecordId, for getting layout data specific to a record. ValueLists, etc.</param>
/// <returns>An instance of the LayoutMetadata class for the specified layout.</returns>
public async override Task<LayoutMetadata> GetLayoutAsync(string database, string layout, int? recordId = null)
public async override Task<LayoutMetadata> GetLayoutAsync(string layout, int? recordId = null)
{
await UpdateTokenDateAsync(); // we're about to use the token so update date used

// generate request url
var uri = $"{_fmsUri}/fmi/data/v1/databases/{database}/layouts/{layout}";
var uri = $"{_fmsUri}/fmi/data/v1/databases/{_fileName}/layouts/{layout}";
if (recordId.HasValue)
{
uri += $"?recordId={recordId}";
Expand Down
23 changes: 16 additions & 7 deletions src/FMData.Xml/FileMakerXmlClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,33 +371,42 @@ public override async Task<IReadOnlyCollection<string>> GetDatabasesAsync()
/// <summary>
/// Gets the metadata for a layout object.
/// </summary>
/// <param name="database">The name of the database the layout is in.</param>
/// <param name="layout">The layout to get data about.</param>
/// <param name="recordId">Optional RecordId, for getting layout data specific to a record. ValueLists, etc.</param>
/// <returns>An instance of the LayoutMetadata class for the specified layout.</returns>
public override Task<LayoutMetadata> GetLayoutAsync(string database, string layout, int? recordId = null)
public override Task<LayoutMetadata> GetLayoutAsync(string layout, int? recordId = null)
{
var url = $"{_fmsUri}/fmi/xml/FMPXMLLAYOUT.xml?-db={database}&-lay={layout}&-view";
var url = $"{_fmsUri}/fmi/xml/FMPXMLLAYOUT.xml?-db={_fileName}&-lay={layout}&-view";

throw new NotImplementedException();
}

/// <summary>
///
/// </summary>
/// <param name="database"></param>
/// <returns></returns>
public override Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync(string database)
public override Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync()
{
throw new NotImplementedException();
}

/// <summary>
///
/// </summary>
/// <param name="database"></param>
/// <returns></returns>
public override Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync(string database)
public override Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync()
{
throw new NotImplementedException();
}

/// <summary>
/// Runs a script with the specified layout context and with an optional (null/empty OK) paramater.
/// </summary>
/// <param name="layout">The layout to use for the context of the script.</param>
/// <param name="script">The name of the script to run.</param>
/// <param name="scriptParameter">The parameter to pass to the script. Null or Empty is OK.</param>
/// <returns>The script result when OK, or the error code if not OK.</returns>
public async override Task<string> RunScriptAsync(string layout, string script, string scriptParameter)
{
throw new NotImplementedException();
}
Expand Down
59 changes: 56 additions & 3 deletions src/FMData/FileMakerApiClientBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ public FileMakerApiClientBase(HttpClient client, ConnectionInfo conn)
}
#endregion

/// <summary>
/// Runs a script with the specified layout context and with an optional (null/empty OK) paramater.
/// </summary>
/// <param name="layout">The layout to use for the context of the script.</param>
/// <param name="script">The name of the script to run.</param>
/// <param name="scriptParameter">The parameter to pass to the script. Null or Empty is OK.</param>
/// <returns>The script result when OK, or the error code if not OK.</returns>
public abstract Task<string> RunScriptAsync(string layout, string script, string scriptParameter);

#region Create
/// <summary>
/// Create a record in the database utilizing the DataContract to target the layout.
Expand Down Expand Up @@ -258,14 +267,42 @@ public Task<ICreateResponse> CreateAsync<T>(
/// </summary>
/// <param name="database">The database to query.</param>
/// <returns>The names of the layouts in the specified database.</returns>
public abstract Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync(string database);
[Obsolete]
public Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync(string database)
{
if(database != _fileName)
{
throw new ArgumentOutOfRangeException("database", database, "Name of the database must match the file used in the constructor.");
}
return GetLayoutsAsync();
}

/// <summary>
/// Gets all the layouts within a database
/// </summary>
/// <returns>The names of the layouts in the specified database.</returns>
public abstract Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync();

/// <summary>
/// Gets all the scripts within a database.
/// </summary>
/// <param name="database">The database to query.</param>
/// <returns>The names of the scripts in the specified database.</returns>
public abstract Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync(string database);
[Obsolete]
public Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync(string database)
{
if (database != _fileName)
{
throw new ArgumentOutOfRangeException("database", database, "Name of the database must match the file used in the constructor.");
}
return GetScriptsAsync();
}

/// <summary>
/// Gets all the scripts within the database.
/// </summary>
/// <returns>The names of the scripts in the database.</returns>
public abstract Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync();

/// <summary>
/// Gets the metadata for a layout object.
Expand All @@ -274,7 +311,23 @@ public Task<ICreateResponse> CreateAsync<T>(
/// <param name="layout">The layout to get data about.</param>
/// <param name="recordId">Optional RecordId, for getting layout data specific to a record. ValueLists, etc.</param>
/// <returns>An instance of the LayoutMetadata class for the specified layout.</returns>
public abstract Task<LayoutMetadata> GetLayoutAsync(string database, string layout, int? recordId = null);
[Obsolete]
public Task<LayoutMetadata> GetLayoutAsync(string database, string layout, int? recordId = null)
{
if (database != _fileName)
{
throw new ArgumentOutOfRangeException("database", database, "Name of the database must match the file used in the constructor.");
}
return GetLayoutAsync(layout, recordId);
}

/// <summary>
/// Gets the metadata for a layout object.
/// </summary>
/// <param name="layout">The layout to get data about.</param>
/// <param name="recordId">Optional RecordId, for getting layout data specific to a record. ValueLists, etc.</param>
/// <returns>An instance of the LayoutMetadata class for the specified layout.</returns>
public abstract Task<LayoutMetadata> GetLayoutAsync(string layout, int? recordId = null);
#endregion

#region Find
Expand Down
32 changes: 32 additions & 0 deletions src/FMData/IFileMakerApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ public interface IFileMakerApiClient
IDeleteRequest GenerateDeleteRequest();
#endregion

/// <summary>
/// Runs a script with the specified layout context and with an optional (null/empty OK) paramater.
/// </summary>
/// <param name="layout">The layout to use for the context of the script.</param>
/// <param name="script">The name of the script to run.</param>
/// <param name="scriptParameter">The parameter to pass to the script. Null or Empty is OK.</param>
/// <returns>The script result when OK, or the error code if not OK.</returns>
Task<string> RunScriptAsync(string layout, string script, string scriptParameter);

#region Create
/// <summary>
/// Create a record in the file, attempt to use the [TableAttribute] to determine the layout.
Expand Down Expand Up @@ -157,23 +166,46 @@ public interface IFileMakerApiClient
/// </summary>
/// <param name="database">The database to query.</param>
/// <returns>The names of the layouts in the specified database.</returns>
[Obsolete]
Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync(string database);

/// <summary>
/// Gets all the layouts within the database.
/// </summary>
/// <returns>The names of the layouts in the database.</returns>
Task<IReadOnlyCollection<LayoutListItem>> GetLayoutsAsync();

/// <summary>
/// Gets the metadata for a layout object.
/// </summary>
/// <param name="database">The name of the database the layout is in.</param>
/// <param name="layout">The layout to get data about.</param>
/// <param name="recordId">Optional RecordId, for getting layout data specific to a record. ValueLists, etc.</param>
/// <returns>An instance of the LayoutMetadata class for the specified layout.</returns>
[Obsolete]
Task<LayoutMetadata> GetLayoutAsync(string database, string layout, int? recordId = null);

/// <summary>
/// Gets the metadata for a layout object.
/// </summary>
/// <param name="layout">The layout to get data about.</param>
/// <param name="recordId">Optional RecordId, for getting layout data specific to a record. ValueLists, etc.</param>
/// <returns>An instance of the LayoutMetadata class for the specified layout.</returns>
Task<LayoutMetadata> GetLayoutAsync(string layout, int? recordId = null);

/// <summary>
/// Gets all the scripts within a database.
/// </summary>
/// <param name="database">The database to query.</param>
/// <returns>The names of the scripts in the specified database.</returns>
[Obsolete]
Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync(string database);

/// <summary>
/// Gets all the scripts within the database.
/// </summary>
/// <returns>The names of the scripts in the database.</returns>
Task<IReadOnlyCollection<ScriptListItem>> GetScriptsAsync();
#endregion

#endregion
Expand Down
5 changes: 5 additions & 0 deletions src/FMData/Responses/ActionResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@ public class ActionResponse
/// Script Error (if any)
/// </summary>
public int ScriptError { get; set; }

/// <summary>
/// Result of the script that was run as part of this action.
/// </summary>
public string ScriptResult { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/FMData/Responses/IFindResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public interface IFindResponse<TResponseType>
/// Needed to wrap the response in a 'Response' object.
/// </summary>
/// <typeparam name="T"></typeparam>
public class FindResultType<T>
public class FindResultType<T> : ActionResponse
{
/// <summary>
/// The data contained in the response.
Expand Down
5 changes: 4 additions & 1 deletion tests/FMData.Rest.Tests/FMData.Rest.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
<None Update="ResponseData\b64-string.dat">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="ResponseData\ScriptResponseOK.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="ResponseData\fms-find-with-portal.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down Expand Up @@ -41,7 +44,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="moq" Version="4.13.0" />
<PackageReference Include="moq" Version="4.13.1" />
<PackageReference Include="RichardSzalay.MockHttp" Version="5.0.0" />
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<PackageReference Include="xunit" Version="2.4.1" />
Expand Down
25 changes: 0 additions & 25 deletions tests/FMData.Rest.Tests/MetadataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,30 +133,5 @@ public async Task GetLayout_Should_Return_Layout_Name_With_Metadata()
Assert.NotNull(response);
Assert.Equal("layout", response.Name);
}

[Fact(DisplayName = "Get Scripts Should Return Script List")]
public async Task GetScripts_Should_Return_Script_List()
{
var mockHttp = new MockHttpMessageHandler();

var server = "http://localhost";
var file = "test-file";
var user = "unit";
var pass = "test";

mockHttp.When(HttpMethod.Post, $"{server}/fmi/data/v1/databases/{file}/sessions")
.Respond("application/json", DataApiResponses.SuccessfulAuthentication());

var layoutData = System.IO.File.ReadAllText("ResponseData\\ScriptList.json");
mockHttp.When($"{server}/fmi/data/v1/databases/{file}/scripts")
.Respond("application/json", layoutData);

var fdc = new FileMakerRestClient(mockHttp.ToHttpClient(), new ConnectionInfo { FmsUri = server, Database = file, Username = user, Password = pass });

var response = await fdc.GetScriptsAsync(file);

Assert.NotNull(response);
Assert.Equal("GotoFirst", response.First().Name);
}
}
}
Loading

0 comments on commit 3bbc64c

Please sign in to comment.