✨ Custom apps create payment orders
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
using DysonNetwork.Pass.Auth;
 | 
			
		||||
using DysonNetwork.Shared.Models;
 | 
			
		||||
using DysonNetwork.Shared.Proto;
 | 
			
		||||
using Microsoft.AspNetCore.Authorization;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
@@ -8,36 +9,87 @@ namespace DysonNetwork.Pass.Wallet;
 | 
			
		||||
 | 
			
		||||
[ApiController]
 | 
			
		||||
[Route("/api/orders")]
 | 
			
		||||
public class OrderController(PaymentService payment, AuthService auth, AppDatabase db) : ControllerBase
 | 
			
		||||
public class OrderController(
 | 
			
		||||
    PaymentService payment,
 | 
			
		||||
    Pass.Auth.AuthService auth,
 | 
			
		||||
    AppDatabase db,
 | 
			
		||||
    CustomAppService.CustomAppServiceClient customApps
 | 
			
		||||
) : ControllerBase
 | 
			
		||||
{
 | 
			
		||||
    public class CreateOrderRequest
 | 
			
		||||
    {
 | 
			
		||||
        public string Currency { get; set; } = null!;
 | 
			
		||||
        public decimal Amount { get; set; }
 | 
			
		||||
        public string? Remarks { get; set; }
 | 
			
		||||
        public string? ProductIdentifier { get; set; }
 | 
			
		||||
        public Dictionary<string, object>? Meta { get; set; }
 | 
			
		||||
        public int DurationHours { get; set; } = 24;
 | 
			
		||||
 | 
			
		||||
        public string ClientId { get; set; } = null!;
 | 
			
		||||
        public string ClientSecret { get; set; } = null!;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [HttpPost]
 | 
			
		||||
    public async Task<ActionResult<SnWalletOrder>> CreateOrder([FromBody] CreateOrderRequest request)
 | 
			
		||||
    {
 | 
			
		||||
        var clientResp = await customApps.GetCustomAppAsync(new GetCustomAppRequest { Slug = request.ClientId });
 | 
			
		||||
        if (clientResp.App is null) return BadRequest("Client not found");
 | 
			
		||||
        var client = SnCustomApp.FromProtoValue(clientResp.App);
 | 
			
		||||
 | 
			
		||||
        var secret = await customApps.CheckCustomAppSecretAsync(new CheckCustomAppSecretRequest
 | 
			
		||||
        {
 | 
			
		||||
            AppId = client.Id.ToString(),
 | 
			
		||||
            Secret = request.ClientSecret,
 | 
			
		||||
        });
 | 
			
		||||
        if (!secret.Valid) return BadRequest("Invalid client secret");
 | 
			
		||||
 | 
			
		||||
        var order = await payment.CreateOrderAsync(
 | 
			
		||||
            default,
 | 
			
		||||
            request.Currency,
 | 
			
		||||
            request.Amount,
 | 
			
		||||
            NodaTime.Duration.FromHours(request.DurationHours),
 | 
			
		||||
            request.ClientId,
 | 
			
		||||
            request.ProductIdentifier,
 | 
			
		||||
            request.Remarks,
 | 
			
		||||
            request.Meta
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return Ok(order);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [HttpGet("{id:guid}")]
 | 
			
		||||
    public async Task<ActionResult<SnWalletOrder>> GetOrderById(Guid id)
 | 
			
		||||
    {
 | 
			
		||||
        var order = await db.PaymentOrders.FindAsync(id);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        if (order == null)
 | 
			
		||||
            return NotFound();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        return Ok(order);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    public class PayOrderRequest
 | 
			
		||||
    {
 | 
			
		||||
        public string PinCode { get; set; } = string.Empty;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [HttpPost("{id:guid}/pay")]
 | 
			
		||||
    [Authorize]
 | 
			
		||||
    public async Task<ActionResult<SnWalletOrder>> PayOrder(Guid id, [FromBody] PayOrderRequest request)
 | 
			
		||||
    {
 | 
			
		||||
        if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        // Validate PIN code
 | 
			
		||||
        if (!await auth.ValidatePinCode(currentUser.Id, request.PinCode))
 | 
			
		||||
            return StatusCode(403, "Invalid PIN Code");
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // Get the wallet for the current user
 | 
			
		||||
            var wallet = await db.Wallets.FirstOrDefaultAsync(w => w.AccountId == currentUser.Id);
 | 
			
		||||
            if (wallet == null)
 | 
			
		||||
                return BadRequest("Wallet was not found.");
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
            // Pay the order
 | 
			
		||||
            var paidOrder = await payment.PayOrderAsync(id, wallet);
 | 
			
		||||
            return Ok(paidOrder);
 | 
			
		||||
@@ -49,7 +101,3 @@ public class OrderController(PaymentService payment, AuthService auth, AppDataba
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class PayOrderRequest
 | 
			
		||||
{
 | 
			
		||||
    public string PinCode { get; set; } = string.Empty;
 | 
			
		||||
}
 | 
			
		||||
@@ -34,7 +34,7 @@ public class SnCustomApp : ModelBase, IIdentifiedResource
 | 
			
		||||
 | 
			
		||||
    public Guid ProjectId { get; set; }
 | 
			
		||||
    public SnDevProject Project { get; set; } = null!;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    [NotMapped]
 | 
			
		||||
    public SnDeveloper Developer => Project.Developer;
 | 
			
		||||
 | 
			
		||||
@@ -81,36 +81,41 @@ public class SnCustomApp : ModelBase, IIdentifiedResource
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SnCustomApp FromProtoValue(Proto.CustomApp p)
 | 
			
		||||
    public static SnCustomApp FromProtoValue(Proto.CustomApp p)
 | 
			
		||||
    {
 | 
			
		||||
        Id = Guid.Parse(p.Id);
 | 
			
		||||
        Slug = p.Slug;
 | 
			
		||||
        Name = p.Name;
 | 
			
		||||
        Description = string.IsNullOrEmpty(p.Description) ? null : p.Description;
 | 
			
		||||
        Status = p.Status switch
 | 
			
		||||
        var obj = new SnCustomApp
 | 
			
		||||
        {
 | 
			
		||||
            Shared.Proto.CustomAppStatus.Developing => CustomAppStatus.Developing,
 | 
			
		||||
            Shared.Proto.CustomAppStatus.Staging => CustomAppStatus.Staging,
 | 
			
		||||
            Shared.Proto.CustomAppStatus.Production => CustomAppStatus.Production,
 | 
			
		||||
            Shared.Proto.CustomAppStatus.Suspended => CustomAppStatus.Suspended,
 | 
			
		||||
            _ => CustomAppStatus.Developing
 | 
			
		||||
            Id = Guid.Parse(p.Id),
 | 
			
		||||
            Slug = p.Slug,
 | 
			
		||||
            Name = p.Name,
 | 
			
		||||
            Description = string.IsNullOrEmpty(p.Description) ? null : p.Description,
 | 
			
		||||
            Status = p.Status switch
 | 
			
		||||
            {
 | 
			
		||||
                Shared.Proto.CustomAppStatus.Developing => CustomAppStatus.Developing,
 | 
			
		||||
                Shared.Proto.CustomAppStatus.Staging => CustomAppStatus.Staging,
 | 
			
		||||
                Shared.Proto.CustomAppStatus.Production => CustomAppStatus.Production,
 | 
			
		||||
                Shared.Proto.CustomAppStatus.Suspended => CustomAppStatus.Suspended,
 | 
			
		||||
                _ => CustomAppStatus.Developing
 | 
			
		||||
            },
 | 
			
		||||
            ProjectId = string.IsNullOrEmpty(p.ProjectId) ? Guid.Empty : Guid.Parse(p.ProjectId),
 | 
			
		||||
            CreatedAt = p.CreatedAt.ToInstant(),
 | 
			
		||||
            UpdatedAt = p.UpdatedAt.ToInstant(),
 | 
			
		||||
        };
 | 
			
		||||
        ProjectId = string.IsNullOrEmpty(p.ProjectId) ? Guid.Empty : Guid.Parse(p.ProjectId);
 | 
			
		||||
        CreatedAt = p.CreatedAt.ToInstant();
 | 
			
		||||
        UpdatedAt = p.UpdatedAt.ToInstant();
 | 
			
		||||
        if (p.Picture is not null) Picture = SnCloudFileReferenceObject.FromProtoValue(p.Picture);
 | 
			
		||||
        if (p.Background is not null) Background = SnCloudFileReferenceObject.FromProtoValue(p.Background);
 | 
			
		||||
        if (p.Verification is not null) Verification = SnVerificationMark.FromProtoValue(p.Verification);
 | 
			
		||||
 | 
			
		||||
        if (p.Picture is not null) obj.Picture = SnCloudFileReferenceObject.FromProtoValue(p.Picture);
 | 
			
		||||
        if (p.Background is not null) obj.Background = SnCloudFileReferenceObject.FromProtoValue(p.Background);
 | 
			
		||||
        if (p.Verification is not null) obj.Verification = SnVerificationMark.FromProtoValue(p.Verification);
 | 
			
		||||
        if (p.Links is not null)
 | 
			
		||||
        {
 | 
			
		||||
            Links = new SnCustomAppLinks
 | 
			
		||||
            obj.Links = new SnCustomAppLinks
 | 
			
		||||
            {
 | 
			
		||||
                HomePage = string.IsNullOrEmpty(p.Links.HomePage) ? null : p.Links.HomePage,
 | 
			
		||||
                PrivacyPolicy = string.IsNullOrEmpty(p.Links.PrivacyPolicy) ? null : p.Links.PrivacyPolicy,
 | 
			
		||||
                TermsOfService = string.IsNullOrEmpty(p.Links.TermsOfService) ? null : p.Links.TermsOfService
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        return this;
 | 
			
		||||
 | 
			
		||||
        return obj;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user