diff options
| author | crupest <crupest@outlook.com> | 2022-12-23 11:48:11 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2022-12-23 11:48:11 +0800 | 
| commit | e19d5550d88c114acaab77799345135d63117fcc (patch) | |
| tree | eff2982e0e8ea24f7952bba4678a18d7dcb250d5 /docker/crupest-api/CrupestApi/CrupestApi.Commons | |
| parent | 5784abdad21724b1813bf54e0838ca0935cd1c01 (diff) | |
| download | crupest-e19d5550d88c114acaab77799345135d63117fcc.tar.gz crupest-e19d5550d88c114acaab77799345135d63117fcc.tar.bz2 crupest-e19d5550d88c114acaab77799345135d63117fcc.zip  | |
Develop secret api. v60
Diffstat (limited to 'docker/crupest-api/CrupestApi/CrupestApi.Commons')
6 files changed, 120 insertions, 75 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs index dc32387..a56790a 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs @@ -72,7 +72,7 @@ public class CrudService<TEntity> : IDisposable where TEntity : class          var result = _table.Select<TEntity>(_dbConnection, null, WhereClause.Create().Eq(_table.KeyColumn.ColumnName, key)).SingleOrDefault();          if (result is null)          { -            throw new EntityNotExistException("Required entity not found."); +            throw new EntityNotExistException($"Required entity for key {key} not found.");          }          return result;      } @@ -91,7 +91,7 @@ public class CrudService<TEntity> : IDisposable where TEntity : class      public object Create(TEntity entity)      {          var insertClause = ConvertEntityToInsertClauses(entity); -        var key = _table.Insert(_dbConnection, insertClause); +        _table.Insert(_dbConnection, insertClause, out var key);          return key;      } @@ -108,14 +108,16 @@ public class CrudService<TEntity> : IDisposable where TEntity : class          return result;      } -    public void UpdateByKey(object key, TEntity entity, UpdateBehavior behavior = UpdateBehavior.None) +    // Return new key. +    public object UpdateByKey(object key, TEntity entity, UpdateBehavior behavior = UpdateBehavior.None)      {          var affectedCount = _table.Update(_dbConnection, WhereClause.Create().Eq(_table.KeyColumn.ColumnName, key), -            ConvertEntityToUpdateClauses(entity, behavior)); +            ConvertEntityToUpdateClauses(entity, behavior), out var newKey);          if (affectedCount == 0)          { -            throw new EntityNotExistException("Required entity not found."); +            throw new EntityNotExistException($"Required entity for key {key} not found.");          } +        return newKey ?? key;      }      public bool DeleteByKey(object key) diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs index dfb67d1..c9e43f2 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs @@ -53,8 +53,8 @@ public static class CrudWebApplicationExtensions              var jsonDocument = await context.Request.ReadJsonAsync();              var entity = entityJsonHelper.ConvertJsonToEntityForUpdate(jsonDocument.RootElement, out var updateBehavior); -            crudService.UpdateByKey(key, entity, updateBehavior); -            await context.ResponseJsonAsync(entityJsonHelper.ConvertEntityToDictionary(crudService.GetByKey(key))); +            var newKey = crudService.UpdateByKey(key, entity, updateBehavior); +            await context.ResponseJsonAsync(entityJsonHelper.ConvertEntityToDictionary(crudService.GetByKey(newKey)));          });          app.MapDelete(path + "/{key}", async (context) => diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs index 406e214..cf3f178 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs @@ -1,3 +1,4 @@ +using System.Globalization;  using System.Text.Json;  using Microsoft.Extensions.Options; @@ -46,34 +47,63 @@ public class EntityJsonHelper<TEntity> where TEntity : class          return JsonSerializer.Serialize(dictionary, _jsonSerializerOptions.CurrentValue);      } -    private static Type MapJsonValueKindToType(JsonElement jsonElement, out object? value) +    private object? ConvertJsonValue(JsonElement? optionalJsonElement, Type type, string propertyName)      { -        switch (jsonElement.ValueKind) +        if (optionalJsonElement is null)          { -            case JsonValueKind.String: -                { -                    value = jsonElement.GetString()!; -                    return typeof(string); -                } -            case JsonValueKind.Number: -                { -                    value = jsonElement.GetDouble(); -                    return typeof(double); -                } -            case JsonValueKind.True: -            case JsonValueKind.False: -                { -                    value = jsonElement.GetBoolean(); -                    return typeof(bool); -                } -            case JsonValueKind.Null: -                { -                    value = null; -                    return typeof(object); -                } -            default: -                throw new UserException("Unsupported json value type."); +            return null; +        } + +        var jsonElement = optionalJsonElement.Value; + +        if (jsonElement.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined) +        { +            return null; +        } + +        if (jsonElement.ValueKind is JsonValueKind.String) +        { +            if (type != typeof(string)) +            { +                throw new UserException($"Property {propertyName} must be a string."); +            } +            return jsonElement.GetString()!; +        } + +        if (jsonElement.ValueKind is JsonValueKind.True or JsonValueKind.False) +        { +            if (type != typeof(bool)) +            { +                throw new UserException($"Property {propertyName} must be a boolean."); +            } +            return jsonElement.GetBoolean(); +        } + +        if (jsonElement.ValueKind is JsonValueKind.Number) +        { +            try +            { +                return Convert.ChangeType(jsonElement.GetRawText(), type, CultureInfo.InvariantCulture); +            } +            catch (Exception) +            { +                throw new UserException($"Property {propertyName} must be a valid number."); +            } +        } + +        throw new UserException($"Property {propertyName} is of wrong type."); +    } + +    public Dictionary<string, JsonElement> ConvertJsonObjectToDictionary(JsonElement jsonElement) +    { +        var result = new Dictionary<string, JsonElement>(); + +        foreach (var property in jsonElement.EnumerateObject()) +        { +            result[property.Name.ToLower()] = property.Value;          } + +        return result;      }      public TEntity ConvertJsonToEntityForInsert(JsonElement jsonElement) @@ -82,31 +112,23 @@ public class EntityJsonHelper<TEntity> where TEntity : class              throw new ArgumentException("The jsonElement must be an object.");          var result = Activator.CreateInstance<TEntity>(); + +        Dictionary<string, JsonElement> jsonProperties = ConvertJsonObjectToDictionary(jsonElement); +          foreach (var column in _table.PropertyColumns)          { -            if (jsonElement.TryGetProperty(column.ColumnName, out var jsonValue)) +            var jsonPropertyValue = jsonProperties.GetValueOrDefault(column.ColumnName.ToLower()); +            var value = ConvertJsonValue(jsonPropertyValue, column.ColumnType.DatabaseClrType, column.ColumnName); +            if (column.IsOnlyGenerated && value is not null)              { -                if (column.IsOnlyGenerated) -                { -                    throw new UserException($"Property {column.ColumnName} is auto generated, you cannot set it."); -                } - -                var valueType = MapJsonValueKindToType(jsonValue, out var value); -                if (!valueType.IsAssignableTo(column.ColumnType.DatabaseClrType)) -                { -                    throw new UserException($"Property {column.ColumnName} is of wrong type."); -                } - -                var realValue = column.ColumnType.ConvertFromDatabase(value); -                column.PropertyInfo!.SetValue(result, realValue); +                throw new UserException($"Property {column.ColumnName} is auto generated, you cannot set it.");              } -            else +            if (!column.CanBeGenerated && value is null && column.IsNotNull)              { -                if (!column.CanBeGenerated) -                { -                    throw new UserException($"Property {column.ColumnName} is not auto generated, you must set it."); -                } +                throw new UserException($"Property {column.ColumnName} can NOT be generated, you must set it.");              } +            var realValue = column.ColumnType.ConvertFromDatabase(value); +            column.PropertyInfo!.SetValue(result, realValue);          }          return result; @@ -125,11 +147,15 @@ public class EntityJsonHelper<TEntity> where TEntity : class          updateBehavior = UpdateBehavior.None; -        if (jsonElement.TryGetProperty("$saveNull", out var saveNullValue)) +        Dictionary<string, JsonElement> jsonProperties = ConvertJsonObjectToDictionary(jsonElement); + +        bool saveNull = false; +        if (jsonProperties.TryGetValue("$saveNull".ToLower(), out var saveNullValue))          {              if (saveNullValue.ValueKind is JsonValueKind.True)              {                  updateBehavior |= UpdateBehavior.SaveNull; +                saveNull = true;              }              else if (saveNullValue.ValueKind is JsonValueKind.False)              { @@ -144,26 +170,28 @@ public class EntityJsonHelper<TEntity> where TEntity : class          var result = Activator.CreateInstance<TEntity>();          foreach (var column in _table.PropertyColumns)          { -            if (jsonElement.TryGetProperty(column.ColumnName, out var jsonValue)) +            if (jsonProperties.TryGetValue(column.ColumnName.ToLower(), out var jsonPropertyValue))              { -                if (column.IsOnlyGenerated) +                if (jsonPropertyValue.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)                  { -                    throw new UserException($"Property {column.ColumnName} is auto generated, you cannot set it."); -                } +                    if ((column.IsOnlyGenerated || column.IsNoUpdate) && saveNull) +                    { +                        throw new UserException($"Property {column.ColumnName} is auto generated or not updatable, you cannot set it."); +                    } -                if (column.IsNoUpdate) -                { -                    throw new UserException($"Property {column.ColumnName} is not updatable, you cannot set it."); +                    column.PropertyInfo!.SetValue(result, null);                  } - -                var valueType = MapJsonValueKindToType(jsonValue, out var value); -                if (!valueType.IsAssignableTo(column.ColumnType.DatabaseClrType)) +                else                  { -                    throw new UserException($"Property {column.ColumnName} is of wrong type."); +                    if (column.IsOnlyGenerated || column.IsNoUpdate) +                    { +                        throw new UserException($"Property {column.ColumnName} is auto generated or not updatable, you cannot set it."); +                    } + +                    var value = ConvertJsonValue(jsonPropertyValue, column.ColumnType.DatabaseClrType, column.ColumnName); +                    var realValue = column.ColumnType.ConvertFromDatabase(value); +                    column.PropertyInfo!.SetValue(result, realValue);                  } - -                var realValue = column.ColumnType.ConvertFromDatabase(value); -                column.PropertyInfo!.SetValue(result, realValue);              }          } diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs index bc580f2..41ef097 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs @@ -492,9 +492,9 @@ CREATE TABLE {tableName}(      /// Insert a entity and call hooks.      /// </summary>      /// <returns>The key of insert entity.</returns> -    public object Insert(IDbConnection dbConnection, IInsertClause insert) +    public int Insert(IDbConnection dbConnection, IInsertClause insert, out object key)      { -        object? key = null; +        object? finalKey = null;          var realInsert = InsertClause.Create(); @@ -546,23 +546,31 @@ CREATE TABLE {tableName}(              if (realInsertItem.ColumnName == KeyColumn.ColumnName)              { -                key = realInsertItem.Value; +                finalKey = realInsertItem.Value;              }          } +        if (finalKey is null) throw new Exception("No key???"); +        key = finalKey; +          var (sql, parameters) = GenerateInsertSql(realInsert); -        dbConnection.Execute(sql, ConvertParameters(parameters)); +        var affectedRowCount = dbConnection.Execute(sql, ConvertParameters(parameters)); + +        if (affectedRowCount != 1) +            throw new Exception("Failed to insert."); -        return key ?? throw new Exception("No key???"); +        return affectedRowCount;      }      /// <summary>      /// Upgrade a entity and call hooks.      /// </summary>      /// <returns>The key of insert entity.</returns> -    public virtual int Update(IDbConnection dbConnection, IWhereClause? where, IUpdateClause update) +    public virtual int Update(IDbConnection dbConnection, IWhereClause? where, IUpdateClause update, out object? newKey)      { +        newKey = null; +          var realUpdate = UpdateClause.Create();          foreach (var column in Columns) @@ -580,6 +588,11 @@ CREATE TABLE {tableName}(                  column.InvokeValidator(value);                  realUpdate.Add(column.ColumnName, value); + +                if (column.ColumnName == KeyColumn.ColumnName) +                { +                    newKey = value; +                }              }          } diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs index 2ad2c1f..a0b2d89 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs @@ -33,8 +33,10 @@ public static class CrupestApiJsonExtensions      public static async Task<JsonDocument> ReadJsonAsync(this HttpRequest request)      { +        var jsonOptions = request.HttpContext.RequestServices.GetRequiredService<IOptionsSnapshot<JsonSerializerOptions>>();          using var stream = request.Body; -        return await JsonDocument.ParseAsync(stream); +        var body = await JsonSerializer.DeserializeAsync<JsonDocument>(stream, jsonOptions.Value); +        return body!;      }      public static async Task WriteJsonAsync<T>(this HttpResponse response, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Secrets/SecretService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Secrets/SecretService.cs index c2242ff..9a0ec95 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Secrets/SecretService.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Secrets/SecretService.cs @@ -19,7 +19,7 @@ public class SecretService : CrudService<SecretInfo>, ISecretService              .Add(nameof(SecretInfo.Key), SecretsConstants.SecretManagementKey)              .Add(nameof(SecretInfo.Secret), "crupest")              .Add(nameof(SecretInfo.Description), "This is the init key. Please revoke it immediately after creating a new one."); -        _table.Insert(connection, insertClause); +        _table.Insert(connection, insertClause, out var _);          transaction.Commit();      } @@ -30,7 +30,7 @@ public class SecretService : CrudService<SecretInfo>, ISecretService                 .Add(nameof(SecretInfo.Key), key)                 .Add(nameof(SecretInfo.Secret), secret)                 .Add(nameof(SecretInfo.Description), "Test secret."); -        _table.Insert(connection, insertClause); +        _table.Insert(connection, insertClause, out var _);      }      public List<string> GetPermissions(string secret)  | 
