✨ Remix file service
This commit is contained in:
@ -29,7 +29,7 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile
|
|||||||
{
|
{
|
||||||
public string Id { get; set; } = null!;
|
public string Id { get; set; } = null!;
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public Dictionary<string, object>? FileMeta { get; set; } = null!;
|
public Dictionary<string, object?> FileMeta { get; set; } = null!;
|
||||||
public Dictionary<string, object>? UserMeta { get; set; } = null!;
|
public Dictionary<string, object>? UserMeta { get; set; } = null!;
|
||||||
public string? MimeType { get; set; }
|
public string? MimeType { get; set; }
|
||||||
public string? Hash { get; set; }
|
public string? Hash { get; set; }
|
||||||
@ -45,7 +45,7 @@ public class CloudFile : ModelBase, ICloudFile, IIdentifiedResource
|
|||||||
|
|
||||||
[MaxLength(1024)] public string Name { get; set; } = string.Empty;
|
[MaxLength(1024)] public string Name { get; set; } = string.Empty;
|
||||||
[MaxLength(4096)] public string? Description { get; set; }
|
[MaxLength(4096)] public string? Description { get; set; }
|
||||||
[Column(TypeName = "jsonb")] public Dictionary<string, object>? FileMeta { get; set; } = null!;
|
[Column(TypeName = "jsonb")] public Dictionary<string, object?> FileMeta { get; set; } = null!;
|
||||||
[Column(TypeName = "jsonb")] public Dictionary<string, object>? UserMeta { get; set; } = null!;
|
[Column(TypeName = "jsonb")] public Dictionary<string, object>? UserMeta { get; set; } = null!;
|
||||||
[Column(TypeName = "jsonb")] public List<ContentSensitiveMark>? SensitiveMarks { get; set; } = [];
|
[Column(TypeName = "jsonb")] public List<ContentSensitiveMark>? SensitiveMarks { get; set; } = [];
|
||||||
[MaxLength(256)] public string? MimeType { get; set; }
|
[MaxLength(256)] public string? MimeType { get; set; }
|
||||||
|
@ -5,15 +5,18 @@ using Duration = NodaTime.Duration;
|
|||||||
|
|
||||||
namespace DysonNetwork.Drive.Storage
|
namespace DysonNetwork.Drive.Storage
|
||||||
{
|
{
|
||||||
public class FileReferenceServiceGrpc(FileReferenceService fileReferenceService) : Shared.Proto.FileReferenceService.FileReferenceServiceBase
|
public class FileReferenceServiceGrpc(FileReferenceService fileReferenceService)
|
||||||
|
: Shared.Proto.FileReferenceService.FileReferenceServiceBase
|
||||||
{
|
{
|
||||||
public override async Task<Shared.Proto.CloudFileReference> CreateReference(CreateReferenceRequest request, ServerCallContext context)
|
public override async Task<Shared.Proto.CloudFileReference> CreateReference(CreateReferenceRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
Instant? expiredAt = null;
|
Instant? expiredAt = null;
|
||||||
if (request.ExpiredAt != null)
|
if (request.ExpiredAt != null)
|
||||||
expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds);
|
expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds);
|
||||||
else if (request.Duration != null)
|
else if (request.Duration != null)
|
||||||
expiredAt = SystemClock.Instance.GetCurrentInstant() + Duration.FromTimeSpan(request.Duration.ToTimeSpan());
|
expiredAt = SystemClock.Instance.GetCurrentInstant() +
|
||||||
|
Duration.FromTimeSpan(request.Duration.ToTimeSpan());
|
||||||
|
|
||||||
var reference = await fileReferenceService.CreateReferenceAsync(
|
var reference = await fileReferenceService.CreateReferenceAsync(
|
||||||
request.FileId,
|
request.FileId,
|
||||||
@ -24,7 +27,8 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
return reference.ToProtoValue();
|
return reference.ToProtoValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<GetReferencesResponse> GetReferences(GetReferencesRequest request, ServerCallContext context)
|
public override async Task<GetReferencesResponse> GetReferences(GetReferencesRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var references = await fileReferenceService.GetReferencesAsync(request.FileId);
|
var references = await fileReferenceService.GetReferencesAsync(request.FileId);
|
||||||
var response = new GetReferencesResponse();
|
var response = new GetReferencesResponse();
|
||||||
@ -32,13 +36,15 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<GetReferenceCountResponse> GetReferenceCount(GetReferenceCountRequest request, ServerCallContext context)
|
public override async Task<GetReferenceCountResponse> GetReferenceCount(GetReferenceCountRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var count = await fileReferenceService.GetReferenceCountAsync(request.FileId);
|
var count = await fileReferenceService.GetReferenceCountAsync(request.FileId);
|
||||||
return new GetReferenceCountResponse { Count = count };
|
return new GetReferenceCountResponse { Count = count };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<GetReferencesResponse> GetResourceReferences(GetResourceReferencesRequest request, ServerCallContext context)
|
public override async Task<GetReferencesResponse> GetResourceReferences(GetResourceReferencesRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var references = await fileReferenceService.GetResourceReferencesAsync(request.ResourceId, request.Usage);
|
var references = await fileReferenceService.GetResourceReferencesAsync(request.ResourceId, request.Usage);
|
||||||
var response = new GetReferencesResponse();
|
var response = new GetReferencesResponse();
|
||||||
@ -46,7 +52,8 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<GetResourceFilesResponse> GetResourceFiles(GetResourceFilesRequest request, ServerCallContext context)
|
public override async Task<GetResourceFilesResponse> GetResourceFiles(GetResourceFilesRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var files = await fileReferenceService.GetResourceFilesAsync(request.ResourceId, request.Usage);
|
var files = await fileReferenceService.GetResourceFilesAsync(request.ResourceId, request.Usage);
|
||||||
var response = new GetResourceFilesResponse();
|
var response = new GetResourceFilesResponse();
|
||||||
@ -54,19 +61,27 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<DeleteResourceReferencesResponse> DeleteResourceReferences(DeleteResourceReferencesRequest request, ServerCallContext context)
|
public override async Task<DeleteResourceReferencesResponse> DeleteResourceReferences(
|
||||||
|
DeleteResourceReferencesRequest request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
var deletedCount = await fileReferenceService.DeleteResourceReferencesAsync(request.ResourceId, request.Usage);
|
var deletedCount = 0;
|
||||||
|
if (request.Usage is null)
|
||||||
|
deletedCount = await fileReferenceService.DeleteResourceReferencesAsync(request.ResourceId);
|
||||||
|
else
|
||||||
|
deletedCount =
|
||||||
|
await fileReferenceService.DeleteResourceReferencesAsync(request.ResourceId, request.Usage!);
|
||||||
return new DeleteResourceReferencesResponse { DeletedCount = deletedCount };
|
return new DeleteResourceReferencesResponse { DeletedCount = deletedCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<DeleteReferenceResponse> DeleteReference(DeleteReferenceRequest request, ServerCallContext context)
|
public override async Task<DeleteReferenceResponse> DeleteReference(DeleteReferenceRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var success = await fileReferenceService.DeleteReferenceAsync(Guid.Parse(request.ReferenceId));
|
var success = await fileReferenceService.DeleteReferenceAsync(Guid.Parse(request.ReferenceId));
|
||||||
return new DeleteReferenceResponse { Success = success };
|
return new DeleteReferenceResponse { Success = success };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<UpdateResourceFilesResponse> UpdateResourceFiles(UpdateResourceFilesRequest request, ServerCallContext context)
|
public override async Task<UpdateResourceFilesResponse> UpdateResourceFiles(UpdateResourceFilesRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
Instant? expiredAt = null;
|
Instant? expiredAt = null;
|
||||||
if (request.ExpiredAt != null)
|
if (request.ExpiredAt != null)
|
||||||
@ -75,7 +90,8 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
}
|
}
|
||||||
else if (request.Duration != null)
|
else if (request.Duration != null)
|
||||||
{
|
{
|
||||||
expiredAt = SystemClock.Instance.GetCurrentInstant() + Duration.FromTimeSpan(request.Duration.ToTimeSpan());
|
expiredAt = SystemClock.Instance.GetCurrentInstant() +
|
||||||
|
Duration.FromTimeSpan(request.Duration.ToTimeSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
var references = await fileReferenceService.UpdateResourceFilesAsync(
|
var references = await fileReferenceService.UpdateResourceFilesAsync(
|
||||||
@ -89,7 +105,8 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<SetReferenceExpirationResponse> SetReferenceExpiration(SetReferenceExpirationRequest request, ServerCallContext context)
|
public override async Task<SetReferenceExpirationResponse> SetReferenceExpiration(
|
||||||
|
SetReferenceExpirationRequest request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
Instant? expiredAt = null;
|
Instant? expiredAt = null;
|
||||||
if (request.ExpiredAt != null)
|
if (request.ExpiredAt != null)
|
||||||
@ -98,21 +115,25 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
}
|
}
|
||||||
else if (request.Duration != null)
|
else if (request.Duration != null)
|
||||||
{
|
{
|
||||||
expiredAt = SystemClock.Instance.GetCurrentInstant() + Duration.FromTimeSpan(request.Duration.ToTimeSpan());
|
expiredAt = SystemClock.Instance.GetCurrentInstant() +
|
||||||
|
Duration.FromTimeSpan(request.Duration.ToTimeSpan());
|
||||||
}
|
}
|
||||||
|
|
||||||
var success = await fileReferenceService.SetReferenceExpirationAsync(Guid.Parse(request.ReferenceId), expiredAt);
|
var success =
|
||||||
|
await fileReferenceService.SetReferenceExpirationAsync(Guid.Parse(request.ReferenceId), expiredAt);
|
||||||
return new SetReferenceExpirationResponse { Success = success };
|
return new SetReferenceExpirationResponse { Success = success };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<SetFileReferencesExpirationResponse> SetFileReferencesExpiration(SetFileReferencesExpirationRequest request, ServerCallContext context)
|
public override async Task<SetFileReferencesExpirationResponse> SetFileReferencesExpiration(
|
||||||
|
SetFileReferencesExpirationRequest request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
var expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds);
|
var expiredAt = Instant.FromUnixTimeSeconds(request.ExpiredAt.Seconds);
|
||||||
var updatedCount = await fileReferenceService.SetFileReferencesExpirationAsync(request.FileId, expiredAt);
|
var updatedCount = await fileReferenceService.SetFileReferencesExpirationAsync(request.FileId, expiredAt);
|
||||||
return new SetFileReferencesExpirationResponse { UpdatedCount = updatedCount };
|
return new SetFileReferencesExpirationResponse { UpdatedCount = updatedCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<HasFileReferencesResponse> HasFileReferences(HasFileReferencesRequest request, ServerCallContext context)
|
public override async Task<HasFileReferencesResponse> HasFileReferences(HasFileReferencesRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var hasReferences = await fileReferenceService.HasFileReferencesAsync(request.FileId);
|
var hasReferences = await fileReferenceService.HasFileReferencesAsync(request.FileId);
|
||||||
return new HasFileReferencesResponse { HasReferences = hasReferences };
|
return new HasFileReferencesResponse { HasReferences = hasReferences };
|
||||||
|
@ -12,7 +12,8 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
return file?.ToProtoValue() ?? throw new RpcException(new Status(StatusCode.NotFound, "File not found"));
|
return file?.ToProtoValue() ?? throw new RpcException(new Status(StatusCode.NotFound, "File not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Shared.Proto.CloudFile> UpdateFile(UpdateFileRequest request, ServerCallContext context)
|
public override async Task<Shared.Proto.CloudFile> UpdateFile(UpdateFileRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var file = await fileService.GetFileAsync(request.File.Id);
|
var file = await fileService.GetFileAsync(request.File.Id);
|
||||||
if (file == null)
|
if (file == null)
|
||||||
@ -33,113 +34,10 @@ namespace DysonNetwork.Drive.Storage
|
|||||||
return new Empty();
|
return new Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Shared.Proto.CloudFile> ProcessNewFile(IAsyncStreamReader<ProcessNewFileRequest> requestStream,
|
public override async Task<LoadFromReferenceResponse> LoadFromReference(
|
||||||
ServerCallContext context)
|
LoadFromReferenceRequest request,
|
||||||
{
|
ServerCallContext context
|
||||||
ProcessNewFileRequest? metadataRequest = null;
|
)
|
||||||
var chunks = new List<byte[]>();
|
|
||||||
|
|
||||||
await foreach (var message in requestStream.ReadAllAsync())
|
|
||||||
{
|
|
||||||
if (message.DataCase == ProcessNewFileRequest.DataOneofCase.Metadata)
|
|
||||||
{
|
|
||||||
metadataRequest = message;
|
|
||||||
}
|
|
||||||
else if (message.DataCase == ProcessNewFileRequest.DataOneofCase.Chunk)
|
|
||||||
{
|
|
||||||
chunks.Add(message.Chunk.ToByteArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadataRequest == null || metadataRequest.Metadata == null)
|
|
||||||
{
|
|
||||||
throw new RpcException(new Status(StatusCode.InvalidArgument, "Missing file metadata"));
|
|
||||||
}
|
|
||||||
|
|
||||||
var metadata = metadataRequest.Metadata;
|
|
||||||
using var memoryStream = new MemoryStream();
|
|
||||||
foreach (var chunk in chunks)
|
|
||||||
{
|
|
||||||
await memoryStream.WriteAsync(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
|
|
||||||
// Assuming you have an Account object available or can create a dummy one for now
|
|
||||||
// You might need to adjust this based on how accounts are handled in your system
|
|
||||||
var dummyAccount = new Account { Id = metadata.AccountId };
|
|
||||||
|
|
||||||
var cloudFile = await fileService.ProcessNewFileAsync(
|
|
||||||
dummyAccount,
|
|
||||||
metadata.FileId,
|
|
||||||
memoryStream,
|
|
||||||
metadata.FileName,
|
|
||||||
metadata.ContentType
|
|
||||||
);
|
|
||||||
return cloudFile.ToProtoValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<Shared.Proto.CloudFile> UploadFileToRemote(
|
|
||||||
IAsyncStreamReader<UploadFileToRemoteRequest> requestStream, ServerCallContext context)
|
|
||||||
{
|
|
||||||
UploadFileToRemoteRequest? metadataRequest = null;
|
|
||||||
var chunks = new List<byte[]>();
|
|
||||||
|
|
||||||
await foreach (var message in requestStream.ReadAllAsync())
|
|
||||||
{
|
|
||||||
if (message.DataCase == UploadFileToRemoteRequest.DataOneofCase.Metadata)
|
|
||||||
{
|
|
||||||
metadataRequest = message;
|
|
||||||
}
|
|
||||||
else if (message.DataCase == UploadFileToRemoteRequest.DataOneofCase.Chunk)
|
|
||||||
{
|
|
||||||
chunks.Add(message.Chunk.ToByteArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadataRequest == null || metadataRequest.Metadata == null)
|
|
||||||
{
|
|
||||||
throw new RpcException(new Status(StatusCode.InvalidArgument, "Missing upload metadata"));
|
|
||||||
}
|
|
||||||
|
|
||||||
var metadata = metadataRequest.Metadata;
|
|
||||||
using var memoryStream = new MemoryStream();
|
|
||||||
foreach (var chunk in chunks)
|
|
||||||
{
|
|
||||||
await memoryStream.WriteAsync(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
|
|
||||||
var file = await fileService.GetFileAsync(metadata.FileId);
|
|
||||||
if (file == null)
|
|
||||||
{
|
|
||||||
throw new RpcException(new Status(StatusCode.NotFound, "File not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
var uploadedFile = await fileService.UploadFileToRemoteAsync(
|
|
||||||
file,
|
|
||||||
memoryStream,
|
|
||||||
metadata.TargetRemote,
|
|
||||||
metadata.Suffix
|
|
||||||
);
|
|
||||||
return uploadedFile.ToProtoValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<Empty> DeleteFileData(DeleteFileDataRequest request, ServerCallContext context)
|
|
||||||
{
|
|
||||||
var file = await fileService.GetFileAsync(request.FileId);
|
|
||||||
if (file == null)
|
|
||||||
{
|
|
||||||
throw new RpcException(new Status(StatusCode.NotFound, "File not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
await fileService.DeleteFileDataAsync(file);
|
|
||||||
return new Empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<LoadFromReferenceResponse> LoadFromReference(LoadFromReferenceRequest request,
|
|
||||||
ServerCallContext context)
|
|
||||||
{
|
{
|
||||||
// Assuming CloudFileReferenceObject is a simple class/struct that holds an ID
|
// Assuming CloudFileReferenceObject is a simple class/struct that holds an ID
|
||||||
// You might need to define this or adjust the LoadFromReference method in FileService
|
// You might need to define this or adjust the LoadFromReference method in FileService
|
||||||
|
@ -78,7 +78,7 @@ public abstract class Leveling
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccountProfile : ModelBase
|
public class AccountProfile : ModelBase, IIdentifiedResource
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
[MaxLength(256)] public string? FirstName { get; set; }
|
[MaxLength(256)] public string? FirstName { get; set; }
|
||||||
@ -104,10 +104,6 @@ public class AccountProfile : ModelBase
|
|||||||
: (Experience - Leveling.ExperiencePerLevel[Level]) * 100.0 /
|
: (Experience - Leveling.ExperiencePerLevel[Level]) * 100.0 /
|
||||||
(Leveling.ExperiencePerLevel[Level + 1] - Leveling.ExperiencePerLevel[Level]);
|
(Leveling.ExperiencePerLevel[Level + 1] - Leveling.ExperiencePerLevel[Level]);
|
||||||
|
|
||||||
// Outdated fields, for backward compability
|
|
||||||
[MaxLength(32)] public string? PictureId { get; set; }
|
|
||||||
[MaxLength(32)] public string? BackgroundId { get; set; }
|
|
||||||
|
|
||||||
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Picture { get; set; }
|
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Picture { get; set; }
|
||||||
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Background { get; set; }
|
[Column(TypeName = "jsonb")] public CloudFileReferenceObject? Background { get; set; }
|
||||||
|
|
||||||
@ -132,8 +128,6 @@ public class AccountProfile : ModelBase
|
|||||||
Experience = Experience,
|
Experience = Experience,
|
||||||
Level = Level,
|
Level = Level,
|
||||||
LevelingProgress = LevelingProgress,
|
LevelingProgress = LevelingProgress,
|
||||||
PictureId = PictureId ?? string.Empty,
|
|
||||||
BackgroundId = BackgroundId ?? string.Empty,
|
|
||||||
Picture = Picture?.ToProtoValue(),
|
Picture = Picture?.ToProtoValue(),
|
||||||
Background = Background?.ToProtoValue(),
|
Background = Background?.ToProtoValue(),
|
||||||
AccountId = AccountId.ToString(),
|
AccountId = AccountId.ToString(),
|
||||||
@ -143,6 +137,8 @@ public class AccountProfile : ModelBase
|
|||||||
|
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ResourceIdentifier => $"account:profile:{Id}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccountContact : ModelBase
|
public class AccountContact : ModelBase
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using DysonNetwork.Pass.Auth;
|
using DysonNetwork.Pass.Auth;
|
||||||
using DysonNetwork.Pass;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
using NodaTime.Extensions;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using DysonNetwork.Pass.Account;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Account;
|
namespace DysonNetwork.Pass.Account;
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using DysonNetwork.Pass.Auth;
|
|
||||||
using DysonNetwork.Pass.Permission;
|
using DysonNetwork.Pass.Permission;
|
||||||
|
using DysonNetwork.Shared.Data;
|
||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
|
using AuthService = DysonNetwork.Pass.Auth.AuthService;
|
||||||
|
using AuthSession = DysonNetwork.Pass.Auth.AuthSession;
|
||||||
|
using ChallengePlatform = DysonNetwork.Pass.Auth.ChallengePlatform;
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Account;
|
namespace DysonNetwork.Pass.Account;
|
||||||
|
|
||||||
@ -15,7 +19,9 @@ public class AccountCurrentController(
|
|||||||
AppDatabase db,
|
AppDatabase db,
|
||||||
AccountService accounts,
|
AccountService accounts,
|
||||||
AccountEventService events,
|
AccountEventService events,
|
||||||
AuthService auth
|
AuthService auth,
|
||||||
|
FileService.FileServiceClient files,
|
||||||
|
FileReferenceService.FileReferenceServiceClient fileRefs
|
||||||
) : ControllerBase
|
) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@ -94,12 +100,37 @@ public class AccountCurrentController(
|
|||||||
|
|
||||||
if (request.PictureId is not null)
|
if (request.PictureId is not null)
|
||||||
{
|
{
|
||||||
// TODO: Create reference, set profile picture
|
var file = await files.GetFileAsync(new GetFileRequest { Id = request.PictureId });
|
||||||
|
if (profile.Picture is not null)
|
||||||
|
await fileRefs.DeleteResourceReferencesAsync(
|
||||||
|
new DeleteResourceReferencesRequest { ResourceId = profile.ResourceIdentifier }
|
||||||
|
);
|
||||||
|
await fileRefs.CreateReferenceAsync(
|
||||||
|
new CreateReferenceRequest
|
||||||
|
{
|
||||||
|
ResourceId = profile.ResourceIdentifier,
|
||||||
|
FileId = request.PictureId,
|
||||||
|
Usage = "profile.picture"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
profile.Picture = CloudFileReferenceObject.FromProtoValue(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.BackgroundId is not null)
|
if (request.BackgroundId is not null)
|
||||||
{
|
{
|
||||||
// TODO: Create reference, set profile background
|
var file = await files.GetFileAsync(new GetFileRequest { Id = request.BackgroundId });
|
||||||
|
if (profile.Background is not null)
|
||||||
|
await fileRefs.DeleteResourceReferencesAsync(
|
||||||
|
new DeleteResourceReferencesRequest { ResourceId = profile.ResourceIdentifier }
|
||||||
|
);
|
||||||
|
await fileRefs.CreateReferenceAsync(
|
||||||
|
new CreateReferenceRequest
|
||||||
|
{
|
||||||
|
ResourceId = profile.ResourceIdentifier,
|
||||||
|
FileId = request.BackgroundId,
|
||||||
|
Usage = "profile.background"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
profile.Background = CloudFileReferenceObject.FromProtoValue(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Update(profile);
|
db.Update(profile);
|
||||||
|
@ -100,7 +100,7 @@ public class AccountEventService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cacheMissUserIds.Any())
|
if (cacheMissUserIds.Count != 0)
|
||||||
{
|
{
|
||||||
var now = SystemClock.Instance.GetCurrentInstant();
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
var statusesFromDb = await db.AccountStatuses
|
var statusesFromDb = await db.AccountStatuses
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
using Google.Protobuf.WellKnownTypes;
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
|
||||||
namespace DysonNetwork.Shared.Data;
|
namespace DysonNetwork.Shared.Data;
|
||||||
@ -10,13 +11,30 @@ public class CloudFileReferenceObject : ModelBase, ICloudFile
|
|||||||
{
|
{
|
||||||
public string Id { get; set; } = null!;
|
public string Id { get; set; } = null!;
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public Dictionary<string, object>? FileMeta { get; set; } = null!;
|
public Dictionary<string, object?> FileMeta { get; set; } = null!;
|
||||||
public Dictionary<string, object>? UserMeta { get; set; } = null!;
|
public Dictionary<string, object?> UserMeta { get; set; } = null!;
|
||||||
public string? MimeType { get; set; }
|
public string? MimeType { get; set; }
|
||||||
public string? Hash { get; set; }
|
public string? Hash { get; set; }
|
||||||
public long Size { get; set; }
|
public long Size { get; set; }
|
||||||
public bool HasCompression { get; set; } = false;
|
public bool HasCompression { get; set; } = false;
|
||||||
|
|
||||||
|
public static CloudFileReferenceObject FromProtoValue(Proto.CloudFile proto)
|
||||||
|
{
|
||||||
|
return new CloudFileReferenceObject
|
||||||
|
{
|
||||||
|
Id = proto.Id,
|
||||||
|
Name = proto.Name,
|
||||||
|
FileMeta = proto.FileMeta
|
||||||
|
.ToDictionary(kvp => kvp.Key, kvp => GrpcTypeHelper.ConvertField(kvp.Value)),
|
||||||
|
UserMeta = proto.UserMeta
|
||||||
|
.ToDictionary(kvp => kvp.Key, kvp => GrpcTypeHelper.ConvertField(kvp.Value)),
|
||||||
|
MimeType = proto.MimeType,
|
||||||
|
Hash = proto.Hash,
|
||||||
|
Size = proto.Size,
|
||||||
|
HasCompression = proto.HasCompression
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the current object to its protobuf representation
|
/// Converts the current object to its protobuf representation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -26,7 +26,7 @@ public interface ICloudFile
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the file metadata dictionary.
|
/// Gets the file metadata dictionary.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<string, object>? FileMeta { get; }
|
Dictionary<string, object?> FileMeta { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user metadata dictionary.
|
/// Gets the user metadata dictionary.
|
||||||
|
@ -75,7 +75,7 @@ public abstract class GrpcTypeHelper
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object? ConvertField(Value value)
|
public static object? ConvertField(Value value)
|
||||||
{
|
{
|
||||||
return value.KindCase switch
|
return value.KindCase switch
|
||||||
{
|
{
|
||||||
|
@ -51,10 +51,6 @@ message AccountProfile {
|
|||||||
int32 level = 15;
|
int32 level = 15;
|
||||||
double leveling_progress = 16;
|
double leveling_progress = 16;
|
||||||
|
|
||||||
// Legacy fields
|
|
||||||
google.protobuf.StringValue picture_id = 17;
|
|
||||||
google.protobuf.StringValue background_id = 18;
|
|
||||||
|
|
||||||
CloudFile picture = 19;
|
CloudFile picture = 19;
|
||||||
CloudFile background = 20;
|
CloudFile background = 20;
|
||||||
|
|
||||||
|
@ -58,15 +58,6 @@ service FileService {
|
|||||||
// Delete a file reference
|
// Delete a file reference
|
||||||
rpc DeleteFile(DeleteFileRequest) returns (google.protobuf.Empty);
|
rpc DeleteFile(DeleteFileRequest) returns (google.protobuf.Empty);
|
||||||
|
|
||||||
// Process and upload a new file
|
|
||||||
rpc ProcessNewFile(stream ProcessNewFileRequest) returns (CloudFile);
|
|
||||||
|
|
||||||
// Upload a file to remote storage
|
|
||||||
rpc UploadFileToRemote(stream UploadFileToRemoteRequest) returns (CloudFile);
|
|
||||||
|
|
||||||
// Delete file data from storage
|
|
||||||
rpc DeleteFileData(DeleteFileDataRequest) returns (google.protobuf.Empty);
|
|
||||||
|
|
||||||
// Load files from references
|
// Load files from references
|
||||||
rpc LoadFromReference(LoadFromReferenceRequest) returns (LoadFromReferenceResponse);
|
rpc LoadFromReference(LoadFromReferenceRequest) returns (LoadFromReferenceResponse);
|
||||||
|
|
||||||
@ -88,14 +79,6 @@ message UpdateFileRequest {
|
|||||||
google.protobuf.FieldMask update_mask = 2;
|
google.protobuf.FieldMask update_mask = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request message for DeleteFile
|
|
||||||
message ProcessNewFileRequest {
|
|
||||||
oneof data {
|
|
||||||
FileMetadata metadata = 1;
|
|
||||||
bytes chunk = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message FileMetadata {
|
message FileMetadata {
|
||||||
string file_id = 1;
|
string file_id = 1;
|
||||||
string file_name = 2;
|
string file_name = 2;
|
||||||
@ -103,13 +86,6 @@ message FileMetadata {
|
|||||||
string account_id = 4;
|
string account_id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UploadFileToRemoteRequest {
|
|
||||||
oneof data {
|
|
||||||
UploadMetadata metadata = 1;
|
|
||||||
bytes chunk = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message UploadMetadata {
|
message UploadMetadata {
|
||||||
string file_id = 1;
|
string file_id = 1;
|
||||||
string target_remote = 2;
|
string target_remote = 2;
|
||||||
@ -122,11 +98,6 @@ message DeleteFileRequest {
|
|||||||
bool purge = 2;
|
bool purge = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteFileDataRequest {
|
|
||||||
string file_id = 1;
|
|
||||||
bool force = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message LoadFromReferenceRequest {
|
message LoadFromReferenceRequest {
|
||||||
repeated string reference_ids = 1;
|
repeated string reference_ids = 1;
|
||||||
}
|
}
|
||||||
@ -201,7 +172,7 @@ message GetResourceReferencesRequest {
|
|||||||
|
|
||||||
message GetResourceFilesRequest {
|
message GetResourceFilesRequest {
|
||||||
string resource_id = 1;
|
string resource_id = 1;
|
||||||
string usage = 2; // Optional
|
optional string usage = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetResourceFilesResponse {
|
message GetResourceFilesResponse {
|
||||||
@ -210,7 +181,7 @@ message GetResourceFilesResponse {
|
|||||||
|
|
||||||
message DeleteResourceReferencesRequest {
|
message DeleteResourceReferencesRequest {
|
||||||
string resource_id = 1;
|
string resource_id = 1;
|
||||||
string usage = 2; // Optional
|
optional string usage = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteResourceReferencesResponse {
|
message DeleteResourceReferencesResponse {
|
||||||
|
Reference in New Issue
Block a user