Adds a full flashcards system: FSRS-based scheduling, cloze/basic card types, CSV import/export, media storage, and study UI, wired into navigation and the dashboard alongside existing question flows.
42 lines
1.4 KiB
C#
42 lines
1.4 KiB
C#
using MongoDB.Bson;
|
|
using MongoDB.Driver;
|
|
using QuestionsApi.Models;
|
|
|
|
namespace QuestionsApi.Services.Flashcards;
|
|
|
|
public sealed class FlashcardMediaStore
|
|
{
|
|
private readonly IMongoCollection<FlashcardMediaAsset> _assets;
|
|
|
|
public FlashcardMediaStore(MongoDatabaseProvider mongo)
|
|
{
|
|
_assets = mongo.Database.GetCollection<FlashcardMediaAsset>("FlashcardMediaAssets");
|
|
_assets.Indexes.CreateOne(new CreateIndexModel<FlashcardMediaAsset>(
|
|
Builders<FlashcardMediaAsset>.IndexKeys.Ascending(v => v.UserId),
|
|
new CreateIndexOptions { Name = "flashcard_media_user" }));
|
|
}
|
|
|
|
public async Task<FlashcardMediaAsset> CreateAsync(string userId, string fileName, string contentType, byte[] bytes)
|
|
{
|
|
var asset = new FlashcardMediaAsset
|
|
{
|
|
UserId = userId,
|
|
FileName = fileName,
|
|
ContentType = contentType,
|
|
Bytes = bytes,
|
|
CreatedUtc = DateTime.UtcNow
|
|
};
|
|
await _assets.InsertOneAsync(asset);
|
|
return asset;
|
|
}
|
|
|
|
public async Task<FlashcardMediaAsset?> GetAsync(string userId, string id)
|
|
{
|
|
if (!ObjectId.TryParse(id, out _)) return null;
|
|
return await _assets.Find(v => v.UserId == userId && v.Id == id).FirstOrDefaultAsync();
|
|
}
|
|
|
|
public Task<long> DeleteAsync(string userId, string id) =>
|
|
_assets.DeleteOneAsync(v => v.UserId == userId && v.Id == id).ContinueWith(t => t.Result.DeletedCount);
|
|
}
|