Add backend structure with Docker support and initial configuration files
Java CI / build (push) Successful in 1m56s
Java CI / build (push) Successful in 1m56s
Signed-off-by: Dmitrii <computer@yawaflua.tech> Took 4 hours 25 minutes
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MongoDB.Driver;
|
||||
using SpMega.Backend.Persistent.Database;
|
||||
using SpMega.Backend.Persistent.Models.DTO;
|
||||
using SpMega.Backend.Persistent.Models.Users;
|
||||
using SpMega.Backend.Services;
|
||||
using SPWorldsApi;
|
||||
using SPWorldsApi.Types.Interfaces;
|
||||
|
||||
namespace SpMega.Backend.Controllers.v1;
|
||||
|
||||
|
||||
public record GetSessionIdBody(string userName, Guid userUUID);
|
||||
public record ValidateSessionBody(string sessionId, Guid userUUID);
|
||||
[Route("api/v1/auth")]
|
||||
[ApiController]
|
||||
public class AuthController(AppDbContext dbContext, TokenService tokenService, ILogger<AuthController> logger) : ControllerBase
|
||||
{
|
||||
private const string BASE_URL = "https://spworlds.ru/api/public";
|
||||
public AuthenticationHeaderValue? AuthHeader { get; set; }
|
||||
|
||||
[HttpPost("start")]
|
||||
public async Task<IActionResult> GetSessionIdAsync([FromBody] GetSessionIdBody body)
|
||||
{
|
||||
var userSession = new UserSession
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Token = Program.GenerateRandomString(15),
|
||||
UserId = body.userUUID,
|
||||
UserName = body.userName,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
await dbContext.UserSessions.AddAsync(userSession);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
|
||||
return Ok(new { sessionId = userSession.Token});
|
||||
}
|
||||
|
||||
[HttpPost("validate")]
|
||||
public async Task<ActionResult<User>> ValidateSessionAsync([FromBody]ValidateSessionBody body)
|
||||
{
|
||||
try
|
||||
{
|
||||
var session =
|
||||
await dbContext.UserSessions.FirstOrDefaultAsync(k => k.UserId == body.userUUID && k.Token == body.sessionId);
|
||||
if (session == null || session.CreatedAt.AddMinutes(2) < DateTime.UtcNow || session.IsDeleted)
|
||||
throw new Exception("Session expired or not fount");
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
using var request = new HttpRequestMessage(
|
||||
HttpMethod.Get,
|
||||
$"https://sessionserver.mojang.com/session/minecraft/hasJoined?username={session.UserName}&serverId={session.Token}"
|
||||
);
|
||||
session.IsDeleted = true;
|
||||
session.DeletedAt = DateTime.UtcNow;
|
||||
session.UpdatedAt = DateTime.UtcNow;
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
var resp = await httpClient.SendAsync(request);
|
||||
if (resp.StatusCode != HttpStatusCode.OK) throw new Exception("Mojang response is not OK");
|
||||
Console.WriteLine(await resp.Content.ReadAsStringAsync());
|
||||
var dto = await resp.Content.ReadFromJsonAsync<MojangDto>();
|
||||
if (dto == null || dto.Name != session.UserName || Guid.Parse(dto.Id) != session.UserId) throw new Exception("Session expired, or dto is not acceptable.");
|
||||
var token = tokenService.GenerateAccessToken(session.UserName, body.userUUID);
|
||||
var user = await dbContext.Users.FirstOrDefaultAsync(k => k.Id == session.UserId);
|
||||
if (user != null)
|
||||
{
|
||||
user.Token = token;
|
||||
dbContext.Update(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
user = new User
|
||||
{
|
||||
Id = body.userUUID,
|
||||
Username = session.UserName,
|
||||
Token = token,
|
||||
};
|
||||
await dbContext.AddAsync(user);
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return Ok(user);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "Error when validation session.");
|
||||
return BadRequest("I think ure try to fool us. Try again later");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[HttpPut("cards")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> AddCardAsync([FromBody] AddCardBody body)
|
||||
{
|
||||
try
|
||||
{
|
||||
var BearerToken = $"{body.id}:{body.token}";
|
||||
string Base64BearerToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(BearerToken));
|
||||
var resp = await SendRequest("/accounts/me", new("Bearer", Base64BearerToken));
|
||||
var me = JsonSerializer.Deserialize<UserAccountDTO>(resp);
|
||||
Console.WriteLine(resp);
|
||||
var user = ((User)HttpContext.Items["@me"]);
|
||||
Console.WriteLine(me.id);
|
||||
Console.WriteLine(user.Id.ToString());
|
||||
if (user == null || user.Id.ToString() != me.minecraftUUID)
|
||||
{
|
||||
throw new Exception("Its not ur card");
|
||||
}
|
||||
|
||||
var card = me.cards.First(k => k.id == body.id);
|
||||
var existingCard = user.Cards.FirstOrDefault(k => k.Id.ToString() == card.id);
|
||||
if (existingCard == null)
|
||||
user.Cards.Add(new Card
|
||||
{
|
||||
Id = Guid.Parse(card.id),
|
||||
Name = card.name,
|
||||
SpworldsID = card.number,
|
||||
Token = Base64BearerToken,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
});
|
||||
else
|
||||
{
|
||||
|
||||
existingCard.Name = card.name;
|
||||
existingCard.SpworldsID = card.number;
|
||||
existingCard.Token = Base64BearerToken;
|
||||
existingCard.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
}
|
||||
await dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "Error when adding card.");
|
||||
return BadRequest("Error when adding card.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet("cards")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<Card>>> GetAllCardsAsync()
|
||||
{
|
||||
return Ok(((User)HttpContext.Items["@me"]).Cards.Where(k => !k.IsDeleted).ToList());
|
||||
}
|
||||
|
||||
[HttpDelete("cards/{id}")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> DeleteCardAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = (HttpContext.Items["@me"] as User);
|
||||
user.Cards.RemoveAll(c => c.Id == id);
|
||||
await dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "Error when deleting card.");
|
||||
return BadRequest("Error when deleting card.");
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<string> SendRequest(string endpoint, AuthenticationHeaderValue AuthHeader, HttpMethod method = null, object body = null)
|
||||
{
|
||||
method ??= body == null ? HttpMethod.Get : HttpMethod.Post;
|
||||
|
||||
HttpResponseMessage message;
|
||||
var client = new System.Net.Http.HttpClient();
|
||||
|
||||
using (var requestMessage = new HttpRequestMessage(method, BASE_URL + endpoint))
|
||||
{
|
||||
requestMessage.Content = new StringContent(
|
||||
JsonSerializer.Serialize(body),
|
||||
Encoding.UTF8, "application/json"
|
||||
);
|
||||
|
||||
requestMessage.Headers.Authorization = AuthHeader;
|
||||
|
||||
message = await client.SendAsync(requestMessage);
|
||||
|
||||
}
|
||||
|
||||
client.Dispose();
|
||||
|
||||
return await message.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public record AddCardBody(string id, string token);
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SpMega.Backend.Persistent.Database;
|
||||
using SpMega.Backend.Persistent.Models.Transactions;
|
||||
using SpMega.Backend.Persistent.Models.Users;
|
||||
using SPWorldsApi;
|
||||
|
||||
namespace SpMega.Backend.Controllers.v1;
|
||||
|
||||
[Route("api/v1/transactions")]
|
||||
[ApiController]
|
||||
public class TransactionsController(AppDbContext context, ILogger<TransactionsController> logger, IConfiguration config) : ControllerBase
|
||||
{
|
||||
private const string BASE_URL = "https://spworlds.ru/api/public";
|
||||
|
||||
[HttpGet("{billId}")]
|
||||
public async Task<IActionResult> GetBill(string billId)
|
||||
{
|
||||
var transaction = await context.Transactions
|
||||
.FirstOrDefaultAsync(t => t.ShortId == billId);
|
||||
|
||||
if (transaction == null)
|
||||
{
|
||||
if (billId == "00000000")
|
||||
{
|
||||
return Ok(new Transaction
|
||||
{
|
||||
Id = Guid.Empty,
|
||||
ShortId = "00000000",
|
||||
ReceiverName = "yawaflua",
|
||||
ReceiverCardNumber = "00000",
|
||||
Sender = new User
|
||||
{
|
||||
Id = default,
|
||||
Username = "yawaflua",
|
||||
Token = "123",
|
||||
},
|
||||
SenderCardNumber = "010101",
|
||||
Amount = 42,
|
||||
Comment = "API FIRST",
|
||||
TransactionDate = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
return NotFound(new { error = "Transaction not found" });
|
||||
}
|
||||
|
||||
return Ok(transaction);
|
||||
}
|
||||
|
||||
[HttpPut()]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<Transaction>> CreateTransaction([FromBody] CreateTransactionBody body)
|
||||
{
|
||||
var BearerToken = $"{body.cardToUse.Id}:{body.cardToUse.Token}";
|
||||
string Base64BearerToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(BearerToken));
|
||||
|
||||
|
||||
var shortId = Program.GenerateRandomString(8);
|
||||
var transaction = new Transaction
|
||||
{
|
||||
ReceiverName = body.receiverName,
|
||||
ShortId = shortId,
|
||||
ReceiverCardNumber = body.receiverCard,
|
||||
Sender = HttpContext.Items["@me"] as User,
|
||||
SenderCardNumber = body.cardToUse.SpworldsID,
|
||||
Amount = body.amount,
|
||||
Comment = body.comment,
|
||||
};
|
||||
try
|
||||
{
|
||||
var uri = new Uri(new Uri(config["Url"] ?? "https://spmega.yawaflua.tech"), "/" + shortId);
|
||||
var transitionInfo = new Dictionary<string, object>
|
||||
{
|
||||
{ "receiver", body.receiverCard },
|
||||
{ "amount", body.amount },
|
||||
{ "comment", "Чек: "+ uri }
|
||||
};
|
||||
|
||||
await SendRequest(endpoint: "transactions", body: transitionInfo, AuthHeader:new("Bearer", Base64BearerToken));
|
||||
|
||||
} catch (Exception exception)
|
||||
{
|
||||
logger.LogError(exception, "Error creating transaction");
|
||||
return BadRequest(new { error = "Failed to create transaction" });
|
||||
}
|
||||
await context.AddAsync(transaction);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return Ok(new Transaction
|
||||
{
|
||||
Id = transaction.Id,
|
||||
ReceiverName = transaction.ReceiverName,
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet()]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<Transaction>>> GetAllTransactions()
|
||||
{
|
||||
return Ok(await context.Transactions.Where(k => k.Sender.Id == ((User)HttpContext.Items["@me"]).Id).ToListAsync());
|
||||
}
|
||||
|
||||
internal async Task<string> SendRequest(string endpoint, AuthenticationHeaderValue AuthHeader, HttpMethod method = null, object body = null)
|
||||
{
|
||||
method ??= body == null ? HttpMethod.Get : HttpMethod.Post;
|
||||
|
||||
HttpResponseMessage message;
|
||||
var client = new System.Net.Http.HttpClient();
|
||||
|
||||
using (var requestMessage = new HttpRequestMessage(method, BASE_URL + endpoint))
|
||||
{
|
||||
requestMessage.Content = new StringContent(
|
||||
JsonSerializer.Serialize(body),
|
||||
Encoding.UTF8, "application/json"
|
||||
);
|
||||
|
||||
requestMessage.Headers.Authorization = AuthHeader;
|
||||
|
||||
message = await client.SendAsync(requestMessage);
|
||||
|
||||
}
|
||||
|
||||
client.Dispose();
|
||||
|
||||
return await message.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
public record CreateTransactionBody(Card cardToUse, string receiverCard, string receiverName, string comment, int amount);
|
||||
Reference in New Issue
Block a user