finance api implementation
This commit is contained in:
parent
d2f70644ef
commit
c5b27421a3
5 changed files with 191 additions and 10 deletions
60
src/EllieBot.GrpcApiBase/protos/fin.proto
Normal file
60
src/EllieBot.GrpcApiBase/protos/fin.proto
Normal file
|
@ -0,0 +1,60 @@
|
|||
syntax = "proto3";
|
||||
|
||||
option csharp_namespace = "EllieBot.GrpcApi";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
package fin;
|
||||
|
||||
service GrpcFin {
|
||||
rpc GetTransactions(GetTransactionsRequest) returns (GetTransactionsReply);
|
||||
rpc GetHoldings(GetHoldingsRequest) returns (GetHoldingsReply);
|
||||
rpc Withdraw(WithdrawRequest) returns (WithdrawReply);
|
||||
rpc Deposit(DepositRequest) returns (DepositReply);
|
||||
}
|
||||
|
||||
message GetTransactionsRequest {
|
||||
int32 page = 1;
|
||||
uint64 userId = 2;
|
||||
}
|
||||
|
||||
message GetTransactionsReply {
|
||||
repeated TransactionReply transactions = 1;
|
||||
int32 total = 2;
|
||||
}
|
||||
|
||||
message TransactionReply {
|
||||
int64 amount = 1;
|
||||
string note = 2;
|
||||
string type = 3;
|
||||
string extra = 4;
|
||||
google.protobuf.Timestamp timestamp = 5;
|
||||
string id = 6;
|
||||
}
|
||||
|
||||
message GetHoldingsRequest {
|
||||
uint64 userId = 1;
|
||||
}
|
||||
|
||||
message GetHoldingsReply {
|
||||
int64 cash = 1;
|
||||
int64 bank = 2;
|
||||
}
|
||||
|
||||
message WithdrawRequest {
|
||||
uint64 userId = 1;
|
||||
int64 amount = 2;
|
||||
}
|
||||
|
||||
message WithdrawReply {
|
||||
bool success = 1;
|
||||
}
|
||||
|
||||
message DepositRequest {
|
||||
uint64 userId = 1;
|
||||
int64 amount = 2;
|
||||
}
|
||||
|
||||
message DepositReply {
|
||||
bool success = 1;
|
||||
}
|
|
@ -110,7 +110,7 @@ public sealed class NCanvasService : INCanvasService, IReadyExecutor, IEService
|
|||
|
||||
var wallet = await _cs.GetWalletAsync(userId);
|
||||
|
||||
var paid = await wallet.Take(price, new("canvas", "pixel", $"Bought pixel #{position}"));
|
||||
var paid = await wallet.Take(price, new("canvas", "pixel-buy", $"Bought pixel {new kwum(position)}"));
|
||||
if (!paid)
|
||||
{
|
||||
return SetPixelResult.NotEnoughMoney;
|
||||
|
@ -138,7 +138,7 @@ public sealed class NCanvasService : INCanvasService, IReadyExecutor, IEService
|
|||
|
||||
if (!success)
|
||||
{
|
||||
await wallet.Add(price, new("canvas", "pixel-refund", $"Refund pixel #{position} purchase"));
|
||||
await wallet.Add(price, new("canvas", "pixel-refund", $"Refund pixel {new kwum(position)} purchase"));
|
||||
}
|
||||
|
||||
return success ? SetPixelResult.Success : SetPixelResult.InsufficientPayment;
|
||||
|
|
89
src/EllieBot/Services/GrpcApi/FinSvc.cs
Normal file
89
src/EllieBot/Services/GrpcApi/FinSvc.cs
Normal file
|
@ -0,0 +1,89 @@
|
|||
using Google.Protobuf.WellKnownTypes;
|
||||
using Grpc.Core;
|
||||
using EllieBot.Db.Models;
|
||||
using EllieBot.Modules.Gambling.Bank;
|
||||
using EllieBot.Modules.EllieExpressions;
|
||||
using EllieBot.Modules.Utility;
|
||||
|
||||
namespace EllieBot.GrpcApi;
|
||||
|
||||
public class FinSvc : GrpcFin.GrpcFinBase, IGrpcSvc, IEService
|
||||
{
|
||||
private readonly ICurrencyService _cs;
|
||||
private readonly IBankService _bank;
|
||||
|
||||
public FinSvc(ICurrencyService cs, IBankService bank)
|
||||
{
|
||||
_cs = cs;
|
||||
_bank = bank;
|
||||
}
|
||||
|
||||
public ServerServiceDefinition Bind()
|
||||
=> GrpcFin.BindService(this);
|
||||
|
||||
[GrpcNoAuthRequired]
|
||||
public override async Task<DepositReply> Deposit(DepositRequest request, ServerCallContext context)
|
||||
{
|
||||
if (request.Amount <= 0)
|
||||
throw new RpcException(new Status(StatusCode.InvalidArgument, "Amount must be greater than 0"));
|
||||
|
||||
var succ = await _bank.DepositAsync(request.UserId, request.Amount);
|
||||
|
||||
return new DepositReply
|
||||
{
|
||||
Success = succ
|
||||
};
|
||||
}
|
||||
|
||||
[GrpcNoAuthRequired]
|
||||
public override async Task<WithdrawReply> Withdraw(WithdrawRequest request, ServerCallContext context)
|
||||
{
|
||||
if (request.Amount <= 0)
|
||||
throw new RpcException(new Status(StatusCode.InvalidArgument, "Amount must be greater than 0"));
|
||||
|
||||
var succ = await _bank.WithdrawAsync(request.UserId, request.Amount);
|
||||
|
||||
return new WithdrawReply
|
||||
{
|
||||
Success = succ
|
||||
};
|
||||
}
|
||||
|
||||
[GrpcNoAuthRequired]
|
||||
public override async Task<GetHoldingsReply> GetHoldings(GetHoldingsRequest request, ServerCallContext context)
|
||||
{
|
||||
return new GetHoldingsReply
|
||||
{
|
||||
Bank = await _bank.GetBalanceAsync(request.UserId),
|
||||
Cash = await _cs.GetBalanceAsync(request.UserId)
|
||||
};
|
||||
}
|
||||
|
||||
[GrpcNoAuthRequired]
|
||||
public override async Task<GetTransactionsReply> GetTransactions(
|
||||
GetTransactionsRequest request,
|
||||
ServerCallContext context)
|
||||
{
|
||||
if (request.Page < 1)
|
||||
throw new RpcException(new Status(StatusCode.InvalidArgument, "Page must be greater than 0"));
|
||||
|
||||
var trs = await _cs.GetTransactionsAsync(request.UserId, request.Page - 1);
|
||||
|
||||
var reply = new GetTransactionsReply
|
||||
{
|
||||
Total = await _cs.GetTransactionsCountAsync(request.UserId)
|
||||
};
|
||||
|
||||
reply.Transactions.AddRange(trs.Select(x => new TransactionReply()
|
||||
{
|
||||
Id = new kwum(x.Id).ToString(),
|
||||
Timestamp = Timestamp.FromDateTime(DateTime.UtcNow),
|
||||
Amount = x.Amount,
|
||||
Extra = x.Extra ?? string.Empty,
|
||||
Note = x.Note ?? string.Empty,
|
||||
Type = x.Type ?? string.Empty,
|
||||
}));
|
||||
|
||||
return reply;
|
||||
}
|
||||
}
|
|
@ -40,4 +40,11 @@ public interface ICurrencyService
|
|||
TxData? txData);
|
||||
|
||||
Task<IReadOnlyList<DiscordUser>> GetTopRichest(ulong ignoreId, int page = 0, int perPage = 9);
|
||||
|
||||
Task<IReadOnlyList<CurrencyTransaction>> GetTransactionsAsync(
|
||||
ulong userId,
|
||||
int page,
|
||||
int perPage = 15);
|
||||
|
||||
Task<int> GetTransactionsCountAsync(ulong userId);
|
||||
}
|
|
@ -55,14 +55,14 @@ public sealed class CurrencyService : ICurrencyService, IEService
|
|||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx
|
||||
.GetTable<DiscordUser>()
|
||||
.Where(x => userIds.Contains(x.UserId))
|
||||
.UpdateAsync(du => new()
|
||||
{
|
||||
CurrencyAmount = du.CurrencyAmount >= amount
|
||||
? du.CurrencyAmount - amount
|
||||
: 0
|
||||
});
|
||||
.GetTable<DiscordUser>()
|
||||
.Where(x => userIds.Contains(x.UserId))
|
||||
.UpdateAsync(du => new()
|
||||
{
|
||||
CurrencyAmount = du.CurrencyAmount >= amount
|
||||
? du.CurrencyAmount - amount
|
||||
: 0
|
||||
});
|
||||
await ctx.SaveChangesAsync();
|
||||
return;
|
||||
}
|
||||
|
@ -112,4 +112,29 @@ public sealed class CurrencyService : ICurrencyService, IEService
|
|||
await using var uow = _db.GetDbContext();
|
||||
return await uow.Set<DiscordUser>().GetTopRichest(ignoreId, page, perPage);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<CurrencyTransaction>> GetTransactionsAsync(
|
||||
ulong userId,
|
||||
int page,
|
||||
int perPage = 15)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
|
||||
var trs = await uow.GetTable<CurrencyTransaction>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.OrderByDescending(x => x.DateAdded)
|
||||
.Skip(perPage * page)
|
||||
.Take(perPage)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
return trs;
|
||||
}
|
||||
|
||||
public async Task<int> GetTransactionsCountAsync(ulong userId)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.GetTable<CurrencyTransaction>()
|
||||
.Where(x => x.UserId == userId)
|
||||
.CountAsyncLinqToDB();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue