Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions DevDash/Attributes/CacheAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System.Text;
using DevDash.Services.IService;

namespace DevDash.Attributes
{
public class CacheAttribute(int durationInSec) : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var cacheService = context.HttpContext.RequestServices.GetRequiredService<ICacheService>();

var cacheKey = GenerateCacheKey(context.HttpContext.Request);

var result = await cacheService.GetCacheValueAsync(cacheKey);
if (!string.IsNullOrEmpty(result))
{
//return response
context.Result = new ContentResult()
{
ContentType = "application/json",
StatusCode = StatusCodes.Status200OK,
Content = result
};
return;
}
//Execute the endpoint
var contextResult = await next.Invoke();
if (contextResult.Result is OkObjectResult okObject)
{
await cacheService.SetCacheValueAsync(cacheKey, okObject, TimeSpan.FromSeconds(durationInSec));
}

}

private string GenerateCacheKey(HttpRequest request)
{
var key = new StringBuilder();
key.Append(request.Path);
foreach (var item in request.Query.OrderBy(q => q.Key))
{
key.Append($"|{item.Key}-{item.Value}");
}
// /api/Products?typeid=1&Sort=pricedesc&PageIndex=1&PageSize=5
// /api/Products|typeid-1|Sort-pricedesc|PageIndex-1
return key.ToString();

}
}
}
3 changes: 3 additions & 0 deletions DevDash/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Org.BouncyCastle.Crypto.Generators;
using AutoMapper;
using DevDash.DTO.Tenant;
using DevDash.Attributes;

