Skip to content

Commit e87dfba

Browse files
committed
Add slack notification for status change
1 parent 57a110f commit e87dfba

File tree

7 files changed

+184
-38
lines changed

7 files changed

+184
-38
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Initium.Extensions;
2+
using Initium.Request;
3+
using Microsoft.AspNetCore.Mvc;
4+
using Microsoft.AspNetCore.Mvc.Filters;
5+
6+
namespace Initium.Attributes;
7+
8+
[AttributeUsage(AttributeTargets.Method)]
9+
public class PaginateAttribute : ActionFilterAttribute
10+
{
11+
private PaginationParameters? _paginationParameters;
12+
public int PageSize { get; set; } = 30;
13+
14+
public override void OnActionExecuting(ActionExecutingContext context)
15+
{
16+
_paginationParameters = context.ActionArguments.Values.FirstOrDefault(arg => arg is PaginationParameters) as PaginationParameters;
17+
18+
_paginationParameters ??= new PaginationParameters();
19+
_paginationParameters.PageSize = PageSize;
20+
21+
// context.ActionArguments["pagination"] = _paginationParameters;
22+
// if (_paginationParameters == null)
23+
// {
24+
// _paginationParameters = new PaginationParameters();
25+
// context.ActionArguments["pagination"] = _paginationParameters;
26+
// }
27+
//
28+
// if (_paginationParameters.PageSize <= 0)
29+
// {
30+
// _paginationParameters.PageSize = PageSize;
31+
// }
32+
}
33+
34+
public override void OnActionExecuted(ActionExecutedContext context)
35+
{
36+
if (_paginationParameters == null) return;
37+
38+
if (context.Result is not ObjectResult { Value: IEnumerable<object> collection } objectResult) return;
39+
40+
objectResult.Value = collection.ApplyPagination(_paginationParameters);
41+
}
42+
}
Lines changed: 91 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,104 @@
1+
using System.Linq.Expressions;
12
using System.Net;
23
using System.Reflection;
4+
using Initium.Constants;
35
using Initium.Exceptions;
46
using Microsoft.AspNetCore.Mvc;
57
using Microsoft.AspNetCore.Mvc.Filters;
68
using Microsoft.Extensions.Primitives;
79

810
namespace Initium.Attributes;
911

