1
0
mirror of https://github.com/bitwarden/server synced 2026-01-03 00:53:37 +00:00

PM-25576 made changes to member access query to use views and add avatar color.

This commit is contained in:
Graham Walker
2025-11-19 22:24:09 -06:00
parent 3c874646e8
commit 3a69a68609
22 changed files with 10817 additions and 106 deletions

View File

@@ -8,6 +8,7 @@ public class MemberAccessReportDetail
public Guid? UserGuid { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string AvatarColor { get; set; }
public bool TwoFactorEnabled { get; set; }
public bool AccountRecoveryEnabled { get; set; }
public bool UsesKeyConnector { get; set; }

View File

@@ -1,13 +1,14 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
namespace Bit.Core.Dirt.Reports.Models.Data;
namespace Bit.Core.Dirt.Models.Data;
public class OrganizationMemberBaseDetail
{
public Guid? UserGuid { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string AvatarColor { get; set; }
public string TwoFactorProviders { get; set; }
public bool UsesKeyConnector { get; set; }
public string ResetPasswordKey { get; set; }
@@ -18,5 +19,5 @@ public class OrganizationMemberBaseDetail
public bool? ReadOnly { get; set; }
public bool? HidePasswords { get; set; }
public bool? Manage { get; set; }
public Guid CipherId { get; set; }
public Guid? CipherId { get; set; }
}

View File

@@ -48,6 +48,7 @@ public class MemberAccessReportQuery(
b.UserGuid,
b.UserName,
b.Email,
b.AvatarColor,
b.TwoFactorProviders,
b.ResetPasswordKey,
b.UsesKeyConnector,
@@ -64,6 +65,7 @@ public class MemberAccessReportQuery(
UserGuid = g.Key.UserGuid,
UserName = g.Key.UserName,
Email = g.Key.Email,
AvatarColor = g.Key.AvatarColor,
TwoFactorEnabled = orgUsersTwoFactorEnabled.FirstOrDefault(x => x.userId == g.Key.UserGuid).twoFactorIsEnabled,
AccountRecoveryEnabled = !string.IsNullOrWhiteSpace(g.Key.ResetPasswordKey) && orgAbility.UseResetPassword,
UsesKeyConnector = g.Key.UsesKeyConnector,
@@ -74,7 +76,7 @@ public class MemberAccessReportQuery(
ReadOnly = g.Key.ReadOnly,
HidePasswords = g.Key.HidePasswords,
Manage = g.Key.Manage,
CipherIds = g.Select(c => c.CipherId)
CipherIds = g.Select(c => c.CipherId).Where(id => id.HasValue).Select(id => id.Value)
});
var accessDetailsCount = accessDetails.Count();

View File

@@ -1,4 +1,4 @@
using Bit.Core.Dirt.Reports.Models.Data;
using Bit.Core.Dirt.Models.Data;
namespace Bit.Core.Dirt.Reports.Repositories;

View File

@@ -1,5 +1,5 @@
using System.Data;
using Bit.Core.Dirt.Reports.Models.Data;
using Bit.Core.Dirt.Models.Data;
using Bit.Core.Dirt.Reports.Repositories;
using Bit.Core.Settings;
using Bit.Infrastructure.Dapper.Repositories;

View File

@@ -1,12 +1,12 @@
using AutoMapper;
using Bit.Core.Dirt.Reports.Models.Data;
using Bit.Core.Dirt.Models.Data;
using Bit.Core.Dirt.Reports.Repositories;
using Bit.Infrastructure.EntityFramework.Repositories;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Bit.Infrastructure.EntityFramework.Dirt;
namespace Bit.Infrastructure.EntityFramework.Dirt.Repositories;
public class OrganizationMemberBaseDetailRepository : BaseEntityFrameworkRepository, IOrganizationMemberBaseDetailRepository
{

View File

@@ -1,5 +1,5 @@
using Bit.Core;
using Bit.Core.Dirt.Reports.Models.Data;
using Bit.Core.Dirt.Models.Data;
using Bit.Infrastructure.EntityFramework.AdminConsole.Models;
using Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider;
using Bit.Infrastructure.EntityFramework.Auth.Models;

View File

@@ -0,0 +1,109 @@
CREATE PROCEDURE dbo.MemberAccessReport_GetMemberAccessCipherDetailsByOrganizationId
@OrganizationId UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
IF @OrganizationId IS NULL
THROW 50000, 'OrganizationId cannot be null', 1;
-- Direct user-collection permissions
SELECT
OU.[Id] AS [UserGuid],
OU.[Name] AS [UserName],
OU.[Email],
OU.[AvatarColor],
OU.[TwoFactorProviders],
OU.[UsesKeyConnector],
OU.[ResetPasswordKey],
CUP.[CollectionId],
CUP.[CollectionName],
NULL AS [GroupId],
NULL AS [GroupName],
CUP.[ReadOnly],
CUP.[HidePasswords],
CUP.[Manage],
CCD.[CipherId]
FROM
[dbo].[OrganizationUserUserDetailsView] OU
INNER JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
INNER JOIN
[dbo].[CollectionUserPermissionsView] CUP ON CUP.[OrganizationUserId] = OU.[Id]
INNER JOIN
[dbo].[CollectionCipherDetailsView] CCD ON CCD.[CollectionId] = CUP.[CollectionId]
WHERE
O.[Id] = @OrganizationId
AND O.[Enabled] = 1
AND CUP.[OrganizationId] = @OrganizationId
AND CCD.[CipherOrganizationId] = @OrganizationId
AND OU.[Status] IN (0, 1, 2) -- Invited, Accepted, Confirmed
AND CCD.[DeletedDate] IS NULL
UNION ALL
-- Group-based collection permissions
SELECT
OU.[Id] AS [UserGuid],
OU.[Name] AS [UserName],
OU.[Email],
OU.[AvatarColor],
OU.[TwoFactorProviders],
OU.[UsesKeyConnector],
OU.[ResetPasswordKey],
CGP.[CollectionId],
CGP.[CollectionName],
CGP.[GroupId],
CGP.[GroupName],
CGP.[ReadOnly],
CGP.[HidePasswords],
CGP.[Manage],
CCD.[CipherId]
FROM
[dbo].[OrganizationUserUserDetailsView] OU
INNER JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
INNER JOIN
[dbo].[CollectionGroupPermissionsView] CGP ON CGP.[OrganizationUserId] = OU.[Id]
INNER JOIN
[dbo].[CollectionCipherDetailsView] CCD ON CCD.[CollectionId] = CGP.[CollectionId]
WHERE
O.[Id] = @OrganizationId
AND O.[Enabled] = 1
AND CGP.[OrganizationId] = @OrganizationId
AND CCD.[CipherOrganizationId] = @OrganizationId
AND OU.[Status] IN (0, 1, 2) -- Invited, Accepted, Confirmed
AND CCD.[DeletedDate] IS NULL
UNION ALL
-- Users without collection access
SELECT
OU.[Id] AS [UserGuid],
OU.[Name] AS [UserName],
OU.[Email],
OU.[AvatarColor],
OU.[TwoFactorProviders],
OU.[UsesKeyConnector],
OU.[ResetPasswordKey],
NULL AS [CollectionId],
NULL AS [CollectionName],
NULL AS [GroupId],
NULL AS [GroupName],
NULL AS [ReadOnly],
NULL AS [HidePasswords],
NULL AS [Manage],
NULL AS [CipherId]
FROM
[dbo].[OrganizationUserUserDetailsView] OU
INNER JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
WHERE
O.[Id] = @OrganizationId
AND O.[Enabled] = 1
AND OU.[Status] IN (0, 1, 2) -- Invited, Accepted, Confirmed
AND NOT EXISTS (
SELECT 1
FROM [dbo].[CollectionUserPermissionsView] CUP
WHERE CUP.[OrganizationUserId] = OU.[Id]
AND CUP.[OrganizationId] = @OrganizationId
);

View File

@@ -1,92 +0,0 @@
CREATE PROCEDURE dbo.MemberAccessReport_GetMemberAccessCipherDetailsByOrganizationId
@OrganizationId UNIQUEIDENTIFIER
AS
SET NOCOUNT ON;
IF @OrganizationId IS NULL
THROW 50000, 'OrganizationId cannot be null', 1;
SELECT
OU.Id AS UserGuid,
U.Name AS UserName,
ISNULL(U.Email, OU.Email) as 'Email',
U.TwoFactorProviders,
U.UsesKeyConnector,
OU.ResetPasswordKey,
CC.CollectionId,
C.Name AS CollectionName,
NULL AS GroupId,
NULL AS GroupName,
CU.ReadOnly,
CU.HidePasswords,
CU.Manage,
Cipher.Id AS CipherId
FROM dbo.OrganizationUser OU
LEFT JOIN dbo.[User] U ON U.Id = OU.UserId
INNER JOIN dbo.Organization O ON O.Id = OU.OrganizationId
AND O.Id = @OrganizationId
AND O.Enabled = 1
INNER JOIN dbo.CollectionUser CU ON CU.OrganizationUserId = OU.Id
INNER JOIN dbo.Collection C ON C.Id = CU.CollectionId and C.OrganizationId = @OrganizationId
INNER JOIN dbo.CollectionCipher CC ON CC.CollectionId = C.Id
INNER JOIN dbo.Cipher Cipher ON Cipher.Id = CC.CipherId AND Cipher.OrganizationId = @OrganizationId
WHERE OU.Status IN (0,1,2) -- Invited, Accepted and Confirmed Users
AND Cipher.DeletedDate IS NULL
UNION ALL
-- Group-based collection permissions
SELECT
OU.Id AS UserGuid,
U.Name AS UserName,
ISNULL(U.Email, OU.Email) as 'Email',
U.TwoFactorProviders,
U.UsesKeyConnector,
OU.ResetPasswordKey,
CC.CollectionId,
C.Name AS CollectionName,
G.Id AS GroupId,
G.Name AS GroupName,
CG.ReadOnly,
CG.HidePasswords,
CG.Manage,
Cipher.Id AS CipherId
FROM dbo.OrganizationUser OU
LEFT JOIN dbo.[User] U ON U.Id = OU.UserId
INNER JOIN dbo.Organization O ON O.Id = OU.OrganizationId
AND O.Id = @OrganizationId
AND O.Enabled = 1
INNER JOIN dbo.GroupUser GU ON GU.OrganizationUserId = OU.Id
INNER JOIN dbo.[Group] G ON G.Id = GU.GroupId
INNER JOIN dbo.CollectionGroup CG ON CG.GroupId = G.Id
INNER JOIN dbo.Collection C ON C.Id = CG.CollectionId AND C.OrganizationId = @OrganizationId
INNER JOIN dbo.CollectionCipher CC ON CC.CollectionId = C.Id
INNER JOIN dbo.Cipher Cipher ON Cipher.Id = CC.CipherId and Cipher.OrganizationId = @OrganizationId
WHERE OU.Status IN (0,1,2) -- Invited, Accepted and Confirmed Users
AND Cipher.DeletedDate IS NULL
UNION ALL
-- Users without collection access (invited users)
-- typically invited users who have not yet accepted the invitation
-- and not yet assigned to any collection
SELECT
OU.Id AS UserGuid,
U.Name AS UserName,
ISNULL(U.Email, OU.Email) as 'Email',
U.TwoFactorProviders,
U.UsesKeyConnector,
OU.ResetPasswordKey,
null as CollectionId,
null AS CollectionName,
NULL AS GroupId,
NULL AS GroupName,
null as [ReadOnly],
null as HidePasswords,
null as Manage,
null AS CipherId
FROM dbo.OrganizationUser OU
LEFT JOIN dbo.[User] U ON U.Id = OU.UserId
INNER JOIN dbo.Organization O ON O.Id = OU.OrganizationId AND O.Id = @OrganizationId AND O.Enabled = 1
WHERE OU.Status IN (0,1,2) -- Invited, Accepted and Confirmed Users
AND OU.Id not in (
select OU1.Id from dbo.OrganizationUser OU1
inner join dbo.CollectionUser CU1 on CU1.OrganizationUserId = OU1.Id
WHERE OU1.OrganizationId = @organizationId
)

View File

@@ -0,0 +1,15 @@
CREATE OR ALTER VIEW [dbo].[CollectionCipherDetailsView]
AS
SELECT
CC.[CollectionId],
C.[OrganizationId] AS [CollectionOrganizationId],
CC.[CipherId],
Ci.[OrganizationId] AS [CipherOrganizationId],
Ci.[DeletedDate]
FROM
[dbo].[CollectionCipher] CC
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CC.[CollectionId]
INNER JOIN
[dbo].[Cipher] Ci ON Ci.[Id] = CC.[CipherId]
GO

View File

@@ -0,0 +1,21 @@
CREATE OR ALTER VIEW [dbo].[CollectionGroupPermissionsView]
AS
SELECT
GU.[OrganizationUserId],
G.[Id] AS [GroupId],
G.[Name] AS [GroupName],
G.[OrganizationId],
CG.[CollectionId],
C.[Name] AS [CollectionName],
CG.[ReadOnly],
CG.[HidePasswords],
CG.[Manage]
FROM
[dbo].[GroupUser] GU
INNER JOIN
[dbo].[Group] G ON G.[Id] = GU.[GroupId]
INNER JOIN
[dbo].[CollectionGroup] CG ON CG.[GroupId] = G.[Id]
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CG.[CollectionId]
GO

View File

@@ -0,0 +1,15 @@
CREATE OR ALTER VIEW [dbo].[CollectionUserPermissionsView]
AS
SELECT
CU.[OrganizationUserId],
CU.[CollectionId],
C.[OrganizationId],
C.[Name] AS [CollectionName],
CU.[ReadOnly],
CU.[HidePasswords],
CU.[Manage]
FROM
[dbo].[CollectionUser] CU
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CU.[CollectionId]
GO

View File

@@ -0,0 +1,166 @@
CREATE OR ALTER VIEW [dbo].[CollectionCipherDetailsView]
AS
SELECT
CC.[CollectionId],
C.[OrganizationId] AS [CollectionOrganizationId],
CC.[CipherId],
Ci.[OrganizationId] AS [CipherOrganizationId],
Ci.[DeletedDate]
FROM
[dbo].[CollectionCipher] CC
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CC.[CollectionId]
INNER JOIN
[dbo].[Cipher] Ci ON Ci.[Id] = CC.[CipherId]
GO
CREATE OR ALTER VIEW [dbo].[CollectionGroupPermissionsView]
AS
SELECT
GU.[OrganizationUserId],
G.[Id] AS [GroupId],
G.[Name] AS [GroupName],
G.[OrganizationId],
CG.[CollectionId],
C.[Name] AS [CollectionName],
CG.[ReadOnly],
CG.[HidePasswords],
CG.[Manage]
FROM
[dbo].[GroupUser] GU
INNER JOIN
[dbo].[Group] G ON G.[Id] = GU.[GroupId]
INNER JOIN
[dbo].[CollectionGroup] CG ON CG.[GroupId] = G.[Id]
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CG.[CollectionId]
GO
CREATE OR ALTER VIEW [dbo].[CollectionUserPermissionsView]
AS
SELECT
CU.[OrganizationUserId],
CU.[CollectionId],
C.[OrganizationId],
C.[Name] AS [CollectionName],
CU.[ReadOnly],
CU.[HidePasswords],
CU.[Manage]
FROM
[dbo].[CollectionUser] CU
INNER JOIN
[dbo].[Collection] C ON C.[Id] = CU.[CollectionId]
GO
CREATE OR ALTER PROCEDURE [dbo].[MemberAccessReport_GetMemberAccessCipherDetailsByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
IF @OrganizationId IS NULL
THROW 50000, 'OrganizationId cannot be null', 1;
-- Direct user-collection permissions
SELECT
OU.[Id] AS [UserGuid],
OU.[Name] AS [UserName],
OU.[Email],
OU.[AvatarColor],
OU.[TwoFactorProviders],
OU.[UsesKeyConnector],
OU.[ResetPasswordKey],
CUP.[CollectionId],
CUP.[CollectionName],
NULL AS [GroupId],
NULL AS [GroupName],
CUP.[ReadOnly],
CUP.[HidePasswords],
CUP.[Manage],
CCD.[CipherId]
FROM
[dbo].[OrganizationUserUserDetailsView] OU
INNER JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
INNER JOIN
[dbo].[CollectionUserPermissionsView] CUP ON CUP.[OrganizationUserId] = OU.[Id]
INNER JOIN
[dbo].[CollectionCipherDetailsView] CCD ON CCD.[CollectionId] = CUP.[CollectionId]
WHERE
O.[Id] = @OrganizationId
AND O.[Enabled] = 1
AND CUP.[OrganizationId] = @OrganizationId
AND CCD.[CipherOrganizationId] = @OrganizationId
AND OU.[Status] IN (0, 1, 2) -- Invited, Accepted, Confirmed
AND CCD.[DeletedDate] IS NULL
UNION ALL
-- Group-based collection permissions
SELECT
OU.[Id] AS [UserGuid],
OU.[Name] AS [UserName],
OU.[Email],
OU.[AvatarColor],
OU.[TwoFactorProviders],
OU.[UsesKeyConnector],
OU.[ResetPasswordKey],
CGP.[CollectionId],
CGP.[CollectionName],
CGP.[GroupId],
CGP.[GroupName],
CGP.[ReadOnly],
CGP.[HidePasswords],
CGP.[Manage],
CCD.[CipherId]
FROM
[dbo].[OrganizationUserUserDetailsView] OU
INNER JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
INNER JOIN
[dbo].[CollectionGroupPermissionsView] CGP ON CGP.[OrganizationUserId] = OU.[Id]
INNER JOIN
[dbo].[CollectionCipherDetailsView] CCD ON CCD.[CollectionId] = CGP.[CollectionId]
WHERE
O.[Id] = @OrganizationId
AND O.[Enabled] = 1
AND CGP.[OrganizationId] = @OrganizationId
AND CCD.[CipherOrganizationId] = @OrganizationId
AND OU.[Status] IN (0, 1, 2) -- Invited, Accepted, Confirmed
AND CCD.[DeletedDate] IS NULL
UNION ALL
-- Users without collection access
SELECT
OU.[Id] AS [UserGuid],
OU.[Name] AS [UserName],
OU.[Email],
OU.[AvatarColor],
OU.[TwoFactorProviders],
OU.[UsesKeyConnector],
OU.[ResetPasswordKey],
NULL AS [CollectionId],
NULL AS [CollectionName],
NULL AS [GroupId],
NULL AS [GroupName],
NULL AS [ReadOnly],
NULL AS [HidePasswords],
NULL AS [Manage],
NULL AS [CipherId]
FROM
[dbo].[OrganizationUserUserDetailsView] OU
INNER JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
WHERE
O.[Id] = @OrganizationId
AND O.[Enabled] = 1
AND OU.[Status] IN (0, 1, 2) -- Invited, Accepted, Confirmed
AND NOT EXISTS (
SELECT 1
FROM [dbo].[CollectionUserPermissionsView] CUP
WHERE CUP.[OrganizationUserId] = OU.[Id]
AND CUP.[OrganizationId] = @OrganizationId
)
END
GO

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
/// <inheritdoc />
public partial class _20251119_00_UpdateMemberAccessQuery : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<Guid>(
name: "CipherId",
table: "OrganizationMemberBaseDetails",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AddColumn<string>(
name: "AvatarColor",
table: "OrganizationMemberBaseDetails",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AvatarColor",
table: "OrganizationMemberBaseDetails");
migrationBuilder.AlterColumn<Guid>(
name: "CipherId",
table: "OrganizationMemberBaseDetails",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
}
}

View File

@@ -22,9 +22,12 @@ namespace Bit.MySqlMigrations.Migrations
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Bit.Core.Dirt.Reports.Models.Data.OrganizationMemberBaseDetail", b =>
modelBuilder.Entity("Bit.Core.Dirt.Models.Data.OrganizationMemberBaseDetail", b =>
{
b.Property<Guid>("CipherId")
b.Property<string>("AvatarColor")
.HasColumnType("longtext");
b.Property<Guid?>("CipherId")
.HasColumnType("char(36)");
b.Property<Guid?>("CollectionId")

View File

@@ -0,0 +1,45 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
/// <inheritdoc />
public partial class _20251119_00_UpdateMemberAccessQuery : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<Guid>(
name: "CipherId",
table: "OrganizationMemberBaseDetails",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AddColumn<string>(
name: "AvatarColor",
table: "OrganizationMemberBaseDetails",
type: "text",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AvatarColor",
table: "OrganizationMemberBaseDetails");
migrationBuilder.AlterColumn<Guid>(
name: "CipherId",
table: "OrganizationMemberBaseDetails",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
}
}

View File

@@ -23,9 +23,12 @@ namespace Bit.PostgresMigrations.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Bit.Core.Dirt.Reports.Models.Data.OrganizationMemberBaseDetail", b =>
modelBuilder.Entity("Bit.Core.Dirt.Models.Data.OrganizationMemberBaseDetail", b =>
{
b.Property<Guid>("CipherId")
b.Property<string>("AvatarColor")
.HasColumnType("text");
b.Property<Guid?>("CipherId")
.HasColumnType("uuid");
b.Property<Guid?>("CollectionId")

View File

@@ -0,0 +1,45 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
/// <inheritdoc />
public partial class _20251119_00_UpdateMemberAccessQuery : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<Guid>(
name: "CipherId",
table: "OrganizationMemberBaseDetails",
type: "TEXT",
nullable: true,
oldClrType: typeof(Guid),
oldType: "TEXT");
migrationBuilder.AddColumn<string>(
name: "AvatarColor",
table: "OrganizationMemberBaseDetails",
type: "TEXT",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AvatarColor",
table: "OrganizationMemberBaseDetails");
migrationBuilder.AlterColumn<Guid>(
name: "CipherId",
table: "OrganizationMemberBaseDetails",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "TEXT",
oldNullable: true);
}
}

View File

@@ -17,9 +17,12 @@ namespace Bit.SqliteMigrations.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.8");
modelBuilder.Entity("Bit.Core.Dirt.Reports.Models.Data.OrganizationMemberBaseDetail", b =>
modelBuilder.Entity("Bit.Core.Dirt.Models.Data.OrganizationMemberBaseDetail", b =>
{
b.Property<Guid>("CipherId")
b.Property<string>("AvatarColor")
.HasColumnType("TEXT");
b.Property<Guid?>("CipherId")
.HasColumnType("TEXT");
b.Property<Guid?>("CollectionId")