namespace DevDash.Controllers
{
Expand Down Expand Up @@ -132,6 +133,8 @@ public async Task<IActionResult> Logout([FromBody] TokenDTO tokenDTO)

[HttpGet("Profile")]
[Authorize]
[Cache(2000)]

public async Task<IActionResult> GetUserProfile()
{
var userId = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
Expand Down
5 changes: 5 additions & 0 deletions DevDash/Controllers/CommentController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutoMapper;
using DevDash.Attributes;
using DevDash.DTO.Comment;
using DevDash.DTO.Sprint;
using DevDash.Migrations;
Expand Down Expand Up @@ -38,6 +39,8 @@ public CommentController(ICommentRepository commentRepo, IIssueRepository dbissu
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetComments([FromQuery] int IssueId,[FromQuery] string? search, int pageSize = 0, int pageNumber = 1)
{
try
Expand Down Expand Up @@ -68,6 +71,8 @@ public async Task<ActionResult<APIResponse>> GetComments([FromQuery] int IssueId
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetComment(int id)
{
try
Expand Down
26 changes: 8 additions & 18 deletions DevDash/Controllers/DashBoardController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutoMapper;
using DevDash.Attributes;
using DevDash.DTO.Account;
using DevDash.DTO.Issue;
using DevDash.DTO.Project;
Expand Down Expand Up @@ -58,6 +59,7 @@ IPinnedItemRepository pinnedItemRepository
[Authorize]
[HttpGet("Tenants")]
[ProducesResponseType(StatusCodes.Status200OK)]
[Cache(2000)]
public async Task<ActionResult<APIResponse>> GetTenantAnalysis([FromQuery] int Tenantid)
{
try
Expand Down Expand Up @@ -96,9 +98,11 @@ public async Task<ActionResult<APIResponse>> GetTenantAnalysis([FromQuery] int T
return _response;
}


[Authorize]
[HttpGet("Projects")]
[ProducesResponseType(StatusCodes.Status200OK)]
[Cache(2000)]
public async Task<ActionResult<APIResponse>> GetProjectAnalysis([FromQuery] int Projectid)
{
try
Expand Down Expand Up @@ -137,23 +141,8 @@ public async Task<ActionResult<APIResponse>> GetProjectAnalysis([FromQuery] int
}

















[Authorize]

[Cache(2000)]
[HttpGet("allproject")]
public async Task<ActionResult<APIResponse>> GetprojectDashboard()
{
Expand Down Expand Up @@ -185,6 +174,7 @@ public async Task<ActionResult<APIResponse>> GetprojectDashboard()
}

[Authorize]
[Cache(2000)]
[HttpGet("allissue")]
public async Task<ActionResult<APIResponse>> GetissueDashboard()
{
Expand Down Expand Up @@ -219,7 +209,7 @@ public async Task<ActionResult<APIResponse>> GetissueDashboard()

[Authorize]
[HttpGet("Calender")]

[Cache(2000)]
public async Task<ActionResult<APIResponse>> GetCalendar()
{

Expand Down Expand Up @@ -257,7 +247,7 @@ public async Task<ActionResult<APIResponse>> GetCalendar()

[Authorize]
[HttpGet("Pinneditems")]

[Cache(2000)]
public async Task<ActionResult<APIResponse>> GetPinnedItems()
{
try
Expand Down
8 changes: 5 additions & 3 deletions DevDash/Controllers/IssueController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutoMapper;
using DevDash.Attributes;
using DevDash.DTO.Issue;
using DevDash.model;
using DevDash.Repository.IRepository;
Expand Down Expand Up @@ -36,6 +37,7 @@ public IssueController(IIssueRepository dbissue, IProjectRepository dbProject, I
}

[HttpGet("backlog")]
[Cache(2000)]
public async Task<ActionResult<APIResponse>> GetBacklogIssues([FromQuery] int projectId, [FromQuery] string? search, int pageSize = 0, int pageNumber = 1)
{
try
Expand Down Expand Up @@ -88,6 +90,7 @@ public async Task<ActionResult<APIResponse>> GetBacklogIssues([FromQuery] int pr
return _response;
}
[HttpGet("sprint")]
[Cache(2000)]
public async Task<ActionResult<APIResponse>> GetSprintIssues([FromQuery] int sprintId, [FromQuery] string? search, int pageSize = 0, int pageNumber = 1)
{
try
Expand Down Expand Up @@ -129,6 +132,8 @@ public async Task<ActionResult<APIResponse>> GetSprintIssues([FromQuery] int spr
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetIssue(int id)
{
try
Expand Down Expand Up @@ -348,9 +353,6 @@ public async Task<ActionResult<APIResponse>> CreateSprintIssue([FromQuery] int s
}





[HttpDelete("{id:int}", Name = "DeleteIssue")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
Expand Down
5 changes: 4 additions & 1 deletion DevDash/Controllers/NotificationController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DevDash.model;
using DevDash.Attributes;
using DevDash.model;
using DevDash.Repository.IRepository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
Expand All @@ -24,6 +25,8 @@ public NotificationController(INotificationRepository notificationRepository,ITe
}

[HttpGet]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetNotifications(string? search = null)
{
try
Expand Down
5 changes: 5 additions & 0 deletions DevDash/Controllers/ProjectController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using AutoMapper;
using Azure;
using DevDash.Attributes;
using DevDash.DTO.Project;
using DevDash.DTO.Tenant;
using DevDash.DTO.User;
Expand Down Expand Up @@ -51,6 +52,8 @@ public ProjectController(IProjectRepository dbProject, ITenantRepository dbTenan
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetProjects([FromQuery] int tenantId, [FromQuery] string? search, int pageSize = 0, int pageNumber = 1)
{
try
Expand Down Expand Up @@ -128,6 +131,8 @@ public async Task<ActionResult<APIResponse>> GetProjects([FromQuery] int tenantI
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetProject([FromRoute] int projectId)
{
try
Expand Down
5 changes: 4 additions & 1 deletion DevDash/Controllers/SearchController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DevDash.model;
using DevDash.Attributes;
using DevDash.model;
using DevDash.Repository.IRepository;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
Expand All @@ -16,6 +17,8 @@ public SearchController(ISearchRepository searchRepository)
}

[HttpGet("global")]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GlobalSearch([FromQuery] string query)
{
try
Expand Down
5 changes: 5 additions & 0 deletions DevDash/Controllers/SprintController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutoMapper;
using DevDash.Attributes;
using DevDash.DTO.Sprint;
using DevDash.Migrations;
using DevDash.model;
Expand Down Expand Up @@ -37,6 +38,8 @@ public SprintController(ISprintRepository sprintRepo, IMapper mapper, IProjectRe

[HttpGet( Name = "GetSprints")]
[ProducesResponseType(StatusCodes.Status200OK)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetSprints([FromQuery] int projectid, [FromQuery] string? search, int pageSize = 0, int pageNumber = 1)
{
try
Expand Down Expand Up @@ -81,6 +84,8 @@ public async Task<ActionResult<APIResponse>> GetSprints([FromQuery] int projecti
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetSprint([FromRoute] int sprintId)
{
try
Expand Down
4 changes: 4 additions & 0 deletions DevDash/Controllers/TenantController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AutoMapper;
using DevDash.Attributes;
using DevDash.DTO.Tenant;
using DevDash.DTO.UserTenant;
using DevDash.Migrations;
Expand Down Expand Up @@ -38,6 +39,7 @@ public TenantController(ITenantRepository tenantRepo,IMapper mapper
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[Cache(2000)]
public async Task<ActionResult<APIResponse>> GetTenants([FromQuery] string? search, int pageSize = 0, int pageNumber = 1)
{
try
Expand Down Expand Up @@ -92,6 +94,8 @@ public async Task<ActionResult<APIResponse>> GetTenants([FromQuery] string? sear
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[Cache(2000)]

public async Task<ActionResult<APIResponse>> GetTenant([FromRoute] int tenantId)
{
try
Expand Down
1 change: 1 addition & 0 deletions DevDash/DevDash.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="MimeKit" Version="4.11.0" />
<PackageReference Include="NetcodeHub.Packages.Extensions.LocalStorage" Version="1.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.41" />
<PackageReference Include="Stripe.net" Version="48.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
Expand Down
18 changes: 18 additions & 0 deletions DevDash/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
using System.Text;
using Stripe;
using DevDash.Services.IServices;
using StackExchange.Redis;
using DevDash.Services.IService;

namespace DevDash
{
Expand Down Expand Up @@ -69,6 +71,22 @@ public static void Main(string[] args)
builder.Services.AddScoped<INotificationRepository, NotificationRepository>();
builder.Services.AddScoped<IPasswordRecoveryRepository, PasswordRecoveryRepository>();

builder.Services.AddSingleton<IConnectionMultiplexer>(sp =>
{
var configuration = sp.GetRequiredService<IConfiguration>();
var redisConnectionString = configuration.GetConnectionString("Redis");

if (string.IsNullOrEmpty(redisConnectionString))
{
throw new InvalidOperationException("Redis connection string is missing in configuration.");
}

return ConnectionMultiplexer.Connect(redisConnectionString);
});

builder.Services.AddScoped<ICacheRepository, CacheRepositroy>();
builder.Services.AddScoped<ICacheService, CacheService>();

builder.Services.Configure<EmailSetting>(builder.Configuration.GetSection("EmailSettings"));
builder.Services.AddScoped<IEmailService, EmailService>();

Expand Down
22 changes: 22 additions & 0 deletions DevDash/Repository/CacheRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using DevDash.Repository.IRepository;
using StackExchange.Redis;
using System.Text.Json;

namespace DevDash.Repository
{
public class CacheRepositroy(IConnectionMultiplexer connection) : ICacheRepository
{
private readonly IDatabase _database = connection.GetDatabase();
public async Task<string> GetAsync(string key)
{
var value = await _database.StringGetAsync(key);
return !value.IsNullOrEmpty ? value : default;
}

public async Task SetAsync(string key, object value, TimeSpan duration)
{
var redisValue = JsonSerializer.Serialize(value);
await _database.StringSetAsync(key, redisValue, duration);
}
}
}
8 changes: 8 additions & 0 deletions DevDash/Repository/IRepository/ICacheRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace DevDash.Repository.IRepository
{
public interface ICacheRepository
{
Task SetAsync(string key, object value, TimeSpan duration);
Task<string> GetAsync(string key);
}
}
Loading