12+
// /// <summary>
13+
// /// An attribute to filter query results based on a specified property and enum type.
14+
// /// </summary>
15+
// /// <typeparam name="T">The type of the objects being filtered.</typeparam>
16+
// [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
17+
// public class QueryFilterAttribute<T>(string propertyName, Type propertyType) : Attribute, IActionFilter
18+
// {
19+
// /// <summary>
20+
// /// Called before the action method executes. No operation is performed in this implementation.
21+
// /// </summary>
22+
// /// <param name="context">The context for the executed action.</param>
23+
// public void OnActionExecuting(ActionExecutingContext context) { }
24+
//
25+
// /// <summary>
26+
// /// Executes after the action method is invoked. Filters the result based on the specified property and enum value.
27+
// /// </summary>
28+
// /// <param name="context">The context for the action filter.</param>
29+
// public void OnActionExecuted(ActionExecutedContext context)
30+
// {
31+
// if (!propertyType.IsEnum)
32+
// throw new ApiException(HttpStatusCode.BadRequest, $"QueryFilter only accepts enum types for filters. The property '{propertyName}' is not an enum.");
33+
//
34+
// if (context.Result is not ObjectResult { Value: IEnumerable<T> enumerable } objectResult) return;
35+
//
36+
// var query = context.HttpContext.Request.Query;
37+
// if (!query.TryGetValue(propertyName, out var parameterValue)) return;
38+
//
39+
// if (StringValues.IsNullOrEmpty(parameterValue))
40+
// throw new ApiException(HttpStatusCode.BadRequest, "Query parameter is required but was not provided.");
41+
//
42+
// if (!Enum.TryParse(propertyType, parameterValue, ignoreCase: true, out var enumValue))
43+
// throw new ApiException(HttpStatusCode.BadRequest, $"Invalid query parameter value: `{parameterValue}` for `{propertyName}`. Allowed values are: {string.Join(", ", Enum.GetNames(propertyType))}.");
44+
//
45+
// objectResult.Value = enumerable.Where(item =>
46+
// {
47+
// var property = typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
48+
// if (property == null) return false;
49+
// var value = property.GetValue(item);
50+
// return value?.Equals(enumValue) == true;
51+
// });
52+
// }
53+
// }
54+
1055
/// <summary>
11-
/// An attribute to filter query results based on a specified property and enum type.
56+
/// A flexible query filter that applies filtering based on a property selector and comparison type.
1257
/// </summary>
13-
/// <typeparam name="T">The type of the objects being filtered.</typeparam>
14-
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
15-
public class QueryFilterAttribute<T>(string propertyName, Type propertyType) : Attribute, IActionFilter
16-
{
17-
/// <summary>
18-
/// Called before the action method executes. No operation is performed in this implementation.
19-
/// </summary>
20-
/// <param name="context">The context for the executed action.</param>
21-
public void OnActionExecuting(ActionExecutingContext context) { }
22-
23-
/// <summary>
24-
/// Executes after the action method is invoked. Filters the result based on the specified property and enum value.
25-
/// </summary>
26-
/// <param name="context">The context for the action filter.</param>
27-
public void OnActionExecuted(ActionExecutedContext context)
28-
{
29-
if (!propertyType.IsEnum)
30-
throw new ApiException(HttpStatusCode.BadRequest, $"QueryFilter only accepts enum types for filters. The property '{propertyName}' is not an enum.");
31-
32-
if (context.Result is not ObjectResult { Value: IEnumerable<T> enumerable } objectResult) return;
33-
34-
var query = context.HttpContext.Request.Query;
35-
if (!query.TryGetValue(propertyName, out var parameterValue)) return;
36-
37-
if (StringValues.IsNullOrEmpty(parameterValue))
38-
throw new ApiException(HttpStatusCode.BadRequest, "Query parameter is required but was not provided.");
58+
/// <typeparam name="T">The type of objects being filtered.</typeparam>
59+
// [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
60+
// public class QueryFilterAttribute<T>(Expression<Func<T, object>> propertySelector, ComparisonTypes comparisonType = ComparisonTypes.Equals) : Attribute, IActionFilter
61+
// {
62+
// public void OnActionExecuting(ActionExecutingContext context)
63+
// {
64+
// }
65+
//
66+
// public void OnActionExecuted(ActionExecutedContext context)
67+
// {
68+
// if (context.Result is not ObjectResult { Value: IEnumerable<T> enumerable } objectResult)
69+
// return;
70+
//
71+
// var query = context.HttpContext.Request.Query;
72+
// if (!query.TryGetValue(queryParameterName, out var parameterValue))
73+
// return;
74+
//
75+
// var compiledSelector = propertySelector.Compile();
76+
//
77+
// objectResult.Value = enumerable.Where(item =>
78+
// {
79+
// var propertyValue = compiledSelector(item)?.ToString();
80+
// if (propertyValue == null || string.IsNullOrEmpty(parameterValue))
81+
// return false;
82+
//
83+
// return comparisonType switch
84+
// {
85+
// ComparisonTypes.StartsWith => propertyValue.StartsWith(parameterValue, StringComparison.OrdinalIgnoreCase),
86+
// ComparisonTypes.Contains => propertyValue.Contains(parameterValue, StringComparison.OrdinalIgnoreCase),
87+
// _ => propertyValue.Equals(parameterValue, StringComparison.OrdinalIgnoreCase)
88+
// };
89+
// }).ToList();
90+
// }
91+
// }
3992

40-
if (!Enum.TryParse(propertyType, parameterValue, ignoreCase: true, out var enumValue))
41-
throw new ApiException(HttpStatusCode.BadRequest, $"Invalid query parameter value: `{parameterValue}` for `{propertyName}`. Allowed values are: {string.Join(", ", Enum.GetNames(propertyType))}.");
4293

43-
objectResult.Value = enumerable.Where(item =>
44-
{
45-
var property = typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
46-
if (property == null) return false;
47-
var value = property.GetValue(item);
48-
return value?.Equals(enumValue) == true;
49-
});
50-
}
51-
}
94+
// return parameterValue != null && value != null && CompareValues(value, parameterValue);
95+
//
96+
// private bool CompareValues(object propertyValue, string parameterValue)
97+
// {
98+
// return !string.IsNullOrEmpty(parameterValue) && comparisonType switch
99+
// {
100+
// ComparisonType.StartsWith => propertyValue.ToString()?.StartsWith(parameterValue, StringComparison.OrdinalIgnoreCase) == true,
101+
// ComparisonType.Contains => propertyValue.ToString()?.Contains(parameterValue, StringComparison.OrdinalIgnoreCase) == true,
102+
// _ => propertyValue.ToString()?.Equals(parameterValue, StringComparison.OrdinalIgnoreCase) == true,
103+
// };
104+
// }
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Text.Json.Serialization;
2+
using Tapper;
3+
4+
namespace Initium.Constants;
5+
6+
[TranspilationSource]
7+
[JsonConverter(typeof(JsonStringEnumConverter))]
8+
public enum ComparisonTypes
9+
{
10+
Equals,
11+
StartsWith,
12+
Contains
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using Initium.Domain.Entities;
2+
3+
namespace Initium.Infrastructure.Extensions;
4+
5+
internal static class BaseEntityExtensions
6+
{
7+
public static void Touch<TKey>(this BaseEntity<TKey> entity) => entity.UpdatedAt = DateTimeOffset.UtcNow;
8+
}

src/Initium/Initium.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,8 @@
3737
<None Include="../../LICENSE.md" Pack="true" PackagePath="/"/>
3838
<None Include="logo.png" Pack="true" PackagePath="/" />
3939
</ItemGroup>
40+
41+
<ItemGroup>
42+
<Folder Include="Infrastructure\Response\" />
43+
</ItemGroup>
4044
</Project>

src/Initium/Response/RequestDetails.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Tapper;
2+
using YamlDotNet.Serialization;
23

34
namespace Initium.Response;
45

@@ -7,6 +8,8 @@ public class RequestDetails
78
{
89
public string? ClientIp { get; set; }
910
public string? Endpoint { get; set; }
11+
12+
[YamlIgnore]
1013
public DateTimeOffset Date { get; set; } = DateTimeOffset.UtcNow;
1114
public string? UserAgent { get; set; }
1215
public long Timestamp => Date.ToUnixTimeMilliseconds();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Initium.Results;
2+
3+
namespace Initium.Services;
4+
5+
public interface ICrudService<TEntity>
6+
{
7+
ServiceResult Create(TEntity entity);
8+
IEnumerable<TEntity> FindAll();
9+
IEnumerable<TEntity> FindById(Guid entityId);
10+
IEnumerable<TEntity> FindBy(Func<TEntity, bool> predicate);
11+
ServiceResult Update(Guid entityId, TEntity entity);
12+
ServiceResult Delete(Guid entityId);
13+
ServiceResult DeleteBy(Func<TEntity, bool> predicate);
14+
ServiceResult DeleteAll();
15+
16+
// BaseResult Create(TEntity entity);
17+
// BaseResult Create(TCreateRequest createRequest);
18+
// IQueryable<TEntity> Read();
19+
// TEntity? Read(TPrimaryKeyType entityId);
20+
// BaseResult Update(TPrimaryKeyType entityId, TEntity entity);
21+
// BaseResult Delete(TPrimaryKeyType entityId);
22+
// BaseResult Delete();
23+
}

0 commit comments

Comments
 (0)