MCDO fixes
add groups to individuals stuff don't show your own data lmao don't allow to share to not joined groups fix shared bug maybe fucking braces improve CharaDataGetShared() remove unnecessary double-query on get shared data optimize remove shit
This commit is contained in:
@@ -5,7 +5,6 @@ using MareSynchronosShared.Models;
|
||||
using MareSynchronosShared.Utils;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace MareSynchronosServer.Hubs;
|
||||
@@ -116,6 +115,8 @@ public partial class MareHub
|
||||
.Include(u => u.OriginalFiles)
|
||||
.Include(u => u.AllowedIndividiuals)
|
||||
.ThenInclude(u => u.AllowedUser)
|
||||
.Include(u => u.AllowedIndividiuals)
|
||||
.ThenInclude(u => u.AllowedGroup)
|
||||
.Include(u => u.Poses)
|
||||
.AsSplitQuery()
|
||||
.Where(c => c.UploaderUID == UserUID).ToListAsync().ConfigureAwait(false);
|
||||
@@ -128,48 +129,34 @@ public partial class MareHub
|
||||
{
|
||||
_logger.LogCallInfo();
|
||||
|
||||
var allPairedUsers = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
||||
List<CharaData> sharedCharaData = [];
|
||||
foreach (var pair in allPairedUsers)
|
||||
var groups = await DbContext.GroupPairs
|
||||
.Where(u => u.GroupUserUID == UserUID)
|
||||
.Select(k => k.GroupGID)
|
||||
.AsNoTracking()
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var validPairs = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
||||
|
||||
var allSharedDataByPair = await DbContext.CharaData
|
||||
.Include(u => u.Files)
|
||||
.Include(u => u.OriginalFiles)
|
||||
.Include(u => u.AllowedIndividiuals)
|
||||
.Include(u => u.Poses)
|
||||
.Include(u => u.Uploader)
|
||||
.Where(p => p.UploaderUID != UserUID && p.ShareType == CharaDataShare.Shared)
|
||||
.Where(p => (validPairs.Contains(p.UploaderUID)
|
||||
|| (p.AllowedIndividiuals.Any(u => u.AllowedUserUID == UserUID || (u.AllowedGroupGID != null && groups.Contains(u.AllowedGroupGID))))))
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
||||
foreach (var charaData in allSharedDataByPair)
|
||||
{
|
||||
var allSharedDataByPair = await DbContext.CharaData
|
||||
.Include(u => u.Files)
|
||||
.Include(u => u.OriginalFiles)
|
||||
.Include(u => u.AllowedIndividiuals)
|
||||
.Include(u => u.Poses)
|
||||
.Include(u => u.Uploader)
|
||||
.Where(p => p.ShareType == CharaDataShare.Shared && p.UploaderUID == pair)
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (var charaData in allSharedDataByPair)
|
||||
{
|
||||
if (await CheckCharaDataAllowance(charaData).ConfigureAwait(false))
|
||||
{
|
||||
sharedCharaData.Add(charaData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var charaDataDirectlyShared = await DbContext.CharaData.Include(u => u.Files)
|
||||
.Include(u => u.OriginalFiles)
|
||||
.Include(u => u.AllowedIndividiuals)
|
||||
.Include(u => u.Poses)
|
||||
.Include(u => u.Uploader)
|
||||
.Where(p => p.ShareType == CharaDataShare.Shared && p.AllowedIndividiuals.Any(u => u.AllowedUserUID == UserUID))
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
foreach (var data in charaDataDirectlyShared)
|
||||
{
|
||||
if (sharedCharaData.Exists(d => string.Equals(d.Id, data.Id, StringComparison.Ordinal)
|
||||
&& string.Equals(d.UploaderUID, d.UploaderUID, StringComparison.Ordinal)))
|
||||
continue;
|
||||
sharedCharaData.Add(data);
|
||||
sharedCharaData.Add(charaData);
|
||||
}
|
||||
|
||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS", sharedCharaData.Count));
|
||||
@@ -185,6 +172,8 @@ public partial class MareHub
|
||||
.Include(u => u.OriginalFiles)
|
||||
.Include(u => u.AllowedIndividiuals)
|
||||
.ThenInclude(u => u.AllowedUser)
|
||||
.Include(u => u.AllowedIndividiuals)
|
||||
.ThenInclude(u => u.AllowedGroup)
|
||||
.Include(u => u.FileSwaps)
|
||||
.Include(u => u.Poses)
|
||||
.AsSplitQuery()
|
||||
@@ -239,29 +228,67 @@ public partial class MareHub
|
||||
|
||||
if (updateDto.AllowedUsers != null)
|
||||
{
|
||||
var individuals = charaData.AllowedIndividiuals.ToList();
|
||||
charaData.AllowedIndividiuals.Clear();
|
||||
DbContext.RemoveRange(individuals);
|
||||
var individuals = charaData.AllowedIndividiuals.Where(k => k.AllowedGroup == null).ToList();
|
||||
var allowedUserList = updateDto.AllowedUsers.ToList();
|
||||
foreach (var user in updateDto.AllowedUsers)
|
||||
{
|
||||
var dbUser = await DbContext.Users.SingleOrDefaultAsync(u => u.UID == user || u.Alias == user).ConfigureAwait(false);
|
||||
if (dbUser != null)
|
||||
if (charaData.AllowedIndividiuals.Any(k => k.AllowedUser != null && (string.Equals(k.AllowedUser.UID, user, StringComparison.Ordinal) || string.Equals(k.AllowedUser.Alias, user, StringComparison.Ordinal))))
|
||||
{
|
||||
if (!allowedUserList.Contains(dbUser.UID, StringComparer.Ordinal) && !allowedUserList.Contains(dbUser.Alias, StringComparer.Ordinal))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
var dbUser = await DbContext.Users.SingleOrDefaultAsync(u => u.UID == user || u.Alias == user).ConfigureAwait(false);
|
||||
if (dbUser != null)
|
||||
{
|
||||
continue;
|
||||
charaData.AllowedIndividiuals.Add(new CharaDataAllowance()
|
||||
{
|
||||
AllowedUser = dbUser,
|
||||
Parent = charaData
|
||||
});
|
||||
}
|
||||
allowedUserList.RemoveAll(u => string.Equals(u, dbUser.UID, StringComparison.Ordinal));
|
||||
allowedUserList.RemoveAll(u => string.Equals(u, dbUser.Alias, StringComparison.Ordinal));
|
||||
|
||||
charaData.AllowedIndividiuals.Add(new CharaDataAllowance()
|
||||
{
|
||||
AllowedUser = dbUser,
|
||||
Parent = charaData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dataUser in individuals.Where(k => !updateDto.AllowedUsers.Contains(k.AllowedUser.UID, StringComparer.Ordinal) && !updateDto.AllowedUsers.Contains(k.AllowedUser.Alias, StringComparer.Ordinal)))
|
||||
{
|
||||
DbContext.Remove(dataUser);
|
||||
charaData.AllowedIndividiuals.Remove(dataUser);
|
||||
}
|
||||
|
||||
anyChanges = true;
|
||||
}
|
||||
|
||||
if (updateDto.AllowedGroups != null)
|
||||
{
|
||||
var individualGroups = charaData.AllowedIndividiuals.Where(k => k.AllowedUser == null).ToList();
|
||||
var allowedGroups = updateDto.AllowedGroups.ToList();
|
||||
foreach (var group in updateDto.AllowedGroups)
|
||||
{
|
||||
if (charaData.AllowedIndividiuals.Any(k => k.AllowedGroup != null && (string.Equals(k.AllowedGroup.GID, group, StringComparison.Ordinal) || string.Equals(k.AllowedGroup.Alias, group, StringComparison.Ordinal))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
var groupUser = await DbContext.GroupPairs.Include(u => u.Group).SingleOrDefaultAsync(u => (u.Group.GID == group || u.Group.Alias == group) && u.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||
if (groupUser != null)
|
||||
{
|
||||
charaData.AllowedIndividiuals.Add(new CharaDataAllowance()
|
||||
{
|
||||
AllowedGroup = groupUser.Group,
|
||||
Parent = charaData
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dataGroup in individualGroups.Where(k => !updateDto.AllowedGroups.Contains(k.AllowedGroup.GID, StringComparer.Ordinal) && !updateDto.AllowedGroups.Contains(k.AllowedGroup.Alias, StringComparer.Ordinal)))
|
||||
{
|
||||
DbContext.Remove(dataGroup);
|
||||
charaData.AllowedIndividiuals.Remove(dataGroup);
|
||||
}
|
||||
|
||||
anyChanges = true;
|
||||
}
|
||||
|
||||
@@ -411,7 +438,8 @@ public partial class MareHub
|
||||
{
|
||||
AccessType = GetAccessTypeDto(charaData.AccessType),
|
||||
ShareType = GetShareTypeDto(charaData.ShareType),
|
||||
AllowedUsers = [.. charaData.AllowedIndividiuals.Select(u => new UserData(u.AllowedUser.UID, u.AllowedUser.Alias))],
|
||||
AllowedUsers = [.. charaData.AllowedIndividiuals.Where(k => !string.IsNullOrEmpty(k.AllowedUserUID)).Select(u => new UserData(u.AllowedUser.UID, u.AllowedUser.Alias))],
|
||||
AllowedGroups = [.. charaData.AllowedIndividiuals.Where(k => !string.IsNullOrEmpty(k.AllowedGroupGID)).Select(k => new GroupData(k.AllowedGroup.GID, k.AllowedGroup.Alias))],
|
||||
CustomizeData = charaData.CustomizeData,
|
||||
Description = charaData.Description,
|
||||
ExpiryDate = charaData.ExpiryDate ?? DateTime.MaxValue,
|
||||
@@ -477,7 +505,7 @@ public partial class MareHub
|
||||
_ => throw new NotSupportedException(),
|
||||
};
|
||||
|
||||
private async Task<bool> CheckCharaDataAllowance(CharaData charaData)
|
||||
private async Task<bool> CheckCharaDataAllowance(CharaData charaData, List<string> joinedGroups)
|
||||
{
|
||||
// check for self
|
||||
if (string.Equals(charaData.UploaderUID, UserUID, StringComparison.Ordinal))
|
||||
@@ -544,7 +572,10 @@ public partial class MareHub
|
||||
throw new InvalidDataException($"No chara data with {id} found");
|
||||
}
|
||||
|
||||
if (!await CheckCharaDataAllowance(charaData).ConfigureAwait(false))
|
||||
var groups = await DbContext.GroupPairs.Where(u => u.GroupUserUID == UserUID).Select(k => k.GroupGID).ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!await CheckCharaDataAllowance(charaData, groups).ConfigureAwait(false))
|
||||
{
|
||||
_logger.LogCallWarning(MareHubLogger.Args("UNAUTHORIZED", id));
|
||||
throw new UnauthorizedAccessException($"User is not allowed to download {id}");
|
||||
|
||||
@@ -262,6 +262,9 @@ public partial class MareHub
|
||||
}
|
||||
}
|
||||
|
||||
var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == userUid).ToListAsync().ConfigureAwait(false);
|
||||
DbContext.CharaDataAllowances.RemoveRange(sharedData);
|
||||
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
||||
|
||||
@@ -191,6 +191,9 @@ public partial class MareHub
|
||||
|
||||
var allUserPairs = await GetAllPairedClientsWithPauseState(pair.GroupUserUID).ConfigureAwait(false);
|
||||
|
||||
var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == pair.GroupUserUID).ToListAsync().ConfigureAwait(false);
|
||||
DbContext.CharaDataAllowances.RemoveRange(sharedData);
|
||||
|
||||
foreach (var groupUserPair in groupPairs.Where(p => !string.Equals(p.GroupUserUID, pair.GroupUserUID, StringComparison.Ordinal)))
|
||||
{
|
||||
await UserGroupLeave(groupUserPair, allUserPairs, pairIdent).ConfigureAwait(false);
|
||||
@@ -463,6 +466,11 @@ public partial class MareHub
|
||||
var groupPairs = DbContext.GroupPairs.Where(p => p.GroupGID == group.GID).AsNoTracking().ToList();
|
||||
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupPairLeft(dto).ConfigureAwait(false);
|
||||
|
||||
var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == dto.UID).ToListAsync().ConfigureAwait(false);
|
||||
DbContext.CharaDataAllowances.RemoveRange(sharedData);
|
||||
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
var userIdent = await GetUserIdent(dto.User.UID).ConfigureAwait(false);
|
||||
if (userIdent == null) return;
|
||||
|
||||
|
||||
@@ -122,7 +122,10 @@ public class MareDbContext : DbContext
|
||||
mb.Entity<CharaDataOriginalFile>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.GamePath });
|
||||
mb.Entity<CharaDataOriginalFile>().HasIndex(c => c.ParentId);
|
||||
mb.Entity<CharaDataAllowance>().ToTable("chara_data_allowance");
|
||||
mb.Entity<CharaDataAllowance>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.AllowedUserUID });
|
||||
mb.Entity<CharaDataAllowance>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.Id });
|
||||
mb.Entity<CharaDataAllowance>().Property(p => p.Id).ValueGeneratedOnAdd();
|
||||
mb.Entity<CharaDataAllowance>().HasIndex(c => c.ParentId);
|
||||
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedGroup).WithMany().HasForeignKey(u => u.AllowedGroupGID).OnDelete(DeleteBehavior.Cascade);
|
||||
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedUser).WithMany().HasForeignKey(u => u.AllowedUserUID).OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
1094
MareSynchronosServer/MareSynchronosShared/Migrations/20250627204223_AllowedGroup.Designer.cs
generated
Normal file
1094
MareSynchronosServer/MareSynchronosShared/Migrations/20250627204223_AllowedGroup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,98 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MareSynchronosServer.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AllowedGroup : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "pk_chara_data_allowance",
|
||||
table: "chara_data_allowance");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "allowed_user_uid",
|
||||
table: "chara_data_allowance",
|
||||
type: "character varying(10)",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(10)");
|
||||
|
||||
migrationBuilder.AddColumn<long>(
|
||||
name: "id",
|
||||
table: "chara_data_allowance",
|
||||
type: "bigint",
|
||||
nullable: false,
|
||||
defaultValue: 0L)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "allowed_group_gid",
|
||||
table: "chara_data_allowance",
|
||||
type: "character varying(20)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "pk_chara_data_allowance",
|
||||
table: "chara_data_allowance",
|
||||
columns: new[] { "parent_id", "parent_uploader_uid", "id" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_chara_data_allowance_allowed_group_gid",
|
||||
table: "chara_data_allowance",
|
||||
column: "allowed_group_gid");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "fk_chara_data_allowance_groups_allowed_group_gid",
|
||||
table: "chara_data_allowance",
|
||||
column: "allowed_group_gid",
|
||||
principalTable: "groups",
|
||||
principalColumn: "gid",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "fk_chara_data_allowance_groups_allowed_group_gid",
|
||||
table: "chara_data_allowance");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "pk_chara_data_allowance",
|
||||
table: "chara_data_allowance");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "ix_chara_data_allowance_allowed_group_gid",
|
||||
table: "chara_data_allowance");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "id",
|
||||
table: "chara_data_allowance");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "allowed_group_gid",
|
||||
table: "chara_data_allowance");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "allowed_user_uid",
|
||||
table: "chara_data_allowance",
|
||||
type: "character varying(10)",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(10)",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "pk_chara_data_allowance",
|
||||
table: "chara_data_allowance",
|
||||
columns: new[] { "parent_id", "parent_uploader_uid", "allowed_user_uid" });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,13 +161,27 @@ namespace MareSynchronosServer.Migrations
|
||||
.HasColumnType("character varying(10)")
|
||||
.HasColumnName("parent_uploader_uid");
|
||||
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("AllowedGroupGID")
|
||||
.HasColumnType("character varying(20)")
|
||||
.HasColumnName("allowed_group_gid");
|
||||
|
||||
b.Property<string>("AllowedUserUID")
|
||||
.HasColumnType("character varying(10)")
|
||||
.HasColumnName("allowed_user_uid");
|
||||
|
||||
b.HasKey("ParentId", "ParentUploaderUID", "AllowedUserUID")
|
||||
b.HasKey("ParentId", "ParentUploaderUID", "Id")
|
||||
.HasName("pk_chara_data_allowance");
|
||||
|
||||
b.HasIndex("AllowedGroupGID")
|
||||
.HasDatabaseName("ix_chara_data_allowance_allowed_group_gid");
|
||||
|
||||
b.HasIndex("AllowedUserUID")
|
||||
.HasDatabaseName("ix_chara_data_allowance_allowed_user_uid");
|
||||
|
||||
@@ -737,11 +751,16 @@ namespace MareSynchronosServer.Migrations
|
||||
|
||||
modelBuilder.Entity("MareSynchronosShared.Models.CharaDataAllowance", b =>
|
||||
{
|
||||
b.HasOne("MareSynchronosShared.Models.Group", "AllowedGroup")
|
||||
.WithMany()
|
||||
.HasForeignKey("AllowedGroupGID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.HasConstraintName("fk_chara_data_allowance_groups_allowed_group_gid");
|
||||
|
||||
b.HasOne("MareSynchronosShared.Models.User", "AllowedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("AllowedUserUID")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_chara_data_allowance_users_allowed_user_uid");
|
||||
|
||||
b.HasOne("MareSynchronosShared.Models.CharaData", "Parent")
|
||||
@@ -751,6 +770,8 @@ namespace MareSynchronosServer.Migrations
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_chara_data_allowance_chara_data_parent_id_parent_uploader_u");
|
||||
|
||||
b.Navigation("AllowedGroup");
|
||||
|
||||
b.Navigation("AllowedUser");
|
||||
|
||||
b.Navigation("Parent");
|
||||
|
||||
@@ -40,11 +40,15 @@ public class CharaData
|
||||
|
||||
public class CharaDataAllowance
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
public virtual CharaData Parent { get; set; }
|
||||
public string ParentId { get; set; }
|
||||
public string ParentUploaderUID { get; set; }
|
||||
public virtual User AllowedUser { get; set; }
|
||||
public string AllowedUserUID { get; set; }
|
||||
public virtual User? AllowedUser { get; set; }
|
||||
public string? AllowedUserUID { get; set; }
|
||||
public virtual Group? AllowedGroup { get; set; }
|
||||
public string? AllowedGroupGID { get; set; }
|
||||
}
|
||||
|
||||
public class CharaDataOriginalFile
|
||||
|
||||
Reference in New Issue
Block a user