All checks were successful
Deploy Promiscuity Auth API / deploy (push) Successful in 48s
Deploy Promiscuity Character API / deploy (push) Successful in 59s
Deploy Promiscuity Inventory API / deploy (push) Successful in 46s
Deploy Promiscuity Locations API / deploy (push) Successful in 1m0s
Deploy Promiscuity Mail API / deploy (push) Successful in 1m9s
k8s smoke test / test (push) Successful in 9s
138 lines
5.1 KiB
C#
138 lines
5.1 KiB
C#
using MailApi.Models;
|
|
using MongoDB.Bson;
|
|
using MongoDB.Bson.Serialization.Attributes;
|
|
using MongoDB.Driver;
|
|
|
|
namespace MailApi.Services;
|
|
|
|
public class MailStore
|
|
{
|
|
private readonly IMongoCollection<MailMessage> _messages;
|
|
private readonly IMongoCollection<CharacterDocument> _characters;
|
|
|
|
public MailStore(IConfiguration cfg)
|
|
{
|
|
var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
|
|
var dbName = cfg["MongoDB:DatabaseName"] ?? "promiscuity";
|
|
var client = new MongoClient(cs);
|
|
var db = client.GetDatabase(dbName);
|
|
_messages = db.GetCollection<MailMessage>("MailMessages");
|
|
_characters = db.GetCollection<CharacterDocument>("Characters");
|
|
|
|
_messages.Indexes.CreateOne(new CreateIndexModel<MailMessage>(
|
|
Builders<MailMessage>.IndexKeys.Ascending(m => m.RecipientCharacterId).Descending(m => m.CreatedUtc)));
|
|
_messages.Indexes.CreateOne(new CreateIndexModel<MailMessage>(
|
|
Builders<MailMessage>.IndexKeys.Ascending(m => m.SenderCharacterId).Descending(m => m.CreatedUtc)));
|
|
}
|
|
|
|
public async Task<CharacterAccessResult> ResolveCharacterAsync(string characterId, string userId, bool allowAnyOwner)
|
|
{
|
|
var character = await _characters.Find(c => c.Id == characterId).FirstOrDefaultAsync();
|
|
if (character is null)
|
|
return new CharacterAccessResult { Exists = false };
|
|
|
|
return new CharacterAccessResult
|
|
{
|
|
Exists = true,
|
|
IsAuthorized = allowAnyOwner || character.OwnerUserId == userId,
|
|
CharacterId = character.Id ?? string.Empty,
|
|
CharacterName = character.Name,
|
|
OwnerUserId = character.OwnerUserId
|
|
};
|
|
}
|
|
|
|
public async Task<List<MailMessage>> GetInboxAsync(string characterId) =>
|
|
await _messages.Find(m => m.RecipientCharacterId == characterId)
|
|
.SortByDescending(m => m.CreatedUtc)
|
|
.ToListAsync();
|
|
|
|
public async Task<List<MailMessage>> GetSentAsync(string characterId) =>
|
|
await _messages.Find(m => m.SenderCharacterId == characterId)
|
|
.SortByDescending(m => m.CreatedUtc)
|
|
.ToListAsync();
|
|
|
|
public async Task<SendMailResult> SendAsync(string senderCharacterId, string recipientCharacterName, string subject, string body)
|
|
{
|
|
var sender = await _characters.Find(c => c.Id == senderCharacterId).FirstOrDefaultAsync();
|
|
if (sender is null)
|
|
return new SendMailResult { Status = SendMailStatus.SenderNotFound };
|
|
|
|
var normalizedRecipientName = recipientCharacterName.Trim();
|
|
var recipients = await _characters.Find(c => c.Name == normalizedRecipientName).ToListAsync();
|
|
if (recipients.Count == 0)
|
|
return new SendMailResult { Status = SendMailStatus.RecipientNotFound };
|
|
if (recipients.Count > 1)
|
|
return new SendMailResult { Status = SendMailStatus.RecipientAmbiguous };
|
|
|
|
var recipient = recipients[0];
|
|
if (recipient.Id == sender.Id)
|
|
return new SendMailResult { Status = SendMailStatus.Invalid };
|
|
|
|
var message = new MailMessage
|
|
{
|
|
SenderCharacterId = sender.Id ?? string.Empty,
|
|
SenderCharacterName = sender.Name,
|
|
RecipientCharacterId = recipient.Id ?? string.Empty,
|
|
RecipientCharacterName = recipient.Name,
|
|
Subject = subject.Trim(),
|
|
Body = body.Trim(),
|
|
CreatedUtc = DateTime.UtcNow
|
|
};
|
|
|
|
await _messages.InsertOneAsync(message);
|
|
return new SendMailResult { Status = SendMailStatus.Ok, Message = message };
|
|
}
|
|
|
|
public async Task<MailMessage?> MarkReadAsync(string characterId, string messageId)
|
|
{
|
|
var filter = Builders<MailMessage>.Filter.And(
|
|
Builders<MailMessage>.Filter.Eq(m => m.Id, messageId),
|
|
Builders<MailMessage>.Filter.Eq(m => m.RecipientCharacterId, characterId)
|
|
);
|
|
var update = Builders<MailMessage>.Update.Set(m => m.ReadUtc, DateTime.UtcNow);
|
|
var options = new FindOneAndUpdateOptions<MailMessage> { ReturnDocument = ReturnDocument.After };
|
|
return await _messages.FindOneAndUpdateAsync(filter, update, options);
|
|
}
|
|
|
|
public class CharacterAccessResult
|
|
{
|
|
public bool Exists { get; set; }
|
|
|
|
public bool IsAuthorized { get; set; }
|
|
|
|
public string CharacterId { get; set; } = string.Empty;
|
|
|
|
public string CharacterName { get; set; } = string.Empty;
|
|
|
|
public string OwnerUserId { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class SendMailResult
|
|
{
|
|
public SendMailStatus Status { get; set; }
|
|
|
|
public MailMessage? Message { get; set; }
|
|
}
|
|
|
|
public enum SendMailStatus
|
|
{
|
|
Ok,
|
|
SenderNotFound,
|
|
RecipientNotFound,
|
|
RecipientAmbiguous,
|
|
Invalid
|
|
}
|
|
|
|
[BsonIgnoreExtraElements]
|
|
private class CharacterDocument
|
|
{
|
|
[BsonId]
|
|
[BsonRepresentation(BsonType.ObjectId)]
|
|
public string? Id { get; set; }
|
|
|
|
public string OwnerUserId { get; set; } = string.Empty;
|
|
|
|
public string Name { get; set; } = string.Empty;
|
|
}
|
|
}
|